nvidia-nat-data-flywheel 1.3.0a20250828__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.
- nat/meta/pypi.md +23 -0
- nat/plugins/data_flywheel/observability/__init__.py +14 -0
- nat/plugins/data_flywheel/observability/exporter/__init__.py +14 -0
- nat/plugins/data_flywheel/observability/exporter/dfw_elasticsearch_exporter.py +74 -0
- nat/plugins/data_flywheel/observability/exporter/dfw_exporter.py +99 -0
- nat/plugins/data_flywheel/observability/mixin/__init__.py +14 -0
- nat/plugins/data_flywheel/observability/mixin/elasticsearch_mixin.py +75 -0
- nat/plugins/data_flywheel/observability/processor/__init__.py +27 -0
- nat/plugins/data_flywheel/observability/processor/dfw_record_processor.py +86 -0
- nat/plugins/data_flywheel/observability/processor/trace_conversion/__init__.py +30 -0
- nat/plugins/data_flywheel/observability/processor/trace_conversion/adapter/__init__.py +14 -0
- nat/plugins/data_flywheel/observability/processor/trace_conversion/adapter/elasticsearch/__init__.py +14 -0
- nat/plugins/data_flywheel/observability/processor/trace_conversion/adapter/elasticsearch/nim_converter.py +44 -0
- nat/plugins/data_flywheel/observability/processor/trace_conversion/adapter/elasticsearch/openai_converter.py +368 -0
- nat/plugins/data_flywheel/observability/processor/trace_conversion/adapter/register.py +24 -0
- nat/plugins/data_flywheel/observability/processor/trace_conversion/span_extractor.py +79 -0
- nat/plugins/data_flywheel/observability/processor/trace_conversion/span_to_dfw_record.py +119 -0
- nat/plugins/data_flywheel/observability/processor/trace_conversion/trace_adapter_registry.py +255 -0
- nat/plugins/data_flywheel/observability/register.py +61 -0
- nat/plugins/data_flywheel/observability/schema/__init__.py +14 -0
- nat/plugins/data_flywheel/observability/schema/provider/__init__.py +14 -0
- nat/plugins/data_flywheel/observability/schema/provider/nim_trace_source.py +24 -0
- nat/plugins/data_flywheel/observability/schema/provider/openai_message.py +31 -0
- nat/plugins/data_flywheel/observability/schema/provider/openai_trace_source.py +95 -0
- nat/plugins/data_flywheel/observability/schema/register.py +21 -0
- nat/plugins/data_flywheel/observability/schema/schema_registry.py +144 -0
- nat/plugins/data_flywheel/observability/schema/sink/__init__.py +14 -0
- nat/plugins/data_flywheel/observability/schema/sink/elasticsearch/__init__.py +20 -0
- nat/plugins/data_flywheel/observability/schema/sink/elasticsearch/contract_version.py +31 -0
- nat/plugins/data_flywheel/observability/schema/sink/elasticsearch/dfw_es_record.py +222 -0
- nat/plugins/data_flywheel/observability/schema/trace_container.py +79 -0
- nat/plugins/data_flywheel/observability/schema/trace_source_base.py +22 -0
- nat/plugins/data_flywheel/observability/utils/deserialize.py +42 -0
- nvidia_nat_data_flywheel-1.3.0a20250828.dist-info/METADATA +34 -0
- nvidia_nat_data_flywheel-1.3.0a20250828.dist-info/RECORD +38 -0
- nvidia_nat_data_flywheel-1.3.0a20250828.dist-info/WHEEL +5 -0
- nvidia_nat_data_flywheel-1.3.0a20250828.dist-info/entry_points.txt +4 -0
- nvidia_nat_data_flywheel-1.3.0a20250828.dist-info/top_level.txt +1 -0
nat/meta/pypi.md
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
<!--
|
2
|
+
SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
3
|
+
SPDX-License-Identifier: Apache-2.0
|
4
|
+
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
you may not use this file except in compliance with the License.
|
7
|
+
You may obtain a copy of the License at
|
8
|
+
|
9
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
See the License for the specific language governing permissions and
|
15
|
+
limitations under the License.
|
16
|
+
-->
|
17
|
+
|
18
|
+

|
19
|
+
|
20
|
+
# NVIDIA Agent Toolkit Subpackage
|
21
|
+
This is a subpackage for NVIDIA Data Flywheel Blueprint integration for continuous model improvement.
|
22
|
+
|
23
|
+
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,14 @@
|
|
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.
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 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.
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 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
|
+
from nat.builder.context import ContextState
|
17
|
+
from nat.plugins.data_flywheel.observability.exporter.dfw_exporter import DFWExporter
|
18
|
+
from nat.plugins.data_flywheel.observability.mixin.elasticsearch_mixin import ElasticsearchMixin
|
19
|
+
from nat.plugins.data_flywheel.observability.schema.sink.elasticsearch import ContractVersion
|
20
|
+
|
21
|
+
|
22
|
+
class DFWElasticsearchExporter(ElasticsearchMixin, DFWExporter):
|
23
|
+
"""Elasticsearch-specific Data Flywheel exporter."""
|
24
|
+
|
25
|
+
def __init__(self,
|
26
|
+
context_state: ContextState | None = None,
|
27
|
+
client_id: str = "default",
|
28
|
+
contract_version: ContractVersion = ContractVersion.V1_1,
|
29
|
+
batch_size: int = 100,
|
30
|
+
flush_interval: float = 5.0,
|
31
|
+
max_queue_size: int = 1000,
|
32
|
+
drop_on_overflow: bool = False,
|
33
|
+
shutdown_timeout: float = 10.0,
|
34
|
+
**elasticsearch_kwargs):
|
35
|
+
"""Initialize the Elasticsearch Data Flywheel exporter.
|
36
|
+
|
37
|
+
Args:
|
38
|
+
context_state: The context state to use for the exporter.
|
39
|
+
client_id: The client ID for the exporter.
|
40
|
+
contract_version: The contract version to use for the exporter.
|
41
|
+
batch_size: The batch size for exporting spans.
|
42
|
+
flush_interval: The flush interval in seconds for exporting spans.
|
43
|
+
max_queue_size: The maximum queue size for exporting spans.
|
44
|
+
drop_on_overflow: Whether to drop spans on overflow.
|
45
|
+
shutdown_timeout: The shutdown timeout in seconds.
|
46
|
+
**elasticsearch_kwargs: Additional arguments for ElasticsearchMixin:
|
47
|
+
- endpoint: The elasticsearch endpoint.
|
48
|
+
- index: The elasticsearch index name.
|
49
|
+
- elasticsearch_auth: The elasticsearch authentication credentials.
|
50
|
+
- headers: The elasticsearch headers.
|
51
|
+
"""
|
52
|
+
# Initialize both mixins - ElasticsearchMixin expects elasticsearch_kwargs,
|
53
|
+
# DFWExporter expects the standard exporter parameters
|
54
|
+
self.contract_version = contract_version
|
55
|
+
super().__init__(export_contract=contract_version.get_contract_class(),
|
56
|
+
context_state=context_state,
|
57
|
+
batch_size=batch_size,
|
58
|
+
flush_interval=flush_interval,
|
59
|
+
max_queue_size=max_queue_size,
|
60
|
+
drop_on_overflow=drop_on_overflow,
|
61
|
+
shutdown_timeout=shutdown_timeout,
|
62
|
+
client_id=client_id,
|
63
|
+
**elasticsearch_kwargs)
|
64
|
+
|
65
|
+
async def export_processed(self, item: dict | list[dict]) -> None:
|
66
|
+
"""Export processed DFW records to Elasticsearch.
|
67
|
+
|
68
|
+
Delegates to ElasticsearchMixin.export_processed() which handles
|
69
|
+
bulk operations for lists and single document indexing for individual records.
|
70
|
+
|
71
|
+
Args:
|
72
|
+
item (dict | list[dict]): Single dictionary or batch of dictionaries to export
|
73
|
+
"""
|
74
|
+
await super().export_processed(item)
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 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
|
+
from abc import abstractmethod
|
18
|
+
|
19
|
+
from pydantic import BaseModel
|
20
|
+
|
21
|
+
from nat.builder.context import ContextState
|
22
|
+
from nat.data_models.span import Span
|
23
|
+
from nat.observability.exporter.span_exporter import SpanExporter
|
24
|
+
from nat.observability.processor.batching_processor import BatchingProcessor
|
25
|
+
from nat.observability.processor.falsy_batch_filter_processor import DictBatchFilterProcessor
|
26
|
+
from nat.observability.processor.processor_factory import processor_factory_from_type
|
27
|
+
from nat.observability.processor.processor_factory import processor_factory_to_type
|
28
|
+
from nat.plugins.data_flywheel.observability.processor import DFWToDictProcessor
|
29
|
+
from nat.plugins.data_flywheel.observability.processor import SpanToDFWRecordProcessor
|
30
|
+
|
31
|
+
logger = logging.getLogger(__name__)
|
32
|
+
|
33
|
+
|
34
|
+
class DictBatchingProcessor(BatchingProcessor[dict]):
|
35
|
+
"""Processor that batches dictionary objects for bulk operations.
|
36
|
+
|
37
|
+
Specializes BatchingProcessor with explicit dict typing to support
|
38
|
+
bulk export operations to sinks.
|
39
|
+
"""
|
40
|
+
pass
|
41
|
+
|
42
|
+
|
43
|
+
class DFWExporter(SpanExporter[Span, dict]):
|
44
|
+
"""Abstract base class for Data Flywheel exporters."""
|
45
|
+
|
46
|
+
def __init__(self,
|
47
|
+
export_contract: type[BaseModel],
|
48
|
+
context_state: ContextState | None = None,
|
49
|
+
batch_size: int = 100,
|
50
|
+
flush_interval: float = 5.0,
|
51
|
+
max_queue_size: int = 1000,
|
52
|
+
drop_on_overflow: bool = False,
|
53
|
+
shutdown_timeout: float = 10.0,
|
54
|
+
client_id: str = "default"):
|
55
|
+
"""Initialize the Data Flywheel exporter.
|
56
|
+
|
57
|
+
Args:
|
58
|
+
export_contract: The Pydantic model type for the export contract.
|
59
|
+
context_state: The context state to use for the exporter.
|
60
|
+
batch_size: The batch size for exporting spans.
|
61
|
+
flush_interval: The flush interval in seconds for exporting spans.
|
62
|
+
max_queue_size: The maximum queue size for exporting spans.
|
63
|
+
drop_on_overflow: Whether to drop spans on overflow.
|
64
|
+
shutdown_timeout: The shutdown timeout in seconds.
|
65
|
+
client_id: The client ID for the exporter.
|
66
|
+
"""
|
67
|
+
super().__init__(context_state)
|
68
|
+
|
69
|
+
# Store the contract for property access
|
70
|
+
self._export_contract = export_contract
|
71
|
+
|
72
|
+
# Define the processor chain
|
73
|
+
ConcreteSpanToDFWRecordProcessor = processor_factory_to_type(SpanToDFWRecordProcessor, export_contract)
|
74
|
+
ConcreteDFWToDictProcessor = processor_factory_from_type(DFWToDictProcessor, export_contract)
|
75
|
+
self.add_processor(ConcreteSpanToDFWRecordProcessor(client_id=client_id)) # type: ignore
|
76
|
+
self.add_processor(ConcreteDFWToDictProcessor())
|
77
|
+
self.add_processor(
|
78
|
+
DictBatchingProcessor(batch_size=batch_size,
|
79
|
+
flush_interval=flush_interval,
|
80
|
+
max_queue_size=max_queue_size,
|
81
|
+
drop_on_overflow=drop_on_overflow,
|
82
|
+
shutdown_timeout=shutdown_timeout))
|
83
|
+
self.add_processor(DictBatchFilterProcessor())
|
84
|
+
|
85
|
+
@property
|
86
|
+
def export_contract(self) -> type[BaseModel]:
|
87
|
+
"""The export contract used for processing spans before converting to dict.
|
88
|
+
|
89
|
+
This type defines the structure of records that spans are converted to
|
90
|
+
before being serialized to dictionaries for export.
|
91
|
+
|
92
|
+
Returns:
|
93
|
+
type[BaseModel]: The Pydantic model type for the export contract.
|
94
|
+
"""
|
95
|
+
return self._export_contract
|
96
|
+
|
97
|
+
@abstractmethod
|
98
|
+
async def export_processed(self, item: dict | list[dict]) -> None:
|
99
|
+
pass
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 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.
|
@@ -0,0 +1,75 @@
|
|
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
|
+
|
18
|
+
from elasticsearch import AsyncElasticsearch
|
19
|
+
|
20
|
+
logger = logging.getLogger(__name__)
|
21
|
+
|
22
|
+
|
23
|
+
class ElasticsearchMixin:
|
24
|
+
"""Mixin for elasticsearch exporters.
|
25
|
+
|
26
|
+
This mixin provides elasticsearch-specific functionality for SpanExporter exporters.
|
27
|
+
It handles elasticsearch-specific resource tagging and uses the AsyncElasticsearch client.
|
28
|
+
"""
|
29
|
+
|
30
|
+
def __init__(self,
|
31
|
+
*args,
|
32
|
+
endpoint: str,
|
33
|
+
index: str,
|
34
|
+
elasticsearch_auth: tuple[str, str],
|
35
|
+
headers: dict[str, str] | None = None,
|
36
|
+
**kwargs):
|
37
|
+
"""Initialize the elasticsearch exporter.
|
38
|
+
|
39
|
+
Args:
|
40
|
+
endpoint (str): The elasticsearch endpoint.
|
41
|
+
index (str): The elasticsearch index.
|
42
|
+
elasticsearch_auth (tuple[str, str]): The elasticsearch authentication credentials.
|
43
|
+
headers (dict[str, str] | None): The elasticsearch headers.
|
44
|
+
"""
|
45
|
+
if headers is None:
|
46
|
+
headers = {"Accept": "application/vnd.elasticsearch+json; compatible-with=8"}
|
47
|
+
|
48
|
+
self._elastic_client = AsyncElasticsearch(endpoint, basic_auth=elasticsearch_auth, headers=headers)
|
49
|
+
self._index = index
|
50
|
+
super().__init__(*args, **kwargs)
|
51
|
+
|
52
|
+
async def export_processed(self, item: dict | list[dict]) -> None:
|
53
|
+
"""Export a batch of spans.
|
54
|
+
|
55
|
+
Args:
|
56
|
+
item (dict | list[dict]): Dictionary or list of dictionaries to export to Elasticsearch.
|
57
|
+
"""
|
58
|
+
if isinstance(item, list):
|
59
|
+
if not item: # Empty list
|
60
|
+
return
|
61
|
+
if not all(isinstance(doc, dict) for doc in item):
|
62
|
+
raise ValueError("All items in list must be dictionaries")
|
63
|
+
|
64
|
+
# Format for bulk operations: each document needs an action/metadata line
|
65
|
+
bulk_operations = []
|
66
|
+
for doc in item:
|
67
|
+
bulk_operations.append({"index": {"_index": self._index}}) # action/metadata with index
|
68
|
+
bulk_operations.append(doc) # document
|
69
|
+
|
70
|
+
await self._elastic_client.bulk(operations=bulk_operations)
|
71
|
+
elif isinstance(item, dict):
|
72
|
+
# Single document export
|
73
|
+
await self._elastic_client.index(index=self._index, document=item)
|
74
|
+
else:
|
75
|
+
raise ValueError(f"Invalid item type: {type(item)}. Expected dict or list[dict]")
|
@@ -0,0 +1,27 @@
|
|
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
|
+
# DFW Record Processors
|
17
|
+
from .dfw_record_processor import DFWToDictProcessor
|
18
|
+
from .dfw_record_processor import SpanToDFWRecordProcessor
|
19
|
+
|
20
|
+
# Trace Source Registry
|
21
|
+
from .trace_conversion.trace_adapter_registry import TraceAdapterRegistry
|
22
|
+
|
23
|
+
__all__ = [
|
24
|
+
"SpanToDFWRecordProcessor", # DFW Record Processors
|
25
|
+
"DFWToDictProcessor",
|
26
|
+
"TraceAdapterRegistry", # Trace Source Registry
|
27
|
+
]
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 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 json
|
17
|
+
import logging
|
18
|
+
from typing import TypeVar
|
19
|
+
from typing import cast
|
20
|
+
|
21
|
+
from pydantic import BaseModel
|
22
|
+
|
23
|
+
from nat.data_models.intermediate_step import IntermediateStepType
|
24
|
+
from nat.data_models.span import Span
|
25
|
+
from nat.observability.mixin.type_introspection_mixin import TypeIntrospectionMixin
|
26
|
+
from nat.observability.processor.processor import Processor
|
27
|
+
from nat.plugins.data_flywheel.observability.processor.trace_conversion import span_to_dfw_record
|
28
|
+
from nat.utils.type_utils import override
|
29
|
+
|
30
|
+
logger = logging.getLogger(__name__)
|
31
|
+
|
32
|
+
DFWRecordT = TypeVar("DFWRecordT", bound=BaseModel)
|
33
|
+
|
34
|
+
|
35
|
+
class DFWToDictProcessor(Processor[DFWRecordT, dict]):
|
36
|
+
"""Processor that converts a Data Flywheel record to a dictionary.
|
37
|
+
|
38
|
+
Serializes Pydantic DFW record models to dictionaries using model_dump_json()
|
39
|
+
for consistent field aliasing and proper JSON serialization.
|
40
|
+
"""
|
41
|
+
|
42
|
+
@override
|
43
|
+
async def process(self, item: DFWRecordT | None) -> dict:
|
44
|
+
"""Convert a DFW record to a dictionary.
|
45
|
+
|
46
|
+
Args:
|
47
|
+
item (DFWRecordT | None): The DFW record to convert.
|
48
|
+
|
49
|
+
Returns:
|
50
|
+
dict: The converted dictionary.
|
51
|
+
"""
|
52
|
+
if item is None:
|
53
|
+
logger.debug("Cannot process 'None' item, returning empty dict")
|
54
|
+
return {}
|
55
|
+
|
56
|
+
return json.loads(item.model_dump_json(by_alias=True))
|
57
|
+
|
58
|
+
|
59
|
+
class SpanToDFWRecordProcessor(Processor[Span, DFWRecordT], TypeIntrospectionMixin):
|
60
|
+
"""Processor that converts a Span to a Data Flywheel record.
|
61
|
+
|
62
|
+
Extracts trace data from spans and uses the trace adapter registry to convert
|
63
|
+
it to the target DFW record format.
|
64
|
+
"""
|
65
|
+
|
66
|
+
def __init__(self, client_id: str):
|
67
|
+
self._client_id = client_id
|
68
|
+
|
69
|
+
@override
|
70
|
+
async def process(self, item: Span) -> DFWRecordT | None:
|
71
|
+
"""Convert a Span to a DFW record.
|
72
|
+
|
73
|
+
Args:
|
74
|
+
item (Span): The Span to convert.
|
75
|
+
|
76
|
+
Returns:
|
77
|
+
DFWRecordT | None: The converted DFW record.
|
78
|
+
"""
|
79
|
+
|
80
|
+
match item.attributes.get("nat.event_type"):
|
81
|
+
case IntermediateStepType.LLM_START:
|
82
|
+
dfw_record = span_to_dfw_record(span=item, to_type=self.output_type, client_id=self._client_id)
|
83
|
+
return cast(DFWRecordT | None, dfw_record)
|
84
|
+
case _:
|
85
|
+
logger.debug("Unsupported event type: '%s'", item.attributes.get("nat.event_type"))
|
86
|
+
return None
|
@@ -0,0 +1,30 @@
|
|
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
|
+
from .span_extractor import extract_timestamp
|
17
|
+
from .span_extractor import extract_token_usage
|
18
|
+
from .span_extractor import extract_usage_info
|
19
|
+
from .span_to_dfw_record import span_to_dfw_record
|
20
|
+
from .trace_adapter_registry import TraceAdapterRegistry
|
21
|
+
from .trace_adapter_registry import register_adapter
|
22
|
+
|
23
|
+
__all__ = [
|
24
|
+
"extract_timestamp",
|
25
|
+
"extract_usage_info",
|
26
|
+
"extract_token_usage",
|
27
|
+
"span_to_dfw_record",
|
28
|
+
"register_adapter",
|
29
|
+
"TraceAdapterRegistry",
|
30
|
+
]
|
@@ -0,0 +1,14 @@
|
|
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.
|
nat/plugins/data_flywheel/observability/processor/trace_conversion/adapter/elasticsearch/__init__.py
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 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.
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 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
|
+
|
18
|
+
# pylint: disable=line-too-long
|
19
|
+
# flake8: noqa
|
20
|
+
from nat.plugins.data_flywheel.observability.processor.trace_conversion.adapter.elasticsearch.openai_converter import \
|
21
|
+
convert_langchain_openai
|
22
|
+
from nat.plugins.data_flywheel.observability.processor.trace_conversion.trace_adapter_registry import \
|
23
|
+
register_adapter
|
24
|
+
from nat.plugins.data_flywheel.observability.schema.provider.nim_trace_source import \
|
25
|
+
NIMTraceSource
|
26
|
+
from nat.plugins.data_flywheel.observability.schema.sink.elasticsearch.dfw_es_record import \
|
27
|
+
DFWESRecord
|
28
|
+
from nat.plugins.data_flywheel.observability.schema.trace_container import \
|
29
|
+
TraceContainer
|
30
|
+
|
31
|
+
logger = logging.getLogger(__name__)
|
32
|
+
|
33
|
+
|
34
|
+
@register_adapter(trace_source_model=NIMTraceSource)
|
35
|
+
def convert_langchain_nim(trace_source: TraceContainer) -> DFWESRecord:
|
36
|
+
"""Convert a LangChain Nim trace source to a DFWESRecord.
|
37
|
+
|
38
|
+
Args:
|
39
|
+
trace_source (TraceContainer): The trace source to convert
|
40
|
+
|
41
|
+
Returns:
|
42
|
+
DFWESRecord: The converted DFW record
|
43
|
+
"""
|
44
|
+
return convert_langchain_openai(trace_source)
|