Skip to content

Commit

Permalink
feat: jetty-9 http client, commit for PR comments
Browse files Browse the repository at this point in the history
  • Loading branch information
robododge committed May 25, 2021
1 parent b4cab9b commit ea3274d
Show file tree
Hide file tree
Showing 11 changed files with 605 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
apply from: "$rootDir/gradle/instrumentation.gradle"

muzzle {
pass {
group = "org.eclipse.jetty"
module = 'jetty-client'
versions = "[9.1,10)"
assertInverse = true
}
}

def jettyVers = [:]

//Jetty client 9.1 is the best starting point for the v9.x series, v9.0.x is incompatible
jettyVers.base9 = '9.1.0.v20131115'
//jettyVers.base9 = '9.0.0.v20130308'
jettyVers.useInTests9 = '9.3.28.v20191105'

dependencies {
implementation project(':instrumentation:jetty-httpclient:jetty-httpclient-9.0:library')

library "org.eclipse.jetty:jetty-client:${jettyVers.base9}"

testImplementation project(':instrumentation:jetty-httpclient:jetty-httpclient-9.0:testing')
testLibrary "org.eclipse.jetty:jetty-server:${jettyVers.useInTests9}"

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.jetty.httpclient.v9_0;

import static io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge.currentContext;
import static io.opentelemetry.javaagent.instrumentation.jetty.httpclient.v9_0.JettyHttpClient9Tracer.tracer;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static net.bytebuddy.matcher.ElementMatchers.hasSuperType;
import static net.bytebuddy.matcher.ElementMatchers.isInterface;
import static net.bytebuddy.matcher.ElementMatchers.isMethod;
import static net.bytebuddy.matcher.ElementMatchers.named;

import com.google.auto.service.AutoService;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
import java.util.List;
import java.util.Map;
import net.bytebuddy.asm.Advice;
import net.bytebuddy.description.method.MethodDescription;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.matcher.ElementMatcher;
import org.eclipse.jetty.client.api.Request;

@AutoService(InstrumentationModule.class)
public class JettyHttpClient9InstrumentationModule extends InstrumentationModule {

public JettyHttpClient9InstrumentationModule() {
super("jetty-httpclient", "jetty-httpclient-9");
}

@Override
public List<TypeInstrumentation> typeInstrumentations() {
return singletonList(new JettyHttpClient9Instrumentation());
}

public static class JettyHttpClient9Instrumentation implements TypeInstrumentation {

@Override
public ElementMatcher<TypeDescription> typeMatcher() {
return hasSuperType(named("org.eclipse.jetty.client.api.Request").and(isInterface()));
}

@Override
public Map<? extends ElementMatcher<? super MethodDescription>, String> transformers() {

return singletonMap(
isMethod().and(named("send")),
JettyHttpClient9InstrumentationModule.class.getName() + "$JettyHttpClient9Advice");
}
}

public static class JettyHttpClient9Advice {

@Advice.OnMethodEnter(suppress = Throwable.class)
public static void addTracingEnter(
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope,
@Advice.This Request jettyRequest) {

Context parentContext = currentContext();
if (!tracer().shouldStartSpan(parentContext)) {
return;
}

JettyHttpClient9TracingInterceptor interceptor =
new JettyHttpClient9TracingInterceptor(parentContext);
interceptor.attachToRequest(jettyRequest);

scope = interceptor.getCtx().makeCurrent();
context = interceptor.getCtx();
}

@Advice.OnMethodExit(suppress = Throwable.class, onThrowable = Throwable.class)
public static void exitTracingInterceptor(
@Advice.Thrown Throwable throwable,
@Advice.Local("otelContext") Context context,
@Advice.Local("otelScope") Scope scope) {

if (throwable != null) {
tracer().endExceptionally(context, throwable);
}

if (scope != null) {
scope.close();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.jetty.httpclient.v9_0

import io.opentelemetry.context.Context
import io.opentelemetry.instrumentation.test.AgentTestTrait
import org.eclipse.jetty.client.api.Request

class JettyHttpClient9AgentTest extends AbstractJettyClient9Test implements AgentTestTrait {

@Override
void attachInterceptor(Request jettyRequest, Context parentCtx) {
//Do nothing
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
apply from: "$rootDir/gradle/instrumentation-library.gradle"
apply plugin: "net.ltgt.errorprone"

def jettyVers = [:]

//Jetty client 9.1 is the best starting point for the v9.x series, v9.0.x is incompatible
jettyVers.base9 = '9.1.0.v20131115'
//jettyVers.base9 = '9.0.0.v20130308'
jettyVers.useInTests9 = '9.3.28.v20191105'

dependencies {
library "org.eclipse.jetty:jetty-client:${jettyVers.base9}"
testImplementation project(':instrumentation:jetty-httpclient::jetty-httpclient-9.0:testing')

implementation deps.slf4j

testLibrary "org.eclipse.jetty:jetty-server:${jettyVers.useInTests9}"
testLibrary "org.eclipse.jetty:jetty-client:${jettyVers.useInTests9}"


}

Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.jetty.httpclient.v9_0;

import static io.opentelemetry.javaagent.instrumentation.jetty.httpclient.v9_0.RequestHeaderInjectorAdapter.SETTER;

import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.propagation.TextMapSetter;
import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer;
import io.opentelemetry.instrumentation.api.tracer.net.NetPeerAttributes;
import java.net.URI;
import java.net.URISyntaxException;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.http.HttpFields;

public class JettyHttpClient9Tracer extends HttpClientTracer<Request, Request, Response> {
private static final JettyHttpClient9Tracer TRACER = new JettyHttpClient9Tracer();

public static final JettyHttpClient9Tracer tracer() {
return TRACER;
}

private JettyHttpClient9Tracer() {
super(NetPeerAttributes.INSTANCE);
}

@Override
protected String getInstrumentationName() {
return "io.opentelemetry.javaagent.jetty-httpclient-9.0";
}

@Override
protected String method(Request request) {
return request.getMethod();
}

@Override
protected @Nullable URI url(Request request) throws URISyntaxException {
return request.getURI();
}

@Override
protected @Nullable Integer status(Response response) {
return response.getStatus();
}

@Override
protected @Nullable String requestHeader(Request request, String name) {
HttpFields headers = request.getHeaders();
return extractHeader(headers, name);
}

@Override
protected @Nullable String responseHeader(Response response, String name) {
HttpFields headers = response.getHeaders();
return extractHeader(headers, name);
}

/** Override so can be called from interceptor code */
@Override
protected void onRequest(Span span, Request request) {
super.onRequest(span, request);
}

protected void updateSpanName(Span span, Request request) {
span.updateName(super.spanNameForRequest(request));
}

@Override
protected TextMapSetter<Request> getSetter() {
return SETTER;
}

private @Nullable String extractHeader(HttpFields headers, String name) {

String headerVal = null;
if (headers != null) {
headerVal = headers.containsKey(name) ? headers.get(name) : null;
}
return headerVal;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.jetty.httpclient.v9_0;

import static io.opentelemetry.javaagent.instrumentation.jetty.httpclient.v9_0.JettyHttpClient9Tracer.tracer;

import io.opentelemetry.api.trace.Span;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.Scope;
import java.util.List;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.client.api.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class JettyHttpClient9TracingInterceptor
implements Request.BeginListener,
Request.FailureListener,
Response.SuccessListener,
Response.FailureListener,
Response.CompleteListener,
Request.CommitListener {

private static final Logger LOG =
LoggerFactory.getLogger(JettyHttpClient9TracingInterceptor.class);

private @Nullable Context ctx;

@Nullable
public Context getCtx() {
return ctx;
}

private final Context parentContext;

public JettyHttpClient9TracingInterceptor(Context parentCtx) {
this.parentContext = parentCtx;
}

public void attachToRequest(Request jettyRequest) {
List<JettyHttpClient9TracingInterceptor> current =
jettyRequest.getRequestListeners(JettyHttpClient9TracingInterceptor.class);

if (!current.isEmpty()) {
LOG.warn("A tracing interceptor is already in place for this request! ");
return;
}

jettyRequest
.onRequestBegin(this)
.onRequestFailure(this)
.onResponseFailure(this)
.onResponseSuccess(this)
.onRequestCommit(this);

startSpan(jettyRequest);
}

private void startSpan(Request request) {

if (this.parentContext != null) {
if (!tracer().shouldStartSpan(this.parentContext)) {
return;
}
Context context = tracer().startSpan(parentContext, request, request);
this.ctx = context;

} else {
LOG.warn("StartSpan - could not find an otel context");
}
}

@Override
public void onBegin(Request request) {
if (this.ctx != null) {
Span span = Span.fromContext(this.ctx);
tracer().onRequest(span, request);
tracer().updateSpanName(span, request);

try (Scope scope = span.makeCurrent()) {}
}
}

@Override
public void onFailure(Request request, Throwable t) {
if (this.ctx != null) {
tracer().endExceptionally(this.ctx, t);
}
}

@Override
public void onComplete(Result result) {
closeIfPossible(result.getResponse());
}

@Override
public void onSuccess(Response response) {
closeIfPossible(response);
}

@Override
public void onFailure(Response response, Throwable t) {
if (this.ctx != null) {
tracer().endExceptionally(this.ctx, t);
}
}

private void closeIfPossible(Response response) {

if (this.ctx != null) {
tracer().end(this.ctx, response);
} else {
LOG.warn("onComplete - could not find an otel context");
}
}

@Override
public void onCommit(Request request) {
// Doing nothing here yet;
}
}
Loading

0 comments on commit ea3274d

Please sign in to comment.