opentracing / opentracing-java

OpenTracing API for Java. 🛑 This library is DEPRECATED! https://github.com/opentracing/specification/issues/163
http://opentracing.io
Apache License 2.0
1.68k stars 344 forks source link

`NoopSpan` cannot be used as a default, parent span without throwing Exception. #375

Closed arjun-1 closed 4 years ago

arjun-1 commented 4 years ago

I don't use opentracing-java directly, but wrap it through Scala (https://github.com/zio/zio-telemetry). I am in need of a 'default' span for opentracing-java (analogous to DefaultSpan in opentelemetry, to be used for initialization of the library), and thought that NoopSpan would be a suitable candidate.

I can not use NoopSpan as a parent span however without getting ClassCastException. For example in tests (when using .asChildOf):

[info]       java.lang.ClassCastException: class io.opentracing.noop.NoopSpanContextImpl cannot be cast to class io.opentracing.mock.MockSpan$MockContext (io.opentracing.noop.NoopSpanContextImpl and io.opentracing.mock.MockSpan$MockContext are in unnamed module of loader sbt.internal.LayeredClassLoader @71ee261a)
[info]          at io.opentracing.mock.MockTracer$SpanBuilder.addReference(MockTracer.java:340)
[info]          at io.opentracing.mock.MockTracer$SpanBuilder.asChildOf(MockTracer.java:328)
[info]          at io.opentracing.mock.MockTracer$SpanBuilder.asChildOf(MockTracer.java:307)

Or when using jaegertracing:

â•‘ java.lang.ClassCastException: class io.opentracing.noop.NoopSpanContextImpl cannot be cast to class io.jaegertracing.internal.JaegerSpanContext (io.opentracing.noop.NoopSpanContextImpl and io.jaegertracing.internal.JaegerSpanContext are in unnamed module of loader sbt.internal.LayeredClassLoader @446b0577)
â•‘   at io.jaegertracing.internal.JaegerTracer.inject(JaegerTracer.java:211)

Is this intended behavior? I understand a NoopSpan is not intended to be used as a valid root span, but a user of the wrapping library would preferably not be confronted with an exception if a child span is created without creating a valid root span first. Note that the strategy of using DefaultSpan as a default span works in opentelemetry-java without any exception.

yurishkuro commented 4 years ago

In OpenTracing the Tracer is responsible for creating spans. Jaeger tracer will never create a NoopSpan, so the class cast exception should not be happening, unless you're somehow trying to use two different tracers simultaneously.

OpenTelemetry does not have a notion of 'default span' in the spec.

arjun-1 commented 4 years ago

Hi @yurishkuro, thanks for your response. I tried making the following minimal example https://github.com/arjun-1/opentracing-example, explaining the issue (or perhaps my improper use) with opentracing-java.

In this example I create a childspan of a NoopSpan:

val mockTracer = new MockTracer()

val span: Span = NoopSpan.INSTANCE

mockTracer.buildSpan("operationName").asChildOf(span).start()

Which yields a ClassCastException.

There is also another example showcased, which shows a similar issue happening in combination with JaegerTracer:

val span: Span = NoopSpan.INSTANCE
val jaegerTracer = new Configuration("seviceName").getTracerBuilder.build()

val textMapAdapter = new TextMapAdapter(Map.empty.asJava)
jaegerTracer.inject(span.context(), Format.Builtin.TEXT_MAP, textMapAdapter)

In these examples, I only use one tracer at a time. Is it possible though that I am using NoopSpan in a way that is not intended?

whiskeysierra commented 4 years ago

NoopSpan is an implementation detail of NoopTracer, so the following statement is technically false:

In these examples, I only use one tracer at a time.

arjun-1 commented 4 years ago

Ah thanks, I think I get it now. I understand correctly that even though NoopSpan extends Span, NoopSpan cannot be used interchangeably with any other Span, if NoopSpan itself belongs to a different Tracer?

My initial thought was that NoopSpan could be interchangeable be used for any Span, driven by the observation that the equivalent of above examples work fine in java-opentelemetry (using io.opentelemetry.trace.DefaultSpan.INVALID for NoopSpan). But of course that is not any guarantee for a different library :slightly_smiling_face: .

If I want to initialize a 'dummy' value of type Span (not being null) in java-opentracing (and which would work with all kinds of Tracer), would there be a recommended way?

whiskeysierra commented 4 years ago

If I want to initialize a 'dummy' value of type Span (not being null) in java-opentracing (and which would work with all kinds of Tracer), would there be a recommended way?

I don't think that's possible. Most implementations of Tracer that I know of will cast spans and contexts to their implementation classes to access details that are not part of the standard OpenTracing API. See also https://github.com/opentracing-contrib/java-api-extensions/issues/16 for a similar issue.

arjun-1 commented 4 years ago

Thanks, I understand :slightly_smiling_face: