Skip to content

Clarify that a disabled Tracer/Meter/Logger may still generate SDK internal telemetry - #5253

Open
cijothomas wants to merge 2 commits into
open-telemetry:mainfrom
cijothomas:cijothomas/clarify-disabled-logger-self-metrics
Open

Clarify that a disabled Tracer/Meter/Logger may still generate SDK internal telemetry#5253
cijothomas wants to merge 2 commits into
open-telemetry:mainfrom
cijothomas:cijothomas/clarify-disabled-logger-self-metrics

Conversation

@cijothomas

@cijothomas cijothomas commented Aug 6, 2026

Copy link
Copy Markdown
Member

What

Clarifies that a disabled Tracer, Meter, or Logger — which MUST behave as the corresponding No-op — MAY still generate the SDK's own internal (self-observability) telemetry about that disabled signal.

Why

The SDK self-observability metrics (e.g. otel.sdk.log.created, and the span/processor metrics) are intended to be a complete funnel: the top-of-funnel intake count must remain a true superset of everything downstream, so that any drop is visible as a gap. That requires the SDK to be able to record its own internal telemetry even when the application-facing signal is disabled — for example, counting a log record submitted to a disabled Logger, or a span created by a disabled Tracer.

Today the spec says a disabled Tracer/Meter/Logger MUST behave equivalently to a No-op. Read literally, "No-op" could be taken to forbid the SDK from generating any telemetry, including its own internal metrics, which would make these signals blind to records dropped at a disabled signal. This came up in open-telemetry/opentelemetry-java#8697 (discussion: open-telemetry/opentelemetry-java#8697 (comment)).

What this changes

Adds one sentence to each of the Tracer / Meter / Logger config sections stating that, even when disabled, the SDK MAY still generate its own internal telemetry related to that disabled signal. This is a non-normative clarification (MAY); it does not require any SDK to generate such telemetry, and it does not change the No-op behavior observed by the application.

This unblocks defining the self-observability metrics (starting with otel.sdk.log.created) to count at intake, independent of a signal's enabled/disabled state.

Note on cost

A disabled signal is expected to behave as a No-op, which callers reasonably assume is at (or very near) zero cost. If an SDK's internal telemetry generation on the disabled path is not effectively free, that cost surfaces on the No-op path and erodes that assumption. Implementations that choose to generate internal telemetry for a disabled signal should therefore keep its cost as close to zero as possible (for example, a cheap counter increment, and no work at all when self-observability is turned off). The MAY wording deliberately leaves room for an implementation to generate nothing on this path.

@cijothomas
cijothomas force-pushed the cijothomas/clarify-disabled-logger-self-metrics branch from f710950 to a6d9f98 Compare August 6, 2026 16:01
@opentelemetry-pr-dashboard

opentelemetry-pr-dashboard Bot commented Aug 11, 2026

Copy link
Copy Markdown

Pull request dashboard status

Waiting on the author · refreshed 2026-08-24 21:33 UTC

Resolve merge conflicts.

Respond to 4 review items (e.g. link a commit, explain why not, ask a follow-up):

  • Top-level threads: 1, 2, 3, 4
Status above doesn't look right?
  • Just replied or pushed? Anything around or after the refresh time above may not be picked up yet — give it a few minutes.
  • Should this be with reviewers? Comment /dashboard route:reviewers to route it to them.
  • Anything wrong — including the routing? Report it with what you expected; it helps us improve the dashboard.

@jack-berg jack-berg left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On first glance this seems strange, but reviewers consider current behavior of otel.sdk.log.created without this:

In OpenTelemetry SDKs a Logger is enabled by default, and can be disabled via configuration i.e. LoggerConfig.enabled = false when supported; a disabled Logger is a No-op: emitting to it has no effect, so its records are not counted. Every log record submitted to an enabled Logger is counted, even if it is later filtered or dropped within the SDK (e.g. by minimum severity or trace-based rules, or by a processor or the export pipeline), making this metric the top of the log delivery funnel. Records not submitted to the SDK are not counted (e.g. a caller that skips calling Emit() based on an Enabled() check, or an upstream logging library that filters first).

Oddities:

  • The counter is not counted if LoggerConfig.enabled=false, but is counted if the log was filtered due to failing to meet minimum severity or due to trace-based rules.
  • A log that is never submitted to Emit() due to Enabled() returning false is not counted, despite that same log record being counted if submitted and failing to meet minimum severity or due to trace-based rules.

I noted two potential solutions to this:

To me, it seems like the semantics should be one of:

  • If Logger.enabled() returns false for any reason, do not increment otel.sdk.log.created.
  • OR increment otel.sdk.log.created always, regardless of Logger.enabled(). (This would require changing / re-interpretting the "equivalently to a noop" clause)

This PR facilitates the second option by carving out an exception to the "MUST behave equivalently to a No-op" for internal telemetry.

I'll also note that otel.sdk.span.started is missing details about its interaction with TracerConfig.enabled.

…lemetry

Signed-off-by: cijothomas <cijo.thomas@gmail.com>
@cijothomas
cijothomas force-pushed the cijothomas/clarify-disabled-logger-self-metrics branch from a6d9f98 to e8f3a1f Compare August 12, 2026 15:56
@cijothomas
cijothomas marked this pull request as ready for review August 12, 2026 16:01
@cijothomas
cijothomas requested a review from a team as a code owner August 12, 2026 16:01
Comment thread specification/logs/sdk.md Outdated

If a `Logger` is disabled, it MUST behave equivalently
to [No-op Logger](./noop.md#logger).
to [No-op Logger](./noop.md#logger). Even so, the SDK MAY still emit its own

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does emit mean?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed emit->generate, to avoid confusion with "Emit LogRecord". Is that what you meant?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was trying to understand where you are heading:

For example:

  1. A library uses OpenTelemetry API package, an application using that library is not using/initializing the OpenTelemetry SDK. In this case, the API package might still handle things such as context propagation within/across process boundary. Do you want there to be some internal telemetry or not?
  2. If an application has been using the OpenTelemetry SDK and sending telemetry via OTLP exporter, now the dev decided to upgrade it to the latest version, do you expect the dev to see the internal telemetry from the OTLP exhaust, or they need to explicitly ask for / enable it?

@cijothomas
cijothomas force-pushed the cijothomas/clarify-disabled-logger-self-metrics branch from b49fbf7 to de51ee3 Compare August 12, 2026 23:37
@cijothomas cijothomas changed the title Clarify that a disabled Tracer/Meter/Logger may still emit SDK internal telemetry Clarify that a disabled Tracer/Meter/Logger may still generate SDK internal telemetry Aug 12, 2026
@dashpole

Copy link
Copy Markdown
Contributor

are intended to be a complete funnel: the top-of-funnel intake count must remain a true superset of everything downstream, so that any drop is visible as a gap

The thing that feels strange to me about this is mostly that we already miss any telemetry that is recorded with the enabled pattern:

If mylogger.Enabled(ctx) {
    mylogger.Emit(ctx, log.NewRecord("foo"))
}

vs

mylogger.Emit(ctx, log.NewRecord("foo"))

Did you have a use-case in mind for this? I had initially thought it might be useful for estimating telemetry that you would get if you chose to enable the signal, but missing calls gated by Enabled makes this less useful for that.

@lmolkova

Copy link
Copy Markdown
Member
If mylogger.Enabled(ctx) {
    mylogger.Emit(ctx, log.NewRecord("foo"))
}

I think we'd need another metric to cover number of enabled calls to show the funnel. But it's tricky - Emit would also call Enabled, so we'll count unknown number of records twice unless we do some logic to only count public enabled calls.

@jmacd

jmacd commented Aug 18, 2026

Copy link
Copy Markdown
Member

This breaks my assumptions about No-ops. I feel opposed to counting anything when a Tracer/Meter/Logger/Profiler is disabled. The SDK instrument shouldn't be registered, I would say.

@opentelemetry-pr-dashboard

opentelemetry-pr-dashboard Bot commented Aug 20, 2026

Copy link
Copy Markdown

Hi @cijothomas — just a friendly reminder that this pull request is waiting on you. The dashboard status comment has the open items and is kept current.

  • Replying is enough to hand it off — answer, explain why no change is needed, or ask a follow-up. The dashboard routes it onward once nothing on the list is waiting on you.
  • To hand it back for any other reason, including the dashboard getting this wrong, comment /dashboard route:reviewers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In progress

Development

Successfully merging this pull request may close these issues.

6 participants