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

Allow developer to choose whether Helidon injects OTel types which notify span listeners #9610

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

tjquinno
Copy link
Member

@tjquinno tjquinno commented Dec 18, 2024

Description

Resolves #9079

Release Note

As part of Helidon's support for MP Telemetry developers have been able to inject the OpenTelemetry Tracer and Span types into their code. But these types do not support Helidon-specific span listeners (which are notified when spans start and end or scopes are activated and closed).

This PR allows users to assign the config setting telemetry.injection-type to native or neutral:

  • native - the default and the prior behavior - Helidon injects native OTel Tracer and Span objects - span listeners are not notified of state changes related to injected objects
  • neutral - Helidon injects wrappers around the native OTel types which delegate to the underlying OTel object but also notify any registered SpanListener objects (which receive parameters that are the Helidon neutral types: Tracer, Span.Builder, Span, Scope).

Developers need to opt into the new behavior because pre-existing applications might use instanceof or similar type-sensitive constructs on injected values referring to OTel implementation types. If Helidon were to change now to always inject wrapped objects in order to notify span listeners then those constructs would no longer work as before.

Alternative not adopted: always inject the neutral wrapping objects

We could have just changed Helidon so it always inject the neutral wrapping objects, avoiding the addition of the config setting and the parallel producers.

Some people advocated for that, pointing out that developers should probably not be injecting objects (which could be proxies) and then query their types.

But we know that some existing user code checks OTel Span objects to see if they are ReadableSpan and then casts them to use the ReadableSpan API. AFAIK these use cases do not currently do so with injected spans but, if they do or if they tried to, such code would break if Helidon started injecting only the wrapping objects.

That's why this PR added the config setting, maintains the current behavior by default, and gives the user control (and responsibility).

Highlights of the changes

The main point is offer a choice for whether Helidon should inject the native OTel Span and Tracer objects as before or to inject Helidon-written wrappers around those OTel types, wrappers which notify registered span listeners of state changes and also delegate to the native OTel objects.

  1. Add the io.helidon.tracing.Wrapper interface which declares the unwrap method. The neutral injected objects implement Wrapper so developers, if needed, can cast injected objects to Wrapper and then unwrap them to get to the underlying OTel objects.
  2. Add configuration for the injection-type setting. We do not have pre-existing telemetry-based configuration that is Helidon-specific. (There are otel.* settings which Helidon supports in compliance with the MP Telemetry spec but the new setting is Helidon-specific and not related to OTel so should not be under the otel section.)
  3. Generalize the CDI producer for telemetry-related types so there are two implementations, one that returns native OTel objects and one that returns wrapped ones. Configuration determines which is used.
  4. The wrapped implementations of the OTel interfaces contain a reference to the corresponding OTel native object and a reference to a Helidon Tracer or Span etc. wrapper around the native OTel object. Most methods in the wrapper classes simply delegate to the native OTel object. The exception: any method that causes changes of state (which the span listeners observe)--such as starting or ending a span or activating or closing a scope--invoke the Helidon wrapper which does the notification and delegates to the OTel object.
  5. Some new factory methods for the Helidon neutral types allow the new telemetry producer code to create Helidon neutral wrappers around existing OTel objects.
  6. New tests exercise the config and injection of wrappers and check for proper notification of span listeners.
  7. Updates to the telemetry page (under MP) describe the changes.

Documentation

PR includes doc updates.

@tjquinno tjquinno self-assigned this Dec 18, 2024
@oracle-contributor-agreement oracle-contributor-agreement bot added the OCA Verified All contributors have signed the Oracle Contributor Agreement. label Dec 18, 2024
@tjquinno tjquinno changed the title Allow config to enable injection of OTel types which notify span listeners Allow developer to choose whether Helidon injects OTel types which notify span listeners Dec 18, 2024
@tjquinno tjquinno force-pushed the 4.x-mp-telemetry-listeners branch from e9ef661 to 7f98afb Compare January 2, 2025 23:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
OCA Verified All contributors have signed the Oracle Contributor Agreement.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

SpanListener do not get invoked when native OTel tracer is used via Inject or unwrap
1 participant