warpzone-sdk 15.0.0.dev1__tar.gz → 15.0.0.dev3__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 (58) hide show
  1. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/PKG-INFO +1 -1
  2. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/pyproject.toml +1 -1
  3. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/function/monitor.py +25 -3
  4. warpzone_sdk-15.0.0.dev3/warpzone/monitor/traces.py +99 -0
  5. warpzone_sdk-15.0.0.dev1/warpzone/monitor/traces.py +0 -51
  6. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/README.md +0 -0
  7. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/__init__.py +0 -0
  8. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/blobstorage/__init__.py +0 -0
  9. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/blobstorage/client.py +0 -0
  10. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/db/__init__.py +0 -0
  11. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/db/client.py +0 -0
  12. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/deltastorage/__init__.py +0 -0
  13. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/deltastorage/data_types.py +0 -0
  14. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/deltastorage/generated_columns.py +0 -0
  15. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/deltastorage/lock_client.py +0 -0
  16. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/deltastorage/schema.py +0 -0
  17. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/deltastorage/slicing.py +0 -0
  18. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/deltastorage/store.py +0 -0
  19. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/deltastorage/table.py +0 -0
  20. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/enums/__init__.py +0 -0
  21. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/enums/topicenum.py +0 -0
  22. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/function/__init__.py +0 -0
  23. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/function/checks.py +0 -0
  24. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/function/functionize.py +0 -0
  25. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/function/integrations.py +0 -0
  26. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/function/process.py +0 -0
  27. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/function/processors/__init__.py +0 -0
  28. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/function/processors/dependencies.py +0 -0
  29. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/function/processors/outputs.py +0 -0
  30. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/function/processors/triggers.py +0 -0
  31. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/function/signature.py +0 -0
  32. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/function/types.py +0 -0
  33. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/healthchecks/__init__.py +0 -0
  34. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/healthchecks/model.py +0 -0
  35. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/monitor/__init__.py +0 -0
  36. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/monitor/logs.py +0 -0
  37. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/servicebus/data/__init__.py +0 -0
  38. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/servicebus/data/client.py +0 -0
  39. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/servicebus/events/__init__.py +0 -0
  40. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/servicebus/events/client.py +0 -0
  41. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/servicebus/events/triggers.py +0 -0
  42. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/tablestorage/db/__init__.py +0 -0
  43. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/tablestorage/db/base_client.py +0 -0
  44. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/tablestorage/db/client.py +0 -0
  45. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/tablestorage/db/table_config.py +0 -0
  46. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/tablestorage/tables/__init__.py +0 -0
  47. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/tablestorage/tables/client.py +0 -0
  48. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/tablestorage/tables/entities.py +0 -0
  49. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/tablestorage/tables/helpers.py +0 -0
  50. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/testing/__init__.py +0 -0
  51. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/testing/assertions.py +0 -0
  52. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/testing/data.py +0 -0
  53. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/testing/matchers.py +0 -0
  54. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/tools/__init__.py +0 -0
  55. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/tools/copy.py +0 -0
  56. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/transform/__init__.py +0 -0
  57. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/warpzone/transform/data.py +0 -0
  58. {warpzone_sdk-15.0.0.dev1 → warpzone_sdk-15.0.0.dev3}/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.dev1
3
+ Version: 15.0.0.dev3
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.dev1"
3
+ version = "15.0.0.dev3"
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,14 +1,34 @@
1
- import asyncio
1
+ import inspect
2
2
  from contextlib import contextmanager
3
3
  from typing import Callable
4
4
 
5
5
  import azure.functions as func
6
6
  from azure.monitor.opentelemetry import configure_azure_monitor
7
+ from opentelemetry import trace
7
8
 
8
9
  from warpzone.function.types import SingleArgumentCallable
9
10
  from warpzone.monitor import logs, traces
10
11
 
11
- configure_azure_monitor()
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
31
+
12
32
 
13
33
  SUBJECT_IDENTIFIER = "<Subject>"
14
34
 
@@ -45,16 +65,18 @@ def monitor(main: SingleArgumentCallable) -> Callable:
45
65
  """
46
66
 
47
67
  async def wrapper_async(arg, context: func.Context):
68
+ _ensure_monitor_configured()
48
69
  with run_in_trace_context(context):
49
70
  result = await main(arg)
50
71
  return result
51
72
 
52
73
  def wrapper(arg, context: func.Context):
74
+ _ensure_monitor_configured()
53
75
  with run_in_trace_context(context):
54
76
  result = main(arg)
55
77
  return result
56
78
 
57
- if asyncio.iscoroutinefunction(main):
79
+ if inspect.iscoroutinefunction(main):
58
80
  return wrapper_async
59
81
  else:
60
82
  return wrapper
@@ -0,0 +1,99 @@
1
+ from contextlib import contextmanager
2
+
3
+ from azure.core.settings import settings
4
+ from opentelemetry import context, trace
5
+ from opentelemetry.sdk.trace import ReadableSpan, SpanProcessor
6
+ from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
7
+
8
+ settings.tracing_implementation = "opentelemetry"
9
+
10
+
11
+ class AzureSDKTraceFilter(SpanProcessor):
12
+ """Custom SpanProcessor to filter out Azure SDK traces except Service Bus.
13
+
14
+ It drops spans from Azure SDK libraries except Service Bus messages,
15
+ preventing them from being exported to Azure Monitor.
16
+ """
17
+
18
+ def __init__(self, wrapped_processor: SpanProcessor):
19
+ """Initialize with the actual processor to wrap.
20
+
21
+ Args:
22
+ wrapped_processor: The underlying processor (e.g., BatchSpanProcessor)
23
+ """
24
+ self.wrapped_processor = wrapped_processor
25
+
26
+ def on_start(
27
+ self, span: ReadableSpan, parent_context: context.Context = None
28
+ ) -> None:
29
+ """Called when a span is started."""
30
+ self.wrapped_processor.on_start(span, parent_context)
31
+
32
+ def on_end(self, span: ReadableSpan) -> None:
33
+ """Called when a span is ended. Filter based on span attributes."""
34
+ # Check if service bus span - always allow
35
+ if "servicebus.message" in span.name.lower():
36
+ self.wrapped_processor.on_end(span)
37
+ return
38
+
39
+ # Check if this is an Azure SDK span we want to suppress
40
+ instrumentation_scope = span.instrumentation_scope
41
+ if instrumentation_scope and instrumentation_scope.name:
42
+ # Suppress spans from Azure SDK libraries
43
+ if instrumentation_scope.name.startswith("azure."):
44
+ return # Drop this span
45
+
46
+ # Pass through all other spans
47
+ self.wrapped_processor.on_end(span)
48
+
49
+ def shutdown(self) -> None:
50
+ """Shutdown the wrapped processor."""
51
+ self.wrapped_processor.shutdown()
52
+
53
+ def force_flush(self, timeout_millis: int = 30000) -> bool:
54
+ """Force flush the wrapped processor."""
55
+ return self.wrapped_processor.force_flush(timeout_millis)
56
+
57
+
58
+ @contextmanager
59
+ def set_trace_context(trace_parent: str, trace_state: str = ""):
60
+ """Context manager for setting the trace context
61
+
62
+ Args:
63
+ trace_parent (str): Trace parent ID
64
+ trace_state (str, optional): Trace state. Defaults to "".
65
+ """
66
+ carrier = {"traceparent": trace_parent, "tracestate": trace_state}
67
+ ctx = TraceContextTextMapPropagator().extract(carrier=carrier)
68
+
69
+ token = context.attach(ctx) # attach context before run
70
+ try:
71
+ yield
72
+ finally:
73
+ context.detach(token) # detach context after run
74
+
75
+
76
+ def get_tracer(name: str):
77
+ tracer = trace.get_tracer(name)
78
+ return tracer
79
+
80
+
81
+ def get_current_diagnostic_id() -> str:
82
+ """Gets diagnostic id from current span
83
+
84
+ The diagnostic id is a concatenation of operation-id and parent-id
85
+
86
+ Returns:
87
+ str: diagnostic id
88
+ """
89
+ span = trace.get_current_span()
90
+
91
+ if not span.is_recording():
92
+ return ""
93
+
94
+ operation_id = "{:016x}".format(span.context.trace_id)
95
+ parent_id = "{:016x}".format(span.context.span_id)
96
+
97
+ diagnostic_id = f"00-{operation_id}-{parent_id}-01"
98
+
99
+ return diagnostic_id
@@ -1,51 +0,0 @@
1
- from contextlib import contextmanager
2
-
3
- from azure.core.settings import settings
4
- from opentelemetry import context, trace
5
- from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
6
-
7
- settings.tracing_implementation = "opentelemetry"
8
-
9
-
10
- @contextmanager
11
- def set_trace_context(trace_parent: str, trace_state: str = ""):
12
- """Context manager for setting the trace context
13
-
14
- Args:
15
- trace_parent (str): Trace parent ID
16
- trace_state (str, optional): Trace state. Defaults to "".
17
- """
18
- carrier = {"traceparent": trace_parent, "tracestate": trace_state}
19
- ctx = TraceContextTextMapPropagator().extract(carrier=carrier)
20
-
21
- token = context.attach(ctx) # attach context before run
22
- try:
23
- yield
24
- finally:
25
- context.detach(token) # detach context after run
26
-
27
-
28
- def get_tracer(name: str):
29
- tracer = trace.get_tracer(name)
30
- return tracer
31
-
32
-
33
- def get_current_diagnostic_id() -> str:
34
- """Gets diagnostic id from current span
35
-
36
- The diagnostic id is a concatenation of operation-id and parent-id
37
-
38
- Returns:
39
- str: diagnostic id
40
- """
41
- span = trace.get_current_span()
42
-
43
- if not span.is_recording():
44
- return ""
45
-
46
- operation_id = "{:016x}".format(span.context.trace_id)
47
- parent_id = "{:016x}".format(span.context.span_id)
48
-
49
- diagnostic_id = f"00-{operation_id}-{parent_id}-01"
50
-
51
- return diagnostic_id