nvidia-nat-opentelemetry 1.1.0a20251020__py3-none-any.whl

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.
@@ -0,0 +1,228 @@
1
+ # SPDX-FileCopyrightText: Copyright (c) 2024-2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ import logging
17
+ import time
18
+
19
+ from openinference.semconv.trace import OpenInferenceSpanKindValues
20
+ from openinference.semconv.trace import SpanAttributes
21
+
22
+ from nat.data_models.span import Span
23
+ from nat.data_models.span import SpanStatusCode
24
+ from nat.plugins.opentelemetry.otel_span import OtelSpan
25
+ from opentelemetry.trace import SpanContext
26
+ from opentelemetry.trace import SpanKind
27
+ from opentelemetry.trace import Status
28
+ from opentelemetry.trace import StatusCode
29
+ from opentelemetry.trace import TraceFlags
30
+
31
+ logger = logging.getLogger(__name__)
32
+
33
+ SPAN_EVENT_TYPE_TO_SPAN_KIND_MAP = {
34
+ "LLM_START": OpenInferenceSpanKindValues.LLM,
35
+ "LLM_END": OpenInferenceSpanKindValues.LLM,
36
+ "LLM_NEW_TOKEN": OpenInferenceSpanKindValues.LLM,
37
+ "TOOL_START": OpenInferenceSpanKindValues.TOOL,
38
+ "TOOL_END": OpenInferenceSpanKindValues.TOOL,
39
+ "FUNCTION_START": OpenInferenceSpanKindValues.CHAIN,
40
+ "FUNCTION_END": OpenInferenceSpanKindValues.CHAIN,
41
+ "WORKFLOW_START": OpenInferenceSpanKindValues.CHAIN,
42
+ "WORKFLOW_END": OpenInferenceSpanKindValues.CHAIN,
43
+ "TASK_START": OpenInferenceSpanKindValues.CHAIN,
44
+ "TASK_END": OpenInferenceSpanKindValues.CHAIN,
45
+ "CUSTOM_START": OpenInferenceSpanKindValues.CHAIN,
46
+ "CUSTOM_END": OpenInferenceSpanKindValues.CHAIN,
47
+ "EMBEDDER_START": OpenInferenceSpanKindValues.EMBEDDING,
48
+ "EMBEDDER_END": OpenInferenceSpanKindValues.EMBEDDING,
49
+ "RETRIEVER_START": OpenInferenceSpanKindValues.RETRIEVER,
50
+ "RETRIEVER_END": OpenInferenceSpanKindValues.RETRIEVER,
51
+ "AGENT_START": OpenInferenceSpanKindValues.AGENT,
52
+ "AGENT_END": OpenInferenceSpanKindValues.AGENT,
53
+ "RERANKER_START": OpenInferenceSpanKindValues.RERANKER,
54
+ "RERANKER_END": OpenInferenceSpanKindValues.RERANKER,
55
+ "GUARDRAIL_START": OpenInferenceSpanKindValues.GUARDRAIL,
56
+ "GUARDRAIL_END": OpenInferenceSpanKindValues.GUARDRAIL,
57
+ "EVALUATOR_START": OpenInferenceSpanKindValues.EVALUATOR,
58
+ "EVALUATOR_END": OpenInferenceSpanKindValues.EVALUATOR,
59
+ }
60
+
61
+
62
+ # Reuse expensive objects to avoid repeated creation
63
+ class _SharedObjects:
64
+
65
+ def __init__(self):
66
+ self.resource = None # type: ignore
67
+ self.instrumentation_scope = None # type: ignore
68
+
69
+
70
+ _shared = _SharedObjects()
71
+ _SAMPLED_TRACE_FLAGS = TraceFlags(1)
72
+
73
+
74
+ def _get_shared_resource():
75
+ """Get shared resource object to avoid repeated creation."""
76
+ if _shared.resource is None:
77
+ from opentelemetry.sdk.resources import Resource
78
+ _shared.resource = Resource.create() # type: ignore
79
+ return _shared.resource
80
+
81
+
82
+ def _get_shared_instrumentation_scope():
83
+ """Get shared instrumentation scope to avoid repeated creation."""
84
+ if _shared.instrumentation_scope is None:
85
+ from opentelemetry.sdk.trace import InstrumentationScope
86
+ _shared.instrumentation_scope = InstrumentationScope("nat", "1.0.0") # type: ignore
87
+ return _shared.instrumentation_scope
88
+
89
+
90
+ def convert_event_type_to_span_kind(event_type: str) -> OpenInferenceSpanKindValues:
91
+ """Convert an event type to a span kind.
92
+
93
+ Args:
94
+ event_type (str): The event type to convert
95
+
96
+ Returns:
97
+ OpenInferenceSpanKindValues: The corresponding span kind
98
+ """
99
+ return SPAN_EVENT_TYPE_TO_SPAN_KIND_MAP.get(event_type, OpenInferenceSpanKindValues.UNKNOWN)
100
+
101
+
102
+ def convert_span_status_code(nat_status_code: SpanStatusCode) -> StatusCode:
103
+ """Convert NAT SpanStatusCode to OpenTelemetry StatusCode.
104
+
105
+ Args:
106
+ nat_status_code (SpanStatusCode): The NAT span status code to convert
107
+
108
+ Returns:
109
+ StatusCode: The corresponding OpenTelemetry StatusCode
110
+ """
111
+ status_map = {
112
+ SpanStatusCode.OK: StatusCode.OK,
113
+ SpanStatusCode.ERROR: StatusCode.ERROR,
114
+ SpanStatusCode.UNSET: StatusCode.UNSET,
115
+ }
116
+ return status_map.get(nat_status_code, StatusCode.UNSET)
117
+
118
+
119
+ def convert_span_to_otel(nat_span: Span) -> OtelSpan:
120
+ """Convert a NAT Span to an OtelSpan using ultra-fast conversion.
121
+
122
+ Args:
123
+ nat_span (Span): The NAT span to convert
124
+
125
+ Returns:
126
+ OtelSpan: The converted OtelSpan with proper parent hierarchy.
127
+ """
128
+ # Fast path for spans without context
129
+ if not nat_span.context:
130
+ # Create minimal OtelSpan bypassing expensive constructor
131
+ otel_span = object.__new__(OtelSpan) # Bypass __init__
132
+ otel_span._name = nat_span.name
133
+ otel_span._context = None # type: ignore
134
+ otel_span._parent = None
135
+ otel_span._attributes = nat_span.attributes.copy()
136
+ otel_span._events = []
137
+ otel_span._links = []
138
+ otel_span._kind = SpanKind.INTERNAL
139
+ otel_span._start_time = nat_span.start_time
140
+ otel_span._end_time = nat_span.end_time
141
+ otel_span._status = Status(StatusCode.UNSET)
142
+ otel_span._ended = False
143
+ otel_span._resource = _get_shared_resource() # type: ignore
144
+ otel_span._instrumentation_scope = _get_shared_instrumentation_scope() # type: ignore
145
+ otel_span._dropped_attributes = 0
146
+ otel_span._dropped_events = 0
147
+ otel_span._dropped_links = 0
148
+ otel_span._status_description = None
149
+ return otel_span
150
+
151
+ # Process parent efficiently (if needed)
152
+ parent_otel_span = None
153
+ trace_id = nat_span.context.trace_id
154
+
155
+ if nat_span.parent:
156
+ parent_otel_span = convert_span_to_otel(nat_span.parent)
157
+ parent_context = parent_otel_span.get_span_context()
158
+ trace_id = parent_context.trace_id
159
+
160
+ # Create SpanContext efficiently
161
+ otel_span_context = SpanContext(
162
+ trace_id=trace_id,
163
+ span_id=nat_span.context.span_id,
164
+ is_remote=False,
165
+ trace_flags=_SAMPLED_TRACE_FLAGS, # Reuse flags object
166
+ )
167
+
168
+ # Create OtelSpan bypassing expensive constructor
169
+ otel_span = object.__new__(OtelSpan) # Bypass __init__
170
+ otel_span._name = nat_span.name
171
+ otel_span._context = otel_span_context
172
+ otel_span._parent = parent_otel_span
173
+ otel_span._attributes = nat_span.attributes.copy()
174
+ otel_span._events = []
175
+ otel_span._links = []
176
+ otel_span._kind = SpanKind.INTERNAL
177
+ otel_span._start_time = nat_span.start_time
178
+ otel_span._end_time = nat_span.end_time
179
+
180
+ # Reuse status conversion
181
+ status_code = convert_span_status_code(nat_span.status.code)
182
+ otel_span._status = Status(status_code, nat_span.status.message)
183
+
184
+ otel_span._ended = False
185
+ otel_span._resource = _get_shared_resource() # type: ignore
186
+ otel_span._instrumentation_scope = _get_shared_instrumentation_scope() # type: ignore
187
+ otel_span._dropped_attributes = 0
188
+ otel_span._dropped_events = 0
189
+ otel_span._dropped_links = 0
190
+ otel_span._status_description = None
191
+
192
+ # Set span kind efficiently (direct attribute modification)
193
+ event_type = nat_span.attributes.get("nat.event_type", "UNKNOWN")
194
+ span_kind = SPAN_EVENT_TYPE_TO_SPAN_KIND_MAP.get(event_type, OpenInferenceSpanKindValues.UNKNOWN)
195
+ otel_span._attributes[SpanAttributes.OPENINFERENCE_SPAN_KIND] = span_kind.value
196
+
197
+ # Process events (only if they exist)
198
+ if nat_span.events:
199
+ for nat_event in nat_span.events:
200
+ # Optimize timestamp handling
201
+ if isinstance(nat_event.timestamp, int):
202
+ event_timestamp_ns = nat_event.timestamp
203
+ elif nat_event.timestamp:
204
+ event_timestamp_ns = int(nat_event.timestamp)
205
+ else:
206
+ event_timestamp_ns = int(time.time() * 1e9)
207
+
208
+ # Add event directly to internal list (bypass add_event method)
209
+ otel_span._events.append({
210
+ "name": nat_event.name, "attributes": nat_event.attributes, "timestamp": event_timestamp_ns
211
+ })
212
+
213
+ return otel_span
214
+
215
+
216
+ def convert_spans_to_otel_batch(spans: list[Span]) -> list[OtelSpan]:
217
+ """Convert a list of NAT spans to OtelSpans using stateless conversion.
218
+
219
+ This is useful for batch processing or demos. Each span is converted
220
+ independently using the stateless approach.
221
+
222
+ Args:
223
+ spans (list[Span]): List of NAT spans to convert
224
+
225
+ Returns:
226
+ list[OtelSpan]: List of converted OtelSpans with proper parent-child relationships
227
+ """
228
+ return [convert_span_to_otel(span) for span in spans]
@@ -0,0 +1,47 @@
1
+ Metadata-Version: 2.4
2
+ Name: nvidia-nat-opentelemetry
3
+ Version: 1.1.0a20251020
4
+ Summary: Subpackage for OpenTelemetry integration in NeMo Agent toolkit
5
+ Author: NVIDIA Corporation
6
+ Maintainer: NVIDIA Corporation
7
+ License: Apache-2.0
8
+ Project-URL: documentation, https://docs.nvidia.com/nemo/agent-toolkit/latest/
9
+ Project-URL: source, https://github.com/NVIDIA/NeMo-Agent-Toolkit
10
+ Keywords: ai,observability,opentelemetry
11
+ Classifier: Programming Language :: Python
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Requires-Python: <3.14,>=3.11
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE-3rd-party.txt
18
+ License-File: LICENSE.md
19
+ Requires-Dist: nvidia-nat==v1.1.0a20251020
20
+ Requires-Dist: opentelemetry-api~=1.2
21
+ Requires-Dist: opentelemetry-exporter-otlp~=1.3
22
+ Requires-Dist: opentelemetry-sdk~=1.3
23
+ Dynamic: license-file
24
+
25
+ <!--
26
+ SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
27
+ SPDX-License-Identifier: Apache-2.0
28
+
29
+ Licensed under the Apache License, Version 2.0 (the "License");
30
+ you may not use this file except in compliance with the License.
31
+ You may obtain a copy of the License at
32
+
33
+ http://www.apache.org/licenses/LICENSE-2.0
34
+
35
+ Unless required by applicable law or agreed to in writing, software
36
+ distributed under the License is distributed on an "AS IS" BASIS,
37
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
38
+ See the License for the specific language governing permissions and
39
+ limitations under the License.
40
+ -->
41
+
42
+ ![NVIDIA NeMo Agent Toolkit](https://media.githubusercontent.com/media/NVIDIA/NeMo-Agent-Toolkit/refs/heads/main/docs/source/_static/banner.png "NeMo Agent toolkit banner image"
43
+
44
+ # NVIDIA NeMo Agent Toolkit Subpackage
45
+ This is a subpackage for OpenTelemetry integration for observability.
46
+
47
+ For more information about the NVIDIA NeMo Agent toolkit, please visit the [NeMo Agent toolkit GitHub Repo](https://github.com/NVIDIA/NeMo-Agent-Toolkit).
@@ -0,0 +1,17 @@
1
+ nat/meta/pypi.md,sha256=_o1o1BLPY1pvjCkklWxlm7LlIDMPCk-2Rho85NUuN8U,1109
2
+ nat/plugins/opentelemetry/__init__.py,sha256=j-YKuxwSIzGziyDyunw8s_W7WiFiqKLdFjw-utwHPFk,1079
3
+ nat/plugins/opentelemetry/otel_span.py,sha256=MC_ROZ8gSTu0gxRaaz77UDbn1ouZTZP3N_-0PcN140U,16564
4
+ nat/plugins/opentelemetry/otel_span_exporter.py,sha256=YO7JsQgi8Cf2OQBJ_s78HwJjrWx9SdqMvPen3Pa2_bI,6533
5
+ nat/plugins/opentelemetry/otlp_span_adapter_exporter.py,sha256=6xQHkKDhQk3-kObqj6kRv8ZlJtIV2Qqox6YkY0PCOYs,3945
6
+ nat/plugins/opentelemetry/otlp_span_redaction_adapter_exporter.py,sha256=qRrUIxYRlCDaAkEGlFTaEkCJCsb68GBo11EGEiE6S8E,7217
7
+ nat/plugins/opentelemetry/register.py,sha256=KnhV-axY0kJzZ3RReG4e_mTFR1dMr7d3a6ysYiCLTUI,9063
8
+ nat/plugins/opentelemetry/span_converter.py,sha256=Gz3KvRNQeEBBlpaPO8YRAJkw4fmzV7m9bT6dGX0IV2E,8846
9
+ nat/plugins/opentelemetry/mixin/__init__.py,sha256=Xs1JQ16L9btwreh4pdGKwskffAw1YFO48jKrU4ib_7c,685
10
+ nat/plugins/opentelemetry/mixin/otlp_span_exporter_mixin.py,sha256=3vK6DkTJXp6ZFH3AgNYUuuMOzjyskh_nVUWK-qMYKzM,2809
11
+ nvidia_nat_opentelemetry-1.1.0a20251020.dist-info/licenses/LICENSE-3rd-party.txt,sha256=fOk5jMmCX9YoKWyYzTtfgl-SUy477audFC5hNY4oP7Q,284609
12
+ nvidia_nat_opentelemetry-1.1.0a20251020.dist-info/licenses/LICENSE.md,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
13
+ nvidia_nat_opentelemetry-1.1.0a20251020.dist-info/METADATA,sha256=VX0u9wnfXTPSmp6LHHEYLOW9UjuxwiXbQSLToGR24zU,2039
14
+ nvidia_nat_opentelemetry-1.1.0a20251020.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
15
+ nvidia_nat_opentelemetry-1.1.0a20251020.dist-info/entry_points.txt,sha256=gmEKhCafyibUJLGxbn8luTK0UTgIvV2vAtr4uZ8M85I,72
16
+ nvidia_nat_opentelemetry-1.1.0a20251020.dist-info/top_level.txt,sha256=8-CJ2cP6-f0ZReXe5Hzqp-5pvzzHz-5Ds5H2bGqh1-U,4
17
+ nvidia_nat_opentelemetry-1.1.0a20251020.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [nat.components]
2
+ nat_opentelemetry = nat.plugins.opentelemetry.register