Skip to content

Commit 783d5e7

Browse files
make apache httpclient instrumentations indy-ready (#13895)
Co-authored-by: otelbot <[email protected]>
1 parent 239a6a9 commit 783d5e7

File tree

9 files changed

+286
-321
lines changed

9 files changed

+286
-321
lines changed

instrumentation/apache-httpclient/apache-httpclient-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v2_0/ApacheHttpClientInstrumentation.java

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import io.opentelemetry.context.Scope;
1919
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
2020
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
21+
import javax.annotation.Nullable;
2122
import net.bytebuddy.asm.Advice;
2223
import net.bytebuddy.description.type.TypeDescription;
2324
import net.bytebuddy.matcher.ElementMatcher;
@@ -47,32 +48,46 @@ public void transform(TypeTransformer transformer) {
4748
@SuppressWarnings("unused")
4849
public static class ExecuteMethodAdvice {
4950

50-
@Advice.OnMethodEnter(suppress = Throwable.class)
51-
public static void methodEnter(
52-
@Advice.Argument(1) HttpMethod httpMethod,
53-
@Advice.Local("otelContext") Context context,
54-
@Advice.Local("otelScope") Scope scope) {
55-
Context parentContext = currentContext();
56-
if (!instrumenter().shouldStart(parentContext, httpMethod)) {
57-
return;
51+
public static class AdviceScope {
52+
private final Context context;
53+
private final Scope scope;
54+
private final HttpMethod httpMethod;
55+
56+
private AdviceScope(Context context, Scope scope, HttpMethod httpMethod) {
57+
this.context = context;
58+
this.scope = scope;
59+
this.httpMethod = httpMethod;
60+
}
61+
62+
@Nullable
63+
public static AdviceScope start(HttpMethod httpMethod) {
64+
Context parentContext = currentContext();
65+
if (!instrumenter().shouldStart(parentContext, httpMethod)) {
66+
return null;
67+
}
68+
Context context = instrumenter().start(parentContext, httpMethod);
69+
return new AdviceScope(context, context.makeCurrent(), httpMethod);
70+
}
71+
72+
public void end(Throwable throwable) {
73+
scope.close();
74+
instrumenter().end(context, httpMethod, httpMethod, throwable);
5875
}
76+
}
5977

60-
context = instrumenter().start(parentContext, httpMethod);
61-
scope = context.makeCurrent();
78+
@Advice.OnMethodEnter(suppress = Throwable.class)
79+
public static AdviceScope methodEnter(@Advice.Argument(1) HttpMethod httpMethod) {
80+
return AdviceScope.start(httpMethod);
6281
}
6382

6483
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
6584
public static void methodExit(
66-
@Advice.Argument(1) HttpMethod httpMethod,
67-
@Advice.Thrown Throwable throwable,
68-
@Advice.Local("otelContext") Context context,
69-
@Advice.Local("otelScope") Scope scope) {
70-
if (scope == null) {
71-
return;
72-
}
85+
@Advice.Thrown @Nullable Throwable throwable,
86+
@Advice.Enter @Nullable AdviceScope adviceScope) {
7387

74-
scope.close();
75-
instrumenter().end(context, httpMethod, httpMethod, throwable);
88+
if (adviceScope != null) {
89+
adviceScope.end(throwable);
90+
}
7691
}
7792
}
7893
}

instrumentation/apache-httpclient/apache-httpclient-2.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v2_0/ApacheHttpClientInstrumentationModule.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@
1010
import com.google.auto.service.AutoService;
1111
import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule;
1212
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
13+
import io.opentelemetry.javaagent.extension.instrumentation.internal.ExperimentalInstrumentationModule;
1314
import java.util.List;
1415

1516
@AutoService(InstrumentationModule.class)
16-
public class ApacheHttpClientInstrumentationModule extends InstrumentationModule {
17+
public class ApacheHttpClientInstrumentationModule extends InstrumentationModule
18+
implements ExperimentalInstrumentationModule {
1719

1820
public ApacheHttpClientInstrumentationModule() {
1921
super("apache-httpclient", "apache-httpclient-2.0");
@@ -23,4 +25,9 @@ public ApacheHttpClientInstrumentationModule() {
2325
public List<TypeInstrumentation> typeInstrumentations() {
2426
return singletonList(new ApacheHttpClientInstrumentation());
2527
}
28+
29+
@Override
30+
public boolean isIndyReady() {
31+
return true;
32+
}
2633
}

instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/ApacheHttpClientHelper.java

Lines changed: 0 additions & 27 deletions
This file was deleted.

instrumentation/apache-httpclient/apache-httpclient-4.0/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/apachehttpclient/v4_0/ApacheHttpClientInstrumentation.java

Lines changed: 84 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,15 @@
2020
import io.opentelemetry.context.Scope;
2121
import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation;
2222
import io.opentelemetry.javaagent.extension.instrumentation.TypeTransformer;
23+
import javax.annotation.Nullable;
2324
import net.bytebuddy.asm.Advice;
25+
import net.bytebuddy.asm.Advice.AssignReturned;
26+
import net.bytebuddy.asm.Advice.AssignReturned.ToArguments.ToArgument;
2427
import net.bytebuddy.description.type.TypeDescription;
2528
import net.bytebuddy.matcher.ElementMatcher;
2629
import org.apache.http.HttpHost;
2730
import org.apache.http.HttpRequest;
31+
import org.apache.http.HttpResponse;
2832
import org.apache.http.client.ResponseHandler;
2933
import org.apache.http.client.methods.HttpUriRequest;
3034

@@ -123,171 +127,145 @@ public void transform(TypeTransformer transformer) {
123127
this.getClass().getName() + "$RequestWithHandlerAdvice");
124128
}
125129

126-
@SuppressWarnings("unused")
127-
public static class UriRequestAdvice {
130+
public static class AdviceScope {
131+
private final ApacheHttpClientRequest otelRequest;
132+
private final Context parentContext;
133+
private final Context context;
134+
private final Scope scope;
135+
136+
private AdviceScope(
137+
ApacheHttpClientRequest otelRequest, Context parentContext, Context context, Scope scope) {
138+
this.otelRequest = otelRequest;
139+
this.parentContext = parentContext;
140+
this.context = context;
141+
this.scope = scope;
142+
}
128143

129-
@Advice.OnMethodEnter(suppress = Throwable.class)
130-
public static void methodEnter(
131-
@Advice.Argument(0) HttpUriRequest request,
132-
@Advice.Local("otelRequest") ApacheHttpClientRequest otelRequest,
133-
@Advice.Local("otelContext") Context context,
134-
@Advice.Local("otelScope") Scope scope) {
144+
@Nullable
145+
public static AdviceScope start(ApacheHttpClientRequest otelRequest) {
135146
Context parentContext = currentContext();
147+
if (!instrumenter().shouldStart(parentContext, otelRequest)) {
148+
return null;
149+
}
150+
Context context = instrumenter().start(parentContext, otelRequest);
151+
return new AdviceScope(otelRequest, parentContext, context, context.makeCurrent());
152+
}
136153

137-
otelRequest = new ApacheHttpClientRequest(request);
154+
public <T> ResponseHandler<T> wrapHandler(ResponseHandler<T> handler) {
155+
return new WrappingStatusSettingResponseHandler<>(
156+
context, parentContext, otelRequest, handler);
157+
}
138158

139-
if (!instrumenter().shouldStart(parentContext, otelRequest)) {
140-
return;
159+
public void end(@Nullable Object result, @Nullable Throwable throwable) {
160+
scope.close();
161+
if (throwable != null) {
162+
instrumenter().end(context, otelRequest, null, throwable);
163+
} else if (result instanceof HttpResponse) {
164+
instrumenter().end(context, otelRequest, (HttpResponse) result, null);
141165
}
166+
// ended in WrappingStatusSettingResponseHandler
167+
}
168+
}
169+
170+
@SuppressWarnings("unused")
171+
public static class UriRequestAdvice {
142172

143-
context = instrumenter().start(parentContext, otelRequest);
144-
scope = context.makeCurrent();
173+
@Advice.OnMethodEnter(suppress = Throwable.class)
174+
public static AdviceScope methodEnter(@Advice.Argument(0) HttpUriRequest request) {
175+
return AdviceScope.start(new ApacheHttpClientRequest(request));
145176
}
146177

147178
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
148179
public static void methodExit(
149180
@Advice.Argument(0) HttpUriRequest request,
150-
@Advice.Return Object result,
151-
@Advice.Thrown Throwable throwable,
152-
@Advice.Local("otelRequest") ApacheHttpClientRequest otelRequest,
153-
@Advice.Local("otelContext") Context context,
154-
@Advice.Local("otelScope") Scope scope) {
155-
if (scope == null) {
156-
return;
157-
}
181+
@Advice.Return @Nullable Object result,
182+
@Advice.Thrown @Nullable Throwable throwable,
183+
@Advice.Enter @Nullable AdviceScope adviceScope) {
158184

159-
scope.close();
160-
ApacheHttpClientHelper.doMethodExit(context, otelRequest, result, throwable);
185+
if (adviceScope != null) {
186+
adviceScope.end(result, throwable);
187+
}
161188
}
162189
}
163190

164191
@SuppressWarnings("unused")
165192
public static class UriRequestWithHandlerAdvice {
166193

194+
@AssignReturned.ToArguments(@ToArgument(value = 1, index = 1))
167195
@Advice.OnMethodEnter(suppress = Throwable.class)
168-
public static void methodEnter(
196+
public static Object[] methodEnter(
169197
@Advice.Argument(0) HttpUriRequest request,
170-
@Advice.Argument(value = 1, readOnly = false) ResponseHandler<?> handler,
171-
@Advice.Local("otelRequest") ApacheHttpClientRequest otelRequest,
172-
@Advice.Local("otelContext") Context context,
173-
@Advice.Local("otelScope") Scope scope) {
174-
Context parentContext = currentContext();
175-
176-
otelRequest = new ApacheHttpClientRequest(request);
177-
178-
if (!instrumenter().shouldStart(parentContext, otelRequest)) {
179-
return;
180-
}
181-
182-
context = instrumenter().start(parentContext, otelRequest);
183-
scope = context.makeCurrent();
198+
@Advice.Argument(1) ResponseHandler<?> handler) {
184199

200+
AdviceScope adviceScope = AdviceScope.start(new ApacheHttpClientRequest(request));
185201
// Wrap the handler so we capture the status code
186-
if (handler != null) {
187-
handler =
188-
new WrappingStatusSettingResponseHandler<>(
189-
context, parentContext, otelRequest, handler);
190-
}
202+
return new Object[] {
203+
adviceScope, adviceScope == null ? handler : adviceScope.wrapHandler(handler)
204+
};
191205
}
192206

193207
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
194208
public static void methodExit(
195-
@Advice.Argument(0) HttpUriRequest request,
196209
@Advice.Return Object result,
197210
@Advice.Thrown Throwable throwable,
198-
@Advice.Local("otelRequest") ApacheHttpClientRequest otelRequest,
199-
@Advice.Local("otelContext") Context context,
200-
@Advice.Local("otelScope") Scope scope) {
201-
if (scope == null) {
202-
return;
203-
}
211+
@Advice.Enter Object[] enterResult) {
204212

205-
scope.close();
206-
ApacheHttpClientHelper.doMethodExit(context, otelRequest, result, throwable);
213+
AdviceScope adviceScope = (AdviceScope) enterResult[0];
214+
if (adviceScope != null) {
215+
adviceScope.end(result, throwable);
216+
}
207217
}
208218
}
209219

210220
@SuppressWarnings("unused")
211221
public static class RequestAdvice {
212222

213223
@Advice.OnMethodEnter(suppress = Throwable.class)
214-
public static void methodEnter(
215-
@Advice.Argument(0) HttpHost host,
216-
@Advice.Argument(1) HttpRequest request,
217-
@Advice.Local("otelRequest") ApacheHttpClientRequest otelRequest,
218-
@Advice.Local("otelContext") Context context,
219-
@Advice.Local("otelScope") Scope scope) {
220-
Context parentContext = currentContext();
221-
222-
otelRequest = new ApacheHttpClientRequest(host, request);
223-
224-
if (!instrumenter().shouldStart(parentContext, otelRequest)) {
225-
return;
226-
}
227-
228-
context = instrumenter().start(parentContext, otelRequest);
229-
scope = context.makeCurrent();
224+
public static AdviceScope methodEnter(
225+
@Advice.Argument(0) HttpHost host, @Advice.Argument(1) HttpRequest request) {
226+
return AdviceScope.start(new ApacheHttpClientRequest(host, request));
230227
}
231228

232229
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
233230
public static void methodExit(
234231
@Advice.Return Object result,
235232
@Advice.Thrown Throwable throwable,
236-
@Advice.Local("otelRequest") ApacheHttpClientRequest otelRequest,
237-
@Advice.Local("otelContext") Context context,
238-
@Advice.Local("otelScope") Scope scope) {
239-
if (scope == null) {
240-
return;
241-
}
233+
@Advice.Enter AdviceScope adviceScope) {
242234

243-
scope.close();
244-
ApacheHttpClientHelper.doMethodExit(context, otelRequest, result, throwable);
235+
if (adviceScope != null) {
236+
adviceScope.end(result, throwable);
237+
}
245238
}
246239
}
247240

248241
@SuppressWarnings("unused")
249242
public static class RequestWithHandlerAdvice {
250243

244+
@AssignReturned.ToArguments(@ToArgument(value = 2, index = 1))
251245
@Advice.OnMethodEnter(suppress = Throwable.class)
252-
public static void methodEnter(
246+
public static Object[] methodEnter(
253247
@Advice.Argument(0) HttpHost host,
254248
@Advice.Argument(1) HttpRequest request,
255-
@Advice.Argument(value = 2, readOnly = false) ResponseHandler<?> handler,
256-
@Advice.Local("otelRequest") ApacheHttpClientRequest otelRequest,
257-
@Advice.Local("otelContext") Context context,
258-
@Advice.Local("otelScope") Scope scope) {
259-
Context parentContext = currentContext();
260-
261-
otelRequest = new ApacheHttpClientRequest(host, request);
262-
263-
if (!instrumenter().shouldStart(parentContext, otelRequest)) {
264-
return;
265-
}
266-
267-
context = instrumenter().start(parentContext, otelRequest);
268-
scope = context.makeCurrent();
269-
270-
// Wrap the handler so we capture the status code
271-
if (handler != null) {
272-
handler =
273-
new WrappingStatusSettingResponseHandler<>(
274-
context, parentContext, otelRequest, handler);
275-
}
249+
@Advice.Argument(2) ResponseHandler<?> handler) {
250+
251+
AdviceScope adviceScope = AdviceScope.start(new ApacheHttpClientRequest(host, request));
252+
return new Object[] {
253+
adviceScope,
254+
// Wrap the handler so we capture the status code
255+
adviceScope == null ? handler : adviceScope.wrapHandler(handler)
256+
};
276257
}
277258

278259
@Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class)
279260
public static void methodExit(
280261
@Advice.Return Object result,
281262
@Advice.Thrown Throwable throwable,
282-
@Advice.Local("otelRequest") ApacheHttpClientRequest otelRequest,
283-
@Advice.Local("otelContext") Context context,
284-
@Advice.Local("otelScope") Scope scope) {
285-
if (scope == null) {
286-
return;
287-
}
263+
@Advice.Enter Object[] enterResult) {
288264

289-
scope.close();
290-
ApacheHttpClientHelper.doMethodExit(context, otelRequest, result, throwable);
265+
AdviceScope adviceScope = (AdviceScope) enterResult[0];
266+
if (adviceScope != null) {
267+
adviceScope.end(result, throwable);
268+
}
291269
}
292270
}
293271
}

0 commit comments

Comments
 (0)