Skip to content

Commit 83b1cdb

Browse files
authored
Emit telemetry under the instrumentation's own scope (#632)
* fix instrumentation scope name and version, add tests * Enforce the instrumentation scope with a shared test fixture Replace the per-package instrumentation-scope tests with an autouse fixture that checks every TelemetryHandler built by instrumentation code during any test. * Require util-genai 1.2b0.dev where the scope arguments are used claude-agent-sdk, crewai and dspy declared older floors, so their oldest envs resolved a util-genai without instrumentation_scope_name. Assisted-by: Claude Opus 5 * Renumber changelog fragments to the PR number * Apply suggestion from @lmolkova * Keep the fallback scope name and version consistent Assisted-by: Claude Opus 5 * Fix changelog wording * Use package names for instrumentation scopes Assisted-by: ChatGPT 5 * Apply scope test formatting
1 parent ba8f9ff commit 83b1cdb

57 files changed

Lines changed: 563 additions & 38 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.github/instructions/instrumentation.instructions.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ prefer opt-in or additive. Breaking changes need explicit justification in the P
3737

3838
- Spans, logs, metrics, and events must go through `opentelemetry-util-genai`. Direct use of
3939
`Tracer`, `Meter`, `Logger`, or event APIs is not allowed.
40+
- `TelemetryHandler` must use the dotted instrumentation package path as
41+
`instrumentation_scope_name` and its `__version__` as `instrumentation_scope_version` so spans,
42+
metrics, and logs carry the instrumentation's own scope. `__package__` may be used when it
43+
resolves to that exact path. The shared `TelemetryHandlerScopeTest` enforces both values. Flag
44+
handlers built without them. `get_telemetry_handler()` is deprecated; flag new uses.
4045
- Content capture, hooks, and other cross-cutting configuration are owned by the util.
4146
Instrumentations must not introduce their own env vars, settings, or hook interfaces.
4247
- Completion hook wiring must follow the util's contract (reference:

‎AGENTS.md‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,12 @@ Apply to packages under `instrumentation/`.
191191
- Spans, logs, metrics, and events should go through `opentelemetry-util-genai`. Do not call OTel
192192
`Tracer`/`Meter`/`Logger` directly, and import only its public surface — never an
193193
`opentelemetry.util.genai._*` module.
194+
- Construct the `TelemetryHandler` with the dotted instrumentation package path as
195+
`instrumentation_scope_name` and the package's `__version__` as
196+
`instrumentation_scope_version`. Use `__package__` when it resolves to that exact package path;
197+
do not use a submodule's `__name__`. Import `__version__` from the package's `version` module.
198+
Subclass `opentelemetry.test_util_genai.scope.TelemetryHandlerScopeTest` in each package to verify
199+
its exact name and version on spans, metrics, and logs.
194200
- Content capture, hooks, and configuration are owned by the util. Don't add instrumentation-local
195201
env vars or settings.
196202
- Models describing complex attributes are owned by `opentelemetry.util.genai.types`. Land new type
@@ -208,8 +214,7 @@ as the reference:
208214

209215
- In `_instrument(**kwargs)`, resolve the hook as
210216
`kwargs.get("completion_hook") or load_completion_hook()` and pass it to the handler
211-
(`TelemetryHandler(..., completion_hook=...)` or
212-
`get_telemetry_handler(..., completion_hook=...)`). `load_completion_hook()` returns the hook
217+
(`TelemetryHandler(..., completion_hook=...)`). `load_completion_hook()` returns the hook
213218
named by `OTEL_INSTRUMENTATION_GENAI_COMPLETION_HOOK` (e.g. `upload`) via its entry point, or a
214219
no-op. An explicit `instrument(completion_hook=…)` argument takes precedence over the env var.
215220
- Don't define your own hook interface, call `on_completion` yourself, or wrap it in `try/except` —
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Emit telemetry under the `opentelemetry.instrumentation.genai.agno` instrumentation scope instead of `opentelemetry.util.genai.handler`

‎instrumentation/opentelemetry-instrumentation-genai-agno/src/opentelemetry/instrumentation/genai/agno/__init__.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
patch_agent,
4141
unpatch_agent,
4242
)
43+
from opentelemetry.instrumentation.genai.agno.version import __version__
4344
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
4445
from opentelemetry.util.genai.completion_hook import load_completion_hook
4546
from opentelemetry.util.genai.handler import TelemetryHandler
@@ -75,6 +76,8 @@ def _instrument(self, **kwargs: Any) -> None:
7576
meter_provider=meter_provider,
7677
logger_provider=logger_provider,
7778
completion_hook=completion_hook,
79+
instrumentation_scope_name=__package__,
80+
instrumentation_scope_version=__version__,
7881
)
7982
patch_agent(handler)
8083

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Copyright The OpenTelemetry Authors
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
from opentelemetry.instrumentation.genai.agno import AgnoInstrumentor
5+
from opentelemetry.instrumentation.genai.agno.version import __version__
6+
from opentelemetry.test_util_genai.scope import TelemetryHandlerScopeTest
7+
8+
9+
class TestInstrumentationScope(TelemetryHandlerScopeTest):
10+
instrumentor_class = AgnoInstrumentor
11+
instrumentation_scope_name = "opentelemetry.instrumentation.genai.agno"
12+
instrumentation_scope_version = __version__
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Emit telemetry under the `opentelemetry.instrumentation.genai.anthropic` instrumentation scope instead of `opentelemetry.util.genai.handler`

‎instrumentation/opentelemetry-instrumentation-genai-anthropic/src/opentelemetry/instrumentation/genai/anthropic/__init__.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343

4444
from wrapt import wrap_function_wrapper
4545

46+
from opentelemetry.instrumentation.genai.anthropic.version import __version__
4647
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
4748
from opentelemetry.instrumentation.utils import unwrap
4849
from opentelemetry.util.genai.completion_hook import load_completion_hook
@@ -114,6 +115,8 @@ def _instrument(self, **kwargs: Any) -> None:
114115
logger_provider=logger_provider,
115116
completion_hook=kwargs.get("completion_hook")
116117
or load_completion_hook(),
118+
instrumentation_scope_name=__package__,
119+
instrumentation_scope_version=__version__,
117120
)
118121

119122
wrap_function_wrapper(
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Copyright The OpenTelemetry Authors
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
from opentelemetry.instrumentation.genai.anthropic import AnthropicInstrumentor
5+
from opentelemetry.instrumentation.genai.anthropic.version import __version__
6+
from opentelemetry.test_util_genai.scope import TelemetryHandlerScopeTest
7+
8+
9+
class TestInstrumentationScope(TelemetryHandlerScopeTest):
10+
instrumentor_class = AnthropicInstrumentor
11+
instrumentation_scope_name = (
12+
"opentelemetry.instrumentation.genai.anthropic"
13+
)
14+
instrumentation_scope_version = __version__
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Emit telemetry under the `opentelemetry.instrumentation.genai.bedrock` instrumentation scope instead of `opentelemetry.util.genai.handler`

‎instrumentation/opentelemetry-instrumentation-genai-bedrock/src/opentelemetry/instrumentation/genai/bedrock/__init__.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from collections.abc import Collection
99
from typing import Any
1010

11+
from opentelemetry.instrumentation.genai.bedrock.version import __version__
1112
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
1213
from opentelemetry.util.genai.completion_hook import load_completion_hook
1314
from opentelemetry.util.genai.handler import TelemetryHandler
@@ -36,6 +37,8 @@ def _instrument(self, **kwargs: Any) -> None:
3637
meter_provider=kwargs.get("meter_provider"),
3738
logger_provider=kwargs.get("logger_provider"),
3839
completion_hook=completion_hook,
40+
instrumentation_scope_name=__package__,
41+
instrumentation_scope_version=__version__,
3942
)
4043
patch_bedrock(self._handler)
4144

0 commit comments

Comments
 (0)