warpzone-sdk 15.0.0.dev2__tar.gz → 15.0.0.dev4__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.dev2 → warpzone_sdk-15.0.0.dev4}/PKG-INFO +1 -1
  2. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/pyproject.toml +1 -1
  3. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/function/monitor.py +5 -8
  4. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/monitor/logs.py +12 -2
  5. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/monitor/traces.py +30 -8
  6. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/README.md +0 -0
  7. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/__init__.py +0 -0
  8. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/blobstorage/__init__.py +0 -0
  9. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/blobstorage/client.py +0 -0
  10. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/db/__init__.py +0 -0
  11. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/db/client.py +0 -0
  12. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/deltastorage/__init__.py +0 -0
  13. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/deltastorage/data_types.py +0 -0
  14. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/deltastorage/generated_columns.py +0 -0
  15. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/deltastorage/lock_client.py +0 -0
  16. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/deltastorage/schema.py +0 -0
  17. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/deltastorage/slicing.py +0 -0
  18. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/deltastorage/store.py +0 -0
  19. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/deltastorage/table.py +0 -0
  20. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/enums/__init__.py +0 -0
  21. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/enums/topicenum.py +0 -0
  22. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/function/__init__.py +0 -0
  23. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/function/checks.py +0 -0
  24. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/function/functionize.py +0 -0
  25. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/function/integrations.py +0 -0
  26. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/function/process.py +0 -0
  27. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/function/processors/__init__.py +0 -0
  28. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/function/processors/dependencies.py +0 -0
  29. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/function/processors/outputs.py +0 -0
  30. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/function/processors/triggers.py +0 -0
  31. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/function/signature.py +0 -0
  32. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/function/types.py +0 -0
  33. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/healthchecks/__init__.py +0 -0
  34. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/healthchecks/model.py +0 -0
  35. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/monitor/__init__.py +0 -0
  36. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/servicebus/data/__init__.py +0 -0
  37. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/servicebus/data/client.py +0 -0
  38. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/servicebus/events/__init__.py +0 -0
  39. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/servicebus/events/client.py +0 -0
  40. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/servicebus/events/triggers.py +0 -0
  41. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/tablestorage/db/__init__.py +0 -0
  42. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/tablestorage/db/base_client.py +0 -0
  43. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/tablestorage/db/client.py +0 -0
  44. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/tablestorage/db/table_config.py +0 -0
  45. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/tablestorage/tables/__init__.py +0 -0
  46. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/tablestorage/tables/client.py +0 -0
  47. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/tablestorage/tables/entities.py +0 -0
  48. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/tablestorage/tables/helpers.py +0 -0
  49. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/testing/__init__.py +0 -0
  50. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/testing/assertions.py +0 -0
  51. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/testing/data.py +0 -0
  52. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/testing/matchers.py +0 -0
  53. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/tools/__init__.py +0 -0
  54. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/tools/copy.py +0 -0
  55. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/transform/__init__.py +0 -0
  56. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/warpzone/transform/data.py +0 -0
  57. {warpzone_sdk-15.0.0.dev2 → warpzone_sdk-15.0.0.dev4}/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.dev2
3
+ Version: 15.0.0.dev4
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.dev2"
3
+ version = "15.0.0.dev4"
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"
@@ -7,9 +7,11 @@ from azure.monitor.opentelemetry import configure_azure_monitor
7
7
  from opentelemetry import trace
8
8
 
9
9
  from warpzone.function.types import SingleArgumentCallable
10
- from warpzone.monitor import logs, traces
10
+ from warpzone.monitor import traces
11
11
 
12
- # Configure Azure Monitor first
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.
13
15
  configure_azure_monitor()
14
16
 
15
17
  # Apply trace filtering to suppress all Azure SDK traces except Service Bus
@@ -22,16 +24,11 @@ if hasattr(tracer_provider, "_active_span_processor"):
22
24
 
23
25
  SUBJECT_IDENTIFIER = "<Subject>"
24
26
 
25
- tracer = traces.get_tracer(__name__)
26
- logger = logs.get_logger(__name__)
27
-
28
27
 
29
28
  @contextmanager
30
29
  def run_in_trace_context(context: func.Context):
31
30
  trace_context = context.trace_context
32
- with traces.set_trace_context(
33
- trace_context.trace_parent, trace_context.trace_state
34
- ):
31
+ with traces.set_trace_context(trace_context.trace_parent):
35
32
  yield
36
33
 
37
34
 
@@ -17,8 +17,18 @@ logging.getLogger("azure.monitor.opentelemetry.exporter").setLevel(logging.WARNI
17
17
 
18
18
 
19
19
  def get_logger(name: str):
20
- # set up standard logger
20
+ """Get a logger instance.
21
+
22
+ The logger will automatically use the current OpenTelemetry trace context
23
+ for correlation in Application Insights. The trace context is set by the
24
+ monitor decorator's run_in_trace_context context manager.
25
+
26
+ Args:
27
+ name: Logger name, typically __name__
28
+
29
+ Returns:
30
+ A configured logger instance
31
+ """
21
32
  logger = logging.getLogger(name)
22
33
  logger.setLevel(logging.INFO)
23
-
24
34
  return logger
@@ -31,8 +31,15 @@ class AzureSDKTraceFilter(SpanProcessor):
31
31
 
32
32
  def on_end(self, span: ReadableSpan) -> None:
33
33
  """Called when a span is ended. Filter based on span attributes."""
34
+ # Safely get span name, handling None or mock objects
35
+ span_name = getattr(span, "name", None)
36
+ if span_name is None or not isinstance(span_name, str):
37
+ # Pass through spans without valid names (e.g., in test mocks)
38
+ self.wrapped_processor.on_end(span)
39
+ return
40
+
34
41
  # Check if service bus span - always allow
35
- if "servicebus.message" in span.name.lower():
42
+ if "servicebus.message" in span_name.lower():
36
43
  self.wrapped_processor.on_end(span)
37
44
  return
38
45
 
@@ -56,21 +63,36 @@ class AzureSDKTraceFilter(SpanProcessor):
56
63
 
57
64
 
58
65
  @contextmanager
59
- def set_trace_context(trace_parent: str, trace_state: str = ""):
60
- """Context manager for setting the trace context
66
+ def set_trace_context(trace_parent: str):
67
+ """Context manager for setting the trace context.
68
+
69
+ Attaches the propagated trace context with a NonRecordingSpan so that
70
+ logs emitted within this context are properly correlated with the trace
71
+ created by Azure Functions.
72
+
73
+ The NonRecordingSpan is necessary because the LoggingHandler needs an
74
+ actual span (not just a SpanContext) to extract trace correlation IDs.
75
+ Using NonRecordingSpan avoids creating duplicate spans while still
76
+ providing the trace_id and span_id for log correlation.
61
77
 
62
78
  Args:
63
- trace_parent (str): Trace parent ID
64
- trace_state (str, optional): Trace state. Defaults to "".
79
+ trace_parent (str): Trace parent ID from the incoming request
65
80
  """
66
- carrier = {"traceparent": trace_parent, "tracestate": trace_state}
81
+ carrier = {"traceparent": trace_parent}
67
82
  ctx = TraceContextTextMapPropagator().extract(carrier=carrier)
68
83
 
69
- token = context.attach(ctx) # attach context before run
84
+ # Get the span from the extracted context - this is a NonRecordingSpan
85
+ # created by the propagator with the correct trace_id and span_id
86
+ span = trace.get_current_span(ctx)
87
+
88
+ # Set this span as the current span in context
89
+ ctx = trace.set_span_in_context(span)
90
+
91
+ token = context.attach(ctx)
70
92
  try:
71
93
  yield
72
94
  finally:
73
- context.detach(token) # detach context after run
95
+ context.detach(token)
74
96
 
75
97
 
76
98
  def get_tracer(name: str):