netra-sdk 0.1.6__py3-none-any.whl → 0.1.7__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.
Potentially problematic release.
This version of netra-sdk might be problematic. Click here for more details.
- netra/__init__.py +5 -5
- netra/config.py +5 -0
- netra/{session.py → span_wrapper.py} +23 -38
- netra/version.py +1 -1
- {netra_sdk-0.1.6.dist-info → netra_sdk-0.1.7.dist-info}/METADATA +20 -22
- {netra_sdk-0.1.6.dist-info → netra_sdk-0.1.7.dist-info}/RECORD +8 -8
- {netra_sdk-0.1.6.dist-info → netra_sdk-0.1.7.dist-info}/LICENCE +0 -0
- {netra_sdk-0.1.6.dist-info → netra_sdk-0.1.7.dist-info}/WHEEL +0 -0
netra/__init__.py
CHANGED
|
@@ -8,8 +8,8 @@ from .config import Config
|
|
|
8
8
|
|
|
9
9
|
# Instrumentor functions
|
|
10
10
|
from .instrumentation import init_instrumentations
|
|
11
|
-
from .session import Session
|
|
12
11
|
from .session_manager import SessionManager
|
|
12
|
+
from .span_wrapper import SpanWrapper, UsageModel
|
|
13
13
|
from .tracer import Tracer
|
|
14
14
|
|
|
15
15
|
logger = logging.getLogger(__name__)
|
|
@@ -133,16 +133,16 @@ class Netra:
|
|
|
133
133
|
SessionManager.set_custom_event(event_name, attributes)
|
|
134
134
|
|
|
135
135
|
@classmethod
|
|
136
|
-
def
|
|
136
|
+
def start_span(
|
|
137
137
|
cls,
|
|
138
138
|
name: str,
|
|
139
139
|
attributes: Optional[Dict[str, str]] = None,
|
|
140
140
|
module_name: str = "combat_sdk",
|
|
141
|
-
) ->
|
|
141
|
+
) -> SpanWrapper:
|
|
142
142
|
"""
|
|
143
143
|
Start a new session.
|
|
144
144
|
"""
|
|
145
|
-
return
|
|
145
|
+
return SpanWrapper(name, attributes, module_name)
|
|
146
146
|
|
|
147
147
|
|
|
148
|
-
__all__ = ["Netra"]
|
|
148
|
+
__all__ = ["Netra", "UsageModel"]
|
netra/config.py
CHANGED
|
@@ -86,6 +86,11 @@ class Config:
|
|
|
86
86
|
env_tc = os.getenv("NETRA_TRACE_CONTENT")
|
|
87
87
|
self.trace_content = False if (env_tc is not None and env_tc.lower() in ("0", "false")) else True
|
|
88
88
|
|
|
89
|
+
if not self.trace_content:
|
|
90
|
+
os.environ["TRACELOOP_TRACE_CONTENT"] = "false"
|
|
91
|
+
else:
|
|
92
|
+
os.environ["TRACELOOP_TRACE_CONTENT"] = "true"
|
|
93
|
+
|
|
89
94
|
# 7. Environment: param override, else env
|
|
90
95
|
if environment is not None:
|
|
91
96
|
self.environment = environment
|
|
@@ -18,8 +18,8 @@ logger = logging.getLogger(__name__)
|
|
|
18
18
|
|
|
19
19
|
class UsageModel(BaseModel): # type: ignore[misc]
|
|
20
20
|
model: str
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
usage_type: str
|
|
22
|
+
units_used: Optional[int] = None
|
|
23
23
|
cost_in_usd: Optional[float] = None
|
|
24
24
|
|
|
25
25
|
|
|
@@ -28,27 +28,24 @@ class ATTRIBUTE:
|
|
|
28
28
|
MODEL = "model"
|
|
29
29
|
PROMPT = "prompt"
|
|
30
30
|
NEGATIVE_PROMPT = "negative_prompt"
|
|
31
|
-
HEIGHT = "height"
|
|
32
|
-
WIDTH = "width"
|
|
33
|
-
OUTPUT_TYPE = "output_type"
|
|
34
31
|
USAGE = "usage"
|
|
35
32
|
STATUS = "status"
|
|
36
33
|
DURATION_MS = "duration_ms"
|
|
37
34
|
ERROR_MESSAGE = "error_message"
|
|
38
35
|
|
|
39
36
|
|
|
40
|
-
class
|
|
37
|
+
class SpanWrapper:
|
|
41
38
|
"""
|
|
42
39
|
Context manager for tracking observability data for external API calls.
|
|
43
40
|
|
|
44
41
|
Usage:
|
|
45
|
-
with combat.
|
|
46
|
-
|
|
42
|
+
with combat.start_span("video_gen_task") as span:
|
|
43
|
+
span.set_prompt("A cat playing piano").set_image_height("1024")
|
|
47
44
|
|
|
48
45
|
# External API call
|
|
49
46
|
result = external_api.generate_video(...)
|
|
50
47
|
|
|
51
|
-
|
|
48
|
+
span.set_usage(usage_data)
|
|
52
49
|
"""
|
|
53
50
|
|
|
54
51
|
def __init__(self, name: str, attributes: Optional[Dict[str, str]] = None, module_name: str = "combat_sdk"):
|
|
@@ -65,8 +62,8 @@ class Session:
|
|
|
65
62
|
self.span: Optional[trace.Span] = None
|
|
66
63
|
self.context_token: Optional[Any] = None
|
|
67
64
|
|
|
68
|
-
def __enter__(self) -> "
|
|
69
|
-
"""Start the
|
|
65
|
+
def __enter__(self) -> "SpanWrapper":
|
|
66
|
+
"""Start the span wrapper, begin time tracking, and create OpenTelemetry span."""
|
|
70
67
|
self.start_time = time.time()
|
|
71
68
|
|
|
72
69
|
# Create OpenTelemetry span
|
|
@@ -76,11 +73,11 @@ class Session:
|
|
|
76
73
|
ctx = set_span_in_context(self.span)
|
|
77
74
|
self.context_token = context_api.attach(ctx)
|
|
78
75
|
|
|
79
|
-
logger.info(f"Started
|
|
76
|
+
logger.info(f"Started span wrapper: {self.name}")
|
|
80
77
|
return self
|
|
81
78
|
|
|
82
79
|
def __exit__(self, exc_type: Optional[type], exc_val: Optional[Exception], exc_tb: Any) -> Literal[False]:
|
|
83
|
-
"""End the
|
|
80
|
+
"""End the span wrapper, calculate duration, handle errors, and close OpenTelemetry span."""
|
|
84
81
|
self.end_time = time.time()
|
|
85
82
|
duration_ms = (self.end_time - self.start_time) * 1000 if self.start_time is not None else None
|
|
86
83
|
|
|
@@ -101,7 +98,7 @@ class Session:
|
|
|
101
98
|
self.span.set_status(Status(StatusCode.ERROR, self.error_message))
|
|
102
99
|
if exc_val is not None:
|
|
103
100
|
self.span.record_exception(exc_val)
|
|
104
|
-
logger.error(f"
|
|
101
|
+
logger.error(f"Span wrapper {self.name} failed: {self.error_message}")
|
|
105
102
|
|
|
106
103
|
self.set_attribute(f"{Config.LIBRARY_NAME}.{ATTRIBUTE.STATUS}", self.status)
|
|
107
104
|
|
|
@@ -117,15 +114,15 @@ class Session:
|
|
|
117
114
|
context_api.detach(self.context_token)
|
|
118
115
|
|
|
119
116
|
logger.info(
|
|
120
|
-
f"Ended
|
|
117
|
+
f"Ended span wrapper: {self.name} (Status: {self.status}, Duration: {duration_ms:.2f}ms)"
|
|
121
118
|
if duration_ms is not None
|
|
122
|
-
else f"Ended
|
|
119
|
+
else f"Ended span wrapper: {self.name} (Status: {self.status})"
|
|
123
120
|
)
|
|
124
121
|
|
|
125
122
|
# Don't suppress exceptions
|
|
126
123
|
return False
|
|
127
124
|
|
|
128
|
-
def set_attribute(self, key: str, value: str) -> "
|
|
125
|
+
def set_attribute(self, key: str, value: str) -> "SpanWrapper":
|
|
129
126
|
"""Set a single attribute and return self for method chaining."""
|
|
130
127
|
self.attributes[key] = value
|
|
131
128
|
# Also set on the span if it exists
|
|
@@ -133,41 +130,29 @@ class Session:
|
|
|
133
130
|
self.span.set_attribute(key, value)
|
|
134
131
|
return self
|
|
135
132
|
|
|
136
|
-
def set_prompt(self, prompt: str) -> "
|
|
133
|
+
def set_prompt(self, prompt: str) -> "SpanWrapper":
|
|
137
134
|
"""Set the input prompt."""
|
|
138
135
|
return self.set_attribute(f"{Config.LIBRARY_NAME}.{ATTRIBUTE.PROMPT}", prompt)
|
|
139
136
|
|
|
140
|
-
def set_negative_prompt(self, negative_prompt: str) -> "
|
|
137
|
+
def set_negative_prompt(self, negative_prompt: str) -> "SpanWrapper":
|
|
141
138
|
"""Set the negative prompt."""
|
|
142
139
|
return self.set_attribute(f"{Config.LIBRARY_NAME}.{ATTRIBUTE.NEGATIVE_PROMPT}", negative_prompt)
|
|
143
140
|
|
|
144
|
-
def
|
|
145
|
-
"""Set the height."""
|
|
146
|
-
return self.set_attribute(f"{Config.LIBRARY_NAME}.{ATTRIBUTE.HEIGHT}", height)
|
|
147
|
-
|
|
148
|
-
def set_width(self, width: str) -> "Session":
|
|
149
|
-
"""Set the width."""
|
|
150
|
-
return self.set_attribute(f"{Config.LIBRARY_NAME}.{ATTRIBUTE.WIDTH}", width)
|
|
151
|
-
|
|
152
|
-
def set_output_type(self, output_type: str) -> "Session":
|
|
153
|
-
"""Set the output type."""
|
|
154
|
-
return self.set_attribute(f"{Config.LIBRARY_NAME}.{ATTRIBUTE.OUTPUT_TYPE}", output_type)
|
|
155
|
-
|
|
156
|
-
def set_usage(self, usage: List[UsageModel]) -> "Session":
|
|
141
|
+
def set_usage(self, usage: List[UsageModel]) -> "SpanWrapper":
|
|
157
142
|
"""Set the usage data as a JSON string."""
|
|
158
143
|
usage_dict = [u.model_dump() for u in usage]
|
|
159
144
|
usage_json = json.dumps(usage_dict)
|
|
160
145
|
return self.set_attribute(f"{Config.LIBRARY_NAME}.{ATTRIBUTE.USAGE}", usage_json)
|
|
161
146
|
|
|
162
|
-
def set_model(self, model: str) -> "
|
|
147
|
+
def set_model(self, model: str) -> "SpanWrapper":
|
|
163
148
|
"""Set the model used."""
|
|
164
149
|
return self.set_attribute(f"{Config.LIBRARY_NAME}.{ATTRIBUTE.MODEL}", model)
|
|
165
150
|
|
|
166
|
-
def set_llm_system(self, system: str) -> "
|
|
151
|
+
def set_llm_system(self, system: str) -> "SpanWrapper":
|
|
167
152
|
"""Set the LLM system used."""
|
|
168
153
|
return self.set_attribute(f"{Config.LIBRARY_NAME}.{ATTRIBUTE.LLM_SYSTEM}", system)
|
|
169
154
|
|
|
170
|
-
def set_error(self, error_message: str) -> "
|
|
155
|
+
def set_error(self, error_message: str) -> "SpanWrapper":
|
|
171
156
|
"""Manually set an error message."""
|
|
172
157
|
self.status = "error"
|
|
173
158
|
self.error_message = error_message
|
|
@@ -175,14 +160,14 @@ class Session:
|
|
|
175
160
|
self.span.set_status(Status(StatusCode.ERROR, error_message))
|
|
176
161
|
return self.set_attribute(f"{Config.LIBRARY_NAME}.{ATTRIBUTE.ERROR_MESSAGE}", error_message)
|
|
177
162
|
|
|
178
|
-
def set_success(self) -> "
|
|
179
|
-
"""Manually mark the
|
|
163
|
+
def set_success(self) -> "SpanWrapper":
|
|
164
|
+
"""Manually mark the span wrapper as successful."""
|
|
180
165
|
self.status = "success"
|
|
181
166
|
if self.span:
|
|
182
167
|
self.span.set_status(Status(StatusCode.OK))
|
|
183
168
|
return self
|
|
184
169
|
|
|
185
|
-
def add_event(self, name: str, attributes: Optional[Dict[str, str]] = None) -> "
|
|
170
|
+
def add_event(self, name: str, attributes: Optional[Dict[str, str]] = None) -> "SpanWrapper":
|
|
186
171
|
"""Add an event to the span."""
|
|
187
172
|
if self.span:
|
|
188
173
|
self.span.add_event(name, attributes or {})
|
netra/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.1.
|
|
1
|
+
__version__ = "0.1.7"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: netra-sdk
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.7
|
|
4
4
|
Summary: A Python SDK for AI application observability that provides OpenTelemetry-based monitoring, tracing, and PII protection for LLM and vector database applications. Enables easy instrumentation, session tracking, and privacy-focused data collection for AI systems in production environments.
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
Keywords: netra,tracing,observability,sdk,ai,llm,vector,database
|
|
@@ -402,46 +402,44 @@ Netra.set_custom_event(event_name="conversion", attributes={
|
|
|
402
402
|
"value": 99.99
|
|
403
403
|
})
|
|
404
404
|
```
|
|
405
|
-
## 🔄 Custom
|
|
405
|
+
## 🔄 Custom Span Tracking
|
|
406
406
|
|
|
407
|
-
Use the custom
|
|
407
|
+
Use the custom span tracking utility to track external API calls with detailed observability:
|
|
408
408
|
|
|
409
409
|
```python
|
|
410
|
-
from netra import Netra,
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
session.set_width("1024")
|
|
420
|
-
session.set_model("dall-e-3")
|
|
421
|
-
session.set_llm_system("openai")
|
|
410
|
+
from netra import Netra, UsageModel
|
|
411
|
+
|
|
412
|
+
# Start a new span
|
|
413
|
+
with Netra.start_span("image_generation") as span:
|
|
414
|
+
# Set span attributes
|
|
415
|
+
span.set_prompt("A beautiful sunset over mountains")
|
|
416
|
+
span.set_negative_prompt("blurry, low quality")
|
|
417
|
+
span.set_model("dall-e-3")
|
|
418
|
+
span.set_llm_system("openai")
|
|
422
419
|
|
|
423
420
|
# Set usage data with UsageModel
|
|
424
421
|
usage_data = [
|
|
425
422
|
UsageModel(
|
|
426
423
|
model="dall-e-3",
|
|
427
|
-
|
|
428
|
-
|
|
424
|
+
usage_type="image_generation",
|
|
425
|
+
units_used=1,
|
|
429
426
|
cost_in_usd=0.02
|
|
430
427
|
)
|
|
431
428
|
]
|
|
432
|
-
|
|
429
|
+
span.set_usage(usage_data)
|
|
433
430
|
|
|
434
431
|
# Your API calls here
|
|
435
432
|
# ...
|
|
436
433
|
|
|
437
434
|
# Set custom attributes
|
|
438
|
-
|
|
435
|
+
span.set_attribute("custom_key", "custom_value")
|
|
439
436
|
|
|
440
437
|
# Add events
|
|
441
|
-
|
|
442
|
-
|
|
438
|
+
span.add_event("generation_started", {"step": "1", "status": "processing"})
|
|
439
|
+
span.add_event("processing_completed", {"step": "rendering"})
|
|
443
440
|
|
|
444
|
-
#
|
|
441
|
+
# Get the current active open telemetry span
|
|
442
|
+
current_span = span.get_current_span()
|
|
445
443
|
```
|
|
446
444
|
|
|
447
445
|
## 🔧 Advanced Configuration
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
netra/__init__.py,sha256=
|
|
1
|
+
netra/__init__.py,sha256=1ZYHSUVsWMBsBZtpBGDreYDvMfwSUyr7-4VaTb6dgZE,4705
|
|
2
2
|
netra/anonymizer/__init__.py,sha256=KeGPPZqKVZbtkbirEKYTYhj6aZHlakjdQhD7QHqBRio,133
|
|
3
3
|
netra/anonymizer/anonymizer.py,sha256=1VeYAsFpF_tYDlqJF-Q82-ZXGOR4YWBqrKUsRw3qOrA,3539
|
|
4
4
|
netra/anonymizer/base.py,sha256=ytPxHCUD2OXlEY6fNTuMmwImNdIjgj294I41FIgoXpU,5946
|
|
5
5
|
netra/anonymizer/fp_anonymizer.py,sha256=_6svIYmE0eejdIMkhKBUWCNjGtGimtrGtbLvPSOp8W4,6493
|
|
6
|
-
netra/config.py,sha256=
|
|
6
|
+
netra/config.py,sha256=v8tZMrlNj4yjmOOne5qUlG3kFmdx1DFAp8ewbUMIst8,4930
|
|
7
7
|
netra/decorators.py,sha256=V_WpZ2IgW2Y7B_WnSXmKUGGhkM5Cra2TwONddmJpPaI,6837
|
|
8
8
|
netra/exceptions/__init__.py,sha256=uDgcBxmC4WhdS7HRYQk_TtJyxH1s1o6wZmcsnSHLAcM,174
|
|
9
9
|
netra/exceptions/injection.py,sha256=ke4eUXRYUFJkMZgdSyPPkPt5PdxToTI6xLEBI0hTWUQ,1332
|
|
@@ -32,11 +32,11 @@ netra/processors/__init__.py,sha256=G16VumYTpgV4jsWrKNFSgm6xMQAsZ2Rrux25UVeo5YQ,
|
|
|
32
32
|
netra/processors/error_detection_processor.py,sha256=TtSZoJ7BCMHlVaXWYfqLHSZ6uIx43tdqYb7AFXpt0BA,2898
|
|
33
33
|
netra/processors/session_span_processor.py,sha256=qcsBl-LnILWefsftI8NQhXDGb94OWPc8LvzhVA0JS_c,2432
|
|
34
34
|
netra/scanner.py,sha256=wqjMZnEbVvrGMiUSI352grUyHpkk94oBfHfMiXPhpGU,3866
|
|
35
|
-
netra/session.py,sha256=o1wXrPzMauqj_3P-iNBHVlcIR7zcKcbsmkrcHjQMKuY,7263
|
|
36
35
|
netra/session_manager.py,sha256=EVcnWcSj4NdkH--HmqHx0mmzivQiM4GCyFLu6lwi33M,6252
|
|
36
|
+
netra/span_wrapper.py,sha256=Lr4s9uSqtBJzWzQ_YVuh5XrEo1FbLj049b_lBbWpuWc,6733
|
|
37
37
|
netra/tracer.py,sha256=9jAKdIHXbaZ6WV_p8I1syQiMdqXVCXMhpEhCBsbbci8,3538
|
|
38
|
-
netra/version.py,sha256=
|
|
39
|
-
netra_sdk-0.1.
|
|
40
|
-
netra_sdk-0.1.
|
|
41
|
-
netra_sdk-0.1.
|
|
42
|
-
netra_sdk-0.1.
|
|
38
|
+
netra/version.py,sha256=YpKDcdV7CqL8n45u267wKtyloM13FSVbOdrqgNZnSLM,22
|
|
39
|
+
netra_sdk-0.1.7.dist-info/LICENCE,sha256=8B_UoZ-BAl0AqiHAHUETCgd3I2B9yYJ1WEQtVb_qFMA,11359
|
|
40
|
+
netra_sdk-0.1.7.dist-info/METADATA,sha256=X8r06jPoZDkZ9oxdLXLhOQhdht_IR2VAaIBn0aJX-0k,23628
|
|
41
|
+
netra_sdk-0.1.7.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
42
|
+
netra_sdk-0.1.7.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|