warpzone-sdk 15.1.1.dev1__tar.gz → 15.1.2.dev1__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.
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/PKG-INFO +2 -2
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/pyproject.toml +2 -2
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/db/client.py +6 -6
- warpzone_sdk-15.1.2.dev1/warpzone/monitor/traces.py +128 -0
- warpzone_sdk-15.1.1.dev1/warpzone/monitor/traces.py +0 -228
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/README.md +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/__init__.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/blobstorage/__init__.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/blobstorage/client.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/db/__init__.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/deltastorage/__init__.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/deltastorage/data_types.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/deltastorage/generated_columns.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/deltastorage/lock_client.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/deltastorage/schema.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/deltastorage/slicing.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/deltastorage/store.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/deltastorage/table.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/enums/__init__.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/enums/topicenum.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/function/__init__.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/function/checks.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/function/functionize.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/function/integrations.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/function/monitor.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/function/process.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/function/processors/__init__.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/function/processors/dependencies.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/function/processors/outputs.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/function/processors/triggers.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/function/signature.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/function/types.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/healthchecks/__init__.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/healthchecks/model.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/monitor/__init__.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/monitor/logs.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/servicebus/data/__init__.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/servicebus/data/client.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/servicebus/events/__init__.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/servicebus/events/client.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/servicebus/events/triggers.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/tablestorage/db/__init__.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/tablestorage/db/base_client.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/tablestorage/db/client.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/tablestorage/db/table_config.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/tablestorage/tables/__init__.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/tablestorage/tables/client.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/tablestorage/tables/entities.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/tablestorage/tables/helpers.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/testing/__init__.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/testing/assertions.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/testing/data.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/testing/matchers.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/tools/__init__.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/tools/copy.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/transform/__init__.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/transform/data.py +0 -0
- {warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/transform/schema.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: warpzone-sdk
|
|
3
|
-
Version: 15.1.
|
|
3
|
+
Version: 15.1.2.dev1
|
|
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
|
|
@@ -21,7 +21,7 @@ Requires-Dist: azure-servicebus (>=7.8.0)
|
|
|
21
21
|
Requires-Dist: azure-storage-blob (>=12.14.1)
|
|
22
22
|
Requires-Dist: cryptography (==43.0.3)
|
|
23
23
|
Requires-Dist: datamazing (>=5.1.6)
|
|
24
|
-
Requires-Dist: deltalake (
|
|
24
|
+
Requires-Dist: deltalake (>=1.4.0)
|
|
25
25
|
Requires-Dist: numpy (>=1.26.4)
|
|
26
26
|
Requires-Dist: obstore (>=0.8.2)
|
|
27
27
|
Requires-Dist: opentelemetry-sdk (>=1.32.0)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "warpzone-sdk"
|
|
3
|
-
version = "15.1.
|
|
3
|
+
version = "15.1.2.dev1"
|
|
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"
|
|
@@ -14,7 +14,7 @@ requires-poetry = ">=2.2"
|
|
|
14
14
|
pandas = ">=2.0.3"
|
|
15
15
|
polars = ">=1.33.1"
|
|
16
16
|
obstore = ">=0.8.2"
|
|
17
|
-
deltalake = "
|
|
17
|
+
deltalake = ">=1.4.0"
|
|
18
18
|
pyarrow = ">=19.0.0"
|
|
19
19
|
datamazing = ">=5.1.6"
|
|
20
20
|
azure-core = ">=1.26.3"
|
|
@@ -195,12 +195,10 @@ class WarpzoneDatabaseClient:
|
|
|
195
195
|
include_validity_period_columns (bool, optional): Whether to include
|
|
196
196
|
validity period columns in the result;
|
|
197
197
|
(`valid_from_time_utc`, `valid_to_time_utc`).
|
|
198
|
-
Defaults to False.
|
|
199
|
-
to include these columns in the `columns`-list.
|
|
198
|
+
Defaults to False.
|
|
200
199
|
include_generated_columns (bool, optional): Whether to include generated
|
|
201
200
|
columns in the result; (e.g. `valid_from_time_utc`, `valid_to_time_utc`).
|
|
202
|
-
Defaults to False.
|
|
203
|
-
to include these columns in the `columns`-list.
|
|
201
|
+
Defaults to False.
|
|
204
202
|
|
|
205
203
|
Returns:
|
|
206
204
|
pd.DataFrame: The result of the query.
|
|
@@ -252,10 +250,12 @@ class WarpzoneDatabaseClient:
|
|
|
252
250
|
for field in table.schema().fields:
|
|
253
251
|
if field.generated_as is not None:
|
|
254
252
|
generated_cols.append(field.column_name)
|
|
255
|
-
pd_df = pd_df.drop(columns=generated_cols)
|
|
253
|
+
pd_df = pd_df.drop(columns=generated_cols, errors="ignore")
|
|
256
254
|
|
|
257
255
|
# Drop valid-from/to columns
|
|
258
256
|
if not include_validity_period_columns:
|
|
259
|
-
pd_df = pd_df.drop(
|
|
257
|
+
pd_df = pd_df.drop(
|
|
258
|
+
columns=["valid_from_time_utc", "valid_to_time_utc"], errors="ignore"
|
|
259
|
+
)
|
|
260
260
|
|
|
261
261
|
return pd_df
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
import threading
|
|
4
|
+
from contextlib import contextmanager
|
|
5
|
+
from logging import StreamHandler
|
|
6
|
+
|
|
7
|
+
from azure.monitor.opentelemetry.exporter import AzureMonitorTraceExporter
|
|
8
|
+
from opentelemetry import context, trace
|
|
9
|
+
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
|
|
10
|
+
from opentelemetry.sdk.trace import TracerProvider
|
|
11
|
+
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
|
12
|
+
from opentelemetry.sdk.trace.sampling import ALWAYS_ON
|
|
13
|
+
from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
logger.addHandler(StreamHandler())
|
|
17
|
+
|
|
18
|
+
tracer = trace.get_tracer(__name__)
|
|
19
|
+
|
|
20
|
+
_TRACING_LOCK = threading.Lock()
|
|
21
|
+
TRACING_IS_CONFIGURED = False
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def configure_tracing():
|
|
25
|
+
global TRACING_IS_CONFIGURED
|
|
26
|
+
# Add thread locking to avoid race conditions during setup
|
|
27
|
+
with _TRACING_LOCK:
|
|
28
|
+
if TRACING_IS_CONFIGURED:
|
|
29
|
+
# tracing should only be set up once
|
|
30
|
+
# to avoid duplicated trace handling.
|
|
31
|
+
# Global variables is the pattern used
|
|
32
|
+
# by opentelemetry, so we use the same
|
|
33
|
+
return
|
|
34
|
+
|
|
35
|
+
# set up tracer provider based on the Azure Function resource
|
|
36
|
+
# (this is make sure App Insights can track the trace source correctly)
|
|
37
|
+
# (https://learn.microsoft.com/en-us/azure/azure-monitor/app/opentelemetry-enable?tabs=net#set-the-cloud-role-name-and-the-cloud-role-instance).
|
|
38
|
+
# We use the ALWAYS ON sampler since otherwise spans will not be
|
|
39
|
+
# recording upon creation
|
|
40
|
+
# (https://anecdotes.dev/opentelemetry-on-google-cloud-unraveling-the-mystery-f61f044c18be)
|
|
41
|
+
service_name = os.getenv("WEBSITE_SITE_NAME") or "unknown-service"
|
|
42
|
+
resource = Resource.create({SERVICE_NAME: service_name})
|
|
43
|
+
trace.set_tracer_provider(
|
|
44
|
+
TracerProvider(
|
|
45
|
+
sampler=ALWAYS_ON,
|
|
46
|
+
resource=resource,
|
|
47
|
+
)
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
# setup azure monitor trace exporter to send telemetry to App Insights
|
|
51
|
+
try:
|
|
52
|
+
trace_exporter = AzureMonitorTraceExporter()
|
|
53
|
+
except ValueError:
|
|
54
|
+
logger.warning(
|
|
55
|
+
"Cant set up tracing to App Insights,"
|
|
56
|
+
" as no connection string is set."
|
|
57
|
+
)
|
|
58
|
+
else:
|
|
59
|
+
span_processor = BatchSpanProcessor(trace_exporter)
|
|
60
|
+
trace.get_tracer_provider().add_span_processor(span_processor)
|
|
61
|
+
|
|
62
|
+
TRACING_IS_CONFIGURED = True
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@contextmanager
|
|
66
|
+
def set_trace_context(trace_parent: str, trace_state: str = ""):
|
|
67
|
+
"""Context manager for setting the trace context
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
trace_parent (str): Trace parent ID
|
|
71
|
+
trace_state (str, optional): Trace state. Defaults to "".
|
|
72
|
+
"""
|
|
73
|
+
carrier = {"traceparent": trace_parent, "tracestate": trace_state}
|
|
74
|
+
ctx = TraceContextTextMapPropagator().extract(carrier=carrier)
|
|
75
|
+
|
|
76
|
+
token = context.attach(ctx) # attach context before run
|
|
77
|
+
try:
|
|
78
|
+
yield
|
|
79
|
+
finally:
|
|
80
|
+
context.detach(token) # detach context after run
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def get_tracer(name: str):
|
|
84
|
+
tracer = trace.get_tracer(name)
|
|
85
|
+
return tracer
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def get_current_diagnostic_id() -> str:
|
|
89
|
+
"""Gets diagnostic id from current span
|
|
90
|
+
|
|
91
|
+
The diagnostic id is a concatenation of operation-id and parent-id
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
str: diagnostic id
|
|
95
|
+
"""
|
|
96
|
+
span = trace.get_current_span()
|
|
97
|
+
|
|
98
|
+
if not span.is_recording():
|
|
99
|
+
return ""
|
|
100
|
+
|
|
101
|
+
operation_id = "{:016x}".format(span.context.trace_id)
|
|
102
|
+
parent_id = "{:016x}".format(span.context.span_id)
|
|
103
|
+
|
|
104
|
+
diagnostic_id = f"00-{operation_id}-{parent_id}-01"
|
|
105
|
+
|
|
106
|
+
return diagnostic_id
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
# Service Bus trace constants (these were removed from azure-servicebus SDK)
|
|
110
|
+
_SB_TRACE_NAMESPACE = "Microsoft.ServiceBus"
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@contextmanager
|
|
114
|
+
def servicebus_send_span(subject: str) -> trace.Span:
|
|
115
|
+
"""Start span for Service Bus message tracing.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
subject: The message subject (used as span name for easy identification)
|
|
119
|
+
|
|
120
|
+
Yields:
|
|
121
|
+
trace.Span: the span
|
|
122
|
+
"""
|
|
123
|
+
with tracer.start_as_current_span(
|
|
124
|
+
subject, kind=trace.SpanKind.PRODUCER
|
|
125
|
+
) as msg_span:
|
|
126
|
+
msg_span.set_attributes({"az.namespace": _SB_TRACE_NAMESPACE})
|
|
127
|
+
|
|
128
|
+
yield msg_span
|
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
import inspect
|
|
2
|
-
import logging
|
|
3
|
-
import os
|
|
4
|
-
import threading
|
|
5
|
-
from contextlib import contextmanager
|
|
6
|
-
from functools import wraps
|
|
7
|
-
from logging import StreamHandler
|
|
8
|
-
from typing import Callable
|
|
9
|
-
|
|
10
|
-
from azure.monitor.opentelemetry.exporter import AzureMonitorTraceExporter
|
|
11
|
-
from opentelemetry import context, trace
|
|
12
|
-
from opentelemetry.sdk.resources import SERVICE_NAME, Resource
|
|
13
|
-
from opentelemetry.sdk.trace import Tracer, TracerProvider
|
|
14
|
-
from opentelemetry.sdk.trace.export import BatchSpanProcessor
|
|
15
|
-
from opentelemetry.sdk.trace.sampling import ALWAYS_ON
|
|
16
|
-
from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
|
|
17
|
-
|
|
18
|
-
logger = logging.getLogger(__name__)
|
|
19
|
-
logger.addHandler(StreamHandler())
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class WarpzoneTracer:
|
|
23
|
-
"""Wrapper around OpenTelemetry tracer with additional trace decorator method"""
|
|
24
|
-
|
|
25
|
-
def __init__(self, otel_tracer: Tracer):
|
|
26
|
-
# Store the original tracer instead of calling super().__init__
|
|
27
|
-
# because we want to wrap an existing tracer, not create a new one
|
|
28
|
-
self._tracer = otel_tracer
|
|
29
|
-
|
|
30
|
-
def __getattr__(self, name):
|
|
31
|
-
"""Delegate all attributes to the underlying tracer"""
|
|
32
|
-
return getattr(self._tracer, name)
|
|
33
|
-
|
|
34
|
-
def trace_function(
|
|
35
|
-
self,
|
|
36
|
-
name: str = None,
|
|
37
|
-
set_args_as_attributes: bool = False,
|
|
38
|
-
on_input: Callable = None,
|
|
39
|
-
on_output: Callable = None,
|
|
40
|
-
):
|
|
41
|
-
"""
|
|
42
|
-
Decorator to trace a function using this tracer object.
|
|
43
|
-
|
|
44
|
-
This decorator wraps functions with OpenTelemetry tracing, allowing for:
|
|
45
|
-
- Automatically create spans for function execution
|
|
46
|
-
- Customize the span name
|
|
47
|
-
- Add custom attributes to the span
|
|
48
|
-
- Add custom logic for inputs and outputs
|
|
49
|
-
|
|
50
|
-
Args:
|
|
51
|
-
name: Optional name for the span. If not provided, uses the function name.
|
|
52
|
-
set_args_as_attributes: If True, sets function arguments as attributes.
|
|
53
|
-
on_input: Optional callback called with (span, *args, **kwargs) before.
|
|
54
|
-
on_output: Optional callback called with (span, result) after.
|
|
55
|
-
|
|
56
|
-
Example:
|
|
57
|
-
# Simple tracing with function name
|
|
58
|
-
tracer = get_tracer(__name__)
|
|
59
|
-
|
|
60
|
-
@tracer.trace_function()
|
|
61
|
-
def my_function():
|
|
62
|
-
pass
|
|
63
|
-
|
|
64
|
-
# Custom tracing with input/output callbacks
|
|
65
|
-
@tracer.trace_function(
|
|
66
|
-
on_input=lambda span, new_data, existing_data, now: (
|
|
67
|
-
span.set_attribute("new_records", len(new_data)),
|
|
68
|
-
span.set_attribute("existing_records", len(existing_data)),
|
|
69
|
-
),
|
|
70
|
-
on_output=lambda span, result: (
|
|
71
|
-
span.set_attribute("merged_records", len(result))
|
|
72
|
-
),
|
|
73
|
-
)
|
|
74
|
-
def merge_new_and_existing(new_data, existing_data, now):
|
|
75
|
-
pass
|
|
76
|
-
"""
|
|
77
|
-
|
|
78
|
-
def decorator(func: Callable) -> Callable:
|
|
79
|
-
@wraps(func)
|
|
80
|
-
def wrapper(*args, **kwargs):
|
|
81
|
-
span_name = name or func.__name__
|
|
82
|
-
with self._tracer.start_as_current_span(span_name) as span:
|
|
83
|
-
if set_args_as_attributes:
|
|
84
|
-
# Get parameter names from function signature
|
|
85
|
-
sig = inspect.signature(func)
|
|
86
|
-
param_names = list(sig.parameters.keys())
|
|
87
|
-
|
|
88
|
-
# Set positional arguments with their parameter names
|
|
89
|
-
for i, arg in enumerate(args):
|
|
90
|
-
if i < len(param_names):
|
|
91
|
-
span.set_attribute(param_names[i], str(arg))
|
|
92
|
-
else:
|
|
93
|
-
# Fallback for *args if there are more args than params
|
|
94
|
-
span.set_attribute(f"arg_{i}", str(arg))
|
|
95
|
-
|
|
96
|
-
# Set keyword arguments
|
|
97
|
-
for key, value in kwargs.items():
|
|
98
|
-
span.set_attribute(str(key), str(value))
|
|
99
|
-
|
|
100
|
-
# Call on_input callback if provided
|
|
101
|
-
if on_input:
|
|
102
|
-
on_input(span, *args, **kwargs)
|
|
103
|
-
|
|
104
|
-
result = func(*args, **kwargs)
|
|
105
|
-
|
|
106
|
-
# Call on_output callback if provided
|
|
107
|
-
if on_output:
|
|
108
|
-
on_output(span, result)
|
|
109
|
-
|
|
110
|
-
return result
|
|
111
|
-
|
|
112
|
-
return wrapper
|
|
113
|
-
|
|
114
|
-
return decorator
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
tracer = WarpzoneTracer(trace.get_tracer(__name__))
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
_TRACING_LOCK = threading.Lock()
|
|
121
|
-
TRACING_IS_CONFIGURED = False
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
def configure_tracing():
|
|
125
|
-
global TRACING_IS_CONFIGURED
|
|
126
|
-
# Add thread locking to avoid race conditions during setup
|
|
127
|
-
with _TRACING_LOCK:
|
|
128
|
-
if TRACING_IS_CONFIGURED:
|
|
129
|
-
# tracing should only be set up once
|
|
130
|
-
# to avoid duplicated trace handling.
|
|
131
|
-
# Global variables is the pattern used
|
|
132
|
-
# by opentelemetry, so we use the same
|
|
133
|
-
return
|
|
134
|
-
|
|
135
|
-
# set up tracer provider based on the Azure Function resource
|
|
136
|
-
# (this is make sure App Insights can track the trace source correctly)
|
|
137
|
-
# (https://learn.microsoft.com/en-us/azure/azure-monitor/app/opentelemetry-enable?tabs=net#set-the-cloud-role-name-and-the-cloud-role-instance).
|
|
138
|
-
# We use the ALWAYS ON sampler since otherwise spans will not be
|
|
139
|
-
# recording upon creation
|
|
140
|
-
# (https://anecdotes.dev/opentelemetry-on-google-cloud-unraveling-the-mystery-f61f044c18be)
|
|
141
|
-
service_name = os.getenv("WEBSITE_SITE_NAME") or "unknown-service"
|
|
142
|
-
resource = Resource.create({SERVICE_NAME: service_name})
|
|
143
|
-
trace.set_tracer_provider(
|
|
144
|
-
TracerProvider(
|
|
145
|
-
sampler=ALWAYS_ON,
|
|
146
|
-
resource=resource,
|
|
147
|
-
)
|
|
148
|
-
)
|
|
149
|
-
|
|
150
|
-
# setup azure monitor trace exporter to send telemetry to App Insights
|
|
151
|
-
try:
|
|
152
|
-
trace_exporter = AzureMonitorTraceExporter()
|
|
153
|
-
except ValueError:
|
|
154
|
-
logger.warning(
|
|
155
|
-
"Cant set up tracing to App Insights,"
|
|
156
|
-
" as no connection string is set."
|
|
157
|
-
)
|
|
158
|
-
else:
|
|
159
|
-
span_processor = BatchSpanProcessor(trace_exporter)
|
|
160
|
-
trace.get_tracer_provider().add_span_processor(span_processor)
|
|
161
|
-
|
|
162
|
-
TRACING_IS_CONFIGURED = True
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
@contextmanager
|
|
166
|
-
def set_trace_context(trace_parent: str, trace_state: str = ""):
|
|
167
|
-
"""Context manager for setting the trace context
|
|
168
|
-
|
|
169
|
-
Args:
|
|
170
|
-
trace_parent (str): Trace parent ID
|
|
171
|
-
trace_state (str, optional): Trace state. Defaults to "".
|
|
172
|
-
"""
|
|
173
|
-
carrier = {"traceparent": trace_parent, "tracestate": trace_state}
|
|
174
|
-
ctx = TraceContextTextMapPropagator().extract(carrier=carrier)
|
|
175
|
-
|
|
176
|
-
token = context.attach(ctx) # attach context before run
|
|
177
|
-
try:
|
|
178
|
-
yield
|
|
179
|
-
finally:
|
|
180
|
-
context.detach(token) # detach context after run
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
def get_tracer(name: str):
|
|
184
|
-
otel_tracer = trace.get_tracer(name)
|
|
185
|
-
return WarpzoneTracer(otel_tracer)
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
def get_current_diagnostic_id() -> str:
|
|
189
|
-
"""Gets diagnostic id from current span
|
|
190
|
-
|
|
191
|
-
The diagnostic id is a concatenation of operation-id and parent-id
|
|
192
|
-
|
|
193
|
-
Returns:
|
|
194
|
-
str: diagnostic id
|
|
195
|
-
"""
|
|
196
|
-
span = trace.get_current_span()
|
|
197
|
-
|
|
198
|
-
if not span.is_recording():
|
|
199
|
-
return ""
|
|
200
|
-
|
|
201
|
-
operation_id = "{:016x}".format(span.context.trace_id)
|
|
202
|
-
parent_id = "{:016x}".format(span.context.span_id)
|
|
203
|
-
|
|
204
|
-
diagnostic_id = f"00-{operation_id}-{parent_id}-01"
|
|
205
|
-
|
|
206
|
-
return diagnostic_id
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
# Service Bus trace constants (these were removed from azure-servicebus SDK)
|
|
210
|
-
_SB_TRACE_NAMESPACE = "Microsoft.ServiceBus"
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
@contextmanager
|
|
214
|
-
def servicebus_send_span(subject: str):
|
|
215
|
-
"""Start span for Service Bus message tracing.
|
|
216
|
-
|
|
217
|
-
Args:
|
|
218
|
-
subject: The message subject (used as span name for easy identification)
|
|
219
|
-
|
|
220
|
-
Yields:
|
|
221
|
-
Span: the span
|
|
222
|
-
"""
|
|
223
|
-
with tracer.start_as_current_span(
|
|
224
|
-
subject, kind=trace.SpanKind.PRODUCER
|
|
225
|
-
) as msg_span:
|
|
226
|
-
msg_span.set_attributes({"az.namespace": _SB_TRACE_NAMESPACE})
|
|
227
|
-
|
|
228
|
-
yield msg_span
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/deltastorage/generated_columns.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/function/processors/__init__.py
RENAMED
|
File without changes
|
{warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/function/processors/dependencies.py
RENAMED
|
File without changes
|
{warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/function/processors/outputs.py
RENAMED
|
File without changes
|
{warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/function/processors/triggers.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/servicebus/events/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/servicebus/events/triggers.py
RENAMED
|
File without changes
|
|
File without changes
|
{warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/tablestorage/db/base_client.py
RENAMED
|
File without changes
|
|
File without changes
|
{warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/tablestorage/db/table_config.py
RENAMED
|
File without changes
|
{warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/tablestorage/tables/__init__.py
RENAMED
|
File without changes
|
{warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/tablestorage/tables/client.py
RENAMED
|
File without changes
|
{warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/tablestorage/tables/entities.py
RENAMED
|
File without changes
|
{warpzone_sdk-15.1.1.dev1 → warpzone_sdk-15.1.2.dev1}/warpzone/tablestorage/tables/helpers.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|