Skip to content

Commit 4830f59

Browse files
committed
Implement OpenAI Agents span processing
1 parent e3cb053 commit 4830f59

File tree

10 files changed

+935
-14
lines changed

10 files changed

+935
-14
lines changed

instrumentation-genai/opentelemetry-instrumentation-openai-agents/src/opentelemetry/instrumentation/openai_agents/__init__.py

Lines changed: 75 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,34 +12,95 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
"""Barebones OpenAI Agents instrumentation package.
15+
"""OpenAI Agents instrumentation for OpenTelemetry."""
1616

17-
This branch provides only the minimal package skeleton:
18-
- Instrumentor class stub
19-
- Version module
20-
- Packaging metadata/entry point
21-
"""
17+
from __future__ import annotations
2218

19+
import importlib
20+
import os
2321
from typing import Collection
2422

2523
from opentelemetry.instrumentation.instrumentor import BaseInstrumentor
24+
from opentelemetry.semconv._incubating.attributes import (
25+
gen_ai_attributes as GenAI,
26+
)
27+
from opentelemetry.semconv.schemas import Schemas
28+
from opentelemetry.trace import get_tracer
2629

2730
from .package import _instruments
31+
from .span_processor import _OpenAIAgentsSpanProcessor
2832
from .version import __version__ # noqa: F401
2933

30-
__all__ = [
31-
"OpenAIAgentsInstrumentor",
32-
]
34+
__all__ = ["OpenAIAgentsInstrumentor"]
35+
36+
37+
def _load_tracing_module():
38+
return importlib.import_module("agents.tracing")
39+
40+
41+
def _resolve_system(value: str | None) -> str:
42+
if not value:
43+
return GenAI.GenAiSystemValues.OPENAI.value
44+
45+
normalized = value.strip().lower()
46+
for member in GenAI.GenAiSystemValues:
47+
if normalized == member.value:
48+
return member.value
49+
if normalized == member.name.lower():
50+
return member.value
51+
return value
52+
53+
54+
def _get_registered_processors(provider) -> list:
55+
multi = getattr(provider, "_multi_processor", None)
56+
processors = getattr(multi, "_processors", ())
57+
return list(processors)
3358

3459

3560
class OpenAIAgentsInstrumentor(BaseInstrumentor):
36-
"""Minimal instrumentor stub (no-op)."""
61+
"""Instrumentation that bridges OpenAI Agents tracing to OpenTelemetry spans."""
62+
63+
def __init__(self) -> None:
64+
super().__init__()
65+
self._processor: _OpenAIAgentsSpanProcessor | None = None
66+
67+
def _instrument(self, **kwargs) -> None:
68+
if self._processor is not None:
69+
return
70+
71+
tracer_provider = kwargs.get("tracer_provider")
72+
tracer = get_tracer(
73+
__name__,
74+
"",
75+
tracer_provider,
76+
schema_url=Schemas.V1_28_0.value,
77+
)
78+
79+
system_override = kwargs.get("system") or os.getenv(
80+
"OTEL_INSTRUMENTATION_OPENAI_AGENTS_SYSTEM"
81+
)
82+
system = _resolve_system(system_override)
83+
84+
processor = _OpenAIAgentsSpanProcessor(tracer=tracer, system=system)
85+
86+
tracing = _load_tracing_module()
87+
provider = tracing.get_trace_provider()
88+
existing = _get_registered_processors(provider)
89+
provider.set_processors([*existing, processor])
90+
self._processor = processor
91+
92+
def _uninstrument(self, **kwargs) -> None:
93+
if self._processor is None:
94+
return
3795

38-
def _instrument(self, **kwargs) -> None: # pragma: no cover - stub
39-
return
96+
tracing = _load_tracing_module()
97+
provider = tracing.get_trace_provider()
98+
current = _get_registered_processors(provider)
99+
filtered = [proc for proc in current if proc is not self._processor]
100+
provider.set_processors(filtered)
40101

41-
def _uninstrument(self, **kwargs) -> None: # pragma: no cover - stub
42-
return
102+
self._processor.shutdown()
103+
self._processor = None
43104

44105
def instrumentation_dependencies(self) -> Collection[str]:
45106
return _instruments

0 commit comments

Comments
 (0)