warpzone-sdk 15.0.0.dev3__py3-none-any.whl → 15.0.0.dev4__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.
@@ -7,41 +7,28 @@ 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
- # Lazy initialization flag to ensure configure_azure_monitor is called only once
13
- _monitor_configured = False
14
-
15
-
16
- def _ensure_monitor_configured():
17
- """Configure Azure Monitor lazily on first use to ensure proper trace context."""
18
- global _monitor_configured
19
- if not _monitor_configured:
20
- configure_azure_monitor()
21
-
22
- # Apply trace filtering to suppress all Azure SDK traces except Service Bus
23
- tracer_provider = trace.get_tracer_provider()
24
- if hasattr(tracer_provider, "_active_span_processor"):
25
- # Wrap the existing span processor with our filter
26
- original_processor = tracer_provider._active_span_processor
27
- filtered_processor = traces.AzureSDKTraceFilter(original_processor)
28
- tracer_provider._active_span_processor = filtered_processor
29
-
30
- _monitor_configured = True
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()
31
16
 
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
32
24
 
33
25
  SUBJECT_IDENTIFIER = "<Subject>"
34
26
 
35
- tracer = traces.get_tracer(__name__)
36
- logger = logs.get_logger(__name__)
37
-
38
27
 
39
28
  @contextmanager
40
29
  def run_in_trace_context(context: func.Context):
41
30
  trace_context = context.trace_context
42
- with traces.set_trace_context(
43
- trace_context.trace_parent, trace_context.trace_state
44
- ):
31
+ with traces.set_trace_context(trace_context.trace_parent):
45
32
  yield
46
33
 
47
34
 
@@ -65,13 +52,11 @@ def monitor(main: SingleArgumentCallable) -> Callable:
65
52
  """
66
53
 
67
54
  async def wrapper_async(arg, context: func.Context):
68
- _ensure_monitor_configured()
69
55
  with run_in_trace_context(context):
70
56
  result = await main(arg)
71
57
  return result
72
58
 
73
59
  def wrapper(arg, context: func.Context):
74
- _ensure_monitor_configured()
75
60
  with run_in_trace_context(context):
76
61
  result = main(arg)
77
62
  return result
warpzone/monitor/logs.py CHANGED
@@ -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):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: warpzone-sdk
3
- Version: 15.0.0.dev3
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
@@ -17,7 +17,7 @@ warpzone/function/__init__.py,sha256=rJOZBpWsUgjMc7YtXMJ1rLGm45KB1AhDJ_Y2ISiSISc
17
17
  warpzone/function/checks.py,sha256=B9YqThymf16ac_fVAYKilv20ru5v9nwXgHlbxYIaG98,1018
18
18
  warpzone/function/functionize.py,sha256=bSV0QvwKbD9Vo3a_8cc1rgV2rzTdMMvidinyXItBfvs,2128
19
19
  warpzone/function/integrations.py,sha256=sDt2BTx6a4mVc-33wTITP9XQVPustwj7rkX4urTyOqo,4018
20
- warpzone/function/monitor.py,sha256=gGWoxrOTaXofds8FJwPwGf58q0XV19Xwj9VRzhr0GM8,2594
20
+ warpzone/function/monitor.py,sha256=qBvnSTSX--6_6qccTZrGPO1iS5nz2tNZlHdhE1XBrbs,2214
21
21
  warpzone/function/process.py,sha256=nbUVywM8ChfUwuaqFisgaD98aNRgeZkK4g5sbtuBdRs,2339
22
22
  warpzone/function/processors/__init__.py,sha256=DhIdSWLBcIeSO8IJdxPqGIhgwwnkDN6_Xqwy93BCLeA,46
23
23
  warpzone/function/processors/dependencies.py,sha256=m17BwdKyQEvzCPxpQZpAW5l1uYRIHWmweDz3XJskmpA,1259
@@ -28,8 +28,8 @@ warpzone/function/types.py,sha256=5m2hRrnLC3eqIlAH5-MM9_wKjMZ6lYawZtCOVStyFuY,72
28
28
  warpzone/healthchecks/__init__.py,sha256=9gc_Mt2szs8sDSwy0V4l3JZ6d9hX41xTpZCkDP2qsY4,2108
29
29
  warpzone/healthchecks/model.py,sha256=mM7DnrirLbUpBPPfi82MUPP654D0eOR2_F65TmzsPD0,1187
30
30
  warpzone/monitor/__init__.py,sha256=ggI5fIUu-szgC44ICzuOmpYrIoVOKPbsMT3zza9ssD4,87
31
- warpzone/monitor/logs.py,sha256=V1A2ImqbPo4c-hDr2qWAZlpr2muyVar30eI9mF2_rzE,986
32
- warpzone/monitor/traces.py,sha256=PhhYeZlPc7EOSq9KVsHdKOwEIivDHCV-RwZnDNVL7ic,3244
31
+ warpzone/monitor/logs.py,sha256=fabjaB5SfHynvvfp2Js3IG-owqU5jZ3lTnnmTTjD6JM,1320
32
+ warpzone/monitor/traces.py,sha256=B_1_fmUNUwHRKB-IYfhWSw5VRluVvn1NQqSYTqNV0wA,4158
33
33
  warpzone/servicebus/data/__init__.py,sha256=lnc0uiaGLF0qMi_rWhCpRSFvaj0CJEiMCAl6Yqn1ZiA,21
34
34
  warpzone/servicebus/data/client.py,sha256=zECS3JwedhYnDk8PntYgIYpBF_uu9YN38KzpPFK7CKs,6511
35
35
  warpzone/servicebus/events/__init__.py,sha256=lnc0uiaGLF0qMi_rWhCpRSFvaj0CJEiMCAl6Yqn1ZiA,21
@@ -52,6 +52,6 @@ warpzone/tools/copy.py,sha256=5fddotMZkXZO8avzUbGOhvs0cp8mce95pNpy0oPVjnQ,2596
52
52
  warpzone/transform/__init__.py,sha256=ruGa7tl-v4ndlWpULE1jSGU_a4_iRc3V6eyNr5xKP9E,27
53
53
  warpzone/transform/data.py,sha256=Abb8PcrgMbbNCJkkIUdtrTHdlY0OfXid387qw1nDpFY,2362
54
54
  warpzone/transform/schema.py,sha256=nbSQtDMvXkyqGKuwhuFCF0WsEDsaNyoPYpMKvbsKlv8,2423
55
- warpzone_sdk-15.0.0.dev3.dist-info/METADATA,sha256=SbdclS53SblY02qVWfnpicAHmSQJXPqKIfz_gAxtaRM,7398
56
- warpzone_sdk-15.0.0.dev3.dist-info/WHEEL,sha256=3ny-bZhpXrU6vSQ1UPG34FoxZBp3lVcvK0LkgUz6VLk,88
57
- warpzone_sdk-15.0.0.dev3.dist-info/RECORD,,
55
+ warpzone_sdk-15.0.0.dev4.dist-info/METADATA,sha256=jxPQ1HTdmdO0ePXvZAFg58OmIGw38qssEwnc6o9eTAI,7398
56
+ warpzone_sdk-15.0.0.dev4.dist-info/WHEEL,sha256=3ny-bZhpXrU6vSQ1UPG34FoxZBp3lVcvK0LkgUz6VLk,88
57
+ warpzone_sdk-15.0.0.dev4.dist-info/RECORD,,