-
Notifications
You must be signed in to change notification settings - Fork 431
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
Distributed tracing support with Micrometer and OpenTelemetry #376
Changes from 5 commits
98ad35e
01e7620
af9e289
8fae4d3
2a2f309
2d5d1b5
fda47dc
56e34d9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package org.lognet.springboot.grpc.tracing; | ||
|
||
import io.grpc.CallOptions; | ||
import io.grpc.Channel; | ||
import io.grpc.ClientCall; | ||
import io.grpc.ClientInterceptor; | ||
import io.grpc.ForwardingClientCall; | ||
import io.grpc.Metadata; | ||
import io.grpc.MethodDescriptor; | ||
import io.opentelemetry.api.trace.Span; | ||
import io.opentelemetry.api.trace.TraceId; | ||
|
||
public class TracingClientInterceptor implements ClientInterceptor { | ||
Check warning on line 13 in grpc-client-spring-boot-starter/src/main/java/org/lognet/springboot/grpc/tracing/TracingClientInterceptor.java
|
||
@Override | ||
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall( | ||
MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) { | ||
|
||
return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(next.newCall(method, callOptions)) { | ||
Check warning on line 18 in grpc-client-spring-boot-starter/src/main/java/org/lognet/springboot/grpc/tracing/TracingClientInterceptor.java
|
||
@Override | ||
public void start(ClientCall.Listener<RespT> responseListener, Metadata headers) { | ||
Span currentSpan = Span.current(); | ||
String traceId = currentSpan.getSpanContext().getTraceId(); | ||
String spanId = currentSpan.getSpanContext().getSpanId(); | ||
Check warning on line 23 in grpc-client-spring-boot-starter/src/main/java/org/lognet/springboot/grpc/tracing/TracingClientInterceptor.java
|
||
|
||
if (!traceId.equals(TraceId.getInvalid())) { | ||
headers.put(Metadata.Key.of("traceId", Metadata.ASCII_STRING_MARSHALLER), traceId); | ||
headers.put(Metadata.Key.of("spanId", Metadata.ASCII_STRING_MARSHALLER), spanId); | ||
Check warning on line 27 in grpc-client-spring-boot-starter/src/main/java/org/lognet/springboot/grpc/tracing/TracingClientInterceptor.java
|
||
} | ||
super.start(responseListener, headers); | ||
} | ||
Check warning on line 30 in grpc-client-spring-boot-starter/src/main/java/org/lognet/springboot/grpc/tracing/TracingClientInterceptor.java
|
||
}; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package org.lognet.springboot.grpc.autoconfigure.tracing; | ||
|
||
import io.opentelemetry.api.trace.Tracer; | ||
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporter; | ||
import io.opentelemetry.exporter.otlp.trace.OtlpGrpcSpanExporterBuilder; | ||
import io.opentelemetry.sdk.OpenTelemetrySdk; | ||
import io.opentelemetry.sdk.trace.SdkTracerProvider; | ||
import io.opentelemetry.sdk.trace.export.BatchSpanProcessor; | ||
import org.lognet.springboot.grpc.tracing.TracingServerInterceptor; | ||
import org.springframework.boot.actuate.autoconfigure.tracing.otlp.OtlpProperties; | ||
import org.springframework.boot.context.properties.EnableConfigurationProperties; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
|
||
@Configuration | ||
@EnableConfigurationProperties(OtlpProperties.class) | ||
public class OtelConfiguration { | ||
Check warning on line 17 in grpc-spring-boot-starter/src/main/java/org/lognet/springboot/grpc/autoconfigure/tracing/OtelConfiguration.java
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this should be conditional on There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. makes sense |
||
|
||
@Bean | ||
public OtlpGrpcSpanExporter otlpExporter(OtlpProperties properties) { | ||
OtlpGrpcSpanExporterBuilder builder = OtlpGrpcSpanExporter.builder().setEndpoint(properties.getEndpoint()); | ||
return builder.build(); | ||
} | ||
Check warning on line 23 in grpc-spring-boot-starter/src/main/java/org/lognet/springboot/grpc/autoconfigure/tracing/OtelConfiguration.java
|
||
|
||
@Bean | ||
public Tracer tracer(OtlpGrpcSpanExporter otlpExporter) { | ||
SdkTracerProvider tracerProvider = SdkTracerProvider.builder() | ||
.addSpanProcessor(BatchSpanProcessor.builder(otlpExporter).build()) | ||
.build(); | ||
|
||
OpenTelemetrySdk openTelemetry = OpenTelemetrySdk.builder() | ||
Check warning on line 31 in grpc-spring-boot-starter/src/main/java/org/lognet/springboot/grpc/autoconfigure/tracing/OtelConfiguration.java
|
||
.setTracerProvider(tracerProvider) | ||
.buildAndRegisterGlobal(); | ||
|
||
Check warning on line 34 in grpc-spring-boot-starter/src/main/java/org/lognet/springboot/grpc/autoconfigure/tracing/OtelConfiguration.java
|
||
return openTelemetry.getTracerProvider().get("grpc-spring-boot-starter"); | ||
} | ||
Check warning on line 36 in grpc-spring-boot-starter/src/main/java/org/lognet/springboot/grpc/autoconfigure/tracing/OtelConfiguration.java
|
||
|
||
@Bean | ||
public TracingServerInterceptor tracingServerInterceptor(Tracer tracer) { | ||
return new TracingServerInterceptor(tracer); | ||
} | ||
Check warning on line 41 in grpc-spring-boot-starter/src/main/java/org/lognet/springboot/grpc/autoconfigure/tracing/OtelConfiguration.java
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package org.lognet.springboot.grpc.log; | ||
|
||
import io.grpc.Metadata; | ||
import io.grpc.ServerCall; | ||
import io.grpc.ServerCallHandler; | ||
import io.grpc.ServerInterceptor; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.springframework.stereotype.Component; | ||
|
||
@Component | ||
public class LogInterceptor implements ServerInterceptor { | ||
Check warning on line 12 in grpc-spring-boot-starter/src/main/java/org/lognet/springboot/grpc/log/LogInterceptor.java
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is an example but LogInterceptor was not a part of grpc-spring-boot-starter. I can add it in a separate PR if needed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this class needed ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just wanted to use it from the library. Not sure why it doesn't exist. Removed |
||
|
||
private final Logger logger = LoggerFactory.getLogger(LogInterceptor.class); | ||
Check warning on line 14 in grpc-spring-boot-starter/src/main/java/org/lognet/springboot/grpc/log/LogInterceptor.java
|
||
|
||
@Override | ||
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall( | ||
ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) { | ||
logger.info(call.getMethodDescriptor().getFullMethodName()); | ||
return next.startCall(call, headers); | ||
Check warning on line 20 in grpc-spring-boot-starter/src/main/java/org/lognet/springboot/grpc/log/LogInterceptor.java
|
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package org.lognet.springboot.grpc.tracing; | ||
|
||
import io.grpc.Metadata; | ||
import io.grpc.ServerCall; | ||
import io.grpc.ServerCallHandler; | ||
import io.grpc.ServerInterceptor; | ||
import io.opentelemetry.api.trace.Span; | ||
import io.opentelemetry.api.trace.SpanBuilder; | ||
import io.opentelemetry.api.trace.SpanContext; | ||
import io.opentelemetry.api.trace.TraceFlags; | ||
import io.opentelemetry.api.trace.TraceState; | ||
import io.opentelemetry.api.trace.Tracer; | ||
import io.opentelemetry.context.Context; | ||
import io.opentelemetry.context.Scope; | ||
|
||
public class TracingServerInterceptor implements ServerInterceptor { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should have the highest precedence https://github.com/LogNet/grpc-spring-boot-starter#421-interceptors-ordering There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. added @order(20)? I don't see you use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. see this, we will need to move There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've set HIGHEST_PRECEDENCE. Do I need to touch recovery and auth here? Please, let me know if you want to change order somehow |
||
|
||
private final Tracer tracer; | ||
|
||
public TracingServerInterceptor(Tracer tracer) { | ||
this.tracer = tracer; | ||
} | ||
Check warning on line 22 in grpc-spring-boot-starter/src/main/java/org/lognet/springboot/grpc/tracing/TracingServerInterceptor.java
|
||
|
||
@Override | ||
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall( | ||
ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) { | ||
|
||
String traceId = headers.get(Metadata.Key.of("traceId", Metadata.ASCII_STRING_MARSHALLER)); | ||
String spanId = headers.get(Metadata.Key.of("spanId", Metadata.ASCII_STRING_MARSHALLER)); | ||
Check warning on line 29 in grpc-spring-boot-starter/src/main/java/org/lognet/springboot/grpc/tracing/TracingServerInterceptor.java
|
||
|
||
Context spanContext = createSpanContext(traceId, spanId); | ||
SpanBuilder spanBuilder = tracer.spanBuilder("grpc-spring-boot-starter-span").setParent(spanContext); | ||
Span span = spanBuilder.startSpan(); | ||
Context scopedContext = Context.current().with(span); | ||
|
||
Check warning on line 35 in grpc-spring-boot-starter/src/main/java/org/lognet/springboot/grpc/tracing/TracingServerInterceptor.java
|
||
try (Scope scope = scopedContext.makeCurrent()) { | ||
return next.startCall(call, headers); | ||
} finally { | ||
Check warning on line 38 in grpc-spring-boot-starter/src/main/java/org/lognet/springboot/grpc/tracing/TracingServerInterceptor.java
|
||
span.end(); | ||
} | ||
Check warning on line 40 in grpc-spring-boot-starter/src/main/java/org/lognet/springboot/grpc/tracing/TracingServerInterceptor.java
|
||
} | ||
|
||
private Context createSpanContext(String traceId, String spanId) { | ||
SpanContext spanContext = SpanContext.createFromRemoteParent( | ||
traceId != null ? traceId : "", | ||
spanId != null ? spanId : "", | ||
Check warning on line 46 in grpc-spring-boot-starter/src/main/java/org/lognet/springboot/grpc/tracing/TracingServerInterceptor.java
|
||
TraceFlags.getDefault(), | ||
TraceState.getDefault() | ||
); | ||
return Context.current().with(Span.wrap(spanContext)); | ||
} | ||
Check warning on line 51 in grpc-spring-boot-starter/src/main/java/org/lognet/springboot/grpc/tracing/TracingServerInterceptor.java
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
io.micrometer:micrometer-tracing-bridge-otel
is it in-use ?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.