-
Notifications
You must be signed in to change notification settings - Fork 27
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
Add support for OpenTelemetry #65
Add support for OpenTelemetry #65
Conversation
Maybe it's better to add additional modules to initialize different OTEL standalone instrumentations. For example, if you want to active OTEL for gRPC, you should add With current Micronaut features ecosystem I can see a list of such modules:
|
* @since 1.0 | ||
*/ | ||
@ConfigurationProperties(PREFIX) | ||
public class DefaultConfiguration implements Toggleable { |
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.
Rename this to something more specific. DefaultConfiguration will too generic a name.
Member
I would probably also use an interface here as it will be simpler:
@ConfigurationProperties(PREFIX)
interface TracingConfiguration extends Toggleable {
String PREFIX = "tracing";
}
*/ | ||
@Singleton | ||
@Primary | ||
OpenTelemetry defaultOpenTelemetry() { |
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.
Probably worth making protected if the intention is to allow the user to subclass and override
public class DefaultTelemetryTracer { | ||
|
||
@Property(name = APPLICATION_NAME) | ||
String applicationName; |
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.
Try not to use field injection. Better to make this final and use constructor injection making the type immutable.
} else { | ||
// must be new | ||
String operationName = newSpan.stringValue().orElse(null); | ||
Optional<String> hystrixCommand = context.stringValue(HYSTRIX_ANNOTATION); |
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.
You can remove this logic, hystrix is deprecated
context.stringValue(HYSTRIX_ANNOTATION, "group").ifPresent(s -> | ||
span.setAttribute(TAG_HYSTRIX_GROUP, s) | ||
); | ||
context.stringValue(HYSTRIX_ANNOTATION, "threadPool").ifPresent(s -> | ||
span.setAttribute(TAG_HYSTRIX_THREAD_POOL, s) | ||
); |
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.
you can remove this hystrix is deprecated
} | ||
|
||
try (Scope ignored = span.makeCurrent()) { | ||
publisher.subscribe(new Subscriber<T>() { |
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.
needs to implement CoreSubscriber
from reactor for propagation to work
* The tracing subscriber. | ||
*/ | ||
@Internal | ||
protected class TracingSubscriber implements Subscriber<T> { |
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.
needs to implement CoreSubscriber
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.
@n0tl3ss please also check the example of gRPC interceptors, which also reuse the official standalone gRPC instrumentation library: https://github.com/tailrocks/micronaut-opentelemetry/tree/7f1e83e70e023375b3fe6684a8c273fc649d1682/opentelemetry/src/main/java/io/micronaut/opentelemetry/instrumentation/grpc
* @author Nemanja Mikic | ||
* @since 1.0 | ||
*/ | ||
public abstract class AbstractOpenTracingFilter implements HttpFilter { |
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.
I suggest don't use a custom implementation of OTEL instrumenter, we can reuse the official library here. The benefit of this approach is that Micronaut traces will have the same format as the official OTEL implementation. For those companies who combine different frameworks and run multiple applications, some with OTEL javaagent they will not see differences in OTEL spans created in Micronaut.
Please check my comments for OpenTracingClientFilter
and OpenTracingServerFilter
, which provide links to examples.
*/ | ||
@Filter(CLIENT_PATH) | ||
@Requires(beans = Tracer.class) | ||
public class OpenTelemetryClientFilter extends AbstractOpenTracingFilter implements HttpClientFilter { |
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.
It's better to use the official opentelemetry-instrumentation-api
library here, which provides API to simplify creating new instrumentation. You can check my example which uses this library: https://github.com/tailrocks/micronaut-opentelemetry/blob/7f1e83e70e023375b3fe6684a8c273fc649d1682/opentelemetry/src/main/java/io/micronaut/opentelemetry/instrumentation/http/client/OpenTelemetryClientFilter.java#L41
If you need some explanation why it's much better than re-implement everything from scratch, please tag me and I will provide some examples.
*/ | ||
@Filter(SERVER_PATH) | ||
@Requires(beans = Tracer.class) | ||
public class OpenTelemetryServerFilter extends AbstractOpenTracingFilter implements HttpServerFilter { |
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.
Please take a look at this example which reuse official opentelemetry-instrumentation-api
library: https://github.com/tailrocks/micronaut-opentelemetry/blob/7f1e83e70e023375b3fe6684a8c273fc649d1682/opentelemetry/src/main/java/io/micronaut/opentelemetry/instrumentation/http/server/OpenTelemetryServerFilter.java#L42
...emetry/src/main/java/io/micronaut/tracing/opentelemetry/instrument/util/MdcInstrumenter.java
Outdated
Show resolved
Hide resolved
...io/micronaut/tracing/opentelemetry/instrument/util/TracingInvocationInstrumenterFactory.java
Outdated
Show resolved
Hide resolved
...ronaut/tracing/opentelemetry/instrument/util/ThreadTracingInvocationInstrumenterFactory.java
Outdated
Show resolved
Hide resolved
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.
I'll try this branch in some of my Micronaut applications and provide you with some feedback.
tracing-opentelemetry/build.gradle
Outdated
dependencies { | ||
api mn.micronaut.runtime | ||
api mn.micronaut.http.client | ||
api mn.micronaut.grpc.server.runtime |
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.
I think we better split it into modules or add all initializers into one module but activate only if the class is provided in the classpath. For example to activate gRPC interceptors you should add:
implementation("io.opentelemetry.instrumentation:opentelemetry-grpc-1.6")
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.
Same for Micronaut HTTP client as well.
* @author Nemanja Mikic | ||
*/ | ||
@Factory | ||
public class GrpcClientTracingInterceptorFactory { |
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.
It's better to write a test, this can be an example: https://github.com/micronaut-projects/micronaut-grpc/blob/master/grpc-client-runtime/src/test/groovy/io/micronaut/grpc/server/tracing/GrpcTracingSpec.groovy
gradle/libs.versions.toml
Outdated
@@ -16,7 +18,14 @@ opentracing = { module = 'io.opentracing:opentracing-api', version.ref = 'opentr | |||
opentracing-util = { module = 'io.opentracing:opentracing-util', version.ref = 'opentracing' } | |||
zipkin-brave-instrumentation = { module = 'io.zipkin.brave:brave-instrumentation-http', version.ref = 'brave-instrumentation' } | |||
zipkin-reporter = { module = 'io.zipkin.reporter2:zipkin-reporter', version.ref = 'zipkin-reporter' } | |||
|
|||
opentelemetry-api = {module='io.opentelemetry:opentelemetry-api', version.ref ='opentelemetry'} |
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.
Seems it's not formatted as usual. Please apply the same format.
opentelemetry-sdk-logs = {module='io.opentelemetry:opentelemetry-sdk-logs', version.ref = 'opentelemetry-alpha'} | ||
opentelemetry-extension-annotations = {module='io.opentelemetry:opentelemetry-extension-annotations', version.ref = 'opentelemetry'} | ||
opentelemetry-instrumentation-api = {module='io.opentelemetry.instrumentation:opentelemetry-instrumentation-api', version.ref = 'opentelemetry-alpha'} | ||
opentelemetry-instrumentation-grpc = {module='io.opentelemetry.instrumentation:opentelemetry-grpc-1.6', version.ref = 'opentelemetry-alpha'} | ||
[plugins] |
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.
Maybe add a new line before [plugins]
?
@donbeave I will try to add grpc tests. Do you want me to create With test I have an issue with generating protobuff classes. Here is an error:
|
Also this test |
I'm not sure which way is better, maybe @graemerocher can give us some feedback. I see two approaches
or
|
@Override | ||
public List<AnnotationValue<?>> map(AnnotationValue<WithSpan> annotation, VisitorContext visitorContext) { | ||
AnnotationValue<InterceptorBinding> interceptorBinding = AnnotationValue.builder(InterceptorBinding.class) | ||
.value(ContinueSpan.class) |
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.
Looks like it's not correct to map WithSpan
to ContinueSpan
annotation, it should be mapped to NewSpan
annotation instead, based on its description from javadoc:
This annotation marks that an execution of this method or constructor should result in a new io.opentelemetry.api.trace.Span.
Application developers can use this annotation to signal OpenTelemetry auto-instrumentation that a new span should be created whenever marked method is executed.
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.
I have changed WithSpan
to match the NewSpan
. Grpc test added, and I don't know how to fix test that is falling on ci / cd because localy it is passing: https://ge.micronaut.io/s/53d2qu5xuicqy. The issue is in mapping/transforming annotations.
...elemetry-grpc/src/test/groovy/io/micronaut/tracing/util/TestDefaultOpenTelemetryFactory.java
Show resolved
Hide resolved
...ava/io/micronaut/tracing/opentelemetry/instrument/http/client/OpenTelemetryClientFilter.java
Outdated
Show resolved
Hide resolved
...ava/io/micronaut/tracing/opentelemetry/instrument/http/server/OpenTelemetryServerFilter.java
Outdated
Show resolved
Hide resolved
...metry/src/main/java/io/micronaut/tracing/opentelemetry/instrument/util/TracingPublisher.java
Show resolved
Hide resolved
...metry/src/main/java/io/micronaut/tracing/opentelemetry/instrument/util/TracingPublisher.java
Outdated
Show resolved
Hide resolved
...ronaut/tracing/opentelemetry/instrument/http/client/MicronautHttpClientTelemetryBuilder.java
Outdated
Show resolved
Hide resolved
@Factory | ||
public class DefaultOpenTelemetryFactory { | ||
|
||
private static final String SERVICE_NAME_KEY = "otel.service.name"; |
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.
Can we have opentelemetry.
instead of otel.
? WDYT @graemerocher
I would also have a constant PREFIX
.
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.
The "otel" prefix comes from https://github.com/open-telemetry/opentelemetry-java/blob/main/sdk-extensions/autoconfigure/README.md and this factory overrides some defaults of this library.
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.
Agree, I think if we want to reuse the original official OpenTelemetry configuration properties we should use otel
as well. Maybe it will be nice to support the configuration of most of these properties directly in the application.yml
file.
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.
@donbeave We already support most of linked properties through application.yml
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.
Fine with me
tracing-aws/src/main/java/io.micronaut.tracing/AwsOpenTelemetryFactory.java
Outdated
Show resolved
Hide resolved
tracing-aws/src/main/java/io.micronaut.tracing/AwsOpenTelemetryFactory.java
Outdated
Show resolved
Hide resolved
...ronaut/tracing/opentelemetry/instrument/http/client/MicronautHttpClientTelemetryBuilder.java
Outdated
Show resolved
Hide resolved
I tried to apply all of your suggestions @graemerocher @dstepanov. Can you please double check everything? |
...io/micronaut/tracing/opentelemetry/instrument/http/client/OpenTelemetryHttpClientConfig.java
Show resolved
Hide resolved
...io/micronaut/tracing/opentelemetry/instrument/http/client/OpenTelemetryHttpClientConfig.java
Show resolved
Hide resolved
...ronaut/tracing/opentelemetry/instrument/http/server/MicronautHttpServerAttributesGetter.java
Outdated
Show resolved
Hide resolved
...cronaut/tracing/opentelemetry/instrument/http/server/MicronautServerAttributesExtractor.java
Outdated
Show resolved
Hide resolved
...io/micronaut/tracing/opentelemetry/instrument/http/server/OpenTelemetryHttpServerConfig.java
Show resolved
Hide resolved
...io/micronaut/tracing/opentelemetry/instrument/http/server/OpenTelemetryHttpServerConfig.java
Show resolved
Hide resolved
...ava/io/micronaut/tracing/opentelemetry/instrument/http/server/OpenTelemetryServerFilter.java
Outdated
Show resolved
Hide resolved
...ronaut/tracing/opentelemetry/instrument/http/client/MicronautHttpClientTelemetryFactory.java
Outdated
Show resolved
Hide resolved
...ronaut/tracing/opentelemetry/instrument/http/client/MicronautHttpClientTelemetryFactory.java
Outdated
Show resolved
Hide resolved
...ava/io/micronaut/tracing/opentelemetry/instrument/http/client/OpenTelemetryClientFilter.java
Outdated
Show resolved
Hide resolved
...ronaut/tracing/opentelemetry/instrument/http/server/MicronautHttpServerTelemetryFactory.java
Outdated
Show resolved
Hide resolved
...ronaut/tracing/opentelemetry/instrument/http/server/MicronautHttpServerTelemetryFactory.java
Outdated
Show resolved
Hide resolved
...ava/io/micronaut/tracing/opentelemetry/instrument/http/server/OpenTelemetryServerFilter.java
Outdated
Show resolved
Hide resolved
@Factory | ||
public class DefaultOpenTelemetryFactory { | ||
|
||
private static final String SERVICE_NAME_KEY = "otel.service.name"; |
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.
Fine with me
...metry/src/main/java/io/micronaut/tracing/opentelemetry/instrument/util/TracingPublisher.java
Outdated
Show resolved
Hide resolved
...metry/src/main/java/io/micronaut/tracing/opentelemetry/instrument/util/TracingPublisher.java
Outdated
Show resolved
Hide resolved
...telemetry/src/main/java/io/micronaut/tracing/opentelemetry/interceptor/TraceInterceptor.java
Outdated
Show resolved
Hide resolved
opentracing = '0.33.0' | ||
managed-opentracing-grpc = '0.2.3' | ||
managed-protobuf = '0.8.17' |
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.
I think this does not need to be managed.
|
||
/** | ||
* Implements tracing logic for <code>ContinueSpan</code> and <code>NewSpan</code> | ||
* using the Open Tracing API. |
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.
Open Tracing API.
Is it a typo? Correct is OpenTelemetry API, right?
If nobody has any further objections this looks like a good initial start to me |
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.
if folks would like to try it out before final release a |
This PR adds OpenTelemetry in the
micronaut-tracing
module.Modules
Five new modules are added:
@WithSpan
and@SpanAttribute
annotations.Supported Features
@WithSpan
and@SpanAttribute
annotations are fully supported. The@SpanTag
,@NewSpan
,@ContinueSpan
from the Open Tracing are also usable.application.yml
fileapplication.yml
.otel.traces.exporter = none
,otel.metrics.exporter = none
,otel.logs.exporte = none
,otel.service.name = value of the application.name
. This values can be overridden throughapplication.yml
file.Other