ddeutil-workflow 0.0.84__py3-none-any.whl → 0.0.86__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.
- ddeutil/workflow/__about__.py +1 -1
- ddeutil/workflow/__init__.py +4 -4
- ddeutil/workflow/api/routes/job.py +3 -2
- ddeutil/workflow/audits.py +8 -6
- ddeutil/workflow/conf.py +9 -20
- ddeutil/workflow/errors.py +34 -19
- ddeutil/workflow/job.py +303 -159
- ddeutil/workflow/plugins/providers/az.py +2 -2
- ddeutil/workflow/result.py +46 -55
- ddeutil/workflow/stages.py +540 -458
- ddeutil/workflow/traces.py +259 -261
- ddeutil/workflow/workflow.py +304 -361
- {ddeutil_workflow-0.0.84.dist-info → ddeutil_workflow-0.0.86.dist-info}/METADATA +13 -16
- {ddeutil_workflow-0.0.84.dist-info → ddeutil_workflow-0.0.86.dist-info}/RECORD +18 -18
- {ddeutil_workflow-0.0.84.dist-info → ddeutil_workflow-0.0.86.dist-info}/WHEEL +0 -0
- {ddeutil_workflow-0.0.84.dist-info → ddeutil_workflow-0.0.86.dist-info}/entry_points.txt +0 -0
- {ddeutil_workflow-0.0.84.dist-info → ddeutil_workflow-0.0.86.dist-info}/licenses/LICENSE +0 -0
- {ddeutil_workflow-0.0.84.dist-info → ddeutil_workflow-0.0.86.dist-info}/top_level.txt +0 -0
ddeutil/workflow/traces.py
CHANGED
@@ -17,6 +17,7 @@ Functions:
|
|
17
17
|
set_logging: Configure logger with custom formatting.
|
18
18
|
get_trace: Factory function for trace instances.
|
19
19
|
"""
|
20
|
+
import contextlib
|
20
21
|
import json
|
21
22
|
import logging
|
22
23
|
import os
|
@@ -38,6 +39,7 @@ from typing import (
|
|
38
39
|
Optional,
|
39
40
|
TypeVar,
|
40
41
|
Union,
|
42
|
+
cast,
|
41
43
|
)
|
42
44
|
from zoneinfo import ZoneInfo
|
43
45
|
|
@@ -56,7 +58,12 @@ EMJ_SKIP: str = "⏭️"
|
|
56
58
|
|
57
59
|
|
58
60
|
@lru_cache
|
59
|
-
def set_logging(
|
61
|
+
def set_logging(
|
62
|
+
name: str,
|
63
|
+
*,
|
64
|
+
message_fmt: Optional[str] = None,
|
65
|
+
datetime_fmt: Optional[str] = None,
|
66
|
+
) -> logging.Logger:
|
60
67
|
"""Configure logger with custom formatting and handlers.
|
61
68
|
|
62
69
|
Creates and configures a logger instance with the custom formatter and
|
@@ -64,7 +71,9 @@ def set_logging(name: str) -> logging.Logger:
|
|
64
71
|
console output and proper formatting for workflow execution tracking.
|
65
72
|
|
66
73
|
Args:
|
67
|
-
name:
|
74
|
+
name (str): A module name to create logger for.
|
75
|
+
message_fmt: (str, default None)
|
76
|
+
datetime_fmt: (str, default None)
|
68
77
|
|
69
78
|
Returns:
|
70
79
|
logging.Logger: Configured logger instance with custom formatting.
|
@@ -81,9 +90,9 @@ def set_logging(name: str) -> logging.Logger:
|
|
81
90
|
# `logging.getLogger('ddeutil.workflow').propagate = False`
|
82
91
|
#
|
83
92
|
_logger.addHandler(logging.NullHandler())
|
84
|
-
|
85
93
|
formatter = logging.Formatter(
|
86
|
-
fmt=
|
94
|
+
fmt=message_fmt,
|
95
|
+
datefmt=datetime_fmt,
|
87
96
|
)
|
88
97
|
stream_handler = logging.StreamHandler()
|
89
98
|
stream_handler.setFormatter(formatter)
|
@@ -92,22 +101,34 @@ def set_logging(name: str) -> logging.Logger:
|
|
92
101
|
return _logger
|
93
102
|
|
94
103
|
|
104
|
+
PrefixType = Literal[
|
105
|
+
"caller",
|
106
|
+
"nested",
|
107
|
+
"stage",
|
108
|
+
"job",
|
109
|
+
"workflow",
|
110
|
+
"release",
|
111
|
+
"schedule",
|
112
|
+
"audit",
|
113
|
+
]
|
95
114
|
PREFIX_LOGS: Final[dict[str, dict]] = {
|
96
|
-
"
|
115
|
+
"caller": {
|
97
116
|
"emoji": "⚙️",
|
98
117
|
"desc": "logs from any usage from custom caller function.",
|
99
118
|
},
|
100
|
-
"
|
101
|
-
"
|
102
|
-
"
|
103
|
-
"
|
104
|
-
"
|
105
|
-
"
|
106
|
-
"
|
119
|
+
"nested": {"emoji": "⛓️", "desc": "logs from stages module."},
|
120
|
+
"stage": {"emoji": "🔗", "desc": "logs from stages module."},
|
121
|
+
"job": {"emoji": "🏗", "desc": "logs from job module."},
|
122
|
+
"workflow": {"emoji": "👟", "desc": "logs from workflow module."},
|
123
|
+
"release": {"emoji": "📅", "desc": "logs from release workflow method."},
|
124
|
+
"schedule": {"emoji": "⏰", "desc": "logs from poke workflow method."},
|
125
|
+
"audit": {"emoji": "📌", "desc": "logs from audit model."},
|
107
126
|
} # pragma: no cov
|
108
|
-
|
127
|
+
PREFIX_LOGS_UPPER: Final[Iterator[str]] = (p.upper() for p in PREFIX_LOGS)
|
128
|
+
PREFIX_DEFAULT: Final[Literal["caller"]] = "caller"
|
129
|
+
PREFIX_EMOJI_DEFAULT: Final[str] = "⚙️"
|
109
130
|
PREFIX_LOGS_REGEX: Final[re.Pattern[str]] = re.compile(
|
110
|
-
rf"(^\[(?P<
|
131
|
+
rf"(^\[(?P<module>{'|'.join(PREFIX_LOGS_UPPER)})]:\s?)?(?P<message>.*)",
|
111
132
|
re.MULTILINE | re.DOTALL | re.ASCII | re.VERBOSE,
|
112
133
|
) # pragma: no cov
|
113
134
|
|
@@ -119,42 +140,58 @@ class Message(BaseModel):
|
|
119
140
|
with emoji support and categorization.
|
120
141
|
"""
|
121
142
|
|
122
|
-
|
123
|
-
default=None,
|
143
|
+
module: Optional[PrefixType] = Field(
|
144
|
+
default=None,
|
145
|
+
description="A prefix module of message it allow to be None.",
|
124
146
|
)
|
125
147
|
message: Optional[str] = Field(default=None, description="A message.")
|
126
148
|
|
149
|
+
@field_validator("module", mode="before", json_schema_input_type=str)
|
150
|
+
def __prepare_module(cls, data: Optional[str]) -> Optional[str]:
|
151
|
+
return data.lower() if data is not None else data
|
152
|
+
|
127
153
|
@classmethod
|
128
|
-
def from_str(cls, msg: str) -> Self:
|
154
|
+
def from_str(cls, msg: str, module: Optional[PrefixType] = None) -> Self:
|
129
155
|
"""Extract message prefix from an input message.
|
130
156
|
|
131
157
|
Args:
|
132
|
-
msg: A message that want to extract.
|
158
|
+
msg (str): A message that want to extract.
|
159
|
+
module (PrefixType, default None): A prefix module type.
|
133
160
|
|
134
161
|
Returns:
|
135
162
|
Message: The validated model from a string message.
|
136
163
|
"""
|
137
|
-
|
138
|
-
|
139
|
-
|
164
|
+
msg = cls.model_validate(PREFIX_LOGS_REGEX.search(msg).groupdict())
|
165
|
+
if msg.module is None and module:
|
166
|
+
msg.module = module
|
167
|
+
return msg
|
140
168
|
|
141
169
|
def prepare(self, extras: Optional[DictData] = None) -> str:
|
142
170
|
"""Prepare message with force add prefix before writing trace log.
|
143
171
|
|
144
172
|
Args:
|
145
|
-
extras: An extra parameter that want to
|
146
|
-
`log_add_emoji` flag.
|
173
|
+
extras (DictData, default None): An extra parameter that want to
|
174
|
+
get the `log_add_emoji` flag.
|
147
175
|
|
148
176
|
Returns:
|
149
177
|
str: The prepared message with prefix and optional emoji.
|
150
178
|
"""
|
151
|
-
|
179
|
+
module = cast(PrefixType, self.module or PREFIX_DEFAULT)
|
180
|
+
module_data: dict[str, str] = PREFIX_LOGS.get(
|
181
|
+
module, {"emoji": PREFIX_EMOJI_DEFAULT}
|
182
|
+
)
|
152
183
|
emoji: str = (
|
153
|
-
f"{
|
184
|
+
f"{module_data['emoji']} "
|
154
185
|
if (extras or {}).get("log_add_emoji", True)
|
155
186
|
else ""
|
156
187
|
)
|
157
|
-
return f"{emoji}[{
|
188
|
+
return f"{emoji}[{module.upper()}]: {self.message}"
|
189
|
+
|
190
|
+
|
191
|
+
class Metric(BaseModel): # pragma: no cov
|
192
|
+
"""Trace Metric model that will validate data from current logging."""
|
193
|
+
|
194
|
+
execution_time: float
|
158
195
|
|
159
196
|
|
160
197
|
class Metadata(BaseModel): # pragma: no cov
|
@@ -172,6 +209,9 @@ class Metadata(BaseModel): # pragma: no cov
|
|
172
209
|
)
|
173
210
|
process: int = Field(description="A process ID.")
|
174
211
|
thread: int = Field(description="A thread ID.")
|
212
|
+
module: Optional[PrefixType] = Field(
|
213
|
+
default=None, description="A prefix module type."
|
214
|
+
)
|
175
215
|
message: str = Field(description="A message log.")
|
176
216
|
cut_id: Optional[str] = Field(
|
177
217
|
default=None, description="A cutting of running ID."
|
@@ -181,17 +221,6 @@ class Metadata(BaseModel): # pragma: no cov
|
|
181
221
|
filename: str = Field(description="A filename of this log.")
|
182
222
|
lineno: int = Field(description="A line number of this log.")
|
183
223
|
|
184
|
-
# Enhanced observability fields
|
185
|
-
workflow_name: Optional[str] = Field(
|
186
|
-
default=None, description="Name of the workflow being executed."
|
187
|
-
)
|
188
|
-
stage_name: Optional[str] = Field(
|
189
|
-
default=None, description="Name of the current stage being executed."
|
190
|
-
)
|
191
|
-
job_name: Optional[str] = Field(
|
192
|
-
default=None, description="Name of the current job being executed."
|
193
|
-
)
|
194
|
-
|
195
224
|
# Performance metrics
|
196
225
|
duration_ms: Optional[float] = Field(
|
197
226
|
default=None, description="Execution duration in milliseconds."
|
@@ -203,44 +232,6 @@ class Metadata(BaseModel): # pragma: no cov
|
|
203
232
|
default=None, description="CPU usage percentage at log time."
|
204
233
|
)
|
205
234
|
|
206
|
-
# Distributed tracing support
|
207
|
-
trace_id: Optional[str] = Field(
|
208
|
-
default=None,
|
209
|
-
description="OpenTelemetry trace ID for distributed tracing.",
|
210
|
-
)
|
211
|
-
span_id: Optional[str] = Field(
|
212
|
-
default=None,
|
213
|
-
description="OpenTelemetry span ID for distributed tracing.",
|
214
|
-
)
|
215
|
-
parent_span_id: Optional[str] = Field(
|
216
|
-
default=None, description="Parent span ID for correlation."
|
217
|
-
)
|
218
|
-
|
219
|
-
# Error context
|
220
|
-
exception_type: Optional[str] = Field(
|
221
|
-
default=None, description="Exception class name if error occurred."
|
222
|
-
)
|
223
|
-
exception_message: Optional[str] = Field(
|
224
|
-
default=None, description="Exception message if error occurred."
|
225
|
-
)
|
226
|
-
stack_trace: Optional[str] = Field(
|
227
|
-
default=None, description="Full stack trace if error occurred."
|
228
|
-
)
|
229
|
-
error_code: Optional[str] = Field(
|
230
|
-
default=None, description="Custom error code for categorization."
|
231
|
-
)
|
232
|
-
|
233
|
-
# Business context
|
234
|
-
user_id: Optional[str] = Field(
|
235
|
-
default=None, description="User ID who triggered the workflow."
|
236
|
-
)
|
237
|
-
tenant_id: Optional[str] = Field(
|
238
|
-
default=None, description="Tenant ID for multi-tenant environments."
|
239
|
-
)
|
240
|
-
environment: Optional[str] = Field(
|
241
|
-
default=None, description="Environment (dev, staging, prod)."
|
242
|
-
)
|
243
|
-
|
244
235
|
# NOTE: System context
|
245
236
|
hostname: Optional[str] = Field(
|
246
237
|
default=None, description="Hostname where workflow is running."
|
@@ -259,7 +250,7 @@ class Metadata(BaseModel): # pragma: no cov
|
|
259
250
|
tags: Optional[list[str]] = Field(
|
260
251
|
default_factory=list, description="Custom tags for categorization."
|
261
252
|
)
|
262
|
-
|
253
|
+
metric: Optional[DictData] = Field(
|
263
254
|
default_factory=dict, description="Additional custom metadata."
|
264
255
|
)
|
265
256
|
|
@@ -299,6 +290,8 @@ class Metadata(BaseModel): # pragma: no cov
|
|
299
290
|
run_id: str,
|
300
291
|
parent_run_id: Optional[str],
|
301
292
|
*,
|
293
|
+
metric: Optional[DictData] = None,
|
294
|
+
module: Optional[PrefixType] = None,
|
302
295
|
extras: Optional[DictData] = None,
|
303
296
|
) -> Self:
|
304
297
|
"""Make the current metric for contract this Metadata model instance.
|
@@ -313,6 +306,8 @@ class Metadata(BaseModel): # pragma: no cov
|
|
313
306
|
cutting_id: A cutting ID string.
|
314
307
|
run_id:
|
315
308
|
parent_run_id:
|
309
|
+
metric:
|
310
|
+
module:
|
316
311
|
extras: An extra parameter that want to override core
|
317
312
|
config values.
|
318
313
|
|
@@ -357,33 +352,17 @@ class Metadata(BaseModel): # pragma: no cov
|
|
357
352
|
),
|
358
353
|
process=os.getpid(),
|
359
354
|
thread=get_ident(),
|
355
|
+
module=module,
|
360
356
|
message=message,
|
361
357
|
cut_id=cutting_id,
|
362
358
|
run_id=run_id,
|
363
359
|
parent_run_id=parent_run_id,
|
364
360
|
filename=frame_info.filename.split(os.path.sep)[-1],
|
365
361
|
lineno=frame_info.lineno,
|
366
|
-
# NOTE: Enhanced observability fields
|
367
|
-
workflow_name=extras_data.get("workflow_name"),
|
368
|
-
stage_name=extras_data.get("stage_name"),
|
369
|
-
job_name=extras_data.get("job_name"),
|
370
362
|
# NOTE: Performance metrics
|
371
363
|
duration_ms=extras_data.get("duration_ms"),
|
372
364
|
memory_usage_mb=extras_data.get("memory_usage_mb"),
|
373
365
|
cpu_usage_percent=extras_data.get("cpu_usage_percent"),
|
374
|
-
# NOTE: Distributed tracing support
|
375
|
-
trace_id=extras_data.get("trace_id"),
|
376
|
-
span_id=extras_data.get("span_id"),
|
377
|
-
parent_span_id=extras_data.get("parent_span_id"),
|
378
|
-
# NOTE: Error context
|
379
|
-
exception_type=extras_data.get("exception_type"),
|
380
|
-
exception_message=extras_data.get("exception_message"),
|
381
|
-
stack_trace=extras_data.get("stack_trace"),
|
382
|
-
error_code=extras_data.get("error_code"),
|
383
|
-
# NOTE: Business context
|
384
|
-
user_id=extras_data.get("user_id"),
|
385
|
-
tenant_id=extras_data.get("tenant_id"),
|
386
|
-
environment=extras_data.get("environment"),
|
387
366
|
# NOTE: System context
|
388
367
|
hostname=hostname,
|
389
368
|
ip_address=ip_address,
|
@@ -391,11 +370,17 @@ class Metadata(BaseModel): # pragma: no cov
|
|
391
370
|
package_version=__version__,
|
392
371
|
# NOTE: Custom metadata
|
393
372
|
tags=extras_data.get("tags", []),
|
394
|
-
|
373
|
+
metric=metric,
|
395
374
|
)
|
396
375
|
|
397
376
|
@property
|
398
|
-
def pointer_id(self):
|
377
|
+
def pointer_id(self) -> str:
|
378
|
+
"""Pointer ID of trace metadata.
|
379
|
+
|
380
|
+
Returns:
|
381
|
+
str: A pointer ID that will choose from parent running ID or running
|
382
|
+
ID.
|
383
|
+
"""
|
399
384
|
return self.parent_run_id or self.run_id
|
400
385
|
|
401
386
|
|
@@ -449,6 +434,27 @@ class ConsoleHandler(BaseHandler):
|
|
449
434
|
"""Console Handler model."""
|
450
435
|
|
451
436
|
type: Literal["console"] = "console"
|
437
|
+
name: str = "ddeutil.workflow"
|
438
|
+
format: str = Field(
|
439
|
+
default=(
|
440
|
+
"%(asctime)s.%(msecs)03d (%(process)-5d, "
|
441
|
+
"%(thread)-5d) [%(levelname)-7s] (%(cut_id)s) %(message)-120s "
|
442
|
+
"(%(filename)s:%(lineno)s) (%(name)-10s)"
|
443
|
+
),
|
444
|
+
description="A log format that will use with logging package.",
|
445
|
+
)
|
446
|
+
datetime_format: str = Field(
|
447
|
+
default="%Y-%m-%d %H:%M:%S",
|
448
|
+
description="A log datetime format.",
|
449
|
+
)
|
450
|
+
|
451
|
+
def pre(self) -> None:
|
452
|
+
"""Pre-process."""
|
453
|
+
set_logging(
|
454
|
+
self.name,
|
455
|
+
message_fmt=self.format,
|
456
|
+
datetime_fmt=self.datetime_format,
|
457
|
+
)
|
452
458
|
|
453
459
|
def emit(
|
454
460
|
self, metadata: Metadata, *, extra: Optional[DictData] = None
|
@@ -512,6 +518,9 @@ class FileHandler(BaseHandler):
|
|
512
518
|
return log_file
|
513
519
|
|
514
520
|
def pre(self) -> None: # pragma: no cov
|
521
|
+
"""Pre-method that will call from getting trace model factory function.
|
522
|
+
This method will create filepath of this parent log.
|
523
|
+
"""
|
515
524
|
if not (p := Path(self.path)).exists():
|
516
525
|
p.mkdir(parents=True)
|
517
526
|
|
@@ -521,7 +530,12 @@ class FileHandler(BaseHandler):
|
|
521
530
|
*,
|
522
531
|
extra: Optional[DictData] = None,
|
523
532
|
) -> None:
|
524
|
-
"""Emit trace log.
|
533
|
+
"""Emit trace log to the file with a specific pointer path.
|
534
|
+
|
535
|
+
Args:
|
536
|
+
metadata (Metadata):
|
537
|
+
extra (DictData, default None):
|
538
|
+
"""
|
525
539
|
pointer: Path = self.pointer(metadata.pointer_id)
|
526
540
|
std_file = "stderr" if metadata.error_flag else "stdout"
|
527
541
|
with self._lock:
|
@@ -541,6 +555,7 @@ class FileHandler(BaseHandler):
|
|
541
555
|
*,
|
542
556
|
extra: Optional[DictData] = None,
|
543
557
|
) -> None: # pragma: no cove
|
558
|
+
"""Async emit trace log."""
|
544
559
|
try:
|
545
560
|
import aiofiles
|
546
561
|
except ImportError as e:
|
@@ -717,22 +732,9 @@ class SQLiteHandler(BaseHandler): # pragma: no cov
|
|
717
732
|
filename TEXT NOT NULL,
|
718
733
|
lineno INTEGER NOT NULL,
|
719
734
|
cut_id TEXT,
|
720
|
-
workflow_name TEXT,
|
721
|
-
stage_name TEXT,
|
722
|
-
job_name TEXT,
|
723
735
|
duration_ms REAL,
|
724
736
|
memory_usage_mb REAL,
|
725
737
|
cpu_usage_percent REAL,
|
726
|
-
trace_id TEXT,
|
727
|
-
span_id TEXT,
|
728
|
-
parent_span_id TEXT,
|
729
|
-
exception_type TEXT,
|
730
|
-
exception_message TEXT,
|
731
|
-
stack_trace TEXT,
|
732
|
-
error_code TEXT,
|
733
|
-
user_id TEXT,
|
734
|
-
tenant_id TEXT,
|
735
|
-
environment TEXT,
|
736
738
|
hostname TEXT,
|
737
739
|
ip_address TEXT,
|
738
740
|
python_version TEXT,
|
@@ -938,28 +940,15 @@ class SQLiteHandler(BaseHandler): # pragma: no cov
|
|
938
940
|
cut_id=record[11],
|
939
941
|
filename=record[9],
|
940
942
|
lineno=record[10],
|
941
|
-
workflow_name=record[12],
|
942
|
-
stage_name=record[13],
|
943
|
-
job_name=record[14],
|
944
943
|
duration_ms=record[15],
|
945
944
|
memory_usage_mb=record[16],
|
946
945
|
cpu_usage_percent=record[17],
|
947
|
-
trace_id=record[18],
|
948
|
-
span_id=record[19],
|
949
|
-
parent_span_id=record[20],
|
950
|
-
exception_type=record[21],
|
951
|
-
exception_message=record[22],
|
952
|
-
stack_trace=record[23],
|
953
|
-
error_code=record[24],
|
954
|
-
user_id=record[25],
|
955
|
-
tenant_id=record[26],
|
956
|
-
environment=record[27],
|
957
946
|
hostname=record[28],
|
958
947
|
ip_address=record[29],
|
959
948
|
python_version=record[30],
|
960
949
|
package_version=record[31],
|
961
950
|
tags=json.loads(record[32]) if record[32] else [],
|
962
|
-
|
951
|
+
metric=(
|
963
952
|
json.loads(record[33]) if record[33] else {}
|
964
953
|
),
|
965
954
|
)
|
@@ -1045,28 +1034,15 @@ class SQLiteHandler(BaseHandler): # pragma: no cov
|
|
1045
1034
|
cut_id=record[11],
|
1046
1035
|
filename=record[9],
|
1047
1036
|
lineno=record[10],
|
1048
|
-
workflow_name=record[12],
|
1049
|
-
stage_name=record[13],
|
1050
|
-
job_name=record[14],
|
1051
1037
|
duration_ms=record[15],
|
1052
1038
|
memory_usage_mb=record[16],
|
1053
1039
|
cpu_usage_percent=record[17],
|
1054
|
-
trace_id=record[18],
|
1055
|
-
span_id=record[19],
|
1056
|
-
parent_span_id=record[20],
|
1057
|
-
exception_type=record[21],
|
1058
|
-
exception_message=record[22],
|
1059
|
-
stack_trace=record[23],
|
1060
|
-
error_code=record[24],
|
1061
|
-
user_id=record[25],
|
1062
|
-
tenant_id=record[26],
|
1063
|
-
environment=record[27],
|
1064
1040
|
hostname=record[28],
|
1065
1041
|
ip_address=record[29],
|
1066
1042
|
python_version=record[30],
|
1067
1043
|
package_version=record[31],
|
1068
1044
|
tags=json.loads(record[32]) if record[32] else [],
|
1069
|
-
|
1045
|
+
metric=json.loads(record[33]) if record[33] else {},
|
1070
1046
|
)
|
1071
1047
|
|
1072
1048
|
meta_list.append(trace_meta)
|
@@ -1394,22 +1370,9 @@ class ElasticHandler(BaseHandler): # pragma: no cov
|
|
1394
1370
|
"filename": {"type": "keyword"},
|
1395
1371
|
"lineno": {"type": "integer"},
|
1396
1372
|
"cut_id": {"type": "keyword"},
|
1397
|
-
"workflow_name": {"type": "keyword"},
|
1398
|
-
"stage_name": {"type": "keyword"},
|
1399
|
-
"job_name": {"type": "keyword"},
|
1400
1373
|
"duration_ms": {"type": "float"},
|
1401
1374
|
"memory_usage_mb": {"type": "float"},
|
1402
1375
|
"cpu_usage_percent": {"type": "float"},
|
1403
|
-
"trace_id": {"type": "keyword"},
|
1404
|
-
"span_id": {"type": "keyword"},
|
1405
|
-
"parent_span_id": {"type": "keyword"},
|
1406
|
-
"exception_type": {"type": "keyword"},
|
1407
|
-
"exception_message": {"type": "text"},
|
1408
|
-
"stack_trace": {"type": "text"},
|
1409
|
-
"error_code": {"type": "keyword"},
|
1410
|
-
"user_id": {"type": "keyword"},
|
1411
|
-
"tenant_id": {"type": "keyword"},
|
1412
|
-
"environment": {"type": "keyword"},
|
1413
1376
|
"hostname": {"type": "keyword"},
|
1414
1377
|
"ip_address": {"type": "ip"},
|
1415
1378
|
"python_version": {"type": "keyword"},
|
@@ -1453,22 +1416,9 @@ class ElasticHandler(BaseHandler): # pragma: no cov
|
|
1453
1416
|
"filename": base_data["filename"],
|
1454
1417
|
"lineno": base_data["lineno"],
|
1455
1418
|
"cut_id": base_data["cut_id"],
|
1456
|
-
"workflow_name": base_data.get("workflow_name"),
|
1457
|
-
"stage_name": base_data.get("stage_name"),
|
1458
|
-
"job_name": base_data.get("job_name"),
|
1459
1419
|
"duration_ms": base_data.get("duration_ms"),
|
1460
1420
|
"memory_usage_mb": base_data.get("memory_usage_mb"),
|
1461
1421
|
"cpu_usage_percent": base_data.get("cpu_usage_percent"),
|
1462
|
-
"trace_id": base_data.get("trace_id"),
|
1463
|
-
"span_id": base_data.get("span_id"),
|
1464
|
-
"parent_span_id": base_data.get("parent_span_id"),
|
1465
|
-
"exception_type": base_data.get("exception_type"),
|
1466
|
-
"exception_message": base_data.get("exception_message"),
|
1467
|
-
"stack_trace": base_data.get("stack_trace"),
|
1468
|
-
"error_code": base_data.get("error_code"),
|
1469
|
-
"user_id": base_data.get("user_id"),
|
1470
|
-
"tenant_id": base_data.get("tenant_id"),
|
1471
|
-
"environment": base_data.get("environment"),
|
1472
1422
|
"hostname": base_data.get("hostname"),
|
1473
1423
|
"ip_address": base_data.get("ip_address"),
|
1474
1424
|
"python_version": base_data.get("python_version"),
|
@@ -1587,28 +1537,15 @@ class ElasticHandler(BaseHandler): # pragma: no cov
|
|
1587
1537
|
cut_id=source.get("cut_id"),
|
1588
1538
|
filename=source["filename"],
|
1589
1539
|
lineno=source["lineno"],
|
1590
|
-
workflow_name=source.get("workflow_name"),
|
1591
|
-
stage_name=source.get("stage_name"),
|
1592
|
-
job_name=source.get("job_name"),
|
1593
1540
|
duration_ms=source.get("duration_ms"),
|
1594
1541
|
memory_usage_mb=source.get("memory_usage_mb"),
|
1595
1542
|
cpu_usage_percent=source.get("cpu_usage_percent"),
|
1596
|
-
trace_id=source.get("trace_id"),
|
1597
|
-
span_id=source.get("span_id"),
|
1598
|
-
parent_span_id=source.get("parent_span_id"),
|
1599
|
-
exception_type=source.get("exception_type"),
|
1600
|
-
exception_message=source.get("exception_message"),
|
1601
|
-
stack_trace=source.get("stack_trace"),
|
1602
|
-
error_code=source.get("error_code"),
|
1603
|
-
user_id=source.get("user_id"),
|
1604
|
-
tenant_id=source.get("tenant_id"),
|
1605
|
-
environment=source.get("environment"),
|
1606
1543
|
hostname=source.get("hostname"),
|
1607
1544
|
ip_address=source.get("ip_address"),
|
1608
1545
|
python_version=source.get("python_version"),
|
1609
1546
|
package_version=source.get("package_version"),
|
1610
1547
|
tags=source.get("tags", []),
|
1611
|
-
|
1548
|
+
metric=source.get("metric", {}),
|
1612
1549
|
)
|
1613
1550
|
|
1614
1551
|
meta_list.append(trace_meta)
|
@@ -1697,28 +1634,15 @@ class ElasticHandler(BaseHandler): # pragma: no cov
|
|
1697
1634
|
cut_id=source.get("cut_id"),
|
1698
1635
|
filename=source["filename"],
|
1699
1636
|
lineno=source["lineno"],
|
1700
|
-
workflow_name=source.get("workflow_name"),
|
1701
|
-
stage_name=source.get("stage_name"),
|
1702
|
-
job_name=source.get("job_name"),
|
1703
1637
|
duration_ms=source.get("duration_ms"),
|
1704
1638
|
memory_usage_mb=source.get("memory_usage_mb"),
|
1705
1639
|
cpu_usage_percent=source.get("cpu_usage_percent"),
|
1706
|
-
trace_id=source.get("trace_id"),
|
1707
|
-
span_id=source.get("span_id"),
|
1708
|
-
parent_span_id=source.get("parent_span_id"),
|
1709
|
-
exception_type=source.get("exception_type"),
|
1710
|
-
exception_message=source.get("exception_message"),
|
1711
|
-
stack_trace=source.get("stack_trace"),
|
1712
|
-
error_code=source.get("error_code"),
|
1713
|
-
user_id=source.get("user_id"),
|
1714
|
-
tenant_id=source.get("tenant_id"),
|
1715
|
-
environment=source.get("environment"),
|
1716
1640
|
hostname=source.get("hostname"),
|
1717
1641
|
ip_address=source.get("ip_address"),
|
1718
1642
|
python_version=source.get("python_version"),
|
1719
1643
|
package_version=source.get("package_version"),
|
1720
1644
|
tags=source.get("tags", []),
|
1721
|
-
|
1645
|
+
metric=source.get("metric", {}),
|
1722
1646
|
)
|
1723
1647
|
|
1724
1648
|
meta_list.append(trace_meta)
|
@@ -1774,71 +1698,94 @@ class BaseEmit(ABC):
|
|
1774
1698
|
self,
|
1775
1699
|
msg: str,
|
1776
1700
|
level: Level,
|
1777
|
-
|
1701
|
+
*,
|
1702
|
+
metric: Optional[DictData] = None,
|
1703
|
+
module: Optional[PrefixType] = None,
|
1704
|
+
) -> None:
|
1778
1705
|
"""Write trace log with append mode and logging this message with any
|
1779
1706
|
logging level.
|
1780
1707
|
|
1781
1708
|
Args:
|
1782
1709
|
msg: A message that want to log.
|
1783
1710
|
level: A logging level.
|
1711
|
+
metric (DictData, default None): A metric data that want to export
|
1712
|
+
to each target handler.
|
1713
|
+
module (PrefixType, default None): A module name that use for adding
|
1714
|
+
prefix at the message value.
|
1784
1715
|
"""
|
1785
1716
|
raise NotImplementedError(
|
1786
|
-
"
|
1717
|
+
"Emit action should be implement for making trace log."
|
1787
1718
|
)
|
1788
1719
|
|
1789
|
-
def debug(self, msg: str):
|
1720
|
+
def debug(self, msg: str, module: Optional[PrefixType] = None):
|
1790
1721
|
"""Write trace log with append mode and logging this message with the
|
1791
1722
|
DEBUG level.
|
1792
1723
|
|
1793
1724
|
Args:
|
1794
1725
|
msg: A message that want to log.
|
1726
|
+
module (PrefixType, default None): A module name that use for adding
|
1727
|
+
prefix at the message value.
|
1795
1728
|
"""
|
1796
|
-
self.emit(msg, level="debug")
|
1729
|
+
self.emit(msg, level="debug", module=module)
|
1797
1730
|
|
1798
|
-
def info(self, msg: str) -> None:
|
1731
|
+
def info(self, msg: str, module: Optional[PrefixType] = None) -> None:
|
1799
1732
|
"""Write trace log with append mode and logging this message with the
|
1800
1733
|
INFO level.
|
1801
1734
|
|
1802
1735
|
Args:
|
1803
1736
|
msg: A message that want to log.
|
1737
|
+
module (PrefixType, default None): A module name that use for adding
|
1738
|
+
prefix at the message value.
|
1804
1739
|
"""
|
1805
|
-
self.emit(msg, level="info")
|
1740
|
+
self.emit(msg, level="info", module=module)
|
1806
1741
|
|
1807
|
-
def warning(self, msg: str) -> None:
|
1742
|
+
def warning(self, msg: str, module: Optional[PrefixType] = None) -> None:
|
1808
1743
|
"""Write trace log with append mode and logging this message with the
|
1809
1744
|
WARNING level.
|
1810
1745
|
|
1811
1746
|
Args:
|
1812
1747
|
msg: A message that want to log.
|
1748
|
+
module (PrefixType, default None): A module name that use for adding
|
1749
|
+
prefix at the message value.
|
1813
1750
|
"""
|
1814
|
-
self.emit(msg, level="warning")
|
1751
|
+
self.emit(msg, level="warning", module=module)
|
1815
1752
|
|
1816
|
-
def error(self, msg: str) -> None:
|
1753
|
+
def error(self, msg: str, module: Optional[PrefixType] = None) -> None:
|
1817
1754
|
"""Write trace log with append mode and logging this message with the
|
1818
1755
|
ERROR level.
|
1819
1756
|
|
1820
1757
|
Args:
|
1821
1758
|
msg: A message that want to log.
|
1759
|
+
module (PrefixType, default None): A module name that use for adding
|
1760
|
+
prefix at the message value.
|
1822
1761
|
"""
|
1823
|
-
self.emit(msg, level="error")
|
1762
|
+
self.emit(msg, level="error", module=module)
|
1824
1763
|
|
1825
|
-
def exception(self, msg: str) -> None:
|
1764
|
+
def exception(self, msg: str, module: Optional[PrefixType] = None) -> None:
|
1826
1765
|
"""Write trace log with append mode and logging this message with the
|
1827
1766
|
EXCEPTION level.
|
1828
1767
|
|
1829
1768
|
Args:
|
1830
1769
|
msg: A message that want to log.
|
1770
|
+
module (PrefixType, default None): A module name that use for adding
|
1771
|
+
prefix at the message value.
|
1831
1772
|
"""
|
1832
|
-
self.emit(msg, level="exception")
|
1773
|
+
self.emit(msg, level="exception", module=module)
|
1833
1774
|
|
1834
1775
|
|
1835
1776
|
class BaseAsyncEmit(ABC):
|
1777
|
+
"""Base Async Emit Abstract class for mixin `amit` method and async
|
1778
|
+
logging that will use prefix with `a` charactor.
|
1779
|
+
"""
|
1836
1780
|
|
1837
1781
|
@abstractmethod
|
1838
1782
|
async def amit(
|
1839
1783
|
self,
|
1840
1784
|
msg: str,
|
1841
1785
|
level: Level,
|
1786
|
+
*,
|
1787
|
+
metric: Optional[DictData] = None,
|
1788
|
+
module: Optional[PrefixType] = None,
|
1842
1789
|
) -> None:
|
1843
1790
|
"""Async write trace log with append mode and logging this message with
|
1844
1791
|
any logging level.
|
@@ -1846,55 +1793,79 @@ class BaseAsyncEmit(ABC):
|
|
1846
1793
|
Args:
|
1847
1794
|
msg (str): A message that want to log.
|
1848
1795
|
level (Mode): A logging level.
|
1796
|
+
metric (DictData, default None): A metric data that want to export
|
1797
|
+
to each target handler.
|
1798
|
+
module (PrefixType, default None): A module name that use for adding
|
1799
|
+
prefix at the message value.
|
1849
1800
|
"""
|
1850
1801
|
raise NotImplementedError(
|
1851
1802
|
"Async Logging action should be implement for making trace log."
|
1852
1803
|
)
|
1853
1804
|
|
1854
|
-
async def adebug(
|
1805
|
+
async def adebug(
|
1806
|
+
self, msg: str, module: Optional[PrefixType] = None
|
1807
|
+
) -> None: # pragma: no cov
|
1855
1808
|
"""Async write trace log with append mode and logging this message with
|
1856
1809
|
the DEBUG level.
|
1857
1810
|
|
1858
1811
|
Args:
|
1859
1812
|
msg: A message that want to log.
|
1813
|
+
module (PrefixType, default None): A module name that use for adding
|
1814
|
+
prefix at the message value.
|
1860
1815
|
"""
|
1861
|
-
await self.amit(msg, level="debug")
|
1816
|
+
await self.amit(msg, level="debug", module=module)
|
1862
1817
|
|
1863
|
-
async def ainfo(
|
1818
|
+
async def ainfo(
|
1819
|
+
self, msg: str, module: Optional[PrefixType] = None
|
1820
|
+
) -> None: # pragma: no cov
|
1864
1821
|
"""Async write trace log with append mode and logging this message with
|
1865
1822
|
the INFO level.
|
1866
1823
|
|
1867
1824
|
Args:
|
1868
1825
|
msg: A message that want to log.
|
1826
|
+
module (PrefixType, default None): A module name that use for adding
|
1827
|
+
prefix at the message value.
|
1869
1828
|
"""
|
1870
|
-
await self.amit(msg, level="info")
|
1829
|
+
await self.amit(msg, level="info", module=module)
|
1871
1830
|
|
1872
|
-
async def awarning(
|
1831
|
+
async def awarning(
|
1832
|
+
self, msg: str, module: Optional[PrefixType] = None
|
1833
|
+
) -> None: # pragma: no cov
|
1873
1834
|
"""Async write trace log with append mode and logging this message with
|
1874
1835
|
the WARNING level.
|
1875
1836
|
|
1876
1837
|
Args:
|
1877
1838
|
msg: A message that want to log.
|
1839
|
+
module (PrefixType, default None): A module name that use for adding
|
1840
|
+
prefix at the message value.
|
1878
1841
|
"""
|
1879
|
-
await self.amit(msg, level="warning")
|
1842
|
+
await self.amit(msg, level="warning", module=module)
|
1880
1843
|
|
1881
|
-
async def aerror(
|
1844
|
+
async def aerror(
|
1845
|
+
self, msg: str, module: Optional[PrefixType] = None
|
1846
|
+
) -> None: # pragma: no cov
|
1882
1847
|
"""Async write trace log with append mode and logging this message with
|
1883
1848
|
the ERROR level.
|
1884
1849
|
|
1885
1850
|
Args:
|
1886
1851
|
msg: A message that want to log.
|
1852
|
+
module (PrefixType, default None): A module name that use for adding
|
1853
|
+
prefix at the message value.
|
1887
1854
|
"""
|
1888
|
-
await self.amit(msg, level="error")
|
1855
|
+
await self.amit(msg, level="error", module=module)
|
1889
1856
|
|
1890
|
-
async def aexception(
|
1857
|
+
async def aexception(
|
1858
|
+
self, msg: str, module: Optional[PrefixType] = None
|
1859
|
+
) -> None: # pragma: no cov
|
1891
1860
|
"""Async write trace log with append mode and logging this message with
|
1892
1861
|
the EXCEPTION level.
|
1893
1862
|
|
1894
1863
|
Args:
|
1895
1864
|
msg: A message that want to log.
|
1865
|
+
module (PrefixType, default None): A module name that use for adding
|
1866
|
+
prefix at the message value.
|
1896
1867
|
"""
|
1897
|
-
await self.amit(msg, level="exception")
|
1868
|
+
await self.amit(msg, level="exception", module=module)
|
1898
1869
|
|
1899
1870
|
|
1900
1871
|
class Trace(BaseModel, BaseEmit, BaseAsyncEmit):
|
@@ -1940,35 +1911,41 @@ class Trace(BaseModel, BaseEmit, BaseAsyncEmit):
|
|
1940
1911
|
cut_parent_run_id: str = cut_id(self.parent_run_id)
|
1941
1912
|
return f"{cut_parent_run_id} -> {cut_run_id}"
|
1942
1913
|
|
1943
|
-
def
|
1944
|
-
|
1945
|
-
|
1946
|
-
|
1947
|
-
|
1948
|
-
|
1949
|
-
|
1950
|
-
|
1951
|
-
"""
|
1952
|
-
return prepare_newline(Message.from_str(msg).prepare(self.extras))
|
1953
|
-
|
1954
|
-
def emit(self, msg: str, level: Level) -> None:
|
1914
|
+
def emit(
|
1915
|
+
self,
|
1916
|
+
msg: str,
|
1917
|
+
level: Level,
|
1918
|
+
*,
|
1919
|
+
metric: Optional[DictData] = None,
|
1920
|
+
module: Optional[PrefixType] = None,
|
1921
|
+
) -> None:
|
1955
1922
|
"""Emit a trace log to all handler. This will use synchronise process.
|
1956
1923
|
|
1957
1924
|
Args:
|
1958
1925
|
msg (str): A message.
|
1959
1926
|
level (Level): A tracing level.
|
1927
|
+
metric (DictData, default None): A metric data that want to export
|
1928
|
+
to each target handler.
|
1929
|
+
module (PrefixType, default None): A module name that use for adding
|
1930
|
+
prefix at the message value.
|
1960
1931
|
"""
|
1961
|
-
_msg:
|
1932
|
+
_msg: Message = Message.from_str(msg, module=module)
|
1962
1933
|
metadata: Metadata = Metadata.make(
|
1963
1934
|
error_flag=(level in ("error", "exception")),
|
1964
1935
|
level=level,
|
1965
|
-
|
1936
|
+
module=_msg.module,
|
1937
|
+
message=prepare_newline(_msg.prepare(self.extras)),
|
1966
1938
|
cutting_id=self.cut_id,
|
1967
1939
|
run_id=self.run_id,
|
1968
1940
|
parent_run_id=self.parent_run_id,
|
1941
|
+
metric=metric,
|
1969
1942
|
extras=self.extras,
|
1970
1943
|
)
|
1944
|
+
|
1945
|
+
# NOTE: Check enable buffer flag was set or not.
|
1971
1946
|
if not self._enable_buffer:
|
1947
|
+
|
1948
|
+
# NOTE: Start emit tracing log data to each handler.
|
1972
1949
|
for handler in self.handlers:
|
1973
1950
|
handler.emit(metadata, extra=self.extras)
|
1974
1951
|
return
|
@@ -1981,56 +1958,76 @@ class Trace(BaseModel, BaseEmit, BaseAsyncEmit):
|
|
1981
1958
|
handler.flush(self._buffer, extra=self.extras)
|
1982
1959
|
self._buffer.clear()
|
1983
1960
|
|
1984
|
-
async def amit(
|
1961
|
+
async def amit(
|
1962
|
+
self,
|
1963
|
+
msg: str,
|
1964
|
+
level: Level,
|
1965
|
+
*,
|
1966
|
+
metric: Optional[DictData] = None,
|
1967
|
+
module: Optional[PrefixType] = None,
|
1968
|
+
) -> None:
|
1985
1969
|
"""Async write trace log with append mode and logging this message with
|
1986
1970
|
any logging level.
|
1987
1971
|
|
1988
1972
|
Args:
|
1989
1973
|
msg (str): A message that want to log.
|
1990
1974
|
level (Level): A logging mode.
|
1975
|
+
metric (DictData, default None): A metric data that want to export
|
1976
|
+
to each target handler.
|
1977
|
+
module (PrefixType, default None): A module name that use for adding
|
1978
|
+
prefix at the message value.
|
1991
1979
|
"""
|
1992
|
-
_msg:
|
1980
|
+
_msg: Message = Message.from_str(msg, module=module)
|
1993
1981
|
metadata: Metadata = Metadata.make(
|
1994
1982
|
error_flag=(level in ("error", "exception")),
|
1995
1983
|
level=level,
|
1996
|
-
|
1984
|
+
module=_msg.module,
|
1985
|
+
message=prepare_newline(_msg.prepare(self.extras)),
|
1997
1986
|
cutting_id=self.cut_id,
|
1998
1987
|
run_id=self.run_id,
|
1999
1988
|
parent_run_id=self.parent_run_id,
|
1989
|
+
metric=metric,
|
2000
1990
|
extras=self.extras,
|
2001
1991
|
)
|
1992
|
+
|
1993
|
+
# NOTE: Start emit tracing log data to each handler.
|
2002
1994
|
for handler in self.handlers:
|
2003
1995
|
await handler.amit(metadata, extra=self.extras)
|
2004
1996
|
|
2005
|
-
|
1997
|
+
@contextlib.contextmanager
|
1998
|
+
def buffer(self, module: Optional[PrefixType] = None) -> Iterator[Self]:
|
2006
1999
|
"""Enter the trace for catching the logs that run so fast. It will use
|
2007
2000
|
buffer strategy to flush the logs instead emit.
|
2001
|
+
|
2002
|
+
Args:
|
2003
|
+
module (PrefixType, default None): A module name that use for adding
|
2004
|
+
prefix at the message value.
|
2005
|
+
|
2006
|
+
Yields:
|
2007
|
+
Self: Itself instance.
|
2008
2008
|
"""
|
2009
2009
|
self._enable_buffer = True
|
2010
|
-
|
2011
|
-
|
2012
|
-
|
2013
|
-
|
2014
|
-
if exc_type:
|
2015
|
-
_msg: str = self.make_message(str(exc_val))
|
2010
|
+
try:
|
2011
|
+
yield self
|
2012
|
+
except Exception as err:
|
2013
|
+
_msg: Message = Message.from_str(str(err), module=module)
|
2016
2014
|
metadata: Metadata = Metadata.make(
|
2017
2015
|
error_flag=True,
|
2018
2016
|
level="error",
|
2019
|
-
|
2017
|
+
module=_msg.module,
|
2018
|
+
message=prepare_newline(_msg.prepare(self.extras)),
|
2020
2019
|
cutting_id=self.cut_id,
|
2021
2020
|
run_id=self.run_id,
|
2022
2021
|
parent_run_id=self.parent_run_id,
|
2023
2022
|
extras=self.extras,
|
2024
2023
|
)
|
2025
2024
|
self._buffer.append(metadata)
|
2026
|
-
|
2027
|
-
|
2028
|
-
|
2029
|
-
handler
|
2030
|
-
|
2031
|
-
|
2032
|
-
# NOTE: Re-raise the exception if one occurred
|
2033
|
-
return False
|
2025
|
+
raise
|
2026
|
+
finally:
|
2027
|
+
if self._buffer:
|
2028
|
+
for handler in self.handlers:
|
2029
|
+
handler.flush(self._buffer, extra=self.extras)
|
2030
|
+
self._buffer.clear()
|
2034
2031
|
|
2035
2032
|
|
2036
2033
|
def get_trace(
|
@@ -2039,38 +2036,39 @@ def get_trace(
|
|
2039
2036
|
handlers: list[Union[DictData, Handler]] = None,
|
2040
2037
|
parent_run_id: Optional[str] = None,
|
2041
2038
|
extras: Optional[DictData] = None,
|
2042
|
-
|
2039
|
+
pre_process: bool = False,
|
2043
2040
|
) -> Trace:
|
2044
|
-
"""Get dynamic Trace instance from the core config.
|
2041
|
+
"""Get dynamic Trace instance from the core config. This function will use
|
2042
|
+
for start some process, and it wants to generated trace object.
|
2045
2043
|
|
2046
|
-
|
2047
|
-
configuration. It can be overridden by extras argument and accepts
|
2048
|
-
and parent running ID.
|
2044
|
+
This factory function returns the appropriate trace implementation based
|
2045
|
+
on configuration. It can be overridden by extras argument and accepts
|
2046
|
+
running ID and parent running ID.
|
2049
2047
|
|
2050
2048
|
Args:
|
2051
2049
|
run_id (str): A running ID.
|
2052
|
-
parent_run_id (str
|
2053
|
-
handlers (list):
|
2054
|
-
|
2055
|
-
config
|
2056
|
-
|
2050
|
+
parent_run_id (str, default None): A parent running ID.
|
2051
|
+
handlers (list[DictData | Handler], default None): A list of handler or
|
2052
|
+
mapping of handler data that want to direct pass instead use
|
2053
|
+
environment variable config.
|
2054
|
+
extras (DictData, default None): An extra parameter that want to
|
2055
|
+
override the core config values.
|
2056
|
+
pre_process (bool, default False) A flag that will auto call pre
|
2057
|
+
method after validate a trace model.
|
2057
2058
|
|
2058
2059
|
Returns:
|
2059
2060
|
Trace: The appropriate trace instance.
|
2060
2061
|
"""
|
2061
|
-
handlers: list[DictData] = dynamic(
|
2062
|
-
"trace_handlers", f=handlers, extras=extras
|
2063
|
-
)
|
2064
2062
|
trace: Trace = Trace.model_validate(
|
2065
2063
|
{
|
2066
2064
|
"run_id": run_id,
|
2067
2065
|
"parent_run_id": parent_run_id,
|
2068
|
-
"handlers": handlers,
|
2066
|
+
"handlers": dynamic("trace_handlers", f=handlers, extras=extras),
|
2069
2067
|
"extras": extras or {},
|
2070
2068
|
}
|
2071
2069
|
)
|
2072
2070
|
# NOTE: Start pre-process when start create trace.
|
2073
|
-
if
|
2071
|
+
if pre_process:
|
2074
2072
|
for handler in trace.handlers:
|
2075
2073
|
handler.pre()
|
2076
2074
|
return trace
|