netra-sdk 0.1.46__py3-none-any.whl → 0.1.47__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 CHANGED
@@ -183,11 +183,12 @@ class Netra:
183
183
  session_id: Session identifier
184
184
  """
185
185
  if not isinstance(session_id, str):
186
- raise TypeError(f"session_id must be a string, got {type(session_id)}")
186
+ logger.error(f"set_session_id: session_id must be a string, got {type(session_id)}")
187
+ return
187
188
  if session_id:
188
189
  SessionManager.set_session_context("session_id", session_id)
189
190
  else:
190
- logger.warning("Session ID must be provided for setting session_id.")
191
+ logger.warning("set_session_id: Session ID must be provided for setting session_id.")
191
192
 
192
193
  @classmethod
193
194
  def set_user_id(cls, user_id: str) -> None:
@@ -198,11 +199,12 @@ class Netra:
198
199
  user_id: User identifier
199
200
  """
200
201
  if not isinstance(user_id, str):
201
- raise TypeError(f"user_id must be a string, got {type(user_id)}")
202
+ logger.error(f"set_user_id: user_id must be a string, got {type(user_id)}")
203
+ return
202
204
  if user_id:
203
205
  SessionManager.set_session_context("user_id", user_id)
204
206
  else:
205
- logger.warning("User ID must be provided for setting user_id.")
207
+ logger.warning("set_user_id: User ID must be provided for setting user_id.")
206
208
 
207
209
  @classmethod
208
210
  def set_tenant_id(cls, tenant_id: str) -> None:
@@ -213,11 +215,12 @@ class Netra:
213
215
  user_account_id: User account identifier
214
216
  """
215
217
  if not isinstance(tenant_id, str):
216
- raise TypeError(f"tenant_id must be a string, got {type(tenant_id)}")
218
+ logger.error(f"set_tenant_id: tenant_id must be a string, got {type(tenant_id)}")
219
+ return
217
220
  if tenant_id:
218
221
  SessionManager.set_session_context("tenant_id", tenant_id)
219
222
  else:
220
- logger.warning("Tenant ID must be provided for setting tenant_id.")
223
+ logger.warning("set_tenant_id: Tenant ID must be provided for setting tenant_id.")
221
224
 
222
225
  @classmethod
223
226
  def set_custom_attributes(cls, key: str, value: Any) -> None:
netra/decorators.py CHANGED
@@ -285,7 +285,8 @@ def _create_function_wrapper(
285
285
  # Set span type if provided
286
286
 
287
287
  if not isinstance(as_type, SpanType):
288
- raise ValueError(f"Invalid span type: {as_type}")
288
+ logger.error("Invalid span type: %s", as_type)
289
+ return
289
290
  try:
290
291
  span.set_attribute("netra.span.type", as_type.value)
291
292
  except Exception:
@@ -344,7 +345,8 @@ def _create_function_wrapper(
344
345
  # Set span type if provided
345
346
  if as_type is not None:
346
347
  if not isinstance(as_type, SpanType):
347
- raise ValueError(f"Invalid span type: {as_type}")
348
+ logger.error("Invalid span type: %s", as_type)
349
+ return
348
350
  try:
349
351
  span.set_attribute("netra.span.type", as_type.value)
350
352
  except Exception:
netra/span_wrapper.py CHANGED
@@ -98,7 +98,8 @@ class SpanWrapper:
98
98
  if isinstance(as_type, SpanType):
99
99
  self.attributes["netra.span.type"] = as_type.value
100
100
  else:
101
- raise ValueError(f"Invalid span type: {as_type}")
101
+ logger.error("Invalid span type: %s", as_type)
102
+ return
102
103
 
103
104
  def __enter__(self) -> "SpanWrapper":
104
105
  """Start the span wrapper, begin time tracking, and create OpenTelemetry span."""
netra/tracer.py CHANGED
@@ -5,10 +5,12 @@ including exporter setup and span processor configuration.
5
5
  """
6
6
 
7
7
  import logging
8
+ import threading
8
9
  from typing import Any, Dict
9
10
 
10
11
  from opentelemetry import trace
11
12
  from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
13
+ from opentelemetry.sdk import trace as sdk_trace
12
14
  from opentelemetry.sdk.resources import DEPLOYMENT_ENVIRONMENT, SERVICE_NAME, Resource
13
15
  from opentelemetry.sdk.trace import TracerProvider
14
16
  from opentelemetry.sdk.trace.export import (
@@ -22,6 +24,8 @@ from netra.exporters import FilteringSpanExporter
22
24
 
23
25
  logger = logging.getLogger(__name__)
24
26
 
27
+ _provider_install_lock = threading.Lock()
28
+
25
29
 
26
30
  class Tracer:
27
31
  """
@@ -55,57 +59,66 @@ class Tracer:
55
59
  resource = Resource(attributes=resource_attrs)
56
60
 
57
61
  # Build TracerProvider
58
- provider = TracerProvider(resource=resource)
59
-
60
- # Configure exporter based on configuration
61
- if not self.cfg.otlp_endpoint:
62
- logger.warning("OTLP endpoint not provided, falling back to console exporter")
63
- exporter = ConsoleSpanExporter()
62
+ current_provider = trace.get_tracer_provider()
63
+ if isinstance(current_provider, sdk_trace.TracerProvider):
64
+ provider = current_provider
65
+ logger.info("Reusing existing TracerProvider. Possible loss of Resource attributes")
64
66
  else:
65
- exporter = OTLPSpanExporter(
66
- endpoint=self._format_endpoint(self.cfg.otlp_endpoint),
67
- headers=self.cfg.headers,
67
+ provider = TracerProvider(resource=resource)
68
+ trace.set_tracer_provider(provider)
69
+ logger.info("Using Netra TracerProvider")
70
+
71
+ with _provider_install_lock:
72
+ if getattr(provider, "_netra_processors_installed", False):
73
+ logger.info("Netra processors already installed on provider; skipping setup")
74
+ return
75
+
76
+ if not self.cfg.otlp_endpoint:
77
+ logger.warning("OTLP endpoint not provided, falling back to console exporter")
78
+ exporter = ConsoleSpanExporter()
79
+ else:
80
+ exporter = OTLPSpanExporter(
81
+ endpoint=self._format_endpoint(self.cfg.otlp_endpoint),
82
+ headers=self.cfg.headers,
83
+ )
84
+ original_exporter = exporter
85
+ try:
86
+ patterns = getattr(self.cfg, "blocked_spans", None) or []
87
+ exporter = FilteringSpanExporter(exporter, patterns)
88
+ if patterns:
89
+ logger.info("Enabled FilteringSpanExporter with %d global pattern(s)", len(patterns))
90
+ else:
91
+ logger.info("Enabled FilteringSpanExporter with local-only rules")
92
+ except (ValueError, TypeError) as e:
93
+ logger.warning("Failed to enable FilteringSpanExporter: %s; using unwrapped exporter", e)
94
+ exporter = original_exporter
95
+
96
+ from netra.processors import (
97
+ InstrumentationSpanProcessor,
98
+ LocalFilteringSpanProcessor,
99
+ ScrubbingSpanProcessor,
100
+ SessionSpanProcessor,
68
101
  )
69
- # Wrap exporter with filtering to support both global and local (baggage-based) rules
70
- try:
71
- patterns = getattr(self.cfg, "blocked_spans", None) or []
72
- exporter = FilteringSpanExporter(exporter, patterns)
73
- if patterns:
74
- logger.info("Enabled FilteringSpanExporter with %d global pattern(s)", len(patterns))
102
+
103
+ provider.add_span_processor(LocalFilteringSpanProcessor())
104
+ provider.add_span_processor(InstrumentationSpanProcessor())
105
+ provider.add_span_processor(SessionSpanProcessor())
106
+
107
+ if self.cfg.enable_scrubbing:
108
+ provider.add_span_processor(ScrubbingSpanProcessor()) # type: ignore[no-untyped-call]
109
+
110
+ if self.cfg.disable_batch:
111
+ provider.add_span_processor(SimpleSpanProcessor(exporter))
75
112
  else:
76
- logger.info("Enabled FilteringSpanExporter with local-only rules")
77
- except Exception as e:
78
- logger.warning("Failed to enable FilteringSpanExporter: %s", e)
79
- # Add span processors: first instrumentation wrapper, then session processor
80
- from netra.processors import (
81
- InstrumentationSpanProcessor,
82
- LocalFilteringSpanProcessor,
83
- ScrubbingSpanProcessor,
84
- SessionSpanProcessor,
85
- )
86
-
87
- # Apply local filtering propagation first so later processors and spans see attributes
88
- provider.add_span_processor(LocalFilteringSpanProcessor())
89
- provider.add_span_processor(InstrumentationSpanProcessor())
90
- provider.add_span_processor(SessionSpanProcessor())
91
-
92
- # Add scrubbing processor if enabled
93
- if self.cfg.enable_scrubbing:
94
- provider.add_span_processor(ScrubbingSpanProcessor()) # type: ignore[no-untyped-call]
95
-
96
- # Install appropriate span processor
97
- if self.cfg.disable_batch:
98
- provider.add_span_processor(SimpleSpanProcessor(exporter))
99
- else:
100
- provider.add_span_processor(BatchSpanProcessor(exporter))
101
-
102
- # Set global tracer provider
103
- trace.set_tracer_provider(provider)
104
- logger.info(
105
- "Netra TracerProvider initialized: endpoint=%s, disable_batch=%s",
106
- self.cfg.otlp_endpoint,
107
- self.cfg.disable_batch,
108
- )
113
+ provider.add_span_processor(BatchSpanProcessor(exporter))
114
+
115
+ setattr(provider, "_netra_processors_installed", True)
116
+
117
+ logger.info(
118
+ "Netra initialized: endpoint=%s, disable_batch=%s",
119
+ self.cfg.otlp_endpoint,
120
+ self.cfg.disable_batch,
121
+ )
109
122
 
110
123
  def _format_endpoint(self, endpoint: str) -> str:
111
124
  """Format the OTLP endpoint URL to ensure it ends with '/v1/traces'.
netra/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.1.46"
1
+ __version__ = "0.1.47"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: netra-sdk
3
- Version: 0.1.46
3
+ Version: 0.1.47
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-Expression: Apache-2.0
6
6
  License-File: LICENCE
@@ -1,10 +1,10 @@
1
- netra/__init__.py,sha256=tbj0UsUHKMG8RHJ58Y0tCvPVDS_XkGb7sF_xM1lxJEY,10454
1
+ netra/__init__.py,sha256=vH9J2iPKtx8j9-dWhDroUqRq10qfqHaBurMl11c4g6Q,10590
2
2
  netra/anonymizer/__init__.py,sha256=KeGPPZqKVZbtkbirEKYTYhj6aZHlakjdQhD7QHqBRio,133
3
3
  netra/anonymizer/anonymizer.py,sha256=IcrYkdwWrFauGWUeAW-0RwrSUM8VSZCFNtoywZhvIqU,3778
4
4
  netra/anonymizer/base.py,sha256=ytPxHCUD2OXlEY6fNTuMmwImNdIjgj294I41FIgoXpU,5946
5
5
  netra/anonymizer/fp_anonymizer.py,sha256=_6svIYmE0eejdIMkhKBUWCNjGtGimtrGtbLvPSOp8W4,6493
6
6
  netra/config.py,sha256=RqLul2vlNHHKGU31OQIJTUpcKMSmVse9IlGFwImW6sE,7032
7
- netra/decorators.py,sha256=NHJZeZo3LEuOxCz-lfz3j74o6CS0jS8JBRw2LvoeeWE,18389
7
+ netra/decorators.py,sha256=b6cNRJVUvroGv97NVE-psMZzL-Upl0X2m63_l_-VBdQ,18433
8
8
  netra/exceptions/__init__.py,sha256=uDgcBxmC4WhdS7HRYQk_TtJyxH1s1o6wZmcsnSHLAcM,174
9
9
  netra/exceptions/injection.py,sha256=ke4eUXRYUFJkMZgdSyPPkPt5PdxToTI6xLEBI0hTWUQ,1332
10
10
  netra/exceptions/pii.py,sha256=MT4p_x-zH3VtYudTSxw1Z9qQZADJDspq64WrYqSWlZc,2438
@@ -49,11 +49,11 @@ netra/processors/scrubbing_span_processor.py,sha256=dJ86Ncmjvmrhm_uAdGTwcGvRpZbV
49
49
  netra/processors/session_span_processor.py,sha256=qcsBl-LnILWefsftI8NQhXDGb94OWPc8LvzhVA0JS_c,2432
50
50
  netra/scanner.py,sha256=kyDpeZiscCPb6pjuhS-sfsVj-dviBFRepdUWh0sLoEY,11554
51
51
  netra/session_manager.py,sha256=jxA62zAgiTsuTyV_UuPkVb2W1Uieb7I5jWsYiJ6jSxk,13897
52
- netra/span_wrapper.py,sha256=80-0MkAw7AOQg0u7dj2YfXfnuUQDE8ymsGNzh6y6JtA,10102
53
- netra/tracer.py,sha256=IPVYMc4x74XZJeKvCfV6b0X9mUHGvsssUzLnRvFPV6M,4629
52
+ netra/span_wrapper.py,sha256=x5ejtMwD40eMRbeYOfsE2GQGrqZcjZz_sZOuLIeZ__8,10118
53
+ netra/tracer.py,sha256=BXlEEOQ7ou5zd2Bf5cUFp6vLoMJLgBywtxfUBr9Di-Q,5175
54
54
  netra/utils.py,sha256=FblSzI8qMTfEbusakGBKE9CNELW0GEBHl09mPPxgI-w,2521
55
- netra/version.py,sha256=X3e_85I7oZGwZD8nW9SBKEUbQU7-_3W9FXuicrfxHjc,23
56
- netra_sdk-0.1.46.dist-info/METADATA,sha256=QWfOewRPrRyNlamWqdvuS-1U01UocBvxcRZQ_H6Qmvw,28208
57
- netra_sdk-0.1.46.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
58
- netra_sdk-0.1.46.dist-info/licenses/LICENCE,sha256=8B_UoZ-BAl0AqiHAHUETCgd3I2B9yYJ1WEQtVb_qFMA,11359
59
- netra_sdk-0.1.46.dist-info/RECORD,,
55
+ netra/version.py,sha256=BqdH88p7_x5NtwJCtqUPLKt1fAJF1mVKUoKH7vlX5dQ,23
56
+ netra_sdk-0.1.47.dist-info/METADATA,sha256=JbzzZzE-IzVy2h8fNa0QT5doUkjgpvJXHgnxf44zj0Y,28208
57
+ netra_sdk-0.1.47.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
58
+ netra_sdk-0.1.47.dist-info/licenses/LICENCE,sha256=8B_UoZ-BAl0AqiHAHUETCgd3I2B9yYJ1WEQtVb_qFMA,11359
59
+ netra_sdk-0.1.47.dist-info/RECORD,,