Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate Netty 4.x client instrumentations (except CONNECT) to Instrum… #4381

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.netty.common.server;
package io.opentelemetry.javaagent.instrumentation.netty.common;

import com.google.auto.value.AutoValue;
import io.netty.channel.Channel;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.netty.common.server;
package io.opentelemetry.javaagent.instrumentation.netty.common;

import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.StatusCode;
import io.opentelemetry.context.Context;
import io.opentelemetry.instrumentation.api.instrumenter.ErrorCauseExtractor;

public final class NettyServerErrorHandler {
public final class NettyErrorHandler {

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

private NettyServerErrorHandler() {}
private NettyErrorHandler() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,87 +7,26 @@

import static io.opentelemetry.api.trace.SpanKind.CLIENT;
import static io.opentelemetry.api.trace.SpanKind.INTERNAL;
import static io.opentelemetry.javaagent.instrumentation.netty.common.client.NettyResponseInjectAdapter.SETTER;
import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.NetTransportValues.IP_TCP;
import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.NetTransportValues.IP_UDP;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.DatagramChannel;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpResponse;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanBuilder;
import io.opentelemetry.context.Context;
import io.opentelemetry.context.propagation.TextMapSetter;
import io.opentelemetry.instrumentation.api.config.Config;
import io.opentelemetry.instrumentation.api.tracer.HttpClientTracer;
import io.opentelemetry.instrumentation.api.tracer.BaseTracer;
import io.opentelemetry.instrumentation.api.tracer.net.NetPeerAttributes;
import io.opentelemetry.semconv.trace.attributes.SemanticAttributes;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
import org.checkerframework.checker.nullness.qual.Nullable;

public abstract class AbstractNettyHttpClientTracer<REQUEST extends AbstractNettyRequestWrapper>
extends HttpClientTracer<REQUEST, HttpHeaders, HttpResponse> {
public abstract class AbstractNettyHttpClientTracer extends BaseTracer {

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

protected AbstractNettyHttpClientTracer() {
super(NetPeerAttributes.INSTANCE);
}

public Context startSpan(Context parentContext, ChannelHandlerContext ctx, REQUEST request) {
SpanBuilder spanBuilder = spanBuilder(parentContext, spanNameForRequest(request), CLIENT);
onRequest(spanBuilder, request);
NetPeerAttributes.INSTANCE.setNetPeer(
spanBuilder, (InetSocketAddress) ctx.channel().remoteAddress());

Context context = withClientSpan(parentContext, spanBuilder.startSpan());
inject(context, request.headers(), SETTER);
return context;
}

@Override
protected String method(REQUEST httpRequest) {
return httpRequest.method().name();
}

@Override
@Nullable
protected String flavor(REQUEST httpRequest) {
return httpRequest.protocolVersion().text();
}

@Override
protected URI url(REQUEST request) throws URISyntaxException {
URI uri = new URI(request.uri());
String hostHeader = request.getHostHeader();
if ((uri.getHost() == null || uri.getHost().equals("")) && hostHeader != null) {
String protocol = request.isHttps() ? "https://" : "http://";
uri = new URI(protocol + hostHeader + request.uri());
}
return uri;
}

@Override
protected String requestHeader(AbstractNettyRequestWrapper httpRequest, String name) {
return httpRequest.headers().get(name);
}

@Override
protected String responseHeader(HttpResponse httpResponse, String name) {
return httpResponse.headers().get(name);
}

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

public Context startConnectionSpan(Context parentContext, SocketAddress remoteAddress) {
if (!alwaysCreateConnectSpan) {
return null;
Expand Down

This file was deleted.

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

package io.opentelemetry.javaagent.instrumentation.netty.common.client;

import io.opentelemetry.context.propagation.TextMapSetter;
import io.opentelemetry.javaagent.instrumentation.netty.common.HttpRequestAndChannel;

final class HttpRequestHeadersSetter implements TextMapSetter<HttpRequestAndChannel> {

@Override
public void set(HttpRequestAndChannel requestAndChannel, String key, String value) {
requestAndChannel.request().headers().set(key, value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.netty.common.client;

import io.netty.handler.codec.http.HttpResponse;
import io.opentelemetry.api.GlobalOpenTelemetry;
import io.opentelemetry.instrumentation.api.instrumenter.Instrumenter;
import io.opentelemetry.instrumentation.api.instrumenter.PeerServiceAttributesExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientMetrics;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanNameExtractor;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpSpanStatusExtractor;
import io.opentelemetry.javaagent.instrumentation.netty.common.HttpRequestAndChannel;

public final class NettyClientInstrumenterFactory {

private final String instrumentationName;

public NettyClientInstrumenterFactory(String instrumentationName) {
this.instrumentationName = instrumentationName;
}

public Instrumenter<HttpRequestAndChannel, HttpResponse> createHttpInstrumenter() {
NettyHttpClientAttributesExtractor httpClientAttributesExtractor =
new NettyHttpClientAttributesExtractor();
NettyNetClientAttributesExtractor netClientAttributesExtractor =
new NettyNetClientAttributesExtractor();

return Instrumenter.<HttpRequestAndChannel, HttpResponse>newBuilder(
GlobalOpenTelemetry.get(),
instrumentationName,
HttpSpanNameExtractor.create(httpClientAttributesExtractor))
.setSpanStatusExtractor(HttpSpanStatusExtractor.create(httpClientAttributesExtractor))
.addAttributesExtractor(httpClientAttributesExtractor)
.addAttributesExtractor(netClientAttributesExtractor)
.addAttributesExtractor(PeerServiceAttributesExtractor.create(netClientAttributesExtractor))
.addRequestMetrics(HttpClientMetrics.get())
.newClientInstrumenter(new HttpRequestHeadersSetter());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.netty.common.client;

import io.netty.channel.ChannelHandler;
import io.netty.handler.codec.http.HttpResponse;
import io.opentelemetry.instrumentation.api.instrumenter.http.HttpClientAttributesExtractor;
import io.opentelemetry.javaagent.instrumentation.netty.common.HttpRequestAndChannel;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import org.checkerframework.checker.nullness.qual.Nullable;

final class NettyHttpClientAttributesExtractor
extends HttpClientAttributesExtractor<HttpRequestAndChannel, HttpResponse> {

private static final Class<? extends ChannelHandler> sslHandlerClass = getSslHandlerClass();

@SuppressWarnings("unchecked")
private static Class<? extends ChannelHandler> getSslHandlerClass() {
try {
return (Class<? extends ChannelHandler>)
Class.forName(
"io.netty.handler.ssl.SslHandler",
false,
NettyHttpClientAttributesExtractor.class.getClassLoader());
} catch (ClassNotFoundException exception) {
return null;
}
}

@Override
protected @Nullable String url(HttpRequestAndChannel requestAndChannel) {
try {
String hostHeader = getHost(requestAndChannel);
String target = requestAndChannel.request().getUri();
URI uri = new URI(target);
if ((uri.getHost() == null || uri.getHost().equals("")) && hostHeader != null) {
boolean isHttps = requestAndChannel.channel().pipeline().get(sslHandlerClass) != null;
String scheme = isHttps ? "https://" : "http://";
return scheme + hostHeader + target;
}
return uri.toString();
} catch (URISyntaxException e) {
return null;
}
}

private String getHost(HttpRequestAndChannel requestAndChannel) {
List<String> values = requestHeader(requestAndChannel, "host");
return values.isEmpty() ? null : values.get(0);
}

@Override
protected String flavor(
HttpRequestAndChannel requestAndChannel, @Nullable HttpResponse response) {
String flavor = requestAndChannel.request().getProtocolVersion().toString();
if (flavor.startsWith("HTTP/")) {
flavor = flavor.substring("HTTP/".length());
}
return flavor;
}

@Override
protected String method(HttpRequestAndChannel requestAndChannel) {
return requestAndChannel.request().getMethod().name();
}

@Override
protected List<String> requestHeader(HttpRequestAndChannel requestAndChannel, String name) {
return requestAndChannel.request().headers().getAll(name);
}

@Override
protected @Nullable Long requestContentLength(
HttpRequestAndChannel requestAndChannel, @Nullable HttpResponse response) {
return null;
}

@Override
protected @Nullable Long requestContentLengthUncompressed(
HttpRequestAndChannel requestAndChannel, @Nullable HttpResponse response) {
return null;
}

@Override
protected Integer statusCode(HttpRequestAndChannel requestAndChannel, HttpResponse response) {
return response.getStatus().code();
}

@Override
protected @Nullable Long responseContentLength(
HttpRequestAndChannel requestAndChannel, HttpResponse response) {
return null;
}

@Override
protected @Nullable Long responseContentLengthUncompressed(
HttpRequestAndChannel requestAndChannel, HttpResponse response) {
return null;
}

@Override
protected List<String> responseHeader(
HttpRequestAndChannel requestAndChannel, HttpResponse response, String name) {
return response.headers().getAll(name);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@
import java.util.concurrent.atomic.AtomicReference;

public class NettyHttpClientTracerAccess {
private static final AtomicReference<AbstractNettyHttpClientTracer<?>>
private static final AtomicReference<AbstractNettyHttpClientTracer>
nettyHttpClientTracerReference = new AtomicReference<>();

public static AbstractNettyHttpClientTracer<?> getTracer() {
public static AbstractNettyHttpClientTracer getTracer() {
return nettyHttpClientTracerReference.get();
}

public static void setTracer(AbstractNettyHttpClientTracer<?> tracer) {
public static void setTracer(AbstractNettyHttpClientTracer tracer) {
nettyHttpClientTracerReference.compareAndSet(null, tracer);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/

package io.opentelemetry.javaagent.instrumentation.netty.common.client;

import io.netty.handler.codec.http.HttpResponse;
import io.opentelemetry.instrumentation.api.instrumenter.net.InetSocketAddressNetClientAttributesExtractor;
import io.opentelemetry.javaagent.instrumentation.netty.common.HttpRequestAndChannel;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import org.checkerframework.checker.nullness.qual.Nullable;

final class NettyNetClientAttributesExtractor
extends InetSocketAddressNetClientAttributesExtractor<HttpRequestAndChannel, HttpResponse> {

@Override
public @Nullable InetSocketAddress getAddress(
HttpRequestAndChannel requestAndChannel, @Nullable HttpResponse response) {
SocketAddress address = requestAndChannel.channel().remoteAddress();
if (address instanceof InetSocketAddress) {
return (InetSocketAddress) address;
}
return null;
}

@Override
public @Nullable String transport(
HttpRequestAndChannel requestAndChannel, @Nullable HttpResponse response) {
return null;
}
}
Loading