-
Notifications
You must be signed in to change notification settings - Fork 433
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 tracing #362
Comments
Hi, yes, sure. Metrics are already exported via micrometer. |
Another thought - may be open telemetry integration is better and faster solution ? It can be integrated as-is with almost zero efforts ? |
I want to add tracing as well.
But I get:
Is there any interceptor we can use to add distributed tracing context?
|
The same issue with
|
I was able to create such a tracing implemented interceptors: 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
class TracingClientInterceptor : ClientInterceptor {
override fun <ReqT, RespT> interceptCall(
method: MethodDescriptor<ReqT, RespT>,
callOptions: CallOptions,
next: Channel
): ClientCall<ReqT, RespT> {
return object : ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(next.newCall(method, callOptions)) {
override fun start(responseListener: ClientCall.Listener<RespT>, headers: Metadata) {
val currentSpan = Span.current()
val traceId = currentSpan.spanContext.traceId
val spanId = currentSpan.spanContext.spanId
if (traceId != TraceId.getInvalid()) {
headers.put(Metadata.Key.of("traceid", Metadata.ASCII_STRING_MARSHALLER), traceId)
headers.put(Metadata.Key.of("spanid", Metadata.ASCII_STRING_MARSHALLER), spanId)
}
super.start(responseListener, headers)
}
}
}
}
...
val managedChannel = ManagedChannelBuilder.forAddress(host, port)
.usePlaintext()
.enableRetry()
.maxInboundMessageSize(maxInboundMessageSize)
.maxInboundMetadataSize(maxInboundMetadataSize)
.idleTimeout(idleTimeout, TimeUnit.MINUTES)
.keepAliveTime(keepAliveTime, TimeUnit.MINUTES)
.keepAliveTimeout(keepAliveTimeout, TimeUnit.MINUTES)
.defaultLoadBalancingPolicy(defaultLoadBalancingPolicy)
.maxRetryAttempts(maxRetryAttempts)
.intercept(TracingClientInterceptor())
.build()
....
Server:
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
class TracingServerInterceptor(private val tracer: Tracer) : ServerInterceptor {
override fun <ReqT, RespT> interceptCall(
call: ServerCall<ReqT, RespT>,
headers: Metadata,
next: ServerCallHandler<ReqT, RespT>
): ServerCall.Listener<ReqT> {
val traceId = headers.get(Metadata.Key.of("traceid", Metadata.ASCII_STRING_MARSHALLER))
val spanId = headers.get(Metadata.Key.of("spanid", Metadata.ASCII_STRING_MARSHALLER))
val spanContext = createSpanContext(traceId, spanId)
val spanBuilder: SpanBuilder = tracer.spanBuilder("span").setParent(spanContext)
val span: Span = spanBuilder.startSpan()
val scopedContext: Context = Context.current().with(span)
val scope: Scope = scopedContext.makeCurrent()
try {
return next.startCall(call, headers)
} finally {
scope.close()
span.end()
}
}
private fun createSpanContext(traceId: String?, spanId: String?): Context {
val spanContext = SpanContext.createFromRemoteParent(
traceId ?: "",
spanId ?: "",
TraceFlags.getDefault(),
TraceState.getDefault()
)
return Context.current().with(Span.wrap(spanContext))
}
}
@Configuration
@EnableConfigurationProperties(OtlpProperties::class)
class OtelConfiguration {
@Bean
fun otlpExporter(properties: OtlpProperties): OtlpGrpcSpanExporter {
val builder = OtlpGrpcSpanExporter.builder().setEndpoint(properties.endpoint)
return builder.build()
}
@Bean
fun tracer(otlpExporter: OtlpGrpcSpanExporter): Tracer {
val tracerProvider = SdkTracerProvider.builder()
.addSpanProcessor(BatchSpanProcessor.builder(otlpExporter).build())
.build()
val openTelemetry = OpenTelemetrySdk.builder()
.setTracerProvider(tracerProvider)
.buildAndRegisterGlobal()
return openTelemetry.tracerProvider.get("service")
}
}
import io.opentelemetry.api.trace.Tracer
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
@Configuration
class GrpcConfig {
@Bean
fun tracingServerInterceptor(tracer: Tracer): TracingServerInterceptor {
return TracingServerInterceptor(tracer)
}
}
...
@GRpcService(interceptors = [LogInterceptor::class, TracingServerInterceptor::class])
... |
Now I trace in my logs:
Not sure how to integrate it with
|
Great, glad to hear that. Do you mind to PR this? |
yeah, I can open a PR with such interceptors |
Opened PR: #376 |
@jvmlet hey, can we merge the PR? Would be nice to have it already |
@jvmlet, is it going to be released anytime soon ? |
It is going to be released, but please be patient with the current disaster in Israel.... |
@jvmlet I am sorry I didn't know you are from there. We stand with Israel, the humanity will win. |
@vicmosin , thanks (writing from the shelter) |
Stay safe and stay strong @jvmlet 🇮🇱 |
@o-shevchenko I saw the PR was closed, any hints how can it be achieved at the end? |
Since spring cloud sleuth doesn't work with Spring Boot 3.X, and the core of this project was moved to Micrometer Tracing which hasn't support natively for gRPC tracing, ¿is there a plan to support Micrometer tracing?
The text was updated successfully, but these errors were encountered: