microsoft-agents-a365-observability-core 0.2.1.dev42__tar.gz → 0.2.1.dev43__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/PKG-INFO +1 -1
  2. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/__init__.py +4 -0
  3. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/execute_tool_scope.py +11 -8
  4. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/inference_scope.py +12 -8
  5. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/invoke_agent_scope.py +11 -0
  6. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/opentelemetry_scope.py +51 -6
  7. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/spans_scopes/output_scope.py +14 -8
  8. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/utils.py +35 -102
  9. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365_observability_core.egg-info/PKG-INFO +1 -1
  10. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/README.md +0 -0
  11. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/agent_details.py +0 -0
  12. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/config.py +0 -0
  13. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/constants.py +0 -0
  14. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/execution_type.py +0 -0
  15. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/exporters/__init__.py +0 -0
  16. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/exporters/agent365_exporter.py +0 -0
  17. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/exporters/agent365_exporter_options.py +0 -0
  18. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/exporters/enriched_span.py +0 -0
  19. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/exporters/enriching_span_processor.py +0 -0
  20. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/exporters/spectra_exporter_options.py +0 -0
  21. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/exporters/utils.py +0 -0
  22. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/inference_call_details.py +0 -0
  23. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/inference_operation_type.py +0 -0
  24. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/invoke_agent_details.py +0 -0
  25. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/middleware/__init__.py +0 -0
  26. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/middleware/baggage_builder.py +0 -0
  27. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/models/__init__.py +0 -0
  28. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/models/agent_type.py +0 -0
  29. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/models/caller_details.py +0 -0
  30. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/models/operation_source.py +0 -0
  31. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/models/response.py +0 -0
  32. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/request.py +0 -0
  33. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/source_metadata.py +0 -0
  34. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/spans_scopes/__init__.py +0 -0
  35. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/tenant_details.py +0 -0
  36. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/tool_call_details.py +0 -0
  37. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/tool_type.py +0 -0
  38. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/trace_processor/__init__.py +0 -0
  39. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/trace_processor/span_processor.py +0 -0
  40. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365/observability/core/trace_processor/util.py +0 -0
  41. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365_observability_core.egg-info/SOURCES.txt +0 -0
  42. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365_observability_core.egg-info/dependency_links.txt +0 -0
  43. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365_observability_core.egg-info/requires.txt +0 -0
  44. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/microsoft_agents_a365_observability_core.egg-info/top_level.txt +0 -0
  45. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/pyproject.toml +0 -0
  46. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/setup.cfg +0 -0
  47. {microsoft_agents_a365_observability_core-0.2.1.dev42 → microsoft_agents_a365_observability_core-0.2.1.dev43}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: microsoft-agents-a365-observability-core
3
- Version: 0.2.1.dev42
3
+ Version: 0.2.1.dev43
4
4
  Summary: Telemetry, tracing, and monitoring components for AI agents
5
5
  Author-email: Microsoft <support@microsoft.com>
6
6
  License: MIT
@@ -33,6 +33,7 @@ from .tenant_details import TenantDetails
33
33
  from .tool_call_details import ToolCallDetails
34
34
  from .tool_type import ToolType
35
35
  from .trace_processor.span_processor import SpanProcessor
36
+ from .utils import extract_context_from_headers, get_traceparent
36
37
 
37
38
  __all__ = [
38
39
  # Main SDK functions
@@ -71,6 +72,9 @@ __all__ = [
71
72
  "ExecutionType",
72
73
  "InferenceOperationType",
73
74
  "ToolType",
75
+ # Utility functions
76
+ "extract_context_from_headers",
77
+ "get_traceparent",
74
78
  # Constants
75
79
  # all constants from constants.py are exported via *
76
80
  ]
@@ -3,6 +3,7 @@
3
3
 
4
4
  from datetime import datetime
5
5
 
6
+ from opentelemetry.context import Context
6
7
  from opentelemetry.trace import SpanKind
7
8
 
8
9
  from .agent_details import AgentDetails
@@ -33,7 +34,7 @@ class ExecuteToolScope(OpenTelemetryScope):
33
34
  agent_details: AgentDetails,
34
35
  tenant_details: TenantDetails,
35
36
  request: Request | None = None,
36
- parent_id: str | None = None,
37
+ parent_context: Context | None = None,
37
38
  start_time: datetime | None = None,
38
39
  end_time: datetime | None = None,
39
40
  span_kind: SpanKind | None = None,
@@ -45,8 +46,9 @@ class ExecuteToolScope(OpenTelemetryScope):
45
46
  agent_details: The details of the agent making the call
46
47
  tenant_details: The details of the tenant
47
48
  request: Optional request details for additional context
48
- parent_id: Optional parent Activity ID used to link this span to an upstream
49
- operation
49
+ parent_context: Optional OpenTelemetry Context used to link this span to an
50
+ upstream operation. Use ``extract_context_from_headers()`` to convert a
51
+ Context from HTTP headers containing W3C traceparent.
50
52
  start_time: Optional explicit start time as a datetime object. Useful when
51
53
  recording a tool call after execution has already completed.
52
54
  end_time: Optional explicit end time as a datetime object. When provided,
@@ -63,7 +65,7 @@ class ExecuteToolScope(OpenTelemetryScope):
63
65
  agent_details,
64
66
  tenant_details,
65
67
  request,
66
- parent_id,
68
+ parent_context,
67
69
  start_time,
68
70
  end_time,
69
71
  span_kind,
@@ -75,7 +77,7 @@ class ExecuteToolScope(OpenTelemetryScope):
75
77
  agent_details: AgentDetails,
76
78
  tenant_details: TenantDetails,
77
79
  request: Request | None = None,
78
- parent_id: str | None = None,
80
+ parent_context: Context | None = None,
79
81
  start_time: datetime | None = None,
80
82
  end_time: datetime | None = None,
81
83
  span_kind: SpanKind | None = None,
@@ -87,8 +89,9 @@ class ExecuteToolScope(OpenTelemetryScope):
87
89
  agent_details: The details of the agent making the call
88
90
  tenant_details: The details of the tenant
89
91
  request: Optional request details for additional context
90
- parent_id: Optional parent Activity ID used to link this span to an upstream
91
- operation
92
+ parent_context: Optional OpenTelemetry Context used to link this span to an
93
+ upstream operation. Use ``extract_context_from_headers()`` to convert a
94
+ Context from HTTP headers containing W3C traceparent.
92
95
  start_time: Optional explicit start time as a datetime object. Useful when
93
96
  recording a tool call after execution has already completed.
94
97
  end_time: Optional explicit end time as a datetime object. When provided,
@@ -103,7 +106,7 @@ class ExecuteToolScope(OpenTelemetryScope):
103
106
  activity_name=f"{EXECUTE_TOOL_OPERATION_NAME} {details.tool_name}",
104
107
  agent_details=agent_details,
105
108
  tenant_details=tenant_details,
106
- parent_id=parent_id,
109
+ parent_context=parent_context,
107
110
  start_time=start_time,
108
111
  end_time=end_time,
109
112
  )
@@ -4,6 +4,8 @@
4
4
  from datetime import datetime
5
5
  from typing import List
6
6
 
7
+ from opentelemetry.context import Context
8
+
7
9
  from .agent_details import AgentDetails
8
10
  from .constants import (
9
11
  CHANNEL_LINK_KEY,
@@ -36,7 +38,7 @@ class InferenceScope(OpenTelemetryScope):
36
38
  agent_details: AgentDetails,
37
39
  tenant_details: TenantDetails,
38
40
  request: Request | None = None,
39
- parent_id: str | None = None,
41
+ parent_context: Context | None = None,
40
42
  start_time: datetime | None = None,
41
43
  end_time: datetime | None = None,
42
44
  ) -> "InferenceScope":
@@ -47,8 +49,9 @@ class InferenceScope(OpenTelemetryScope):
47
49
  agent_details: The details of the agent making the call
48
50
  tenant_details: The details of the tenant
49
51
  request: Optional request details for additional context
50
- parent_id: Optional parent Activity ID used to link this span to an upstream
51
- operation
52
+ parent_context: Optional OpenTelemetry Context used to link this span to an
53
+ upstream operation. Use ``extract_context_from_headers()`` to convert a
54
+ Context from HTTP headers containing W3C traceparent.
52
55
  start_time: Optional explicit start time as a datetime object.
53
56
  end_time: Optional explicit end time as a datetime object.
54
57
 
@@ -56,7 +59,7 @@ class InferenceScope(OpenTelemetryScope):
56
59
  A new InferenceScope instance
57
60
  """
58
61
  return InferenceScope(
59
- details, agent_details, tenant_details, request, parent_id, start_time, end_time
62
+ details, agent_details, tenant_details, request, parent_context, start_time, end_time
60
63
  )
61
64
 
62
65
  def __init__(
@@ -65,7 +68,7 @@ class InferenceScope(OpenTelemetryScope):
65
68
  agent_details: AgentDetails,
66
69
  tenant_details: TenantDetails,
67
70
  request: Request | None = None,
68
- parent_id: str | None = None,
71
+ parent_context: Context | None = None,
69
72
  start_time: datetime | None = None,
70
73
  end_time: datetime | None = None,
71
74
  ):
@@ -76,8 +79,9 @@ class InferenceScope(OpenTelemetryScope):
76
79
  agent_details: The details of the agent making the call
77
80
  tenant_details: The details of the tenant
78
81
  request: Optional request details for additional context
79
- parent_id: Optional parent Activity ID used to link this span to an upstream
80
- operation
82
+ parent_context: Optional OpenTelemetry Context used to link this span to an
83
+ upstream operation. Use ``extract_context_from_headers()`` to convert a
84
+ Context from HTTP headers containing W3C traceparent.
81
85
  start_time: Optional explicit start time as a datetime object.
82
86
  end_time: Optional explicit end time as a datetime object.
83
87
  """
@@ -88,7 +92,7 @@ class InferenceScope(OpenTelemetryScope):
88
92
  activity_name=f"{details.operationName.value} {details.model}",
89
93
  agent_details=agent_details,
90
94
  tenant_details=tenant_details,
91
- parent_id=parent_id,
95
+ parent_context=parent_context,
92
96
  start_time=start_time,
93
97
  end_time=end_time,
94
98
  )
@@ -6,6 +6,7 @@
6
6
  import logging
7
7
  from datetime import datetime
8
8
 
9
+ from opentelemetry.context import Context
9
10
  from opentelemetry.trace import SpanKind
10
11
 
11
12
  from .agent_details import AgentDetails
@@ -50,6 +51,7 @@ class InvokeAgentScope(OpenTelemetryScope):
50
51
  request: Request | None = None,
51
52
  caller_agent_details: AgentDetails | None = None,
52
53
  caller_details: CallerDetails | None = None,
54
+ parent_context: Context | None = None,
53
55
  start_time: datetime | None = None,
54
56
  end_time: datetime | None = None,
55
57
  span_kind: SpanKind | None = None,
@@ -63,6 +65,9 @@ class InvokeAgentScope(OpenTelemetryScope):
63
65
  request: Optional request details for additional context
64
66
  caller_agent_details: Optional details of the caller agent
65
67
  caller_details: Optional details of the non-agentic caller
68
+ parent_context: Optional OpenTelemetry Context used to link this span to an
69
+ upstream operation. Use ``extract_context_from_headers()`` to convert a
70
+ Context from HTTP headers containing W3C traceparent.
66
71
  start_time: Optional explicit start time as a datetime object.
67
72
  end_time: Optional explicit end time as a datetime object.
68
73
  span_kind: Optional span kind override. Defaults to ``SpanKind.CLIENT``.
@@ -77,6 +82,7 @@ class InvokeAgentScope(OpenTelemetryScope):
77
82
  request,
78
83
  caller_agent_details,
79
84
  caller_details,
85
+ parent_context,
80
86
  start_time,
81
87
  end_time,
82
88
  span_kind,
@@ -89,6 +95,7 @@ class InvokeAgentScope(OpenTelemetryScope):
89
95
  request: Request | None = None,
90
96
  caller_agent_details: AgentDetails | None = None,
91
97
  caller_details: CallerDetails | None = None,
98
+ parent_context: Context | None = None,
92
99
  start_time: datetime | None = None,
93
100
  end_time: datetime | None = None,
94
101
  span_kind: SpanKind | None = None,
@@ -101,6 +108,9 @@ class InvokeAgentScope(OpenTelemetryScope):
101
108
  request: Optional request details for additional context
102
109
  caller_agent_details: Optional details of the caller agent
103
110
  caller_details: Optional details of the non-agentic caller
111
+ parent_context: Optional OpenTelemetry Context used to link this span to an
112
+ upstream operation. Use ``extract_context_from_headers()`` to convert a
113
+ Context from HTTP headers containing W3C traceparent.
104
114
  start_time: Optional explicit start time as a datetime object.
105
115
  end_time: Optional explicit end time as a datetime object.
106
116
  span_kind: Optional span kind override. Defaults to ``SpanKind.CLIENT``.
@@ -118,6 +128,7 @@ class InvokeAgentScope(OpenTelemetryScope):
118
128
  activity_name=activity_name,
119
129
  agent_details=invoke_agent_details.details,
120
130
  tenant_details=tenant_details,
131
+ parent_context=parent_context,
121
132
  start_time=start_time,
122
133
  end_time=end_time,
123
134
  )
@@ -10,6 +10,8 @@ from threading import Lock
10
10
  from typing import TYPE_CHECKING, Any
11
11
 
12
12
  from opentelemetry import context, trace
13
+ from opentelemetry.context import Context
14
+ from opentelemetry.propagate import inject
13
15
  from opentelemetry.trace import (
14
16
  Span,
15
17
  SpanKind,
@@ -43,7 +45,7 @@ from .constants import (
43
45
  TELEMETRY_SDK_VERSION_KEY,
44
46
  TENANT_ID_KEY,
45
47
  )
46
- from .utils import get_sdk_version, parse_parent_id_to_context
48
+ from .utils import get_sdk_version
47
49
 
48
50
  if TYPE_CHECKING:
49
51
  from .agent_details import AgentDetails
@@ -97,7 +99,7 @@ class OpenTelemetryScope:
97
99
  activity_name: str,
98
100
  agent_details: "AgentDetails | None" = None,
99
101
  tenant_details: "TenantDetails | None" = None,
100
- parent_id: str | None = None,
102
+ parent_context: Context | None = None,
101
103
  start_time: datetime | None = None,
102
104
  end_time: datetime | None = None,
103
105
  ):
@@ -111,8 +113,9 @@ class OpenTelemetryScope:
111
113
  activity_name: The name of the activity for display purposes
112
114
  agent_details: Optional agent details
113
115
  tenant_details: Optional tenant details
114
- parent_id: Optional parent Activity ID used to link this span to an upstream
115
- operation
116
+ parent_context: Optional OpenTelemetry Context used to link this span to an
117
+ upstream operation. Use ``extract_context_from_headers()`` to extract a
118
+ Context from HTTP headers containing W3C traceparent.
116
119
  start_time: Optional explicit start time as a datetime object.
117
120
  Useful when recording an operation after it has already completed.
118
121
  end_time: Optional explicit end time as a datetime object.
@@ -146,9 +149,8 @@ class OpenTelemetryScope:
146
149
  activity_kind = SpanKind.CONSUMER
147
150
 
148
151
  # Get context for parent relationship
149
- # If parent_id is provided, parse it and use it as the parent context
152
+ # If parent_context is provided, use it directly
150
153
  # Otherwise, use the current context
151
- parent_context = parse_parent_id_to_context(parent_id)
152
154
  span_context = parent_context if parent_context else context.get_current()
153
155
 
154
156
  # Convert custom start time to OTel-compatible format (nanoseconds since epoch)
@@ -286,6 +288,49 @@ class OpenTelemetryScope:
286
288
  else:
287
289
  self._span.end()
288
290
 
291
+ def get_context(self) -> Context | None:
292
+ """Get the OpenTelemetry context for this scope's span.
293
+
294
+ This method returns a Context object containing this scope's span,
295
+ which can be used to propagate trace context to child operations
296
+ or downstream services.
297
+
298
+ Returns:
299
+ A Context containing this scope's span, or None if telemetry
300
+ is disabled or no span exists.
301
+ """
302
+ if self._span and self._is_telemetry_enabled():
303
+ return set_span_in_context(self._span)
304
+ return None
305
+
306
+ def inject_context_to_headers(self) -> dict[str, str]:
307
+ """Inject this span's trace context into W3C HTTP headers.
308
+
309
+ Returns a dictionary of headers containing ``traceparent`` and
310
+ optionally ``tracestate`` that can be forwarded to downstream services
311
+ or stored for later context propagation.
312
+
313
+ Example usage:
314
+
315
+ .. code-block:: python
316
+
317
+ scope = OpenTelemetryScope(...)
318
+ headers = scope.inject_context_to_headers()
319
+ # Add headers to outgoing HTTP request
320
+ requests.get("https://downstream-service/api", headers=headers)
321
+
322
+ Returns:
323
+ A dictionary containing W3C trace context headers. Returns an
324
+ empty dictionary if telemetry is disabled or no span exists.
325
+ """
326
+ headers: dict[str, str] = {}
327
+ if self._span and self._is_telemetry_enabled():
328
+ # Create a context with the current span
329
+ ctx = set_span_in_context(self._span)
330
+ # Use the global propagator to inject trace context into headers
331
+ inject(headers, context=ctx)
332
+ return headers
333
+
289
334
  def __enter__(self):
290
335
  """Enter the context manager and make span active."""
291
336
  if self._span and self._is_telemetry_enabled():
@@ -3,6 +3,8 @@
3
3
 
4
4
  from datetime import datetime
5
5
 
6
+ from opentelemetry.context import Context
7
+
6
8
  from ..agent_details import AgentDetails
7
9
  from ..constants import GEN_AI_OUTPUT_MESSAGES_KEY
8
10
  from ..models.response import Response
@@ -23,7 +25,7 @@ class OutputScope(OpenTelemetryScope):
23
25
  agent_details: AgentDetails,
24
26
  tenant_details: TenantDetails,
25
27
  response: Response,
26
- parent_id: str | None = None,
28
+ parent_context: Context | None = None,
27
29
  start_time: datetime | None = None,
28
30
  end_time: datetime | None = None,
29
31
  ) -> "OutputScope":
@@ -33,22 +35,25 @@ class OutputScope(OpenTelemetryScope):
33
35
  agent_details: The details of the agent
34
36
  tenant_details: The details of the tenant
35
37
  response: The response details from the agent
36
- parent_id: Optional parent Activity ID used to link this span to an upstream
37
- operation
38
+ parent_context: Optional OpenTelemetry Context used to link this span to an
39
+ upstream operation. Use ``extract_context_from_headers()`` to convert a
40
+ Context from HTTP headers containing W3C traceparent.
38
41
  start_time: Optional explicit start time as a datetime object.
39
42
  end_time: Optional explicit end time as a datetime object.
40
43
 
41
44
  Returns:
42
45
  A new OutputScope instance
43
46
  """
44
- return OutputScope(agent_details, tenant_details, response, parent_id, start_time, end_time)
47
+ return OutputScope(
48
+ agent_details, tenant_details, response, parent_context, start_time, end_time
49
+ )
45
50
 
46
51
  def __init__(
47
52
  self,
48
53
  agent_details: AgentDetails,
49
54
  tenant_details: TenantDetails,
50
55
  response: Response,
51
- parent_id: str | None = None,
56
+ parent_context: Context | None = None,
52
57
  start_time: datetime | None = None,
53
58
  end_time: datetime | None = None,
54
59
  ):
@@ -58,8 +63,9 @@ class OutputScope(OpenTelemetryScope):
58
63
  agent_details: The details of the agent
59
64
  tenant_details: The details of the tenant
60
65
  response: The response details from the agent
61
- parent_id: Optional parent Activity ID used to link this span to an upstream
62
- operation
66
+ parent_context: Optional OpenTelemetry Context used to link this span to an
67
+ upstream operation. Use ``extract_context_from_headers()`` to convert a
68
+ Context from HTTP headers containing W3C traceparent.
63
69
  start_time: Optional explicit start time as a datetime object.
64
70
  end_time: Optional explicit end time as a datetime object.
65
71
  """
@@ -69,7 +75,7 @@ class OutputScope(OpenTelemetryScope):
69
75
  activity_name=(f"{OUTPUT_OPERATION_NAME} {agent_details.agent_id}"),
70
76
  agent_details=agent_details,
71
77
  tenant_details=tenant_details,
72
- parent_id=parent_id,
78
+ parent_context=parent_context,
73
79
  start_time=start_time,
74
80
  end_time=end_time,
75
81
  )
@@ -15,11 +15,12 @@ from threading import RLock
15
15
  from typing import Any, Generic, TypeVar, cast
16
16
 
17
17
  from opentelemetry import context
18
+ from opentelemetry.propagate import extract
18
19
  from opentelemetry.semconv.attributes.exception_attributes import (
19
20
  EXCEPTION_MESSAGE,
20
21
  EXCEPTION_STACKTRACE,
21
22
  )
22
- from opentelemetry.trace import NonRecordingSpan, Span, SpanContext, TraceFlags, set_span_in_context
23
+ from opentelemetry.trace import Span
23
24
  from opentelemetry.util.types import AttributeValue
24
25
  from wrapt import ObjectProxy
25
26
 
@@ -29,126 +30,58 @@ logger = logging.getLogger(__name__)
29
30
  logger.addHandler(logging.NullHandler())
30
31
 
31
32
 
32
- # W3C Trace Context constants
33
- W3C_TRACE_CONTEXT_VERSION = "00"
34
- W3C_TRACE_ID_LENGTH = 32 # 32 hex chars = 128 bits
35
- W3C_SPAN_ID_LENGTH = 16 # 16 hex chars = 64 bits
33
+ def extract_context_from_headers(headers: dict[str, str]) -> context.Context:
34
+ """Extract an OpenTelemetry Context from W3C trace HTTP headers.
36
35
 
37
-
38
- def validate_w3c_trace_context_version(version: str) -> bool:
39
- """Validate W3C Trace Context version.
36
+ Parses ``traceparent`` (and optionally ``tracestate``) headers and returns
37
+ an OpenTelemetry Context that can be passed as ``parent_context`` to any
38
+ scope's ``start()`` method.
40
39
 
41
40
  Args:
42
- version: The version string to validate
41
+ headers: Dictionary of HTTP headers containing trace context.
42
+ Expected keys include ``traceparent`` and optionally ``tracestate``.
43
43
 
44
44
  Returns:
45
- True if valid, False otherwise
46
- """
47
- return version == W3C_TRACE_CONTEXT_VERSION
45
+ An OpenTelemetry Context containing the extracted trace information.
46
+ If no valid trace context is found, returns an empty context.
48
47
 
48
+ Example::
49
49
 
50
- def _is_valid_hex(hex_string: str) -> bool:
51
- """Check if a string contains only valid hexadecimal characters.
52
-
53
- Args:
54
- hex_string: The string to validate
50
+ .. code-block:: python
55
51
 
56
- Returns:
57
- True if all characters are valid hexadecimal (0-9, a-f, A-F), False otherwise
52
+ headers = {
53
+ "traceparent": "00-1234567890abcdef1234567890abcdef-abcdefabcdef1234-01"
54
+ }
55
+ parent_context = extract_context_from_headers(headers)
56
+ with InferenceScope.start(
57
+ details, agent, tenant, parent_context=parent_context
58
+ ):
59
+ pass
58
60
  """
59
- return all(c in "0123456789abcdefABCDEF" for c in hex_string)
61
+ return extract(headers)
60
62
 
61
63
 
62
- def validate_trace_id(trace_id_hex: str) -> bool:
63
- """Validate W3C Trace Context trace_id format.
64
+ def get_traceparent(headers: dict[str, str]) -> str | None:
65
+ """Return the W3C ``traceparent`` value from a headers dictionary.
64
66
 
65
67
  Args:
66
- trace_id_hex: The trace_id hex string to validate (should be 32 hex chars)
68
+ headers: Dictionary of HTTP headers, typically obtained from
69
+ :meth:`OpenTelemetryScope.inject_context_to_headers`.
67
70
 
68
71
  Returns:
69
- True if valid (32 hex chars), False otherwise
70
- """
71
- return len(trace_id_hex) == W3C_TRACE_ID_LENGTH and _is_valid_hex(trace_id_hex)
72
+ The traceparent string (e.g.
73
+ ``"00-<trace-id>-<span-id>-<flags>"``), or ``None`` if the
74
+ key is not present.
72
75
 
76
+ Example::
73
77
 
74
- def validate_span_id(span_id_hex: str) -> bool:
75
- """Validate W3C Trace Context span_id format.
76
-
77
- Args:
78
- span_id_hex: The span_id hex string to validate (should be 16 hex chars)
78
+ .. code-block:: python
79
79
 
80
- Returns:
81
- True if valid (16 hex chars), False otherwise
80
+ # Extract traceparent from incoming HTTP request headers
81
+ traceparent = get_traceparent(request.headers)
82
+ turn_context.turn_state[A365_PARENT_TRACEPARENT_KEY] = traceparent
82
83
  """
83
- return len(span_id_hex) == W3C_SPAN_ID_LENGTH and _is_valid_hex(span_id_hex)
84
-
85
-
86
- def parse_parent_id_to_context(parent_id: str | None) -> context.Context | None:
87
- """Parse a W3C trace context parent ID and return a context with the parent span.
88
-
89
- The parent_id format is expected to be W3C Trace Context format:
90
- "00-{trace_id}-{span_id}-{trace_flags}"
91
- Example: "00-1234567890abcdef1234567890abcdef-abcdefabcdef1234-01"
92
-
93
- Args:
94
- parent_id: The W3C Trace Context format parent ID string
95
-
96
- Returns:
97
- A context containing the parent span, or None if parent_id is invalid
98
- """
99
- if not parent_id:
100
- return None
101
-
102
- try:
103
- # W3C Trace Context format: "00-{trace_id}-{span_id}-{trace_flags}"
104
- parts = parent_id.split("-")
105
- if len(parts) != 4:
106
- logger.warning(f"Invalid parent_id format (expected 4 parts): {parent_id}")
107
- return None
108
-
109
- version, trace_id_hex, span_id_hex, trace_flags_hex = parts
110
-
111
- # Validate W3C Trace Context version
112
- if not validate_w3c_trace_context_version(version):
113
- logger.warning(f"Unsupported W3C Trace Context version: {version}")
114
- return None
115
-
116
- # Validate trace_id (must be 32 hex chars)
117
- if not validate_trace_id(trace_id_hex):
118
- logger.warning(
119
- f"Invalid trace_id (expected {W3C_TRACE_ID_LENGTH} hex chars): '{trace_id_hex}'"
120
- )
121
- return None
122
-
123
- # Validate span_id (must be 16 hex chars)
124
- if not validate_span_id(span_id_hex):
125
- logger.warning(
126
- f"Invalid span_id (expected {W3C_SPAN_ID_LENGTH} hex chars): '{span_id_hex}'"
127
- )
128
- return None
129
-
130
- # Parse the hex values
131
- trace_id = int(trace_id_hex, 16)
132
- span_id = int(span_id_hex, 16)
133
- trace_flags = TraceFlags(int(trace_flags_hex, 16))
134
-
135
- # Create a SpanContext from the parsed values
136
- parent_span_context = SpanContext(
137
- trace_id=trace_id,
138
- span_id=span_id,
139
- is_remote=True,
140
- trace_flags=trace_flags,
141
- )
142
-
143
- # Create a NonRecordingSpan with the parent context
144
- parent_span = NonRecordingSpan(parent_span_context)
145
-
146
- # Create a context with the parent span
147
- return set_span_in_context(parent_span)
148
-
149
- except (ValueError, IndexError) as e:
150
- logger.warning(f"Failed to parse parent_id '{parent_id}': {e}")
151
- return None
84
+ return headers.get("traceparent")
152
85
 
153
86
 
154
87
  def safe_json_dumps(obj: Any, **kwargs: Any) -> str:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: microsoft-agents-a365-observability-core
3
- Version: 0.2.1.dev42
3
+ Version: 0.2.1.dev43
4
4
  Summary: Telemetry, tracing, and monitoring components for AI agents
5
5
  Author-email: Microsoft <support@microsoft.com>
6
6
  License: MIT