warpzone-sdk 15.0.0.dev5__tar.gz → 15.0.0.dev7__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.
Files changed (57) hide show
  1. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/PKG-INFO +1 -1
  2. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/pyproject.toml +1 -1
  3. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/function/monitor.py +36 -11
  4. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/monitor/traces.py +9 -9
  5. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/README.md +0 -0
  6. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/__init__.py +0 -0
  7. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/blobstorage/__init__.py +0 -0
  8. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/blobstorage/client.py +0 -0
  9. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/db/__init__.py +0 -0
  10. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/db/client.py +0 -0
  11. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/deltastorage/__init__.py +0 -0
  12. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/deltastorage/data_types.py +0 -0
  13. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/deltastorage/generated_columns.py +0 -0
  14. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/deltastorage/lock_client.py +0 -0
  15. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/deltastorage/schema.py +0 -0
  16. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/deltastorage/slicing.py +0 -0
  17. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/deltastorage/store.py +0 -0
  18. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/deltastorage/table.py +0 -0
  19. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/enums/__init__.py +0 -0
  20. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/enums/topicenum.py +0 -0
  21. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/function/__init__.py +0 -0
  22. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/function/checks.py +0 -0
  23. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/function/functionize.py +0 -0
  24. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/function/integrations.py +0 -0
  25. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/function/process.py +0 -0
  26. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/function/processors/__init__.py +0 -0
  27. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/function/processors/dependencies.py +0 -0
  28. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/function/processors/outputs.py +0 -0
  29. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/function/processors/triggers.py +0 -0
  30. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/function/signature.py +0 -0
  31. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/function/types.py +0 -0
  32. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/healthchecks/__init__.py +0 -0
  33. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/healthchecks/model.py +0 -0
  34. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/monitor/__init__.py +0 -0
  35. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/monitor/logs.py +0 -0
  36. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/servicebus/data/__init__.py +0 -0
  37. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/servicebus/data/client.py +0 -0
  38. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/servicebus/events/__init__.py +0 -0
  39. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/servicebus/events/client.py +0 -0
  40. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/servicebus/events/triggers.py +0 -0
  41. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/tablestorage/db/__init__.py +0 -0
  42. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/tablestorage/db/base_client.py +0 -0
  43. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/tablestorage/db/client.py +0 -0
  44. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/tablestorage/db/table_config.py +0 -0
  45. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/tablestorage/tables/__init__.py +0 -0
  46. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/tablestorage/tables/client.py +0 -0
  47. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/tablestorage/tables/entities.py +0 -0
  48. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/tablestorage/tables/helpers.py +0 -0
  49. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/testing/__init__.py +0 -0
  50. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/testing/assertions.py +0 -0
  51. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/testing/data.py +0 -0
  52. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/testing/matchers.py +0 -0
  53. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/tools/__init__.py +0 -0
  54. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/tools/copy.py +0 -0
  55. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/transform/__init__.py +0 -0
  56. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/transform/data.py +0 -0
  57. {warpzone_sdk-15.0.0.dev5 → warpzone_sdk-15.0.0.dev7}/warpzone/transform/schema.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: warpzone-sdk
3
- Version: 15.0.0.dev5
3
+ Version: 15.0.0.dev7
4
4
  Summary: The main objective of this package is to centralize logic used to interact with Azure Functions, Azure Service Bus and Azure Table Storage
5
5
  Author: Team Enigma
6
6
  Author-email: enigma@energinet.dk
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "warpzone-sdk"
3
- version = "15.0.0.dev5"
3
+ version = "15.0.0.dev7"
4
4
  description = "The main objective of this package is to centralize logic used to interact with Azure Functions, Azure Service Bus and Azure Table Storage"
5
5
  authors = [{ name = "Team Enigma", email = "enigma@energinet.dk" }]
6
6
  requires-python = ">=3.10"
@@ -1,4 +1,5 @@
1
1
  import inspect
2
+ import threading
2
3
  from contextlib import contextmanager
3
4
  from typing import Callable
4
5
 
@@ -9,18 +10,40 @@ from opentelemetry import trace
9
10
  from warpzone.function.types import SingleArgumentCallable
10
11
  from warpzone.monitor import traces
11
12
 
12
- # Configure Azure Monitor at import to ensure proper telemetry setup.
13
- # The trace context is set per-invocation in run_in_trace_context to ensure
14
- # proper operation ID correlation for each function execution.
15
- configure_azure_monitor()
13
+ # Thread-safe lazy initialization of Azure Monitor
14
+ _azure_monitor_configured = False
15
+ _azure_monitor_lock = threading.Lock()
16
+
17
+
18
+ def _ensure_azure_monitor_configured():
19
+ """Ensure Azure Monitor is configured exactly once, thread-safely."""
20
+ global _azure_monitor_configured
21
+ if _azure_monitor_configured:
22
+ return
23
+
24
+ with _azure_monitor_lock:
25
+ # Double-check after acquiring lock
26
+ if _azure_monitor_configured:
27
+ return
28
+
29
+ # Disable OpenTelemetry logging instrumentation - let Azure Functions
30
+ # handle log correlation via its native thread-local storage mechanism.
31
+ # This prevents conflicts between OpenTelemetry's context-based correlation
32
+ # and Azure Functions' invocation_id-based correlation which can cause
33
+ # logs to leak between concurrent function invocations.
34
+ configure_azure_monitor(
35
+ disable_logging=True,
36
+ )
37
+
38
+ # Apply trace filtering to suppress all Azure SDK traces except Service Bus
39
+ tracer_provider = trace.get_tracer_provider()
40
+ if hasattr(tracer_provider, "_active_span_processor"):
41
+ original_processor = tracer_provider._active_span_processor
42
+ filtered_processor = traces.AzureSDKTraceFilter(original_processor)
43
+ tracer_provider._active_span_processor = filtered_processor
44
+
45
+ _azure_monitor_configured = True
16
46
 
17
- # Apply trace filtering to suppress all Azure SDK traces except Service Bus
18
- tracer_provider = trace.get_tracer_provider()
19
- if hasattr(tracer_provider, "_active_span_processor"):
20
- # Wrap the existing span processor with our filter
21
- original_processor = tracer_provider._active_span_processor
22
- filtered_processor = traces.AzureSDKTraceFilter(original_processor)
23
- tracer_provider._active_span_processor = filtered_processor
24
47
 
25
48
  SUBJECT_IDENTIFIER = "<Subject>"
26
49
 
@@ -51,6 +74,8 @@ def monitor(main: SingleArgumentCallable) -> Callable:
51
74
  - return value
52
75
  description: return value of original function
53
76
  """
77
+ # Ensure Azure Monitor is configured before any function runs
78
+ _ensure_azure_monitor_configured()
54
79
 
55
80
  async def wrapper_async(arg, context: func.Context):
56
81
  with run_in_trace_context(context):
@@ -64,12 +64,11 @@ class AzureSDKTraceFilter(SpanProcessor):
64
64
 
65
65
  @contextmanager
66
66
  def set_trace_context(trace_parent: str, span_name: str = "function_execution"):
67
- """Context manager for setting the trace context with a recording span.
67
+ """Context manager for setting the trace context.
68
68
 
69
- Creates a child span of the propagated trace context. This is necessary
70
- because the LoggingHandler requires a recording span to properly correlate
71
- logs with the trace. A NonRecordingSpan (which is what TraceContextTextMapPropagator
72
- creates) may not be correctly handled during log batching/export.
69
+ Attaches the propagated trace context and creates a child span for tracing.
70
+ Note: Log correlation is handled by Azure Functions' native mechanism,
71
+ not OpenTelemetry, so this primarily affects span/dependency tracking.
73
72
 
74
73
  Args:
75
74
  trace_parent (str): Trace parent ID from the incoming request
@@ -78,12 +77,13 @@ def set_trace_context(trace_parent: str, span_name: str = "function_execution"):
78
77
  carrier = {"traceparent": trace_parent}
79
78
  ctx = TraceContextTextMapPropagator().extract(carrier=carrier)
80
79
 
81
- # Start a recording span as a child of the propagated context.
82
- # This ensures logs are properly correlated with the trace.
83
- tracer = trace.get_tracer(__name__)
84
- with trace.use_span(trace.get_current_span(ctx), end_on_exit=False):
80
+ token = context.attach(ctx)
81
+ try:
82
+ tracer = trace.get_tracer(__name__)
85
83
  with tracer.start_as_current_span(span_name):
86
84
  yield
85
+ finally:
86
+ context.detach(token)
87
87
 
88
88
 
89
89
  def get_tracer(name: str):