Skip to content

Commit ac479d4

Browse files
author
Mateusz Rzeszutek
authored
Migrate Netty 4.x client instrumentations (except CONNECT) to Instrum… (#4381)
* Migrate Netty 4.x client instrumentations (except CONNECT) to Instrumenter API * Revert testReadTimeout changes
1 parent 0652894 commit ac479d4

33 files changed

+401
-372
lines changed
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
package io.opentelemetry.javaagent.instrumentation.netty.common.server;
6+
package io.opentelemetry.javaagent.instrumentation.netty.common;
77

88
import com.google.auto.value.AutoValue;
99
import io.netty.channel.Channel;
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
package io.opentelemetry.javaagent.instrumentation.netty.common.server;
6+
package io.opentelemetry.javaagent.instrumentation.netty.common;
77

88
import io.netty.handler.codec.http.HttpResponse;
99
import io.opentelemetry.instrumentation.api.instrumenter.net.InetSocketAddressNetServerAttributesExtractor;
1010
import java.net.InetSocketAddress;
1111
import java.net.SocketAddress;
1212
import org.checkerframework.checker.nullness.qual.Nullable;
1313

14-
final class NettyNetServerAttributesExtractor
14+
public final class NettyCommonNetAttributesExtractor
1515
extends InetSocketAddressNetServerAttributesExtractor<HttpRequestAndChannel, HttpResponse> {
1616

1717
@Override
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
package io.opentelemetry.javaagent.instrumentation.netty.common.server;
6+
package io.opentelemetry.javaagent.instrumentation.netty.common;
77

88
import io.opentelemetry.api.trace.Span;
99
import io.opentelemetry.api.trace.StatusCode;
1010
import io.opentelemetry.context.Context;
1111
import io.opentelemetry.instrumentation.api.instrumenter.ErrorCauseExtractor;
1212

13-
public final class NettyServerErrorHandler {
13+
public final class NettyErrorHandler {
1414

1515
// copied from BaseTracer#onException()
1616
public static void onError(Context context, Throwable error) {
@@ -19,5 +19,5 @@ public static void onError(Context context, Throwable error) {
1919
span.recordException(ErrorCauseExtractor.jdk().extractCause(error));
2020
}
2121

22-
private NettyServerErrorHandler() {}
22+
private NettyErrorHandler() {}
2323
}

instrumentation/netty/netty-4-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/common/client/AbstractNettyHttpClientTracer.java

+2-63
Original file line numberDiff line numberDiff line change
@@ -7,87 +7,26 @@
77

88
import static io.opentelemetry.api.trace.SpanKind.CLIENT;
99
import static io.opentelemetry.api.trace.SpanKind.INTERNAL;
10-
import static io.opentelemetry.javaagent.instrumentation.netty.common.client.NettyResponseInjectAdapter.SETTER;
1110
import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.NetTransportValues.IP_TCP;
1211
import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.NetTransportValues.IP_UDP;
1312

1413
import io.netty.channel.Channel;
15-
import io.netty.channel.ChannelHandlerContext;
1614
import io.netty.channel.socket.DatagramChannel;
17-
import io.netty.handler.codec.http.HttpHeaders;
18-
import io.netty.handler.codec.http.HttpResponse;
1915
import io.opentelemetry.api.trace.Span;
2016
import io.opentelemetry.api.trace.SpanBuilder;
2117
import io.opentelemetry.context.Context;
22-
import io.opentelemetry.context.propagation.TextMapSetter;
2318
import io.opentelemetry.instrumentation.api.config.Config;
24-
import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer;
19+
import io.opentelemetry.instrumentation.api.tracer.BaseTracer;
2520
import io.opentelemetry.instrumentation.api.tracer.net.NetPeerAttributes;
2621
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
2722
import java.net.InetSocketAddress;
2823
import java.net.SocketAddress;
29-
import java.net.URI;
30-
import java.net.URISyntaxException;
31-
import org.checkerframework.checker.nullness.qual.Nullable;
3224

33-
public abstract class AbstractNettyHttpClientTracer<REQUEST extends AbstractNettyRequestWrapper>
34-
extends HttpClientTracer<REQUEST, HttpHeaders, HttpResponse> {
25+
public abstract class AbstractNettyHttpClientTracer extends BaseTracer {
3526

3627
private static final boolean alwaysCreateConnectSpan =
3728
Config.get().getBoolean("otel.instrumentation.netty.always-create-connect-span", false);
3829

39-
protected AbstractNettyHttpClientTracer() {
40-
super(NetPeerAttributes.INSTANCE);
41-
}
42-
43-
public Context startSpan(Context parentContext, ChannelHandlerContext ctx, REQUEST request) {
44-
SpanBuilder spanBuilder = spanBuilder(parentContext, spanNameForRequest(request), CLIENT);
45-
onRequest(spanBuilder, request);
46-
NetPeerAttributes.INSTANCE.setNetPeer(
47-
spanBuilder, (InetSocketAddress) ctx.channel().remoteAddress());
48-
49-
Context context = withClientSpan(parentContext, spanBuilder.startSpan());
50-
inject(context, request.headers(), SETTER);
51-
return context;
52-
}
53-
54-
@Override
55-
protected String method(REQUEST httpRequest) {
56-
return httpRequest.method().name();
57-
}
58-
59-
@Override
60-
@Nullable
61-
protected String flavor(REQUEST httpRequest) {
62-
return httpRequest.protocolVersion().text();
63-
}
64-
65-
@Override
66-
protected URI url(REQUEST request) throws URISyntaxException {
67-
URI uri = new URI(request.uri());
68-
String hostHeader = request.getHostHeader();
69-
if ((uri.getHost() == null || uri.getHost().equals("")) && hostHeader != null) {
70-
String protocol = request.isHttps() ? "https://" : "http://";
71-
uri = new URI(protocol + hostHeader + request.uri());
72-
}
73-
return uri;
74-
}
75-
76-
@Override
77-
protected String requestHeader(AbstractNettyRequestWrapper httpRequest, String name) {
78-
return httpRequest.headers().get(name);
79-
}
80-
81-
@Override
82-
protected String responseHeader(HttpResponse httpResponse, String name) {
83-
return httpResponse.headers().get(name);
84-
}
85-
86-
@Override
87-
protected TextMapSetter<HttpHeaders> getSetter() {
88-
return SETTER;
89-
}
90-
9130
public Context startConnectionSpan(Context parentContext, SocketAddress remoteAddress) {
9231
if (!alwaysCreateConnectSpan) {
9332
return null;

instrumentation/netty/netty-4-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/common/client/AbstractNettyRequestWrapper.java

-38
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.javaagent.instrumentation.netty.common.client;
7+
8+
import io.opentelemetry.context.propagation.TextMapSetter;
9+
import io.opentelemetry.javaagent.instrumentation.netty.common.HttpRequestAndChannel;
10+
11+
final class HttpRequestHeadersSetter implements TextMapSetter<HttpRequestAndChannel> {
12+
13+
@Override
14+
public void set(HttpRequestAndChannel requestAndChannel, String key, String value) {
15+
requestAndChannel.request().headers().set(key, value);
16+
}
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.javaagent.instrumentation.netty.common.client;
7+
8+
import io.netty.handler.codec.http.HttpResponse;
9+
import io.opentelemetry.api.GlobalOpenTelemetry;
10+
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
11+
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
12+
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
13+
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
14+
import io.opentelemetry.javaagent.instrumentation.netty.common.HttpRequestAndChannel;
15+
import io.opentelemetry.javaagent.instrumentation.netty.common.NettyCommonNetAttributesExtractor;
16+
17+
public final class NettyClientInstrumenterFactory {
18+
19+
private final String instrumentationName;
20+
21+
public NettyClientInstrumenterFactory(String instrumentationName) {
22+
this.instrumentationName = instrumentationName;
23+
}
24+
25+
public Instrumenter<HttpRequestAndChannel, HttpResponse> createHttpInstrumenter() {
26+
NettyHttpClientAttributesExtractor httpClientAttributesExtractor =
27+
new NettyHttpClientAttributesExtractor();
28+
29+
return Instrumenter.<HttpRequestAndChannel, HttpResponse>newBuilder(
30+
GlobalOpenTelemetry.get(),
31+
instrumentationName,
32+
HttpSpanNameExtractor.create(httpClientAttributesExtractor))
33+
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(httpClientAttributesExtractor))
34+
.addAttributesExtractor(httpClientAttributesExtractor)
35+
.addAttributesExtractor(new NettyCommonNetAttributesExtractor())
36+
// TODO: add peer extractor attributes once Net*AttributesExtractors are refactored
37+
// .addAttributesExtractor(PeerServiceAttributesExtractor.create(netClientAttributesExtractor))
38+
.addRequestMetrics(HttpClientMetrics.get())
39+
.newClientInstrumenter(new HttpRequestHeadersSetter());
40+
}
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.javaagent.instrumentation.netty.common.client;
7+
8+
import io.netty.channel.ChannelHandler;
9+
import io.netty.handler.codec.http.HttpResponse;
10+
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
11+
import io.opentelemetry.javaagent.instrumentation.netty.common.HttpRequestAndChannel;
12+
import java.net.URI;
13+
import java.net.URISyntaxException;
14+
import java.util.List;
15+
import org.checkerframework.checker.nullness.qual.Nullable;
16+
17+
final class NettyHttpClientAttributesExtractor
18+
extends HttpClientAttributesExtractor<HttpRequestAndChannel, HttpResponse> {
19+
20+
private static final Class<? extends ChannelHandler> sslHandlerClass = getSslHandlerClass();
21+
22+
@SuppressWarnings("unchecked")
23+
private static Class<? extends ChannelHandler> getSslHandlerClass() {
24+
try {
25+
return (Class<? extends ChannelHandler>)
26+
Class.forName(
27+
"io.netty.handler.ssl.SslHandler",
28+
false,
29+
NettyHttpClientAttributesExtractor.class.getClassLoader());
30+
} catch (ClassNotFoundException exception) {
31+
return null;
32+
}
33+
}
34+
35+
@Override
36+
protected @Nullable String url(HttpRequestAndChannel requestAndChannel) {
37+
try {
38+
String hostHeader = getHost(requestAndChannel);
39+
String target = requestAndChannel.request().getUri();
40+
URI uri = new URI(target);
41+
if ((uri.getHost() == null || uri.getHost().equals("")) && hostHeader != null) {
42+
boolean isHttps = requestAndChannel.channel().pipeline().get(sslHandlerClass) != null;
43+
String scheme = isHttps ? "https://" : "http://";
44+
return scheme + hostHeader + target;
45+
}
46+
return uri.toString();
47+
} catch (URISyntaxException e) {
48+
return null;
49+
}
50+
}
51+
52+
private String getHost(HttpRequestAndChannel requestAndChannel) {
53+
List<String> values = requestHeader(requestAndChannel, "host");
54+
return values.isEmpty() ? null : values.get(0);
55+
}
56+
57+
@Override
58+
protected String flavor(
59+
HttpRequestAndChannel requestAndChannel, @Nullable HttpResponse response) {
60+
String flavor = requestAndChannel.request().getProtocolVersion().toString();
61+
if (flavor.startsWith("HTTP/")) {
62+
flavor = flavor.substring("HTTP/".length());
63+
}
64+
return flavor;
65+
}
66+
67+
@Override
68+
protected String method(HttpRequestAndChannel requestAndChannel) {
69+
return requestAndChannel.request().getMethod().name();
70+
}
71+
72+
@Override
73+
protected List<String> requestHeader(HttpRequestAndChannel requestAndChannel, String name) {
74+
return requestAndChannel.request().headers().getAll(name);
75+
}
76+
77+
@Override
78+
protected @Nullable Long requestContentLength(
79+
HttpRequestAndChannel requestAndChannel, @Nullable HttpResponse response) {
80+
return null;
81+
}
82+
83+
@Override
84+
protected @Nullable Long requestContentLengthUncompressed(
85+
HttpRequestAndChannel requestAndChannel, @Nullable HttpResponse response) {
86+
return null;
87+
}
88+
89+
@Override
90+
protected Integer statusCode(HttpRequestAndChannel requestAndChannel, HttpResponse response) {
91+
return response.getStatus().code();
92+
}
93+
94+
@Override
95+
protected @Nullable Long responseContentLength(
96+
HttpRequestAndChannel requestAndChannel, HttpResponse response) {
97+
return null;
98+
}
99+
100+
@Override
101+
protected @Nullable Long responseContentLengthUncompressed(
102+
HttpRequestAndChannel requestAndChannel, HttpResponse response) {
103+
return null;
104+
}
105+
106+
@Override
107+
protected List<String> responseHeader(
108+
HttpRequestAndChannel requestAndChannel, HttpResponse response, String name) {
109+
return response.headers().getAll(name);
110+
}
111+
}

instrumentation/netty/netty-4-common/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/netty/common/client/NettyHttpClientTracerAccess.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@
88
import java.util.concurrent.atomic.AtomicReference;
99

1010
public class NettyHttpClientTracerAccess {
11-
private static final AtomicReference<AbstractNettyHttpClientTracer<?>>
11+
private static final AtomicReference<AbstractNettyHttpClientTracer>
1212
nettyHttpClientTracerReference = new AtomicReference<>();
1313

14-
public static AbstractNettyHttpClientTracer<?> getTracer() {
14+
public static AbstractNettyHttpClientTracer getTracer() {
1515
return nettyHttpClientTracerReference.get();
1616
}
1717

18-
public static void setTracer(AbstractNettyHttpClientTracer<?> tracer) {
18+
public static void setTracer(AbstractNettyHttpClientTracer tracer) {
1919
nettyHttpClientTracerReference.compareAndSet(null, tracer);
2020
}
2121
}

0 commit comments

Comments
 (0)