netra-sdk 0.1.27__tar.gz → 0.1.29__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.

Potentially problematic release.


This version of netra-sdk might be problematic. Click here for more details.

Files changed (51) hide show
  1. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/PKG-INFO +1 -1
  2. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/__init__.py +89 -0
  3. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/config.py +18 -0
  4. netra_sdk-0.1.29/netra/version.py +1 -0
  5. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/pyproject.toml +1 -1
  6. netra_sdk-0.1.27/netra/version.py +0 -1
  7. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/LICENCE +0 -0
  8. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/README.md +0 -0
  9. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/anonymizer/__init__.py +0 -0
  10. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/anonymizer/anonymizer.py +0 -0
  11. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/anonymizer/base.py +0 -0
  12. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/anonymizer/fp_anonymizer.py +0 -0
  13. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/decorators.py +0 -0
  14. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/exceptions/__init__.py +0 -0
  15. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/exceptions/injection.py +0 -0
  16. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/exceptions/pii.py +0 -0
  17. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/input_scanner.py +0 -0
  18. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/instrumentation/__init__.py +0 -0
  19. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/instrumentation/aiohttp/__init__.py +0 -0
  20. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/instrumentation/aiohttp/version.py +0 -0
  21. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/instrumentation/cohere/__init__.py +0 -0
  22. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/instrumentation/cohere/version.py +0 -0
  23. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/instrumentation/fastapi/__init__.py +0 -0
  24. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/instrumentation/fastapi/version.py +0 -0
  25. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/instrumentation/google_genai/__init__.py +0 -0
  26. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/instrumentation/google_genai/config.py +0 -0
  27. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/instrumentation/google_genai/utils.py +0 -0
  28. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/instrumentation/google_genai/version.py +0 -0
  29. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/instrumentation/httpx/__init__.py +0 -0
  30. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/instrumentation/httpx/version.py +0 -0
  31. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/instrumentation/instruments.py +0 -0
  32. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/instrumentation/mistralai/__init__.py +0 -0
  33. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/instrumentation/mistralai/config.py +0 -0
  34. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/instrumentation/mistralai/utils.py +0 -0
  35. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/instrumentation/mistralai/version.py +0 -0
  36. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/instrumentation/openai/__init__.py +0 -0
  37. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/instrumentation/openai/version.py +0 -0
  38. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/instrumentation/openai/wrappers.py +0 -0
  39. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/instrumentation/pydantic_ai/__init__.py +0 -0
  40. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/instrumentation/pydantic_ai/utils.py +0 -0
  41. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/instrumentation/pydantic_ai/version.py +0 -0
  42. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/instrumentation/pydantic_ai/wrappers.py +0 -0
  43. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/instrumentation/weaviate/__init__.py +0 -0
  44. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/instrumentation/weaviate/version.py +0 -0
  45. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/pii.py +0 -0
  46. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/processors/__init__.py +0 -0
  47. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/processors/session_span_processor.py +0 -0
  48. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/scanner.py +0 -0
  49. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/session_manager.py +0 -0
  50. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/span_wrapper.py +0 -0
  51. {netra_sdk-0.1.27 → netra_sdk-0.1.29}/netra/tracer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: netra-sdk
3
- Version: 0.1.27
3
+ Version: 0.1.29
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
@@ -1,7 +1,12 @@
1
+ import atexit
1
2
  import logging
2
3
  import threading
3
4
  from typing import Any, Dict, Optional, Set
4
5
 
6
+ from opentelemetry import context as context_api
7
+ from opentelemetry import trace
8
+ from opentelemetry.trace import SpanKind
9
+
5
10
  from netra.instrumentation.instruments import InstrumentSet, NetraInstruments
6
11
 
7
12
  from .config import Config
@@ -12,7 +17,10 @@ from .session_manager import SessionManager
12
17
  from .span_wrapper import ActionModel, SpanWrapper, UsageModel
13
18
  from .tracer import Tracer
14
19
 
20
+ # Package-level logger. Attach NullHandler by default so library does not emit logs
21
+ # unless explicitly enabled by the user via debug_mode.
15
22
  logger = logging.getLogger(__name__)
23
+ logger.addHandler(logging.NullHandler())
16
24
 
17
25
 
18
26
  class Netra:
@@ -24,6 +32,8 @@ class Netra:
24
32
  _initialized = False
25
33
  # Use RLock so the thread that already owns the lock can re-acquire it safely
26
34
  _init_lock = threading.RLock()
35
+ _root_span = None
36
+ _root_ctx_token = None
27
37
 
28
38
  @classmethod
29
39
  def is_initialized(cls) -> bool:
@@ -42,6 +52,8 @@ class Netra:
42
52
  headers: Optional[str] = None,
43
53
  disable_batch: Optional[bool] = None,
44
54
  trace_content: Optional[bool] = None,
55
+ debug_mode: Optional[bool] = None,
56
+ enable_root_span: Optional[bool] = None,
45
57
  resource_attributes: Optional[Dict[str, Any]] = None,
46
58
  environment: Optional[str] = None,
47
59
  instruments: Optional[Set[NetraInstruments]] = None,
@@ -61,10 +73,32 @@ class Netra:
61
73
  headers=headers,
62
74
  disable_batch=disable_batch,
63
75
  trace_content=trace_content,
76
+ debug_mode=debug_mode,
77
+ enable_root_span=enable_root_span,
64
78
  resource_attributes=resource_attributes,
65
79
  environment=environment,
66
80
  )
67
81
 
82
+ # Configure package logging based on debug mode
83
+ pkg_logger = logging.getLogger("netra")
84
+ # Prevent propagating to root to avoid duplicate logs
85
+ pkg_logger.propagate = False
86
+ # Clear existing handlers to avoid duplicates across repeated init attempts
87
+ pkg_logger.handlers.clear()
88
+ if cfg.debug_mode:
89
+ pkg_logger.setLevel(logging.DEBUG)
90
+ handler = logging.StreamHandler()
91
+ formatter = logging.Formatter(
92
+ fmt="%(asctime)s | %(levelname)s | %(name)s | %(message)s",
93
+ datefmt="%Y-%m-%d %H:%M:%S",
94
+ )
95
+ handler.setFormatter(formatter)
96
+ pkg_logger.addHandler(handler)
97
+ else:
98
+ # Silence SDK logs entirely unless debug is enabled
99
+ pkg_logger.setLevel(logging.CRITICAL)
100
+ pkg_logger.addHandler(logging.NullHandler())
101
+
68
102
  # Initialize tracer (OTLP exporter, span processor, resource)
69
103
  Tracer(cfg)
70
104
 
@@ -81,6 +115,61 @@ class Netra:
81
115
  cls._initialized = True
82
116
  logger.info("Netra successfully initialized.")
83
117
 
118
+ # Create and attach a long-lived root span if enabled
119
+ if cfg.enable_root_span:
120
+ tracer = trace.get_tracer("netra.root.span")
121
+ root_name = f"{Config.LIBRARY_NAME}.root.span"
122
+ root_span = tracer.start_span(root_name, kind=SpanKind.INTERNAL)
123
+ # Add useful attributes
124
+ if cfg.app_name:
125
+ root_span.set_attribute("service.name", cfg.app_name)
126
+ root_span.set_attribute("netra.environment", cfg.environment)
127
+ root_span.set_attribute("netra.library.version", Config.LIBRARY_VERSION)
128
+
129
+ # Attach span to current context so subsequent spans become its children
130
+ ctx = trace.set_span_in_context(root_span)
131
+ token = context_api.attach(ctx)
132
+
133
+ # Save for potential shutdown/cleanup and session tracking
134
+ cls._root_span = root_span
135
+ cls._root_ctx_token = token
136
+ try:
137
+ SessionManager.set_current_span(root_span)
138
+ except Exception:
139
+ pass
140
+ logger.info("Netra root span created and attached to context.")
141
+
142
+ # Ensure cleanup at process exit
143
+ atexit.register(cls.shutdown)
144
+
145
+ @classmethod
146
+ def shutdown(cls) -> None:
147
+ """Optional cleanup to end the root span and detach context."""
148
+ with cls._init_lock:
149
+ if cls._root_ctx_token is not None:
150
+ try:
151
+ context_api.detach(cls._root_ctx_token)
152
+ except Exception:
153
+ pass
154
+ finally:
155
+ cls._root_ctx_token = None
156
+ if cls._root_span is not None:
157
+ try:
158
+ cls._root_span.end()
159
+ except Exception:
160
+ pass
161
+ finally:
162
+ cls._root_span = None
163
+ # Try to flush and shutdown the tracer provider to ensure export
164
+ try:
165
+ provider = trace.get_tracer_provider()
166
+ if hasattr(provider, "force_flush"):
167
+ provider.force_flush()
168
+ if hasattr(provider, "shutdown"):
169
+ provider.shutdown()
170
+ except Exception:
171
+ pass
172
+
84
173
  @classmethod
85
174
  def set_session_id(cls, session_id: str) -> None:
86
175
  """
@@ -16,6 +16,8 @@ class Config:
16
16
  - headers: Additional headers (W3C Correlation-Context format)
17
17
  - disable_batch: Whether to disable batch span processor (bool)
18
18
  - trace_content: Whether to capture prompt/completion content (bool)
19
+ - debug_mode: Whether to enable SDK logging; default False (bool)
20
+ - enable_root_span: Whether to create a process root span; default False (bool)
19
21
  - resource_attributes: Custom resource attributes dict (e.g., {'env': 'prod', 'version': '1.0.0'})
20
22
  """
21
23
 
@@ -30,6 +32,8 @@ class Config:
30
32
  headers: Optional[str] = None,
31
33
  disable_batch: Optional[bool] = None,
32
34
  trace_content: Optional[bool] = None,
35
+ debug_mode: Optional[bool] = None,
36
+ enable_root_span: Optional[bool] = None,
33
37
  resource_attributes: Optional[Dict[str, Any]] = None,
34
38
  environment: Optional[str] = None,
35
39
  ):
@@ -91,12 +95,26 @@ class Config:
91
95
  else:
92
96
  os.environ["TRACELOOP_TRACE_CONTENT"] = "true"
93
97
 
98
+ # Debug mode: enable SDK logging only when True. Default False.
99
+ if debug_mode is not None:
100
+ self.debug_mode = debug_mode
101
+ else:
102
+ env_dbg = os.getenv("NETRA_DEBUG")
103
+ self.debug_mode = True if (env_dbg is not None and env_dbg.lower() in ("1", "true")) else False
104
+
94
105
  # 7. Environment: param override, else env
95
106
  if environment is not None:
96
107
  self.environment = environment
97
108
  else:
98
109
  self.environment = os.getenv("NETRA_ENV", "local")
99
110
 
111
+ # Enable a long-lived root span for the process? Default False.
112
+ if enable_root_span is not None:
113
+ self.enable_root_span = enable_root_span
114
+ else:
115
+ env_root = os.getenv("NETRA_ENABLE_ROOT_SPAN")
116
+ self.enable_root_span = True if (env_root is not None and env_root.lower() in ("1", "true")) else False
117
+
100
118
  # Resource attributes: param override, else parse JSON from env, else empty dict
101
119
  if resource_attributes is not None:
102
120
  self.resource_attributes = resource_attributes
@@ -0,0 +1 @@
1
+ __version__ = "0.1.29"
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
4
4
 
5
5
  [project]
6
6
  name = "netra-sdk"
7
- version = "0.1.27"
7
+ version = "0.1.29"
8
8
  description = "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."
9
9
  authors = [
10
10
  {name = "Sooraj Thomas",email = "sooraj@keyvalue.systems"}
@@ -1 +0,0 @@
1
- __version__ = "0.1.27"
File without changes
File without changes
File without changes
File without changes
File without changes