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

OTEL migration #99

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
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
8 changes: 7 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,13 @@ subprojects {
guice_validator : 'ru.vyarus:guice-validator:1.2.0',
hibernate_validator : 'org.hibernate:hibernate-validator:5.4.1.Final',
javax_el : 'org.glassfish:javax.el:3.0.1-b08',
opentracing : 'io.opentracing:opentracing-api:0.31.0',
opentelemetry_api : 'io.opentelemetry:opentelemetry-api:1.38.0',
opentelemetry_sdk : 'io.opentelemetry:opentelemetry-sdk:1.38.0',
opentelemetry_exporter_logging: 'io.opentelemetry:opentelemetry-exporter-logging:1.38.0',
opentelemetry_sdk_extension_autoconfigure: 'io.opentelemetry:opentelemetry-sdk-extension-autoconfigure:1.38.0',
opentelemetry_java_http_client: 'io.opentelemetry.instrumentation:opentelemetry-java-http-client:2.4.0-alpha',
opentelemetry_exporter_otlp_trace: 'io.opentelemetry:opentelemetry-exporter-otlp-trace:1.7.0',
opentelemetry_exporter_otlp: 'io.opentelemetry:opentelemetry-exporter-otlp:1.7.0',
lombok : 'org.projectlombok:lombok:1.18.2',
grpc_stub : "io.grpc:grpc-stub:${grpcVersion}",
hystrix_core : "com.netflix.hystrix:hystrix-core:1.5.12",
Expand Down
8 changes: 7 additions & 1 deletion core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,13 @@ dependencies {
implementation libraries.jersey
implementation libraries.jersey_freemarker
implementation libraries.servlet
implementation libraries.opentracing
implementation libraries.opentelemetry_api
implementation libraries.opentelemetry_sdk
implementation libraries.opentelemetry_exporter_logging
implementation libraries.opentelemetry_sdk_extension_autoconfigure
implementation libraries.opentelemetry_java_http_client
implementation libraries.opentelemetry_exporter_otlp_trace
implementation libraries.opentelemetry_exporter_otlp
implementation libraries.hystrix_core
implementation libraries.hystrix_metrics_stream
implementation libraries.rxjava2
Expand Down
24 changes: 12 additions & 12 deletions core/src/main/java/com/flipkart/gjex/core/context/GJEXContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,28 @@

import io.grpc.Context;
import io.grpc.Metadata;
import io.opentracing.Span;
import io.opentracing.SpanContext;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanContext;

/**
* Code ported from {@linkplain https://github.com/opentracing-contrib/java-grpc/blob/master/src/main/java/io/opentracing/contrib/grpc/OpenTracingContextKey.java}
*
* Supports storing and propagating useful per-execution data such as current OpenTracing trace state using the gRPC {@link io.grpc.Context}
* Code ported from {@linkplain <a href="https://github.com/opentracing-contrib/java-grpc/blob/master/src/main/java/io/opentracing/contrib/grpc/OpenTracingContextKey.java">...</a>}
*
* Supports storing and propagating useful per-execution data such as current OpenTracing trace state using the gRPC {@link Context}
*
*/
public class GJEXContext {

public static final String KEY_ROOT_SPAN_NAME = "io.opentracing.root-span";
public static final String KEY_ACTIVE_SPAN_NAME = "io.opentracing.active-span";
public static final String KEY_CONTEXT_NAME = "io.opentracing.active-span-context";
public static final String KEY_TRACING_SAMPLER_NAME = "io.opentracing.active-tracing-sampler";
public static final String KEY_ROOT_SPAN_NAME = "io.opentelemetry.root-span";
public static final String KEY_ACTIVE_SPAN_NAME = "io.opentelemetry.active-span";
public static final String KEY_CONTEXT_NAME = "io.opentelemetry.active-span-context";
public static final String KEY_TRACING_SAMPLER_NAME = "io.opentelemetry.active-tracing-sampler";
public static final String KEY_HEADERS_NAME = "com.flipkart.gjex.headers";

private static final Context.Key<Span> KEY_ROOT_SPAN = Context.key(KEY_ROOT_SPAN_NAME);
private static final Context.Key<Span> KEY_ACTIVE_SPAN = Context.key(KEY_ACTIVE_SPAN_NAME);
private static final Context.Key<SpanContext> KEY_CONTEXT = Context.key(KEY_CONTEXT_NAME);
private static final Context.Key<TracingSampler> KEY_TRACING_SAMPLER = Context.key(KEY_TRACING_SAMPLER_NAME);
private static final Context.Key<Metadata> KEY_HEADERS = Context.key(KEY_HEADERS_NAME);
private static final Context.Key<TracingSampler> KEY_TRACING_SAMPLER = Context.key(KEY_TRACING_SAMPLER_NAME);
private static final Context.Key<Metadata> KEY_HEADERS = Context.key(KEY_HEADERS_NAME);

/**
* @return the OpenTracing context key for Root span
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ default void errorLog(String msg, Object... args){

default void addToTrace(String key, String value) {
if (GJEXContext.activeSpan() != null) {
GJEXContext.activeSpan().setTag(key, value);
GJEXContext.activeSpan().setAttribute(key, value);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

import com.flipkart.gjex.core.context.GJEXContext;

import io.opentracing.Span;
import io.opentelemetry.api.trace.Span;;

/**
* An interface that defines how to get the current active span.
Expand Down
3 changes: 2 additions & 1 deletion examples/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#Mon May 27 15:42:49 IST 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
9 changes: 7 additions & 2 deletions guice/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,21 @@ dependencies {
implementation libraries.guice_validator
implementation libraries.hibernate_validator
implementation libraries.javax_el
implementation libraries.opentracing
implementation libraries.lombok
implementation libraries.hystrix_core
implementation libraries.hystrix_metrics_stream
implementation libraries.rxjava2
implementation libraries.opentelemetry_api
implementation libraries.opentelemetry_sdk
implementation libraries.opentelemetry_exporter_logging
implementation libraries.opentelemetry_sdk_extension_autoconfigure
implementation libraries.opentelemetry_java_http_client
implementation libraries.opentelemetry_exporter_otlp

implementation 'org.eclipse.jetty:jetty-server:9.4.22.v20191022'
implementation 'org.eclipse.jetty:jetty-servlet:9.4.22.v20191022'
implementation 'org.eclipse.jetty:jetty-webapp:9.4.22.v20191022'
implementation 'io.opentracing.brave:brave-opentracing:0.31.3'
implementation 'io.opentelemetry:opentelemetry-exporter-zipkin:1.38.0'
implementation 'io.zipkin.reporter2:zipkin-sender-okhttp3:2.7.7'

implementation 'io.prometheus:prometheus-metrics-exporter-servlet-javax:1.2.0'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,15 @@
*/
package com.flipkart.gjex.grpc.interceptor;

import java.util.Iterator;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;

import javax.annotation.Nullable;

import com.flipkart.gjex.core.tracing.ActiveSpanSource;
import com.flipkart.gjex.core.tracing.OperationNameConstructor;
import com.google.common.collect.ImmutableMap;
import io.grpc.*;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanBuilder;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.context.propagation.TextMapPropagator;
import io.opentelemetry.context.propagation.TextMapSetter;

import io.grpc.CallOptions;
import io.grpc.Channel;
import io.grpc.ClientCall;
import io.grpc.ClientInterceptor;
import io.grpc.ClientInterceptors;
import io.grpc.ForwardingClientCall;
import io.grpc.ForwardingClientCallListener;
import io.grpc.Metadata;
import io.grpc.MethodDescriptor;
import io.grpc.Status;
import io.opentracing.Span;
import io.opentracing.Tracer;
import io.opentracing.propagation.Format;
import io.opentracing.propagation.TextMap;

/**
* An intercepter that applies tracing via OpenTracing to all client requests, if a Trace is active.
Expand All @@ -47,16 +32,14 @@
public class ClientTracingInterceptor implements ClientInterceptor {

private final Tracer tracer;
private final OperationNameConstructor operationNameConstructor;
private final ActiveSpanSource activeSpanSource;
private final TextMapPropagator textFormat;

/**
* @param tracer to use to trace requests
*/
public ClientTracingInterceptor(Tracer tracer) {
public ClientTracingInterceptor(Tracer tracer, TextMapPropagator textFormat) {
this.tracer = tracer;
this.operationNameConstructor = OperationNameConstructor.DEFAULT;
this.activeSpanSource = ActiveSpanSource.GRPC_CONTEXT;
this.textFormat = textFormat;
}

/**
Expand All @@ -72,71 +55,37 @@ public Channel intercept(Channel channel) {
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {

Span activeSpan = this.activeSpanSource.getActiveSpan();
if (activeSpan != null) {
final String operationName = operationNameConstructor.constructOperationName(method);

final Span span = createSpanFromParent(activeSpan, operationName);

if (callOptions.getDeadline() == null) {
span.setTag("grpc.deadline_millis", "null");
} else {
span.setTag("grpc.deadline_millis", callOptions.getDeadline().timeRemaining(TimeUnit.MILLISECONDS));
}

return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(next.newCall(method, callOptions)) {

@Override
public void start(Listener<RespT> responseListener, Metadata headers) {
tracer.inject(span.context(), Format.Builtin.HTTP_HEADERS, new TextMap() {
@Override
public void put(String key, String value) {
Metadata.Key<String> headerKey = Metadata.Key.of(key, Metadata.ASCII_STRING_MARSHALLER);
headers.put(headerKey, value);
}
@Override
public Iterator<Entry<String, String>> iterator() {
throw new UnsupportedOperationException(
"TextMapInjectAdapter should only be used with Tracer.inject()");
}
});
Listener<RespT> tracingResponseListener = new ForwardingClientCallListener.SimpleForwardingClientCallListener<RespT>(
responseListener) {
@Override
public void onClose(Status status, Metadata trailers) {
span.finish();
delegate().onClose(status, trailers);
}
};
delegate().start(tracingResponseListener, headers);
}
SpanBuilder spanBuilder = tracer.spanBuilder(method.getFullMethodName());
final Span span = spanBuilder.startSpan();

@Override
public void cancel(@Nullable String message, @Nullable Throwable cause) {
String errorMessage;
if (message == null) {
errorMessage = "Error";
} else {
errorMessage = message;
return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(next.newCall(method, callOptions)) {
@Override
public void start(Listener<RespT> responseListener, Metadata headers) {
textFormat.inject(io.opentelemetry.context.Context.current(), headers, new TextMapSetter<Metadata>() {
@Override
public void set(Metadata carrier, String key, String value) {
carrier.put(Metadata.Key.of(key, Metadata.ASCII_STRING_MARSHALLER), value);
}
if (cause == null) {
span.log(errorMessage);
} else {
span.log(ImmutableMap.of(errorMessage, cause.getMessage()));
});

Listener<RespT> tracingResponseListener = new ForwardingClientCallListener.SimpleForwardingClientCallListener<RespT>(
responseListener) {
@Override
public void onClose(Status status, Metadata trailers) {
span.end();
delegate().onClose(status, trailers);
}
delegate().cancel(message, cause);
}
};
}
return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(next.newCall(method, callOptions)){};
}

private Span createSpanFromParent(Span parentSpan, String operationName) {
if (parentSpan == null) {
return tracer.buildSpan(operationName).start();
} else {
return tracer.buildSpan(operationName).asChildOf(parentSpan).start();
}
}
};
delegate().start(tracingResponseListener, headers);
}


@Override
public void cancel(@Nullable String message, @Nullable Throwable cause) {
span.recordException(cause);
span.end();
delegate().cancel(message, cause);
}
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,9 @@
import io.grpc.ServerCall.Listener;
import io.grpc.ServerCallHandler;
import io.grpc.ServerInterceptor;
import io.opentracing.Span;
import io.opentracing.SpanContext;
import io.opentracing.Tracer;
import io.opentracing.propagation.Format;
import io.opentracing.propagation.TextMapExtractAdapter;
import io.opentelemetry.api.trace.Span;
import io.opentelemetry.api.trace.SpanContext;
import io.opentelemetry.api.trace.Tracer;

/**
* An implementation of the gRPC {@link ServerInterceptor} for Distributed Tracing that retrieves active traces initialized by clients and lets
Expand Down Expand Up @@ -122,9 +120,9 @@ public <ReqT, RespT> Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call,
* Set the client side initiated Trace and Span in the Context.
* Note : we do not active the Span. This will be done in the TracingModule based on sampling enabled/not-enabled for the service's method
*/
Context ctxWithSpan = Context.current().withValues(GJEXContext.getKeyRoot(), span, // root span and active span are the same
io.grpc.Context ctxWithSpan = io.grpc.Context.current().withValues(GJEXContext.getKeyRoot(), span, // root span and active span are the same
GJEXContext.getKeyActiveSpan(), span,
GJEXContext.getSpanContextKey(), span.context(),
GJEXContext.getSpanContextKey(), span.getSpanContext(),
GJEXContext.getTracingSamplerKey(), tracingSampler); // pass on the TracingSampler for use in downstream calls for e.g. in TracingModule

ServerCall.Listener<ReqT> listenerWithContext = Contexts.interceptCall(ctxWithSpan, call, headers, next);
Expand All @@ -137,16 +135,7 @@ public <ReqT, RespT> Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call,
*/
private <ReqT, RespT> Span getSpanFromHeaders(ServerCall<ReqT, RespT> call, Map<String, String> headers) {
String methodInvoked = call.getMethodDescriptor().getFullMethodName();
Span span = null;
try {
SpanContext parentSpanCtx = tracer.extract(Format.Builtin.HTTP_HEADERS, new TextMapExtractAdapter(headers));
span = tracer.buildSpan(methodInvoked).asChildOf(parentSpanCtx).start();
//Service name can be added as a Tag from opentracing-java version v0.31.1 onwards
//Tags.SERVICE.set(span, MethodDescriptor.extractFullServiceName(methodInvoked));
} catch (IllegalArgumentException iae) {
span = tracer.buildSpan(methodInvoked).withTag("Error", "Extract failed and an IllegalArgumentException was thrown")
.start();
}
return span;
return tracer.spanBuilder(methodInvoked).setParent(
io.opentelemetry.context.Context.current()).startSpan();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
import com.google.inject.Provider;
import io.grpc.Channel;
import io.grpc.stub.AbstractStub;
import io.opentracing.Tracer;
import io.opentelemetry.api.trace.Tracer;
import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator;
import io.opentelemetry.context.propagation.TextMapPropagator;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
Expand All @@ -31,10 +33,6 @@
import javax.inject.Inject;
import javax.inject.Named;

/**
* Created by rohit.k on 28/07/18.
*/

/**
* {@link ClientModule} is a guice module to get an Instrumented, Traced instance of GRPC client
*
Expand Down Expand Up @@ -70,9 +68,18 @@ public T get() {
try {
Constructor<T> constructor = clazz.getDeclaredConstructor(Channel.class);
constructor.setAccessible(true);
return constructor.newInstance(channel).withDeadlineAfter(channelConfig.getDeadlineInMs(),
TimeUnit.MILLISECONDS).withInterceptors(new ClientTracingInterceptor(tracer));
} catch (InstantiationException | IllegalAccessException | InvocationTargetException| NoSuchMethodException e) {
T stub = constructor.newInstance(channel);
stub = stub.withDeadlineAfter(channelConfig.getDeadlineInMs(), TimeUnit.MILLISECONDS);

// Create an instance of the OpenTelemetry ClientTracingInterceptor
TextMapPropagator textFormat = W3CTraceContextPropagator.getInstance();
ClientTracingInterceptor clientTracingInterceptor = new ClientTracingInterceptor(tracer, textFormat);

// Add the OpenTelemetry interceptor to the stub
stub = stub.withInterceptors(clientTracingInterceptor);

return stub;
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
throw new RuntimeException("Grpc stub class doesn't have a constructor which only takes 'Channel' as parameter", e);
}
}
Expand Down
Loading