netra-sdk 0.1.45__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
@@ -1,7 +1,7 @@
1
1
  import atexit
2
2
  import logging
3
3
  import threading
4
- from typing import Any, Dict, List, Optional, Set
4
+ from typing import Any, Dict, List, Literal, Optional, Set
5
5
 
6
6
  from opentelemetry import context as context_api
7
7
  from opentelemetry import trace
@@ -14,7 +14,7 @@ from .config import Config
14
14
  # Instrumentor functions
15
15
  from .instrumentation import init_instrumentations
16
16
  from .session_manager import ConversationType, SessionManager
17
- from .span_wrapper import ActionModel, SpanWrapper, UsageModel
17
+ from .span_wrapper import ActionModel, SpanType, SpanWrapper, UsageModel
18
18
  from .tracer import Tracer
19
19
 
20
20
  # Package-level logger. Attach NullHandler by default so library does not emit logs
@@ -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:
@@ -263,11 +266,12 @@ class Netra:
263
266
  name: str,
264
267
  attributes: Optional[Dict[str, str]] = None,
265
268
  module_name: str = "combat_sdk",
269
+ as_type: Optional[SpanType] = SpanType.SPAN,
266
270
  ) -> SpanWrapper:
267
271
  """
268
272
  Start a new session.
269
273
  """
270
- return SpanWrapper(name, attributes, module_name)
274
+ return SpanWrapper(name, attributes, module_name, as_type=as_type)
271
275
 
272
276
 
273
- __all__ = ["Netra", "UsageModel", "ActionModel"]
277
+ __all__ = ["Netra", "UsageModel", "ActionModel", "SpanType"]
netra/config.py CHANGED
@@ -30,7 +30,7 @@ class Config:
30
30
  # Maximum length for any attribute value (strings and bytes). Processors should honor this.
31
31
  ATTRIBUTE_MAX_LEN = 2000
32
32
  # Maximum length specifically for conversation entry content (strings or JSON when serialized)
33
- CONVERSATION_CONTENT_MAX_LEN = 1000
33
+ CONVERSATION_CONTENT_MAX_LEN = 2000
34
34
 
35
35
  def __init__(
36
36
  self,
netra/decorators.py CHANGED
@@ -33,6 +33,7 @@ from opentelemetry import trace
33
33
 
34
34
  from .config import Config
35
35
  from .session_manager import SessionManager
36
+ from .span_wrapper import SpanType
36
37
 
37
38
  logger = logging.getLogger(__name__)
38
39
 
@@ -262,7 +263,12 @@ def _wrap_streaming_response_with_span(
262
263
  return resp
263
264
 
264
265
 
265
- def _create_function_wrapper(func: Callable[P, R], entity_type: str, name: Optional[str] = None) -> Callable[P, R]:
266
+ def _create_function_wrapper(
267
+ func: Callable[P, R],
268
+ entity_type: str,
269
+ name: Optional[str] = None,
270
+ as_type: Optional[SpanType] = SpanType.SPAN,
271
+ ) -> Callable[P, R]:
266
272
  module_name = func.__name__
267
273
  is_async = inspect.iscoroutinefunction(func)
268
274
  span_name = name if name is not None else func.__name__
@@ -276,6 +282,15 @@ def _create_function_wrapper(func: Callable[P, R], entity_type: str, name: Optio
276
282
 
277
283
  tracer = trace.get_tracer(module_name)
278
284
  span = tracer.start_span(span_name)
285
+ # Set span type if provided
286
+
287
+ if not isinstance(as_type, SpanType):
288
+ logger.error("Invalid span type: %s", as_type)
289
+ return
290
+ try:
291
+ span.set_attribute("netra.span.type", as_type.value)
292
+ except Exception:
293
+ pass
279
294
  # Register and activate span
280
295
  try:
281
296
  SessionManager.register_span(span_name, span)
@@ -327,6 +342,15 @@ def _create_function_wrapper(func: Callable[P, R], entity_type: str, name: Optio
327
342
 
328
343
  tracer = trace.get_tracer(module_name)
329
344
  span = tracer.start_span(span_name)
345
+ # Set span type if provided
346
+ if as_type is not None:
347
+ if not isinstance(as_type, SpanType):
348
+ logger.error("Invalid span type: %s", as_type)
349
+ return
350
+ try:
351
+ span.set_attribute("netra.span.type", as_type.value)
352
+ except Exception:
353
+ pass
330
354
  # Register and activate span
331
355
  try:
332
356
  SessionManager.register_span(span_name, span)
@@ -370,7 +394,12 @@ def _create_function_wrapper(func: Callable[P, R], entity_type: str, name: Optio
370
394
  return cast(Callable[P, R], sync_wrapper)
371
395
 
372
396
 
373
- def _wrap_class_methods(cls: C, entity_type: str, name: Optional[str] = None) -> C:
397
+ def _wrap_class_methods(
398
+ cls: C,
399
+ entity_type: str,
400
+ name: Optional[str] = None,
401
+ as_type: Optional[SpanType] = SpanType.SPAN,
402
+ ) -> C:
374
403
  class_name = name if name is not None else cls.__name__
375
404
  for attr_name in cls.__dict__:
376
405
  attr = getattr(cls, attr_name)
@@ -378,7 +407,7 @@ def _wrap_class_methods(cls: C, entity_type: str, name: Optional[str] = None) ->
378
407
  continue
379
408
  if callable(attr) and inspect.isfunction(attr):
380
409
  method_span_name = f"{class_name}.{attr_name}"
381
- wrapped_method = _create_function_wrapper(attr, entity_type, method_span_name)
410
+ wrapped_method = _create_function_wrapper(attr, entity_type, method_span_name, as_type=as_type)
382
411
  setattr(cls, attr_name, wrapped_method)
383
412
  return cls
384
413
 
@@ -416,10 +445,10 @@ def task(
416
445
  ) -> Union[Callable[P, R], C, Callable[[Callable[P, R]], Callable[P, R]]]:
417
446
  def decorator(obj: Union[Callable[P, R], C]) -> Union[Callable[P, R], C]:
418
447
  if inspect.isclass(obj):
419
- return _wrap_class_methods(cast(C, obj), "task", name)
448
+ return _wrap_class_methods(cast(C, obj), "task", name, as_type=SpanType.TOOL)
420
449
  else:
421
450
  # When obj is a function, it should be type Callable[P, R]
422
- return _create_function_wrapper(cast(Callable[P, R], obj), "task", name)
451
+ return _create_function_wrapper(cast(Callable[P, R], obj), "task", name, as_type=SpanType.TOOL)
423
452
 
424
453
  if target is not None:
425
454
  return decorator(target)
@@ -427,14 +456,17 @@ def task(
427
456
 
428
457
 
429
458
  def span(
430
- target: Union[Callable[P, R], C, None] = None, *, name: Optional[str] = None
459
+ target: Union[Callable[P, R], C, None] = None,
460
+ *,
461
+ name: Optional[str] = None,
462
+ as_type: Optional[SpanType] = SpanType.SPAN,
431
463
  ) -> Union[Callable[P, R], C, Callable[[Callable[P, R]], Callable[P, R]]]:
432
464
  def decorator(obj: Union[Callable[P, R], C]) -> Union[Callable[P, R], C]:
433
465
  if inspect.isclass(obj):
434
- return _wrap_class_methods(cast(C, obj), "span", name)
466
+ return _wrap_class_methods(cast(C, obj), "span", name, as_type=as_type)
435
467
  else:
436
468
  # When obj is a function, it should be type Callable[P, R]
437
- return _create_function_wrapper(cast(Callable[P, R], obj), "span", name)
469
+ return _create_function_wrapper(cast(Callable[P, R], obj), "span", name, as_type=as_type)
438
470
 
439
471
  if target is not None:
440
472
  return decorator(target)
@@ -74,9 +74,6 @@ class InstrumentationSpanProcessor(SpanProcessor): # type: ignore[misc]
74
74
  truncated = self._truncate_value(value)
75
75
  # Forward to original
76
76
  original_set_attribute(key, truncated)
77
- # Special rule: if model key set, mark span as llm
78
- if key == "gen_ai.request.model":
79
- original_set_attribute(f"{Config.LIBRARY_NAME}.span.type", "llm")
80
77
  except Exception:
81
78
  # Best-effort; never break span
82
79
  try:
netra/session_manager.py CHANGED
@@ -275,20 +275,27 @@ class SessionManager:
275
275
 
276
276
  # Hard runtime validation of input types and values
277
277
  if not isinstance(conversation_type, ConversationType):
278
- raise TypeError("conversation_type must be a ConversationType enum value (input, output, system)")
278
+ logger.error(
279
+ "add_conversation: conversation_type must be a ConversationType enum value (input, output, system)"
280
+ )
281
+ return
279
282
  normalized_type = conversation_type.value
280
283
 
281
284
  if not isinstance(role, str):
282
- raise TypeError(f"role must be a string, got {type(role)}")
285
+ logger.error("add_conversation: role must be a string")
286
+ return
283
287
 
284
288
  if not isinstance(content, (str, dict)):
285
- raise TypeError(f"content must be a string or dict, got {type(content)}")
289
+ logger.error("add_conversation: content must be a string or dict")
290
+ return
286
291
 
287
292
  if not role:
288
- raise ValueError("role must be a non-empty string")
293
+ logger.error("add_conversation: role must be a non-empty string")
294
+ return
289
295
 
290
296
  if not content:
291
- raise ValueError("content must not be empty")
297
+ logger.error("add_conversation: content must not be empty")
298
+ return
292
299
 
293
300
  try:
294
301
 
netra/span_wrapper.py CHANGED
@@ -2,6 +2,7 @@ import json
2
2
  import logging
3
3
  import time
4
4
  from datetime import datetime
5
+ from enum import Enum
5
6
  from typing import Any, Dict, List, Literal, Optional
6
7
 
7
8
  from opentelemetry import baggage
@@ -49,6 +50,13 @@ class ATTRIBUTE:
49
50
  ACTION = "action"
50
51
 
51
52
 
53
+ class SpanType(str, Enum):
54
+ SPAN = "SPAN"
55
+ GENERATION = "GENERATION"
56
+ TOOL = "TOOL"
57
+ EMBEDDING = "EMBEDDING"
58
+
59
+
52
60
  class SpanWrapper:
53
61
  """
54
62
  Context manager for tracking observability data for external API calls.
@@ -63,9 +71,16 @@ class SpanWrapper:
63
71
  span.set_usage(usage_data)
64
72
  """
65
73
 
66
- def __init__(self, name: str, attributes: Optional[Dict[str, str]] = None, module_name: str = "combat_sdk"):
74
+ def __init__(
75
+ self,
76
+ name: str,
77
+ attributes: Optional[Dict[str, str]] = None,
78
+ module_name: str = "combat_sdk",
79
+ as_type: Optional[SpanType] = SpanType.SPAN,
80
+ ):
67
81
  self.name = name
68
82
  self.attributes = attributes or {}
83
+
69
84
  self.start_time: Optional[float] = None
70
85
  self.end_time: Optional[float] = None
71
86
  self.status = "pending"
@@ -80,6 +95,12 @@ class SpanWrapper:
80
95
  # Token for locally attached baggage (if any)
81
96
  self._local_block_token: Optional[object] = None
82
97
 
98
+ if isinstance(as_type, SpanType):
99
+ self.attributes["netra.span.type"] = as_type.value
100
+ else:
101
+ logger.error("Invalid span type: %s", as_type)
102
+ return
103
+
83
104
  def __enter__(self) -> "SpanWrapper":
84
105
  """Start the span wrapper, begin time tracking, and create OpenTelemetry span."""
85
106
  self.start_time = time.time()
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.45"
1
+ __version__ = "0.1.47"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: netra-sdk
3
- Version: 0.1.45
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=-eEBq3ndX3JAWDo4_Ra0L19KrTfrJhNDjlAwChb3_IA,10353
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
- netra/config.py,sha256=MMSAKrX_HCZ7QECjTocs_jsNFgcOnbP8aAVfOdq9YEs,7032
7
- netra/decorators.py,sha256=qZFHrwdj10FsTFqggo3XjdGB12aMxsrrDMMmslDqZ-0,17424
6
+ netra/config.py,sha256=RqLul2vlNHHKGU31OQIJTUpcKMSmVse9IlGFwImW6sE,7032
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
@@ -43,17 +43,17 @@ netra/instrumentation/weaviate/__init__.py,sha256=EOlpWxobOLHYKqo_kMct_7nu26x1hr
43
43
  netra/instrumentation/weaviate/version.py,sha256=PiCZHjonujPbnIn0KmD3Yl68hrjPRG_oKe5vJF3mmG8,24
44
44
  netra/pii.py,sha256=Rn4SjgTJW_aw9LcbjLuMqF3fKd9b1ndlYt1CaK51Ge0,33125
45
45
  netra/processors/__init__.py,sha256=56RO7xMoBx2aoVuESyQXll65o7IoO98nSHZ5KpR5iQk,471
46
- netra/processors/instrumentation_span_processor.py,sha256=VzurzwtGleFltxzKD_gjVkUQiRC6SGlb0oG4Nlpu85A,4365
46
+ netra/processors/instrumentation_span_processor.py,sha256=7iDnJUSBXyiRcWxoxk3uStoh0r4Yxjh7PBTbFDVMjlA,4150
47
47
  netra/processors/local_filtering_span_processor.py,sha256=Vk_UP--ZxWwdrbJA7a95iRo853QfPCME2C5ChgjiHl8,6664
48
48
  netra/processors/scrubbing_span_processor.py,sha256=dJ86Ncmjvmrhm_uAdGTwcGvRpZbVVWqD9AOFwEMWHZY,6701
49
49
  netra/processors/session_span_processor.py,sha256=qcsBl-LnILWefsftI8NQhXDGb94OWPc8LvzhVA0JS_c,2432
50
50
  netra/scanner.py,sha256=kyDpeZiscCPb6pjuhS-sfsVj-dviBFRepdUWh0sLoEY,11554
51
- netra/session_manager.py,sha256=VzmSAiP63ODCuOWv-irsxyU2LvHoqjOBUuXtyxboBU0,13740
52
- netra/span_wrapper.py,sha256=3xzZs44s85KiB81WXjAJmfQcH_aPMxCuQ_1xjDVGtwE,9682
53
- netra/tracer.py,sha256=IPVYMc4x74XZJeKvCfV6b0X9mUHGvsssUzLnRvFPV6M,4629
51
+ netra/session_manager.py,sha256=jxA62zAgiTsuTyV_UuPkVb2W1Uieb7I5jWsYiJ6jSxk,13897
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=G1Bw5SEeRoSlHVxmFKf6PIpK38SHTYTFhSFGm9d8YQM,23
56
- netra_sdk-0.1.45.dist-info/METADATA,sha256=UbtkH3HwIO59lD3lo1TACHzHWMFWTNXquAaRputrOV4,28208
57
- netra_sdk-0.1.45.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
58
- netra_sdk-0.1.45.dist-info/licenses/LICENCE,sha256=8B_UoZ-BAl0AqiHAHUETCgd3I2B9yYJ1WEQtVb_qFMA,11359
59
- netra_sdk-0.1.45.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,,