mermaid-trace 0.4.0__py3-none-any.whl → 0.4.1__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.
- mermaid_trace/__init__.py +4 -2
- mermaid_trace/cli.py +88 -46
- mermaid_trace/core/context.py +83 -23
- mermaid_trace/core/decorators.py +112 -22
- mermaid_trace/core/events.py +134 -21
- mermaid_trace/core/formatter.py +92 -22
- mermaid_trace/handlers/async_handler.py +70 -17
- mermaid_trace/handlers/mermaid_handler.py +59 -39
- mermaid_trace/integrations/fastapi.py +54 -33
- {mermaid_trace-0.4.0.dist-info → mermaid_trace-0.4.1.dist-info}/METADATA +23 -8
- mermaid_trace-0.4.1.dist-info/RECORD +16 -0
- mermaid_trace-0.4.0.dist-info/RECORD +0 -16
- {mermaid_trace-0.4.0.dist-info → mermaid_trace-0.4.1.dist-info}/WHEEL +0 -0
- {mermaid_trace-0.4.0.dist-info → mermaid_trace-0.4.1.dist-info}/entry_points.txt +0 -0
- {mermaid_trace-0.4.0.dist-info → mermaid_trace-0.4.1.dist-info}/licenses/LICENSE +0 -0
mermaid_trace/__init__.py
CHANGED
|
@@ -29,9 +29,9 @@ Usage Example:
|
|
|
29
29
|
from .core.decorators import trace_interaction, trace
|
|
30
30
|
from .handlers.mermaid_handler import MermaidFileHandler
|
|
31
31
|
from .handlers.async_handler import AsyncMermaidHandler
|
|
32
|
-
from .core.events import FlowEvent
|
|
32
|
+
from .core.events import Event, FlowEvent
|
|
33
33
|
from .core.context import LogContext
|
|
34
|
-
from .core.formatter import MermaidFormatter
|
|
34
|
+
from .core.formatter import BaseFormatter, MermaidFormatter
|
|
35
35
|
# We don't import integrations by default to avoid hard dependencies
|
|
36
36
|
# Integrations (like FastAPI) must be imported explicitly by the user if needed.
|
|
37
37
|
|
|
@@ -126,6 +126,8 @@ __all__ = [
|
|
|
126
126
|
"MermaidFileHandler",
|
|
127
127
|
"AsyncMermaidHandler",
|
|
128
128
|
"LogContext",
|
|
129
|
+
"Event",
|
|
129
130
|
"FlowEvent",
|
|
131
|
+
"BaseFormatter",
|
|
130
132
|
"MermaidFormatter",
|
|
131
133
|
]
|
mermaid_trace/cli.py
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Command Line Interface Module
|
|
3
|
+
|
|
4
|
+
This module provides command-line functionality for MermaidTrace, primarily for
|
|
5
|
+
previewing generated Mermaid diagrams in a web browser with live reload capabilities.
|
|
6
|
+
"""
|
|
7
|
+
|
|
1
8
|
import argparse
|
|
2
9
|
import http.server
|
|
3
10
|
import socketserver
|
|
@@ -8,22 +15,21 @@ from pathlib import Path
|
|
|
8
15
|
from typing import Type, Any
|
|
9
16
|
|
|
10
17
|
try:
|
|
11
|
-
# Watchdog is an optional dependency
|
|
12
|
-
# If installed,
|
|
18
|
+
# Watchdog is an optional dependency for efficient file monitoring
|
|
19
|
+
# If installed, it enables instant file change detection
|
|
13
20
|
from watchdog.observers import Observer
|
|
14
21
|
from watchdog.events import FileSystemEventHandler
|
|
15
22
|
|
|
16
23
|
HAS_WATCHDOG = True
|
|
17
24
|
except ImportError:
|
|
18
|
-
# Fallback
|
|
25
|
+
# Fallback when watchdog is not installed (minimal install case)
|
|
19
26
|
HAS_WATCHDOG = False
|
|
20
27
|
|
|
21
|
-
# HTML Template for the preview page
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
# 3. JavaScript logic for auto-refreshing when the source file changes.
|
|
28
|
+
# HTML Template for the diagram preview page
|
|
29
|
+
# Provides a self-contained environment to render Mermaid diagrams with:
|
|
30
|
+
# 1. Mermaid.js library from CDN for diagram rendering
|
|
31
|
+
# 2. Basic CSS styling for readability and layout
|
|
32
|
+
# 3. JavaScript for auto-refreshing when the source file changes
|
|
27
33
|
HTML_TEMPLATE = """
|
|
28
34
|
<!DOCTYPE html>
|
|
29
35
|
<html lang="en">
|
|
@@ -98,47 +104,59 @@ def _create_handler(
|
|
|
98
104
|
filename: str, path: Path
|
|
99
105
|
) -> Type[http.server.SimpleHTTPRequestHandler]:
|
|
100
106
|
"""
|
|
101
|
-
Factory function to create a custom request handler class.
|
|
107
|
+
Factory function to create a custom HTTP request handler class.
|
|
102
108
|
|
|
103
109
|
This uses a closure to inject `filename` and `path` into the handler's scope,
|
|
104
110
|
allowing the `do_GET` method to access them without global variables.
|
|
105
111
|
|
|
106
112
|
Args:
|
|
107
|
-
filename (str): Display name of the file
|
|
108
|
-
path (Path): Path object to the file on disk
|
|
113
|
+
filename (str): Display name of the file being served
|
|
114
|
+
path (Path): Path object pointing to the file on disk
|
|
109
115
|
|
|
110
116
|
Returns:
|
|
111
|
-
Type[SimpleHTTPRequestHandler]: A custom handler class
|
|
117
|
+
Type[SimpleHTTPRequestHandler]: A custom request handler class
|
|
112
118
|
"""
|
|
113
119
|
|
|
114
120
|
class Handler(http.server.SimpleHTTPRequestHandler):
|
|
115
121
|
"""
|
|
116
|
-
Custom Request Handler
|
|
117
|
-
|
|
122
|
+
Custom HTTP Request Handler for serving Mermaid diagram previews.
|
|
123
|
+
|
|
124
|
+
This handler intercepts GET requests to:
|
|
125
|
+
- Serve the HTML wrapper with embedded diagram content at the root path ('/')
|
|
126
|
+
- Provide file modification time for live reload at '/_status'
|
|
127
|
+
- Fall back to default behavior for other paths
|
|
118
128
|
"""
|
|
119
129
|
|
|
120
130
|
def log_message(self, format: str, *args: Any) -> None:
|
|
121
|
-
|
|
122
|
-
|
|
131
|
+
"""
|
|
132
|
+
Suppress default request logging to keep the console clean.
|
|
133
|
+
|
|
134
|
+
Only application logs are shown, not every HTTP request.
|
|
135
|
+
"""
|
|
123
136
|
pass
|
|
124
137
|
|
|
125
138
|
def do_GET(self) -> None:
|
|
126
139
|
"""
|
|
127
|
-
Handle GET requests.
|
|
128
|
-
|
|
140
|
+
Handle GET requests for different paths.
|
|
141
|
+
|
|
142
|
+
Routes:
|
|
143
|
+
- '/' : Serves HTML wrapper with embedded Mermaid content
|
|
144
|
+
- '/_status' : Returns current file modification time for live reload
|
|
145
|
+
- other paths : Falls back to default SimpleHTTPRequestHandler behavior
|
|
129
146
|
"""
|
|
130
147
|
if self.path == "/":
|
|
148
|
+
# Serve the main HTML page with embedded diagram
|
|
131
149
|
self.send_response(200)
|
|
132
150
|
self.send_header("Content-type", "text/html")
|
|
133
151
|
self.end_headers()
|
|
134
152
|
|
|
135
153
|
try:
|
|
136
|
-
# Read
|
|
154
|
+
# Read current content of the Mermaid file
|
|
137
155
|
content = path.read_text(encoding="utf-8")
|
|
138
156
|
mtime = str(path.stat().st_mtime)
|
|
139
157
|
except Exception as e:
|
|
140
|
-
# Fallback if reading fails (e.g., file locked)
|
|
141
|
-
#
|
|
158
|
+
# Fallback if reading fails (e.g., file locked, permission error)
|
|
159
|
+
# Display error directly in the diagram area
|
|
142
160
|
content = f"sequenceDiagram\nNote right of Error: Failed to read file: {e}"
|
|
143
161
|
mtime = "0"
|
|
144
162
|
|
|
@@ -149,14 +167,15 @@ def _create_handler(
|
|
|
149
167
|
self.wfile.write(html.encode("utf-8"))
|
|
150
168
|
|
|
151
169
|
elif self.path == "/_status":
|
|
152
|
-
# API endpoint for client-side polling
|
|
153
|
-
# Returns
|
|
170
|
+
# API endpoint for client-side polling
|
|
171
|
+
# Returns current file modification time as plain text
|
|
154
172
|
self.send_response(200)
|
|
155
173
|
self.send_header("Content-type", "text/plain")
|
|
156
174
|
self.end_headers()
|
|
157
175
|
try:
|
|
158
176
|
mtime = str(path.stat().st_mtime)
|
|
159
177
|
except OSError:
|
|
178
|
+
# Fallback if file can't be accessed
|
|
160
179
|
mtime = "0"
|
|
161
180
|
self.wfile.write(mtime.encode("utf-8"))
|
|
162
181
|
|
|
@@ -169,35 +188,40 @@ def _create_handler(
|
|
|
169
188
|
|
|
170
189
|
def serve(filename: str, port: int = 8000) -> None:
|
|
171
190
|
"""
|
|
172
|
-
Starts a local HTTP server to preview
|
|
191
|
+
Starts a local HTTP server to preview Mermaid diagrams in a web browser.
|
|
173
192
|
|
|
174
|
-
This function blocks the main thread
|
|
175
|
-
|
|
193
|
+
This function blocks the main thread while running a TCP server. It automatically
|
|
194
|
+
opens the default web browser to the preview URL and supports live reload when
|
|
195
|
+
the source .mmd file changes.
|
|
176
196
|
|
|
177
197
|
Features:
|
|
178
|
-
- Serves
|
|
179
|
-
-
|
|
180
|
-
-
|
|
198
|
+
- Serves .mmd files wrapped in an HTML viewer with Mermaid.js
|
|
199
|
+
- Live reload functionality using Watchdog (if available) or client-side polling
|
|
200
|
+
- Graceful shutdown handling on Ctrl+C
|
|
201
|
+
- Automatic browser opening
|
|
181
202
|
|
|
182
203
|
Args:
|
|
183
|
-
filename (str): Path to the .mmd file to serve
|
|
184
|
-
port (int): Port to bind the server to.
|
|
204
|
+
filename (str): Path to the .mmd file to serve
|
|
205
|
+
port (int, optional): Port to bind the server to. Defaults to 8000.
|
|
185
206
|
"""
|
|
207
|
+
# Resolve the file path
|
|
186
208
|
path = Path(filename)
|
|
187
209
|
if not path.exists():
|
|
188
210
|
print(f"Error: File '{filename}' not found.")
|
|
189
211
|
sys.exit(1)
|
|
190
212
|
|
|
191
|
-
# Setup Watchdog if available
|
|
192
|
-
# Watchdog
|
|
193
|
-
# The actual browser reload is
|
|
194
|
-
# but Watchdog gives immediate feedback in the terminal.
|
|
213
|
+
# Setup Watchdog file watcher if available
|
|
214
|
+
# Watchdog provides immediate file change notifications in the terminal
|
|
215
|
+
# The actual browser reload is handled by client-side polling
|
|
195
216
|
observer = None
|
|
196
217
|
if HAS_WATCHDOG:
|
|
197
218
|
|
|
198
219
|
class FileChangeHandler(FileSystemEventHandler):
|
|
220
|
+
"""Watchdog event handler for detecting changes to the served file"""
|
|
221
|
+
|
|
199
222
|
def on_modified(self, event: Any) -> None:
|
|
200
|
-
|
|
223
|
+
"""Called when a file is modified"""
|
|
224
|
+
# Filter only for modifications to our specific file
|
|
201
225
|
if not event.is_directory and os.path.abspath(event.src_path) == str(
|
|
202
226
|
path.resolve()
|
|
203
227
|
):
|
|
@@ -212,50 +236,68 @@ def serve(filename: str, port: int = 8000) -> None:
|
|
|
212
236
|
"Watchdog not installed. Falling back to polling mode (client-side only)."
|
|
213
237
|
)
|
|
214
238
|
|
|
239
|
+
# Create the custom HTTP handler
|
|
215
240
|
HandlerClass = _create_handler(filename, path)
|
|
216
241
|
|
|
242
|
+
# Print server information
|
|
217
243
|
print(f"Serving {filename} at http://localhost:{port}")
|
|
218
244
|
print("Press Ctrl+C to stop.")
|
|
219
245
|
|
|
220
|
-
#
|
|
246
|
+
# Automatically open the default web browser to the preview URL
|
|
221
247
|
webbrowser.open(f"http://localhost:{port}")
|
|
222
248
|
|
|
223
249
|
# Start the TCP server
|
|
224
|
-
# ThreadingTCPServer
|
|
225
|
-
#
|
|
250
|
+
# Using ThreadingTCPServer to handle multiple requests concurrently
|
|
251
|
+
# This ensures browser polling doesn't block the initial page load
|
|
226
252
|
with socketserver.ThreadingTCPServer(("", port), HandlerClass) as httpd:
|
|
227
253
|
try:
|
|
254
|
+
# Serve forever until interrupted
|
|
228
255
|
httpd.serve_forever()
|
|
229
256
|
except KeyboardInterrupt:
|
|
257
|
+
# Handle Ctrl+C gracefully
|
|
230
258
|
print("\nStopping server...")
|
|
259
|
+
# Stop the watchdog observer if it was started
|
|
231
260
|
if observer:
|
|
232
261
|
observer.stop()
|
|
233
262
|
observer.join()
|
|
263
|
+
# Close the server
|
|
234
264
|
httpd.server_close()
|
|
235
265
|
|
|
236
266
|
|
|
237
267
|
def main() -> None:
|
|
238
268
|
"""
|
|
239
269
|
Entry point for the CLI application.
|
|
240
|
-
|
|
270
|
+
|
|
271
|
+
Parses command-line arguments and dispatches to the appropriate command handler.
|
|
272
|
+
Currently supports only the 'serve' command for previewing Mermaid diagrams.
|
|
241
273
|
"""
|
|
242
|
-
|
|
243
|
-
|
|
274
|
+
# Create argument parser
|
|
275
|
+
parser = argparse.ArgumentParser(
|
|
276
|
+
description="MermaidTrace CLI - Preview Mermaid diagrams in browser"
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
# Add subparsers for different commands
|
|
280
|
+
subparsers = parser.add_subparsers(
|
|
281
|
+
dest="command", required=True, help="Available commands"
|
|
282
|
+
)
|
|
244
283
|
|
|
245
|
-
# 'serve' command
|
|
284
|
+
# Define 'serve' command for previewing diagrams
|
|
246
285
|
serve_parser = subparsers.add_parser(
|
|
247
|
-
"serve", help="Serve a Mermaid file in the browser"
|
|
286
|
+
"serve", help="Serve a Mermaid file in the browser with live reload"
|
|
248
287
|
)
|
|
249
|
-
serve_parser.add_argument("file", help="Path to the .mmd file")
|
|
288
|
+
serve_parser.add_argument("file", help="Path to the .mmd file to serve")
|
|
250
289
|
serve_parser.add_argument(
|
|
251
290
|
"--port", type=int, default=8000, help="Port to bind to (default: 8000)"
|
|
252
291
|
)
|
|
253
292
|
|
|
293
|
+
# Parse arguments and execute command
|
|
254
294
|
args = parser.parse_args()
|
|
255
295
|
|
|
256
296
|
if args.command == "serve":
|
|
297
|
+
# Execute the serve command
|
|
257
298
|
serve(args.file, args.port)
|
|
258
299
|
|
|
259
300
|
|
|
260
301
|
if __name__ == "__main__":
|
|
302
|
+
# Run the main function when script is executed directly
|
|
261
303
|
main()
|
mermaid_trace/core/context.py
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Log Context Management Module
|
|
3
|
+
|
|
4
|
+
This module provides a thread-safe, async-friendly context management system
|
|
5
|
+
for tracking execution context across the application. It uses Python's ContextVar
|
|
6
|
+
mechanism to ensure proper context propagation in both synchronous and asynchronous
|
|
7
|
+
environments.
|
|
8
|
+
"""
|
|
9
|
+
|
|
1
10
|
from contextvars import ContextVar, Token
|
|
2
11
|
from contextlib import asynccontextmanager, contextmanager
|
|
3
12
|
from typing import Any, AsyncIterator, Dict, Iterator
|
|
@@ -9,16 +18,14 @@ class LogContext:
|
|
|
9
18
|
Manages global context information for logging (e.g., request_id, user_id, current_participant).
|
|
10
19
|
|
|
11
20
|
This class utilizes `contextvars.ContextVar` to ensure thread-safety and
|
|
12
|
-
correct context propagation in asynchronous (asyncio) environments.
|
|
13
|
-
|
|
21
|
+
correct context propagation in asynchronous (asyncio) environments. Unlike
|
|
22
|
+
`threading.local()`, `ContextVar` works natively with Python's async/await
|
|
14
23
|
event loop, ensuring that context is preserved across `await` points but isolated
|
|
15
24
|
between different concurrent tasks.
|
|
16
25
|
"""
|
|
17
26
|
|
|
18
|
-
# ContextVar
|
|
19
|
-
#
|
|
20
|
-
# "log_context" is the name of the variable, useful for debugging.
|
|
21
|
-
# The default value is implicitly an empty state if not set (handled in _get_store).
|
|
27
|
+
# ContextVar stores a dictionary unique to the current execution context (Task/Thread)
|
|
28
|
+
# The name "log_context" is used for debugging purposes
|
|
22
29
|
_context_store: ContextVar[Dict[str, Any]] = ContextVar("log_context")
|
|
23
30
|
|
|
24
31
|
@classmethod
|
|
@@ -27,13 +34,19 @@ class LogContext:
|
|
|
27
34
|
Retrieves the current context dictionary.
|
|
28
35
|
|
|
29
36
|
If the context variable has not been set in the current context,
|
|
30
|
-
it
|
|
31
|
-
and
|
|
37
|
+
it creates a fresh empty dictionary, sets it to the contextvar,
|
|
38
|
+
and returns it. This prevents LookupError and ensures there's
|
|
39
|
+
always a valid dictionary to work with.
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
Dict[str, Any]: Current context dictionary for the execution flow
|
|
32
43
|
"""
|
|
33
44
|
try:
|
|
34
45
|
return cls._context_store.get()
|
|
35
46
|
except LookupError:
|
|
36
|
-
|
|
47
|
+
empty_dict: Dict[str, Any] = {}
|
|
48
|
+
cls._context_store.set(empty_dict)
|
|
49
|
+
return empty_dict
|
|
37
50
|
|
|
38
51
|
@classmethod
|
|
39
52
|
def set(cls, key: str, value: Any) -> None:
|
|
@@ -42,10 +55,14 @@ class LogContext:
|
|
|
42
55
|
|
|
43
56
|
Important: ContextVars are immutable collections. To modify the context,
|
|
44
57
|
we must:
|
|
45
|
-
1. Retrieve the current dictionary
|
|
46
|
-
2. Create a shallow copy
|
|
47
|
-
3. Update the copy
|
|
48
|
-
4. Re-set the ContextVar with the new dictionary
|
|
58
|
+
1. Retrieve the current dictionary using _get_store()
|
|
59
|
+
2. Create a shallow copy to avoid affecting parent contexts
|
|
60
|
+
3. Update the copy with the new key-value pair
|
|
61
|
+
4. Re-set the ContextVar with the new dictionary
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
key (str): Name of the context variable to set
|
|
65
|
+
value (Any): Value to associate with the key
|
|
49
66
|
"""
|
|
50
67
|
ctx = cls._get_store().copy()
|
|
51
68
|
ctx[key] = value
|
|
@@ -57,7 +74,10 @@ class LogContext:
|
|
|
57
74
|
Updates multiple keys in the current context at once.
|
|
58
75
|
|
|
59
76
|
This follows the same Copy-Update-Set pattern as `set()` to maintain
|
|
60
|
-
context isolation.
|
|
77
|
+
context isolation between different execution flows.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
data (Dict[str, Any]): Dictionary of key-value pairs to update in context
|
|
61
81
|
"""
|
|
62
82
|
if not data:
|
|
63
83
|
return
|
|
@@ -69,6 +89,13 @@ class LogContext:
|
|
|
69
89
|
def get(cls, key: str, default: Any = None) -> Any:
|
|
70
90
|
"""
|
|
71
91
|
Retrieves a value from the current context safely.
|
|
92
|
+
|
|
93
|
+
Args:
|
|
94
|
+
key (str): Name of the context variable to retrieve
|
|
95
|
+
default (Any, optional): Default value if key doesn't exist. Defaults to None.
|
|
96
|
+
|
|
97
|
+
Returns:
|
|
98
|
+
Any: Value associated with the key, or default if key not found
|
|
72
99
|
"""
|
|
73
100
|
return cls._get_store().get(key, default)
|
|
74
101
|
|
|
@@ -76,6 +103,9 @@ class LogContext:
|
|
|
76
103
|
def get_all(cls) -> Dict[str, Any]:
|
|
77
104
|
"""
|
|
78
105
|
Returns a copy of the entire context dictionary.
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
Dict[str, Any]: Complete copy of the current context
|
|
79
109
|
"""
|
|
80
110
|
return cls._get_store().copy()
|
|
81
111
|
|
|
@@ -92,11 +122,17 @@ class LogContext:
|
|
|
92
122
|
# user_id reverts to previous value (or disappears) here
|
|
93
123
|
|
|
94
124
|
Mechanism:
|
|
95
|
-
1. Copies current context and updates it with new data
|
|
96
|
-
2. Sets the ContextVar to this new state, receiving a `Token
|
|
97
|
-
3. Yields control to the block
|
|
125
|
+
1. Copies current context and updates it with new data
|
|
126
|
+
2. Sets the ContextVar to this new state, receiving a `Token`
|
|
127
|
+
3. Yields control to the block
|
|
98
128
|
4. Finally, uses the `Token` to reset the ContextVar to its exact state
|
|
99
|
-
before the block entered
|
|
129
|
+
before the block entered
|
|
130
|
+
|
|
131
|
+
Args:
|
|
132
|
+
data (Dict[str, Any]): Dictionary of context values to set within the scope
|
|
133
|
+
|
|
134
|
+
Yields:
|
|
135
|
+
None: Control to the block using this context manager
|
|
100
136
|
"""
|
|
101
137
|
current_ctx = cls._get_store().copy()
|
|
102
138
|
current_ctx.update(data)
|
|
@@ -104,7 +140,7 @@ class LogContext:
|
|
|
104
140
|
try:
|
|
105
141
|
yield
|
|
106
142
|
finally:
|
|
107
|
-
#
|
|
143
|
+
# Reset restores context to state before .set() was called
|
|
108
144
|
cls._context_store.reset(token)
|
|
109
145
|
|
|
110
146
|
@classmethod
|
|
@@ -120,6 +156,12 @@ class LogContext:
|
|
|
120
156
|
This is functionally identical to `scope` but designed for `async with` blocks.
|
|
121
157
|
It ensures that even if the code inside `yield` suspends execution (await),
|
|
122
158
|
the context remains valid for that task.
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
data (Dict[str, Any]): Dictionary of context values to set within the scope
|
|
162
|
+
|
|
163
|
+
Yields:
|
|
164
|
+
None: Control to the async block using this context manager
|
|
123
165
|
"""
|
|
124
166
|
current_ctx = cls._get_store().copy()
|
|
125
167
|
current_ctx.update(data)
|
|
@@ -137,6 +179,12 @@ class LogContext:
|
|
|
137
179
|
"""
|
|
138
180
|
Replaces the entire context with the provided data.
|
|
139
181
|
Returns a Token that can be used to manually reset the context later.
|
|
182
|
+
|
|
183
|
+
Args:
|
|
184
|
+
data (Dict[str, Any]): New context dictionary to replace the current one
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
Token[Dict[str, Any]]: Token for resetting context to previous state
|
|
140
188
|
"""
|
|
141
189
|
return cls._context_store.set(data.copy())
|
|
142
190
|
|
|
@@ -144,21 +192,30 @@ class LogContext:
|
|
|
144
192
|
def reset(cls, token: Token[Dict[str, Any]]) -> None:
|
|
145
193
|
"""
|
|
146
194
|
Manually resets the context using a Token obtained from `set` or `set_all`.
|
|
195
|
+
|
|
196
|
+
Args:
|
|
197
|
+
token (Token[Dict[str, Any]]): Token returned by set_all() method
|
|
147
198
|
"""
|
|
148
199
|
cls._context_store.reset(token)
|
|
149
200
|
|
|
150
201
|
@classmethod
|
|
151
202
|
def current_participant(cls) -> str:
|
|
152
203
|
"""
|
|
153
|
-
Helper to get the 'participant' field, representing the current active object/module.
|
|
204
|
+
Helper method to get the 'participant' field, representing the current active object/module.
|
|
154
205
|
Defaults to 'Unknown' if not set.
|
|
206
|
+
|
|
207
|
+
Returns:
|
|
208
|
+
str: Name of the current participant in the trace flow
|
|
155
209
|
"""
|
|
156
210
|
return str(cls.get("participant", "Unknown"))
|
|
157
211
|
|
|
158
212
|
@classmethod
|
|
159
213
|
def set_participant(cls, name: str) -> None:
|
|
160
214
|
"""
|
|
161
|
-
Helper to set the 'participant' field.
|
|
215
|
+
Helper method to set the 'participant' field.
|
|
216
|
+
|
|
217
|
+
Args:
|
|
218
|
+
name (str): Name of the participant to set
|
|
162
219
|
"""
|
|
163
220
|
cls.set("participant", name)
|
|
164
221
|
|
|
@@ -170,9 +227,12 @@ class LogContext:
|
|
|
170
227
|
Lazy Initialization Logic:
|
|
171
228
|
If no trace_id exists in the current context, it generates a new UUIDv4
|
|
172
229
|
and sets it immediately. This ensures that:
|
|
173
|
-
1. A trace ID is always available when asked for
|
|
230
|
+
1. A trace ID is always available when asked for
|
|
174
231
|
2. Once generated, the same ID persists for the duration of the context
|
|
175
|
-
(unless manually changed), linking all subsequent logs together
|
|
232
|
+
(unless manually changed), linking all subsequent logs together
|
|
233
|
+
|
|
234
|
+
Returns:
|
|
235
|
+
str: Unique trace ID for the current execution flow
|
|
176
236
|
"""
|
|
177
237
|
tid = cls.get("trace_id")
|
|
178
238
|
if not tid:
|