atlan-application-sdk 1.0.4__py3-none-any.whl → 1.1.0__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.
- application_sdk/activities/__init__.py +6 -0
- application_sdk/clients/temporal.py +4 -0
- application_sdk/interceptors/correlation_context.py +143 -0
- application_sdk/interceptors/events.py +0 -2
- application_sdk/observability/context.py +18 -0
- application_sdk/observability/logger_adaptor.py +61 -68
- application_sdk/observability/utils.py +16 -1
- application_sdk/server/fastapi/middleware/logmiddleware.py +2 -1
- application_sdk/version.py +1 -1
- {atlan_application_sdk-1.0.4.dist-info → atlan_application_sdk-1.1.0.dist-info}/METADATA +2 -3
- {atlan_application_sdk-1.0.4.dist-info → atlan_application_sdk-1.1.0.dist-info}/RECORD +14 -12
- {atlan_application_sdk-1.0.4.dist-info → atlan_application_sdk-1.1.0.dist-info}/WHEEL +0 -0
- {atlan_application_sdk-1.0.4.dist-info → atlan_application_sdk-1.1.0.dist-info}/licenses/LICENSE +0 -0
- {atlan_application_sdk-1.0.4.dist-info → atlan_application_sdk-1.1.0.dist-info}/licenses/NOTICE +0 -0
|
@@ -206,6 +206,12 @@ class ActivitiesInterface(ABC, Generic[ActivitiesStateType]):
|
|
|
206
206
|
)
|
|
207
207
|
workflow_args["workflow_id"] = workflow_id
|
|
208
208
|
workflow_args["workflow_run_id"] = get_workflow_run_id()
|
|
209
|
+
|
|
210
|
+
# Preserve atlan- prefixed keys from workflow_config for logging context
|
|
211
|
+
for key, value in workflow_config.items():
|
|
212
|
+
if key.startswith("atlan-") and value:
|
|
213
|
+
workflow_args[key] = str(value)
|
|
214
|
+
|
|
209
215
|
return workflow_args
|
|
210
216
|
|
|
211
217
|
except Exception as e:
|
|
@@ -33,6 +33,9 @@ from application_sdk.events.models import (
|
|
|
33
33
|
WorkerTokenRefreshEventData,
|
|
34
34
|
)
|
|
35
35
|
from application_sdk.interceptors.cleanup import CleanupInterceptor, cleanup
|
|
36
|
+
from application_sdk.interceptors.correlation_context import (
|
|
37
|
+
CorrelationContextInterceptor,
|
|
38
|
+
)
|
|
36
39
|
from application_sdk.interceptors.events import EventInterceptor, publish_event
|
|
37
40
|
from application_sdk.interceptors.lock import RedisLockInterceptor
|
|
38
41
|
from application_sdk.observability.logger_adaptor import get_logger
|
|
@@ -430,6 +433,7 @@ class TemporalWorkflowClient(WorkflowClient):
|
|
|
430
433
|
max_concurrent_activities=max_concurrent_activities,
|
|
431
434
|
activity_executor=activity_executor,
|
|
432
435
|
interceptors=[
|
|
436
|
+
CorrelationContextInterceptor(),
|
|
433
437
|
EventInterceptor(),
|
|
434
438
|
CleanupInterceptor(),
|
|
435
439
|
RedisLockInterceptor(activities_dict),
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"""Correlation context interceptor for Temporal workflows.
|
|
2
|
+
|
|
3
|
+
Propagates atlan-* correlation context fields from workflow arguments to activities
|
|
4
|
+
via Temporal headers, ensuring all activity logs include correlation identifiers
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from dataclasses import replace
|
|
8
|
+
from typing import Any, Dict, Optional, Type
|
|
9
|
+
|
|
10
|
+
from temporalio import workflow
|
|
11
|
+
from temporalio.api.common.v1 import Payload
|
|
12
|
+
from temporalio.converter import default as default_converter
|
|
13
|
+
from temporalio.worker import (
|
|
14
|
+
ActivityInboundInterceptor,
|
|
15
|
+
ExecuteActivityInput,
|
|
16
|
+
ExecuteWorkflowInput,
|
|
17
|
+
Interceptor,
|
|
18
|
+
StartActivityInput,
|
|
19
|
+
WorkflowInboundInterceptor,
|
|
20
|
+
WorkflowInterceptorClassInput,
|
|
21
|
+
WorkflowOutboundInterceptor,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
from application_sdk.observability.context import correlation_context
|
|
25
|
+
from application_sdk.observability.logger_adaptor import get_logger
|
|
26
|
+
|
|
27
|
+
logger = get_logger(__name__)
|
|
28
|
+
|
|
29
|
+
ATLAN_HEADER_PREFIX = "atlan-"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class CorrelationContextOutboundInterceptor(WorkflowOutboundInterceptor):
|
|
33
|
+
"""Outbound interceptor that injects atlan-* context into activity headers."""
|
|
34
|
+
|
|
35
|
+
def __init__(
|
|
36
|
+
self,
|
|
37
|
+
next: WorkflowOutboundInterceptor,
|
|
38
|
+
inbound: "CorrelationContextWorkflowInboundInterceptor",
|
|
39
|
+
):
|
|
40
|
+
"""Initialize the outbound interceptor."""
|
|
41
|
+
super().__init__(next)
|
|
42
|
+
self.inbound = inbound
|
|
43
|
+
|
|
44
|
+
def start_activity(self, input: StartActivityInput) -> workflow.ActivityHandle[Any]:
|
|
45
|
+
"""Inject atlan-* headers and trace_id into activity calls."""
|
|
46
|
+
try:
|
|
47
|
+
if self.inbound.correlation_data:
|
|
48
|
+
new_headers: Dict[str, Payload] = dict(input.headers)
|
|
49
|
+
payload_converter = default_converter().payload_converter
|
|
50
|
+
|
|
51
|
+
for key, value in self.inbound.correlation_data.items():
|
|
52
|
+
# Include atlan-* prefixed headers and trace_id
|
|
53
|
+
if (
|
|
54
|
+
key.startswith(ATLAN_HEADER_PREFIX) or key == "trace_id"
|
|
55
|
+
) and value:
|
|
56
|
+
payload = payload_converter.to_payload(value)
|
|
57
|
+
new_headers[key] = payload
|
|
58
|
+
|
|
59
|
+
input = replace(input, headers=new_headers)
|
|
60
|
+
except Exception as e:
|
|
61
|
+
logger.warning(f"Failed to inject correlation context headers: {e}")
|
|
62
|
+
|
|
63
|
+
return self.next.start_activity(input)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class CorrelationContextWorkflowInboundInterceptor(WorkflowInboundInterceptor):
|
|
67
|
+
"""Inbound workflow interceptor that extracts atlan-* context from workflow args."""
|
|
68
|
+
|
|
69
|
+
def __init__(self, next: WorkflowInboundInterceptor):
|
|
70
|
+
"""Initialize the inbound interceptor."""
|
|
71
|
+
super().__init__(next)
|
|
72
|
+
self.correlation_data: Dict[str, str] = {}
|
|
73
|
+
|
|
74
|
+
def init(self, outbound: WorkflowOutboundInterceptor) -> None:
|
|
75
|
+
"""Initialize with correlation context outbound interceptor."""
|
|
76
|
+
context_outbound = CorrelationContextOutboundInterceptor(outbound, self)
|
|
77
|
+
super().init(context_outbound)
|
|
78
|
+
|
|
79
|
+
async def execute_workflow(self, input: ExecuteWorkflowInput) -> Any:
|
|
80
|
+
"""Execute workflow and extract atlan-* fields and trace_id from arguments."""
|
|
81
|
+
try:
|
|
82
|
+
if input.args and len(input.args) > 0:
|
|
83
|
+
workflow_config = input.args[0]
|
|
84
|
+
if isinstance(workflow_config, dict):
|
|
85
|
+
# Extract atlan-* prefixed fields
|
|
86
|
+
self.correlation_data = {
|
|
87
|
+
k: str(v)
|
|
88
|
+
for k, v in workflow_config.items()
|
|
89
|
+
if k.startswith(ATLAN_HEADER_PREFIX) and v
|
|
90
|
+
}
|
|
91
|
+
# Extract trace_id separately (not atlan- prefixed)
|
|
92
|
+
trace_id = workflow_config.get("trace_id", "")
|
|
93
|
+
if trace_id:
|
|
94
|
+
self.correlation_data["trace_id"] = str(trace_id)
|
|
95
|
+
if self.correlation_data:
|
|
96
|
+
correlation_context.set(self.correlation_data)
|
|
97
|
+
except Exception as e:
|
|
98
|
+
logger.warning(f"Failed to extract correlation context from args: {e}")
|
|
99
|
+
|
|
100
|
+
return await super().execute_workflow(input)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class CorrelationContextActivityInboundInterceptor(ActivityInboundInterceptor):
|
|
104
|
+
"""Activity interceptor that reads atlan-* headers and trace_id, sets correlation_context."""
|
|
105
|
+
|
|
106
|
+
async def execute_activity(self, input: ExecuteActivityInput) -> Any:
|
|
107
|
+
"""Execute activity after extracting atlan-* headers and trace_id."""
|
|
108
|
+
try:
|
|
109
|
+
atlan_fields: Dict[str, str] = {}
|
|
110
|
+
payload_converter = default_converter().payload_converter
|
|
111
|
+
|
|
112
|
+
for key, payload in input.headers.items():
|
|
113
|
+
# Extract atlan-* prefixed headers and trace_id
|
|
114
|
+
if key.startswith(ATLAN_HEADER_PREFIX) or key == "trace_id":
|
|
115
|
+
value = payload_converter.from_payload(payload, type_hint=str)
|
|
116
|
+
atlan_fields[key] = value
|
|
117
|
+
|
|
118
|
+
if atlan_fields:
|
|
119
|
+
correlation_context.set(atlan_fields)
|
|
120
|
+
|
|
121
|
+
except Exception as e:
|
|
122
|
+
logger.warning(f"Failed to extract correlation context from headers: {e}")
|
|
123
|
+
|
|
124
|
+
return await super().execute_activity(input)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class CorrelationContextInterceptor(Interceptor):
|
|
128
|
+
"""Main interceptor for propagating atlan-* correlation context.
|
|
129
|
+
|
|
130
|
+
Ensures atlan-* fields are propagated from workflow arguments to all activities via Temporal headers.
|
|
131
|
+
"""
|
|
132
|
+
|
|
133
|
+
def workflow_interceptor_class(
|
|
134
|
+
self, input: WorkflowInterceptorClassInput
|
|
135
|
+
) -> Optional[Type[WorkflowInboundInterceptor]]:
|
|
136
|
+
"""Get the workflow interceptor class."""
|
|
137
|
+
return CorrelationContextWorkflowInboundInterceptor
|
|
138
|
+
|
|
139
|
+
def intercept_activity(
|
|
140
|
+
self, next: ActivityInboundInterceptor
|
|
141
|
+
) -> ActivityInboundInterceptor:
|
|
142
|
+
"""Intercept activity executions to read correlation context."""
|
|
143
|
+
return CorrelationContextActivityInboundInterceptor(next)
|
|
@@ -66,8 +66,6 @@ class EventActivityInboundInterceptor(ActivityInboundInterceptor):
|
|
|
66
66
|
Returns:
|
|
67
67
|
Any: The result of the activity execution.
|
|
68
68
|
"""
|
|
69
|
-
# Extract activity information for tracking
|
|
70
|
-
|
|
71
69
|
start_event = Event(
|
|
72
70
|
event_type=EventTypes.APPLICATION_EVENT.value,
|
|
73
71
|
event_name=ApplicationEventNames.ACTIVITY_START.value,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Shared context variables for observability.
|
|
2
|
+
|
|
3
|
+
This module contains ContextVar definitions that are shared across
|
|
4
|
+
multiple observability modules to avoid circular imports.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from contextvars import ContextVar
|
|
8
|
+
from typing import Any, Dict
|
|
9
|
+
|
|
10
|
+
# Context variable for request-scoped data (e.g., request_id from HTTP middleware)
|
|
11
|
+
request_context: ContextVar[Dict[str, Any] | None] = ContextVar(
|
|
12
|
+
"request_context", default=None
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
# Context variable for correlation context (atlan- prefixed headers for distributed tracing)
|
|
16
|
+
correlation_context: ContextVar[Dict[str, Any] | None] = ContextVar(
|
|
17
|
+
"correlation_context", default=None
|
|
18
|
+
)
|
|
@@ -2,7 +2,6 @@ import asyncio
|
|
|
2
2
|
import logging
|
|
3
3
|
import sys
|
|
4
4
|
import threading
|
|
5
|
-
from contextvars import ContextVar
|
|
6
5
|
from time import time_ns
|
|
7
6
|
from typing import Any, Dict, Optional, Tuple
|
|
8
7
|
|
|
@@ -34,6 +33,7 @@ from application_sdk.constants import (
|
|
|
34
33
|
SERVICE_NAME,
|
|
35
34
|
SERVICE_VERSION,
|
|
36
35
|
)
|
|
36
|
+
from application_sdk.observability.context import correlation_context, request_context
|
|
37
37
|
from application_sdk.observability.observability import AtlanObservability
|
|
38
38
|
from application_sdk.observability.utils import (
|
|
39
39
|
get_observability_dir,
|
|
@@ -42,7 +42,13 @@ from application_sdk.observability.utils import (
|
|
|
42
42
|
|
|
43
43
|
|
|
44
44
|
class LogExtraModel(BaseModel):
|
|
45
|
-
"""Pydantic model for log extra fields.
|
|
45
|
+
"""Pydantic model for log extra fields.
|
|
46
|
+
|
|
47
|
+
This model allows arbitrary extra fields (prefixed with atlan-) to be included
|
|
48
|
+
for correlation context propagation to OTEL.
|
|
49
|
+
"""
|
|
50
|
+
|
|
51
|
+
model_config = {"extra": "allow"}
|
|
46
52
|
|
|
47
53
|
client_host: Optional[str] = None
|
|
48
54
|
duration_ms: Optional[int] = None
|
|
@@ -67,52 +73,8 @@ class LogExtraModel(BaseModel):
|
|
|
67
73
|
heartbeat_timeout: Optional[str] = None
|
|
68
74
|
# Other fields
|
|
69
75
|
log_type: Optional[str] = None
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
"""Pydantic model configuration for LogExtraModel.
|
|
73
|
-
|
|
74
|
-
Provides custom parsing logic for converting dictionary values to appropriate types.
|
|
75
|
-
Handles type conversion for various fields like integers, strings, and other data types.
|
|
76
|
-
"""
|
|
77
|
-
|
|
78
|
-
@classmethod
|
|
79
|
-
def parse_obj(cls, obj):
|
|
80
|
-
if isinstance(obj, dict):
|
|
81
|
-
# Define type mappings for each field
|
|
82
|
-
type_mappings = {
|
|
83
|
-
# Integer fields
|
|
84
|
-
"attempt": int,
|
|
85
|
-
"duration_ms": int,
|
|
86
|
-
"status_code": int,
|
|
87
|
-
# String fields
|
|
88
|
-
"client_host": str,
|
|
89
|
-
"method": str,
|
|
90
|
-
"path": str,
|
|
91
|
-
"request_id": str,
|
|
92
|
-
"url": str,
|
|
93
|
-
"workflow_id": str,
|
|
94
|
-
"run_id": str,
|
|
95
|
-
"workflow_type": str,
|
|
96
|
-
"namespace": str,
|
|
97
|
-
"task_queue": str,
|
|
98
|
-
"activity_id": str,
|
|
99
|
-
"activity_type": str,
|
|
100
|
-
"schedule_to_close_timeout": str,
|
|
101
|
-
"start_to_close_timeout": str,
|
|
102
|
-
"schedule_to_start_timeout": str,
|
|
103
|
-
"heartbeat_timeout": str,
|
|
104
|
-
"log_type": str,
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
# Process each field with its type conversion
|
|
108
|
-
for field, type_func in type_mappings.items():
|
|
109
|
-
if field in obj and obj[field] is not None:
|
|
110
|
-
try:
|
|
111
|
-
obj[field] = type_func(obj[field])
|
|
112
|
-
except (ValueError, TypeError):
|
|
113
|
-
obj[field] = None
|
|
114
|
-
|
|
115
|
-
return super().parse_obj(obj)
|
|
76
|
+
# Trace context
|
|
77
|
+
trace_id: Optional[str] = None
|
|
116
78
|
|
|
117
79
|
|
|
118
80
|
class LogRecordModel(BaseModel):
|
|
@@ -142,6 +104,9 @@ class LogRecordModel(BaseModel):
|
|
|
142
104
|
for k, v in message.record["extra"].items():
|
|
143
105
|
if k != "logger_name" and hasattr(extra, k):
|
|
144
106
|
setattr(extra, k, v)
|
|
107
|
+
# Include atlan- prefixed fields as extra attributes (correlation context)
|
|
108
|
+
elif k.startswith("atlan-") and v is not None:
|
|
109
|
+
setattr(extra, k, str(v))
|
|
145
110
|
|
|
146
111
|
return cls(
|
|
147
112
|
timestamp=message.record["time"].timestamp(),
|
|
@@ -160,8 +125,9 @@ class LogRecordModel(BaseModel):
|
|
|
160
125
|
arbitrary_types_allowed = True
|
|
161
126
|
|
|
162
127
|
|
|
163
|
-
#
|
|
164
|
-
request_context: ContextVar
|
|
128
|
+
# Re-exported from context.py for backward compatibility:
|
|
129
|
+
# - request_context: ContextVar for request-scoped data (e.g., request_id)
|
|
130
|
+
# - correlation_context: ContextVar for atlan- prefixed headers
|
|
165
131
|
|
|
166
132
|
|
|
167
133
|
# Add a Loguru handler for the Python logging system
|
|
@@ -286,23 +252,41 @@ class AtlanLoggerAdapter(AtlanObservability[LogRecordModel]):
|
|
|
286
252
|
"TRACING", no=SEVERITY_MAPPING["TRACING"], color="<magenta>", icon="🔍"
|
|
287
253
|
)
|
|
288
254
|
|
|
289
|
-
#
|
|
290
|
-
|
|
291
|
-
atlan_format_str_plain = (
|
|
292
|
-
"{time:YYYY-MM-DD HH:mm:ss} [{level}] {extra[logger_name]} - {message}"
|
|
293
|
-
)
|
|
255
|
+
# Colorize the logs only if the log level is DEBUG
|
|
256
|
+
colorize = LOG_LEVEL == "DEBUG"
|
|
294
257
|
|
|
295
|
-
|
|
296
|
-
|
|
258
|
+
def get_log_format(record: Any) -> str:
|
|
259
|
+
"""Generate log format string with trace_id for correlation.
|
|
297
260
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
261
|
+
Args:
|
|
262
|
+
record: Loguru record dictionary containing log information.
|
|
263
|
+
|
|
264
|
+
Returns:
|
|
265
|
+
Format string for the log message.
|
|
266
|
+
"""
|
|
267
|
+
# Build trace_id display string (only trace_id is printed, atlan-* go to OTEL)
|
|
268
|
+
trace_id = record["extra"].get("trace_id", "")
|
|
269
|
+
record["extra"]["_trace_id_str"] = (
|
|
270
|
+
f" trace_id={trace_id}" if trace_id else ""
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
if colorize:
|
|
274
|
+
return (
|
|
275
|
+
"<green>{time:YYYY-MM-DD HH:mm:ss}</green> "
|
|
276
|
+
"<blue>[{level}]</blue>"
|
|
277
|
+
"<magenta>{extra[_trace_id_str]}</magenta> "
|
|
278
|
+
"<cyan>{extra[logger_name]}</cyan>"
|
|
279
|
+
" - <level>{message}</level>\n"
|
|
280
|
+
)
|
|
281
|
+
return (
|
|
282
|
+
"{time:YYYY-MM-DD HH:mm:ss} [{level}]"
|
|
283
|
+
"{extra[_trace_id_str]} {extra[logger_name]}"
|
|
284
|
+
" - {message}\n"
|
|
285
|
+
)
|
|
302
286
|
|
|
303
287
|
self.logger.add(
|
|
304
288
|
sys.stderr,
|
|
305
|
-
format=
|
|
289
|
+
format=get_log_format,
|
|
306
290
|
level=SEVERITY_MAPPING[LOG_LEVEL],
|
|
307
291
|
colorize=colorize,
|
|
308
292
|
)
|
|
@@ -538,16 +522,14 @@ class AtlanLoggerAdapter(AtlanObservability[LogRecordModel]):
|
|
|
538
522
|
- Adds request context if available
|
|
539
523
|
- Adds workflow context if in a workflow
|
|
540
524
|
- Adds activity context if in an activity
|
|
525
|
+
- Adds correlation context if available
|
|
541
526
|
"""
|
|
542
527
|
kwargs["logger_name"] = self.logger_name
|
|
543
528
|
|
|
544
529
|
# Get request context
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
kwargs["request_id"] = ctx["request_id"]
|
|
549
|
-
except Exception:
|
|
550
|
-
pass
|
|
530
|
+
ctx = request_context.get()
|
|
531
|
+
if ctx and "request_id" in ctx:
|
|
532
|
+
kwargs["request_id"] = ctx["request_id"]
|
|
551
533
|
|
|
552
534
|
workflow_context = get_workflow_context()
|
|
553
535
|
|
|
@@ -569,6 +551,17 @@ class AtlanLoggerAdapter(AtlanObservability[LogRecordModel]):
|
|
|
569
551
|
except Exception:
|
|
570
552
|
pass
|
|
571
553
|
|
|
554
|
+
# Add correlation context (atlan- prefixed keys and trace_id) to kwargs
|
|
555
|
+
corr_ctx = correlation_context.get()
|
|
556
|
+
if corr_ctx:
|
|
557
|
+
# Add trace_id if present (for log format display)
|
|
558
|
+
if "trace_id" in corr_ctx and corr_ctx["trace_id"]:
|
|
559
|
+
kwargs["trace_id"] = str(corr_ctx["trace_id"])
|
|
560
|
+
# Add atlan-* headers for OTEL
|
|
561
|
+
for key, value in corr_ctx.items():
|
|
562
|
+
if key.startswith("atlan-") and value:
|
|
563
|
+
kwargs[key] = str(value)
|
|
564
|
+
|
|
572
565
|
return msg, kwargs
|
|
573
566
|
|
|
574
567
|
def debug(self, msg: str, *args: Any, **kwargs: Any):
|
|
@@ -9,10 +9,17 @@ from application_sdk.constants import (
|
|
|
9
9
|
OBSERVABILITY_DIR,
|
|
10
10
|
TEMPORARY_PATH,
|
|
11
11
|
)
|
|
12
|
+
from application_sdk.observability.context import correlation_context
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
class WorkflowContext(BaseModel):
|
|
15
|
-
"""Workflow context.
|
|
16
|
+
"""Workflow context.
|
|
17
|
+
|
|
18
|
+
This model supports dynamic correlation context fields (atlan- prefixed)
|
|
19
|
+
through Pydantic's extra="allow" configuration.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
model_config = {"extra": "allow"}
|
|
16
23
|
|
|
17
24
|
in_workflow: str = Field(default="false")
|
|
18
25
|
in_activity: str = Field(default="false")
|
|
@@ -75,4 +82,12 @@ def get_workflow_context() -> WorkflowContext:
|
|
|
75
82
|
except Exception:
|
|
76
83
|
pass
|
|
77
84
|
|
|
85
|
+
# Get correlation context from context variable (atlan- prefixed headers)
|
|
86
|
+
corr_ctx = correlation_context.get()
|
|
87
|
+
if corr_ctx:
|
|
88
|
+
# Add all correlation context fields as extra attributes
|
|
89
|
+
for key, value in corr_ctx.items():
|
|
90
|
+
if key.startswith("atlan-") and value:
|
|
91
|
+
setattr(context, key, str(value))
|
|
92
|
+
|
|
78
93
|
return context
|
|
@@ -6,7 +6,8 @@ from starlette.requests import Request
|
|
|
6
6
|
from starlette.responses import Response
|
|
7
7
|
from starlette.types import ASGIApp
|
|
8
8
|
|
|
9
|
-
from application_sdk.observability.
|
|
9
|
+
from application_sdk.observability.context import request_context
|
|
10
|
+
from application_sdk.observability.logger_adaptor import get_logger
|
|
10
11
|
|
|
11
12
|
logger = get_logger(__name__)
|
|
12
13
|
|
application_sdk/version.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: atlan-application-sdk
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.1.0
|
|
4
4
|
Summary: Atlan Application SDK is a Python library for developing applications on the Atlan Platform
|
|
5
5
|
Project-URL: Repository, https://github.com/atlanhq/application-sdk
|
|
6
6
|
Project-URL: Documentation, https://github.com/atlanhq/application-sdk/README.md
|
|
@@ -100,12 +100,11 @@ poetry add atlan-application-sdk
|
|
|
100
100
|
|
|
101
101
|
## Partner Collaboration
|
|
102
102
|
|
|
103
|
-
- For information on how to collaborate with Atlan on app development and integrations, please see our [Partner
|
|
103
|
+
- For information on how to collaborate with Atlan on app development and integrations, please see our [Partner Journey Guide](https://docs.atlan.com/product/capabilities/build-apps/partner-with-us/concepts/partner-journey).
|
|
104
104
|
|
|
105
105
|
## Need help?
|
|
106
106
|
We’re here whenever you need us:
|
|
107
107
|
|
|
108
|
-
- Email: **connect@atlan.com**
|
|
109
108
|
- Issues: [GitHub Issues](https://github.com/atlanhq/application-sdk/issues)
|
|
110
109
|
|
|
111
110
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
application_sdk/__init__.py,sha256=2e2mvmLJ5dxmJGPELtb33xwP-j6JMdoIuqKycEn7hjg,151
|
|
2
2
|
application_sdk/constants.py,sha256=S3I_WUGFbmAPH5GTtoTKD5rxILGevkZ219zhctLQles,11568
|
|
3
|
-
application_sdk/version.py,sha256=
|
|
3
|
+
application_sdk/version.py,sha256=xVoXV5sbTekcGcuM7ME4fKq1o5UnTZbNNjdI82wrDgw,84
|
|
4
4
|
application_sdk/worker.py,sha256=D3-wtfGv1DLFKi1YSaE3jTcX66eC00N6RwtBu9RkgNc,7555
|
|
5
|
-
application_sdk/activities/__init__.py,sha256=
|
|
5
|
+
application_sdk/activities/__init__.py,sha256=6SiefuOPUDGfN3z6oPY4RkQLiUmkHpoDy5xadzpDzAw,11588
|
|
6
6
|
application_sdk/activities/lock_management.py,sha256=6Wdf3jMKitoarHQP91PIJOoGFz4aaOLS_40c7n1yAOA,3902
|
|
7
7
|
application_sdk/activities/.cursor/BUGBOT.md,sha256=FNykX5aMkdOhzgpiGqstOnSp9JN63iR2XP3onU4AGh8,15843
|
|
8
8
|
application_sdk/activities/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -23,7 +23,7 @@ application_sdk/clients/base.py,sha256=TIn3pG89eXUc1XSYf4jk66m1vajWp0WxcCQOOltda
|
|
|
23
23
|
application_sdk/clients/models.py,sha256=iZOTyH6LO64kozdiUPCFCN0NgLhd_Gtv0lH7ZIPdo8w,1800
|
|
24
24
|
application_sdk/clients/redis.py,sha256=IfAD32vLp88BCvsDTaQtxFHxzHlEx4V7TK7h1HwDDBg,15917
|
|
25
25
|
application_sdk/clients/sql.py,sha256=lXeVu_dute30IaWWK5gHBhjEs2dXp_e0XkOMsbOsq64,19589
|
|
26
|
-
application_sdk/clients/temporal.py,sha256=
|
|
26
|
+
application_sdk/clients/temporal.py,sha256=eWrvnQxEPxocifHjfBEXfZINH3ekv80J6oPn3VQHLS0,20018
|
|
27
27
|
application_sdk/clients/utils.py,sha256=zLFOJbTr_6TOqnjfVFGY85OtIXZ4FQy_rquzjaydkbY,779
|
|
28
28
|
application_sdk/clients/workflow.py,sha256=6bSqmA3sNCk9oY68dOjBUDZ9DhNKQxPD75qqE0cfldc,6104
|
|
29
29
|
application_sdk/clients/.cursor/BUGBOT.md,sha256=7nEDUqWBEMI_uU6eK1jCSZGeXoQtLQcKwOrDn8AIDWo,10595
|
|
@@ -67,15 +67,17 @@ application_sdk/inputs/sql_query.py,sha256=9deGGI5Wob8mDuq-vRjYgQvVrfuU_IjLkiYuf
|
|
|
67
67
|
application_sdk/inputs/.cursor/BUGBOT.md,sha256=hwKGDbopv3NU0bpC_ElpAPDFcS59GWS3TunObGC6eLQ,9731
|
|
68
68
|
application_sdk/interceptors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
69
69
|
application_sdk/interceptors/cleanup.py,sha256=JlFcM_2Y5AIEfGTSNe0aoon7eoE68MIXI0rA3LHsSeY,5966
|
|
70
|
-
application_sdk/interceptors/
|
|
70
|
+
application_sdk/interceptors/correlation_context.py,sha256=j486uXZbLA85eTBJ8hxXS13vA8Ucf3_Nt5KiyA_cJVY,5864
|
|
71
|
+
application_sdk/interceptors/events.py,sha256=BYXbJX1sBTUCayjK1Zp3qm-xqmk5LZdZ7fEtpkHd8SQ,6471
|
|
71
72
|
application_sdk/interceptors/lock.py,sha256=5ETm20zrTaH2b9fepN4Ckp1tGJV-uINqDrno_5RW3aw,6169
|
|
72
73
|
application_sdk/interceptors/.cursor/BUGBOT.md,sha256=pxmUF2c7dtaXAX8yAa1-LBa6FCrj_uw7aQcHrppjf1A,14570
|
|
73
74
|
application_sdk/observability/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
74
|
-
application_sdk/observability/
|
|
75
|
+
application_sdk/observability/context.py,sha256=lJjpfxEjMY_hrdSDqq519YaWcztgc_1nM4d-mGV5shs,634
|
|
76
|
+
application_sdk/observability/logger_adaptor.py,sha256=Fq5OE579ozr0EzsNYEh2H0q3POVAxtlWfJ-PSwWDGLM,30194
|
|
75
77
|
application_sdk/observability/metrics_adaptor.py,sha256=5Oz02lUED60duryoVDF9mbD11fpxhbXi7P1609n_15Y,16446
|
|
76
78
|
application_sdk/observability/observability.py,sha256=MGxNFPx6pOdpWrpNXZp44NPk3SG4xjA9cKrTeZ1ENK8,23681
|
|
77
79
|
application_sdk/observability/traces_adaptor.py,sha256=0eQJPN-tYA_dV8D3uEa5ZiX9g12NDuLnPaFuQMVDdL0,18242
|
|
78
|
-
application_sdk/observability/utils.py,sha256
|
|
80
|
+
application_sdk/observability/utils.py,sha256=-02GAFom8Bg4SNyCTNYySmen2dzvLfTu43bqsNq1AH0,3096
|
|
79
81
|
application_sdk/observability/decorators/observability_decorator.py,sha256=yd6qfrg1MmH5KcZ5Ydzb0RaBzmxx5FrmiI9qwvZx3EU,8963
|
|
80
82
|
application_sdk/outputs/__init__.py,sha256=_n54Fj_VwGGwOpGQk9atvUw3-fd6GMOjd5-Jx-0TpZs,16836
|
|
81
83
|
application_sdk/outputs/iceberg.py,sha256=TdppOMEMfojMhGyBmhWeu1AJQexRyHM-huAYeJmhjdY,5533
|
|
@@ -87,7 +89,7 @@ application_sdk/server/.cursor/BUGBOT.md,sha256=p_MMoWUW5G1894WfOKYReZKWCuyJT_OJ
|
|
|
87
89
|
application_sdk/server/fastapi/__init__.py,sha256=BVqf63z1hxEdpJqLU4LXpFTbk5q8dVkjEbWbu_vbW_Y,29578
|
|
88
90
|
application_sdk/server/fastapi/models.py,sha256=dxhV2eOEg2xL_pLDgHFyRwZeKjRICQBCXXNvwRF-eek,7553
|
|
89
91
|
application_sdk/server/fastapi/utils.py,sha256=2XI4DylhRQsukhX67lpAzRNCHeFCSpbuNd7TlE2IBJA,1164
|
|
90
|
-
application_sdk/server/fastapi/middleware/logmiddleware.py,sha256=
|
|
92
|
+
application_sdk/server/fastapi/middleware/logmiddleware.py,sha256=pNOzxgiFbW-zrWQOIyM7mJugigoWF2TFFAoU-jNhddM,2594
|
|
91
93
|
application_sdk/server/fastapi/middleware/metrics.py,sha256=5ddHAIg5sT-u9tB_HHMGL3Cfu2g1rm9z7ksienIr9ks,1563
|
|
92
94
|
application_sdk/server/fastapi/routers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
93
95
|
application_sdk/server/fastapi/routers/server.py,sha256=vfHQwZCysThzfeVFNVW1IjuAdL0c1Cs4fULKTBK2eNo,4209
|
|
@@ -157,8 +159,8 @@ application_sdk/workflows/metadata_extraction/__init__.py,sha256=jHUe_ZBQ66jx8bg
|
|
|
157
159
|
application_sdk/workflows/metadata_extraction/sql.py,sha256=6ZaVt84n-8U2ZvR9GR7uIJKv5v8CuyQjhlnoRJvDszc,12435
|
|
158
160
|
application_sdk/workflows/query_extraction/__init__.py,sha256=n066_CX5RpJz6DIxGMkKS3eGSRg03ilaCtsqfJWQb7Q,117
|
|
159
161
|
application_sdk/workflows/query_extraction/sql.py,sha256=kT_JQkLCRZ44ZpaC4QvPL6DxnRIIVh8gYHLqRbMI-hA,4826
|
|
160
|
-
atlan_application_sdk-1.0.
|
|
161
|
-
atlan_application_sdk-1.0.
|
|
162
|
-
atlan_application_sdk-1.0.
|
|
163
|
-
atlan_application_sdk-1.0.
|
|
164
|
-
atlan_application_sdk-1.0.
|
|
162
|
+
atlan_application_sdk-1.1.0.dist-info/METADATA,sha256=tp78kB8k9VjMA2r3yzQTkjNE423AhQAk2rtq9Wkqte8,5890
|
|
163
|
+
atlan_application_sdk-1.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
164
|
+
atlan_application_sdk-1.1.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
165
|
+
atlan_application_sdk-1.1.0.dist-info/licenses/NOTICE,sha256=A-XVVGt3KOYuuMmvSMIFkg534F1vHiCggEBp4Ez3wGk,1041
|
|
166
|
+
atlan_application_sdk-1.1.0.dist-info/RECORD,,
|
|
File without changes
|
{atlan_application_sdk-1.0.4.dist-info → atlan_application_sdk-1.1.0.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
{atlan_application_sdk-1.0.4.dist-info → atlan_application_sdk-1.1.0.dist-info}/licenses/NOTICE
RENAMED
|
File without changes
|