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
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Asynchronous Mermaid Handler Module
|
|
3
|
+
|
|
4
|
+
This module provides a non-blocking logging handler that uses a background thread
|
|
5
|
+
for writing logs. It's designed to improve performance in high-throughput applications
|
|
6
|
+
by decoupling the logging I/O from the main execution thread.
|
|
7
|
+
"""
|
|
8
|
+
|
|
1
9
|
import logging
|
|
2
10
|
import logging.handlers
|
|
3
11
|
import queue
|
|
@@ -12,41 +20,86 @@ class AsyncMermaidHandler(logging.handlers.QueueHandler):
|
|
|
12
20
|
This handler pushes log records to a queue, which are then picked up by a
|
|
13
21
|
QueueListener running in a separate thread and dispatched to the actual
|
|
14
22
|
handlers (e.g., MermaidFileHandler).
|
|
23
|
+
|
|
24
|
+
This architecture provides several benefits:
|
|
25
|
+
- Main thread doesn't block waiting for disk I/O
|
|
26
|
+
- Logs are processed in the background
|
|
27
|
+
- Better performance in high-throughput applications
|
|
28
|
+
- Smooth handling of burst traffic
|
|
15
29
|
"""
|
|
16
30
|
|
|
17
|
-
def __init__(self, handlers: List[logging.Handler], queue_size: int =
|
|
31
|
+
def __init__(self, handlers: List[logging.Handler], queue_size: int = 1000):
|
|
18
32
|
"""
|
|
19
33
|
Initialize the async handler.
|
|
20
|
-
|
|
34
|
+
|
|
21
35
|
Args:
|
|
22
36
|
handlers: A list of handlers that should receive the logs from the queue.
|
|
23
|
-
|
|
24
|
-
queue_size: The maximum size of the queue.
|
|
37
|
+
These are typically MermaidFileHandler instances.
|
|
38
|
+
queue_size: The maximum size of the queue. Default is 1000.
|
|
39
|
+
If the queue fills up, new log records may be dropped.
|
|
25
40
|
"""
|
|
41
|
+
# Create a bounded queue with the specified size
|
|
26
42
|
self._log_queue: queue.Queue[logging.LogRecord] = queue.Queue(queue_size)
|
|
43
|
+
self._queue_size = queue_size
|
|
44
|
+
|
|
45
|
+
# Initialize parent QueueHandler with our queue
|
|
27
46
|
super().__init__(self._log_queue)
|
|
28
|
-
|
|
29
|
-
# Initialize QueueListener
|
|
47
|
+
|
|
48
|
+
# Initialize QueueListener to process records from the queue
|
|
30
49
|
# It starts an internal thread to monitor the queue
|
|
31
50
|
# respect_handler_level=True ensures the target handlers' log levels are respected
|
|
32
|
-
self._listener: Optional[logging.handlers.QueueListener] =
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
51
|
+
self._listener: Optional[logging.handlers.QueueListener] = (
|
|
52
|
+
logging.handlers.QueueListener(
|
|
53
|
+
self._log_queue, *handlers, respect_handler_level=True
|
|
54
|
+
)
|
|
36
55
|
)
|
|
56
|
+
|
|
57
|
+
# Start the listener thread
|
|
37
58
|
self._listener.start()
|
|
38
|
-
|
|
39
|
-
#
|
|
40
|
-
# This
|
|
59
|
+
|
|
60
|
+
# Register stop method to be called on program exit
|
|
61
|
+
# This ensures all pending logs are written to disk before termination
|
|
41
62
|
atexit.register(self.stop)
|
|
42
63
|
|
|
64
|
+
def emit(self, record: logging.LogRecord) -> None:
|
|
65
|
+
"""
|
|
66
|
+
Emit a log record to the queue with a timeout and drop policy.
|
|
67
|
+
|
|
68
|
+
If the queue is full, this method will attempt to put the record with
|
|
69
|
+
a short timeout. If that fails, it will drop the record and print a warning.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
record: The log record to emit
|
|
73
|
+
"""
|
|
74
|
+
from typing import cast
|
|
75
|
+
|
|
76
|
+
try:
|
|
77
|
+
# Try to put the record in the queue with a short timeout (0.1 seconds)
|
|
78
|
+
# This prevents the main thread from blocking indefinitely if the queue is full
|
|
79
|
+
# Use cast to tell Mypy this is a queue.Queue instance
|
|
80
|
+
queue_instance = cast(queue.Queue[logging.LogRecord], self.queue)
|
|
81
|
+
queue_instance.put(record, block=True, timeout=0.1)
|
|
82
|
+
except queue.Full:
|
|
83
|
+
# If queue is full, log a warning and drop the record
|
|
84
|
+
if record.levelno >= logging.WARNING:
|
|
85
|
+
# Avoid infinite recursion by not using self.logger
|
|
86
|
+
print(
|
|
87
|
+
f"WARNING: AsyncMermaidHandler queue is full (size: {self._queue_size}), dropping log record: {record.msg}"
|
|
88
|
+
)
|
|
89
|
+
|
|
43
90
|
def stop(self) -> None:
|
|
44
91
|
"""
|
|
45
|
-
Stops the listener and flushes the queue.
|
|
92
|
+
Stops the listener and flushes all pending logs from the queue.
|
|
46
93
|
|
|
47
|
-
This is registered with `atexit` to ensure that all pending logs
|
|
94
|
+
This method is registered with `atexit` to ensure that all pending logs
|
|
48
95
|
are written to disk before the application terminates.
|
|
49
96
|
"""
|
|
50
97
|
if self._listener:
|
|
51
|
-
|
|
52
|
-
|
|
98
|
+
try:
|
|
99
|
+
# Stop the listener - this will process all remaining records in the queue
|
|
100
|
+
self._listener.stop()
|
|
101
|
+
self._listener = None
|
|
102
|
+
except queue.Full:
|
|
103
|
+
# Handle case where queue is full when trying to put sentinel value
|
|
104
|
+
# The listener thread may still be processing, but we can safely exit
|
|
105
|
+
pass
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Mermaid File Handler Module
|
|
3
|
+
|
|
4
|
+
This module provides a custom logging handler that writes FlowEvent objects to
|
|
5
|
+
Mermaid (.mmd) files. It handles the Mermaid syntax formatting, file headers, and
|
|
6
|
+
ensures thread-safe file writing.
|
|
7
|
+
"""
|
|
8
|
+
|
|
1
9
|
import logging
|
|
2
10
|
import os
|
|
3
11
|
|
|
@@ -26,24 +34,23 @@ class MermaidFileHandler(logging.FileHandler):
|
|
|
26
34
|
delay: bool = False,
|
|
27
35
|
):
|
|
28
36
|
"""
|
|
29
|
-
Initialize the handler.
|
|
37
|
+
Initialize the Mermaid file handler.
|
|
30
38
|
|
|
31
39
|
Args:
|
|
32
40
|
filename (str): The path to the output .mmd file.
|
|
33
|
-
title (str): The title of the Mermaid diagram
|
|
34
|
-
mode (str): File open mode. 'w' (overwrite) or 'a' (append).
|
|
35
|
-
encoding (str): File encoding. Defaults to
|
|
36
|
-
delay (bool): If True, file opening is deferred until the first call to emit.
|
|
37
|
-
|
|
41
|
+
title (str, optional): The title of the Mermaid diagram. Defaults to "Log Flow".
|
|
42
|
+
mode (str, optional): File open mode. 'w' (overwrite) or 'a' (append). Defaults to "a".
|
|
43
|
+
encoding (str, optional): File encoding. Defaults to "utf-8".
|
|
44
|
+
delay (bool, optional): If True, file opening is deferred until the first call to emit.
|
|
45
|
+
Useful to avoid creating empty files if no logs occur. Defaults to False.
|
|
38
46
|
"""
|
|
39
|
-
# Ensure directory exists to prevent FileNotFoundError
|
|
47
|
+
# Ensure the directory exists to prevent FileNotFoundError when opening the file
|
|
40
48
|
os.makedirs(os.path.dirname(os.path.abspath(filename)) or ".", exist_ok=True)
|
|
41
49
|
|
|
42
|
-
#
|
|
43
|
-
#
|
|
44
|
-
# 1. We are overwriting the file (mode='w')
|
|
45
|
-
# 2. We are appending (mode='a')
|
|
46
|
-
# This prevents invalid Mermaid files (e.g., multiple "sequenceDiagram" lines).
|
|
50
|
+
# Determine if we need to write a header
|
|
51
|
+
# Header is written only if:
|
|
52
|
+
# 1. We are overwriting the file (mode='w'), or
|
|
53
|
+
# 2. We are appending (mode='a') but the file doesn't exist or is empty
|
|
47
54
|
should_write_header = False
|
|
48
55
|
if mode == "w":
|
|
49
56
|
should_write_header = True
|
|
@@ -51,49 +58,62 @@ class MermaidFileHandler(logging.FileHandler):
|
|
|
51
58
|
if not os.path.exists(filename) or os.path.getsize(filename) == 0:
|
|
52
59
|
should_write_header = True
|
|
53
60
|
|
|
54
|
-
# Initialize
|
|
61
|
+
# Initialize the parent FileHandler (opens the file unless delay=True)
|
|
55
62
|
super().__init__(filename, mode, encoding, delay)
|
|
56
63
|
self.title = title
|
|
57
64
|
|
|
58
|
-
# Write header immediately if needed
|
|
65
|
+
# Write the header immediately if needed
|
|
59
66
|
if should_write_header:
|
|
60
67
|
self._write_header()
|
|
61
68
|
|
|
62
69
|
def _write_header(self) -> None:
|
|
63
70
|
"""
|
|
64
|
-
Writes the initial Mermaid syntax lines.
|
|
71
|
+
Writes the initial Mermaid syntax lines to the file.
|
|
72
|
+
|
|
73
|
+
This setup is required for Mermaid JS or Live Editor to render the diagram correctly.
|
|
74
|
+
It defines:
|
|
75
|
+
- Diagram type (sequenceDiagram)
|
|
76
|
+
- Title of the diagram
|
|
77
|
+
- Autonumbering of steps
|
|
65
78
|
|
|
66
|
-
|
|
67
|
-
|
|
79
|
+
Thread Safety: Uses the handler's internal lock to prevent concurrent writes
|
|
80
|
+
when delay=True, ensuring the header is written only once.
|
|
68
81
|
"""
|
|
69
|
-
#
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
self.stream
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
# Use the handler's internal lock to ensure thread safety
|
|
83
|
+
assert self.lock is not None, "Handler lock should always be initialized"
|
|
84
|
+
with self.lock:
|
|
85
|
+
# Write to the existing stream if available, otherwise open temporarily
|
|
86
|
+
if self.stream:
|
|
87
|
+
# Stream is already open (delay=False or emit() has been called)
|
|
88
|
+
self.stream.write("sequenceDiagram\n")
|
|
89
|
+
self.stream.write(f" title {self.title}\n")
|
|
90
|
+
self.stream.write(" autonumber\n")
|
|
91
|
+
# Flush ensures the header is written to disk immediately
|
|
92
|
+
self.flush()
|
|
93
|
+
else:
|
|
94
|
+
# Handle delay=True case: file not yet opened
|
|
95
|
+
# Temporarily open the file just to write the header
|
|
96
|
+
with open(self.baseFilename, self.mode, encoding=self.encoding) as f:
|
|
97
|
+
f.write("sequenceDiagram\n")
|
|
98
|
+
f.write(f" title {self.title}\n")
|
|
99
|
+
f.write(" autonumber\n")
|
|
85
100
|
|
|
86
101
|
def emit(self, record: logging.LogRecord) -> None:
|
|
87
102
|
"""
|
|
88
|
-
Process a log record.
|
|
103
|
+
Process a log record and write it to the Mermaid file.
|
|
104
|
+
|
|
105
|
+
This method overrides the parent's emit method to filter out non-FlowEvent records.
|
|
89
106
|
|
|
90
107
|
Optimization:
|
|
91
|
-
- Checks for `flow_event` attribute first
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
108
|
+
- Checks for `flow_event` attribute first, acting as a high-performance filter
|
|
109
|
+
- Only processes records containing structured FlowEvent data
|
|
110
|
+
- Delegates actual writing to parent's emit() method, which handles locking and flushing
|
|
111
|
+
|
|
112
|
+
Args:
|
|
113
|
+
record (logging.LogRecord): The log record to process
|
|
96
114
|
"""
|
|
97
115
|
# Only process records that contain our structured FlowEvent data
|
|
116
|
+
# This allows the handler to be attached to the root logger without processing
|
|
117
|
+
# irrelevant system logs
|
|
98
118
|
if hasattr(record, "flow_event"):
|
|
99
119
|
super().emit(record)
|
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
"""
|
|
2
|
+
FastAPI Integration Module
|
|
3
|
+
|
|
4
|
+
This module provides middleware for integrating MermaidTrace with FastAPI applications.
|
|
5
|
+
It automatically traces HTTP requests and responses, converting them into Mermaid
|
|
6
|
+
sequence diagram events.
|
|
7
|
+
"""
|
|
8
|
+
|
|
1
9
|
from typing import Any, TYPE_CHECKING
|
|
2
10
|
import time
|
|
3
11
|
import uuid
|
|
@@ -6,20 +14,23 @@ from ..core.events import FlowEvent
|
|
|
6
14
|
from ..core.context import LogContext
|
|
7
15
|
from ..core.decorators import get_flow_logger
|
|
8
16
|
|
|
17
|
+
# Conditional imports to support optional FastAPI dependency
|
|
9
18
|
if TYPE_CHECKING:
|
|
19
|
+
# For type checking only, import the actual FastAPI/Starlette types
|
|
10
20
|
from fastapi import Request, Response
|
|
11
21
|
from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint
|
|
12
22
|
else:
|
|
13
23
|
try:
|
|
24
|
+
# Try to import FastAPI/Starlette at runtime
|
|
14
25
|
from fastapi import Request, Response
|
|
15
26
|
from starlette.middleware.base import (
|
|
16
27
|
BaseHTTPMiddleware,
|
|
17
28
|
RequestResponseEndpoint,
|
|
18
29
|
)
|
|
19
30
|
except ImportError:
|
|
20
|
-
# Handle the case where FastAPI/Starlette are not installed
|
|
21
|
-
#
|
|
22
|
-
#
|
|
31
|
+
# Handle the case where FastAPI/Starlette are not installed
|
|
32
|
+
# Define dummy types to prevent NameErrors at import time
|
|
33
|
+
# Instantiation will fail explicitly in __init__
|
|
23
34
|
BaseHTTPMiddleware = object # type: ignore[misc,assignment]
|
|
24
35
|
Request = Any # type: ignore[assignment]
|
|
25
36
|
Response = Any # type: ignore[assignment]
|
|
@@ -30,11 +41,12 @@ class MermaidTraceMiddleware(BaseHTTPMiddleware):
|
|
|
30
41
|
"""
|
|
31
42
|
FastAPI Middleware to trace HTTP requests as interactions in the sequence diagram.
|
|
32
43
|
|
|
33
|
-
This middleware acts as the entry point for tracing
|
|
34
|
-
1.
|
|
35
|
-
2.
|
|
36
|
-
3.
|
|
37
|
-
4.
|
|
44
|
+
This middleware acts as the entry point for tracing web requests, handling:
|
|
45
|
+
1. Identification of the client (Source participant)
|
|
46
|
+
2. Logging of incoming requests
|
|
47
|
+
3. Initialization of the `LogContext` for the request lifecycle
|
|
48
|
+
4. Logging of responses or errors
|
|
49
|
+
5. Cleanup of context after request completion
|
|
38
50
|
"""
|
|
39
51
|
|
|
40
52
|
def __init__(self, app: Any, app_name: str = "FastAPI"):
|
|
@@ -42,13 +54,19 @@ class MermaidTraceMiddleware(BaseHTTPMiddleware):
|
|
|
42
54
|
Initialize the middleware.
|
|
43
55
|
|
|
44
56
|
Args:
|
|
45
|
-
app: The FastAPI application instance
|
|
46
|
-
app_name: The name of this service to appear in the diagram (e.g., "UserAPI")
|
|
57
|
+
app: The FastAPI application instance
|
|
58
|
+
app_name: The name of this service to appear in the diagram (e.g., "UserAPI")
|
|
59
|
+
|
|
60
|
+
Raises:
|
|
61
|
+
ImportError: If FastAPI/Starlette are not installed
|
|
47
62
|
"""
|
|
63
|
+
# Check if FastAPI is installed by verifying BaseHTTPMiddleware is not our dummy object
|
|
48
64
|
if BaseHTTPMiddleware is object: # type: ignore[comparison-overlap]
|
|
49
65
|
raise ImportError(
|
|
50
66
|
"FastAPI/Starlette is required to use MermaidTraceMiddleware"
|
|
51
67
|
)
|
|
68
|
+
|
|
69
|
+
# Initialize the parent BaseHTTPMiddleware
|
|
52
70
|
super().__init__(app)
|
|
53
71
|
self.app_name = app_name
|
|
54
72
|
|
|
@@ -56,31 +74,35 @@ class MermaidTraceMiddleware(BaseHTTPMiddleware):
|
|
|
56
74
|
self, request: Request, call_next: RequestResponseEndpoint
|
|
57
75
|
) -> Response:
|
|
58
76
|
"""
|
|
59
|
-
Intercepts
|
|
77
|
+
Intercepts and processes incoming HTTP requests.
|
|
78
|
+
|
|
79
|
+
This method is called for each incoming request and handles the full
|
|
80
|
+
request-response cycle tracing.
|
|
60
81
|
|
|
61
82
|
Args:
|
|
62
|
-
request (Request): The incoming HTTP request
|
|
63
|
-
call_next (
|
|
83
|
+
request (Request): The incoming HTTP request object
|
|
84
|
+
call_next (RequestResponseEndpoint): Function to call the next middleware or endpoint
|
|
64
85
|
|
|
65
86
|
Returns:
|
|
66
|
-
Response: The HTTP response
|
|
87
|
+
Response: The HTTP response object
|
|
67
88
|
"""
|
|
68
|
-
# 1. Determine Source (Client)
|
|
69
|
-
# Try to get a specific ID from
|
|
70
|
-
# otherwise fallback to "Client"
|
|
89
|
+
# 1. Determine Source (Client participant)
|
|
90
|
+
# Try to get a specific ID from X-Source header (useful for distributed tracing),
|
|
91
|
+
# otherwise fallback to "Client"
|
|
71
92
|
source = request.headers.get("X-Source", "Client")
|
|
72
93
|
|
|
73
|
-
# Determine Trace ID
|
|
74
|
-
# Check X-Trace-ID header or generate new UUID
|
|
94
|
+
# 2. Determine Trace ID
|
|
95
|
+
# Check for X-Trace-ID header (for distributed tracing) or generate new UUID
|
|
75
96
|
trace_id = request.headers.get("X-Trace-ID") or str(uuid.uuid4())
|
|
76
97
|
|
|
77
|
-
#
|
|
78
|
-
# Format: "METHOD /path" (e.g., "GET /users")
|
|
98
|
+
# 3. Determine Action name
|
|
99
|
+
# Format: "METHOD /path" (e.g., "GET /users", "POST /items")
|
|
79
100
|
action = f"{request.method} {request.url.path}"
|
|
80
101
|
|
|
81
102
|
logger = get_flow_logger()
|
|
82
103
|
|
|
83
|
-
#
|
|
104
|
+
# 4. Log Request (Source -> App)
|
|
105
|
+
# Create and log the initial request event
|
|
84
106
|
req_event = FlowEvent(
|
|
85
107
|
source=source,
|
|
86
108
|
target=self.app_name,
|
|
@@ -93,21 +115,20 @@ class MermaidTraceMiddleware(BaseHTTPMiddleware):
|
|
|
93
115
|
f"{source}->{self.app_name}: {action}", extra={"flow_event": req_event}
|
|
94
116
|
)
|
|
95
117
|
|
|
96
|
-
#
|
|
97
|
-
#
|
|
98
|
-
#
|
|
99
|
-
# This includes route handlers, dependencies, and other middlewares called after this one.
|
|
118
|
+
# 5. Set Context and Process Request
|
|
119
|
+
# Use async context manager to set the current participant to the app name
|
|
120
|
+
# This context will be inherited by all code called within call_next()
|
|
100
121
|
async with LogContext.ascope(
|
|
101
122
|
{"participant": self.app_name, "trace_id": trace_id}
|
|
102
123
|
):
|
|
103
124
|
start_time = time.time()
|
|
104
125
|
try:
|
|
105
|
-
# Pass control to the
|
|
106
|
-
# This executes the actual route logic
|
|
126
|
+
# Pass control to the next middleware or endpoint
|
|
127
|
+
# This executes the actual route logic and returns the response
|
|
107
128
|
response = await call_next(request)
|
|
108
129
|
|
|
109
|
-
#
|
|
110
|
-
# Calculate execution duration
|
|
130
|
+
# 6. Log Success Response (App -> Source)
|
|
131
|
+
# Calculate execution duration in milliseconds
|
|
111
132
|
duration = (time.time() - start_time) * 1000
|
|
112
133
|
resp_event = FlowEvent(
|
|
113
134
|
source=self.app_name,
|
|
@@ -125,10 +146,9 @@ class MermaidTraceMiddleware(BaseHTTPMiddleware):
|
|
|
125
146
|
return response
|
|
126
147
|
|
|
127
148
|
except Exception as e:
|
|
128
|
-
#
|
|
149
|
+
# 7. Log Error Response (App --x Source)
|
|
129
150
|
# This captures unhandled exceptions that bubble up to the middleware
|
|
130
|
-
# Note: FastAPI's ExceptionHandlers might catch
|
|
131
|
-
# If so, you might see a successful return with 500 status instead.
|
|
151
|
+
# Note: FastAPI's ExceptionHandlers might catch some exceptions before they reach here
|
|
132
152
|
err_event = FlowEvent(
|
|
133
153
|
source=self.app_name,
|
|
134
154
|
target=source,
|
|
@@ -142,4 +162,5 @@ class MermaidTraceMiddleware(BaseHTTPMiddleware):
|
|
|
142
162
|
logger.error(
|
|
143
163
|
f"{self.app_name}-x{source}: Error", extra={"flow_event": err_event}
|
|
144
164
|
)
|
|
165
|
+
# Re-raise the exception to maintain normal error handling flow
|
|
145
166
|
raise
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mermaid-trace
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.1
|
|
4
4
|
Summary: Visualize your Python code execution flow as Mermaid Sequence Diagrams.
|
|
5
5
|
Project-URL: Documentation, https://github.com/xt765/mermaid-trace#readme
|
|
6
6
|
Project-URL: Changelog, https://github.com/xt765/mermaid-trace/blob/main/docs/en/CHANGELOG.md
|
|
@@ -63,17 +63,31 @@ Description-Content-Type: text/markdown
|
|
|
63
63
|
|
|
64
64
|
# MermaidTrace: The Python Logger That Draws Diagrams
|
|
65
65
|
|
|
66
|
-
[
|
|
67
|
-
|
|
66
|
+
🌐 **Language**: [English](README.md) | [中文](README_CN.md)
|
|
67
|
+
|
|
68
|
+
[](https://pypi.org/project/mermaid-trace/)
|
|
69
|
+
[](https://pypi.org/project/mermaid-trace/)
|
|
68
70
|
[](LICENSE)
|
|
69
71
|
[](https://github.com/xt765/mermaid-trace/actions/workflows/ci.yml)
|
|
70
72
|
[](https://codecov.io/gh/xt765/mermaid-trace)
|
|
71
73
|
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## 📋 Overview
|
|
77
|
+
|
|
72
78
|
**Stop reading logs. Start watching them.**
|
|
73
79
|
|
|
74
80
|
MermaidTrace is a specialized logging tool that automatically generates [Mermaid JS](https://mermaid.js.org/) sequence diagrams from your code execution. It's perfect for visualizing complex business logic, microservice interactions, or asynchronous flows.
|
|
75
81
|
|
|
76
|
-
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 📚 Documentation
|
|
85
|
+
|
|
86
|
+
[User Guide](docs/en/USER_GUIDE.md) · [API Reference](docs/en/API.md) · [Contributing Guidelines](docs/en/CONTRIBUTING.md) · [Changelog](docs/en/CHANGELOG.md) · [License](docs/en/LICENSE)
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## ✨ Key Features
|
|
77
91
|
|
|
78
92
|
- **Decorator-Driven**: Just add `@trace` or `@trace_interaction` to your functions.
|
|
79
93
|
- **Auto-Diagramming**: Generates `.mmd` files that can be viewed in VS Code, GitHub, or Mermaid Live Editor.
|
|
@@ -82,6 +96,8 @@ MermaidTrace is a specialized logging tool that automatically generates [Mermaid
|
|
|
82
96
|
- **FastAPI Integration**: Includes middleware for zero-config HTTP request tracing.
|
|
83
97
|
- **CLI Tool**: Built-in viewer to preview diagrams in your browser.
|
|
84
98
|
|
|
99
|
+
---
|
|
100
|
+
|
|
85
101
|
## 🚀 Quick Start
|
|
86
102
|
|
|
87
103
|
### Installation
|
|
@@ -151,15 +167,14 @@ Visualize your generated `.mmd` files instantly:
|
|
|
151
167
|
mermaid-trace serve my_flow.mmd
|
|
152
168
|
```
|
|
153
169
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
- [English Documentation](docs/en/USER_GUIDE.md)
|
|
157
|
-
- [中文文档](README_CN.md)
|
|
170
|
+
---
|
|
158
171
|
|
|
159
172
|
## 🤝 Contributing
|
|
160
173
|
|
|
161
174
|
We welcome contributions! Please see [CONTRIBUTING.md](docs/en/CONTRIBUTING.md) for details.
|
|
162
175
|
|
|
176
|
+
---
|
|
177
|
+
|
|
163
178
|
## 📄 License
|
|
164
179
|
|
|
165
180
|
MIT
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
mermaid_trace/__init__.py,sha256=ZXviz2KlX0eER7FPZJG2edsXfyDewt5iXpfGMifBoyE,5323
|
|
2
|
+
mermaid_trace/cli.py,sha256=w7xh9kvyaokcUcuwIsBAtgwcl9zW8mosXesp5e0CtHg,11224
|
|
3
|
+
mermaid_trace/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
mermaid_trace/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
mermaid_trace/core/context.py,sha256=wr-Ys3c6PsYCtbPUsQTrnaciSkP-fofxOewo4oZ27QM,8556
|
|
6
|
+
mermaid_trace/core/decorators.py,sha256=lNNx_Qj2cDJkPX67qPl3NBH946ofoJ8osqxq3oBoCgU,16164
|
|
7
|
+
mermaid_trace/core/events.py,sha256=h1g8uk1SGUj_NzefuJXYrkWO8ZuezeFjfU8IpYILnB8,5977
|
|
8
|
+
mermaid_trace/core/formatter.py,sha256=A9ULgcu3xHiG3iD6k54sQ7nm9kHceMvplVCHw_nu09I,5259
|
|
9
|
+
mermaid_trace/handlers/async_handler.py,sha256=Cbs6ZuKywf2VWwSIPNRXFOtoPArIhoYl-QHeW05hhWg,4272
|
|
10
|
+
mermaid_trace/handlers/mermaid_handler.py,sha256=rF-S3IXsMvTS-6kgGN7By-_2kqlCyMwcNgaorlci1Q8,5137
|
|
11
|
+
mermaid_trace/integrations/fastapi.py,sha256=H9Hl2pFxdbM3NwqONyJ7kAP-oGdOOnuoG3hEEbpoOjE,6487
|
|
12
|
+
mermaid_trace-0.4.1.dist-info/METADATA,sha256=JLDyn-TuDnehsO34g6GAArjIl-XN4izSVZIVulmiu6c,6539
|
|
13
|
+
mermaid_trace-0.4.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
14
|
+
mermaid_trace-0.4.1.dist-info/entry_points.txt,sha256=WS57KT_870v0A4B87QDjQUqJcddMQxbCQyYeczDAX34,57
|
|
15
|
+
mermaid_trace-0.4.1.dist-info/licenses/LICENSE,sha256=BrBog1Etiq9PdWy0SVQNVByIMD9ss4Edz-R0oXt49zA,1062
|
|
16
|
+
mermaid_trace-0.4.1.dist-info/RECORD,,
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
mermaid_trace/__init__.py,sha256=yhc-shETKioVEQEfqmCGFyVelRR3_ypeClbMR_D2oBQ,5267
|
|
2
|
-
mermaid_trace/cli.py,sha256=F5-QfnKp_Et719IKWvU5IAWZTpq9ft01ow62DqNpHdA,9477
|
|
3
|
-
mermaid_trace/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
-
mermaid_trace/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
-
mermaid_trace/core/context.py,sha256=WyTKbC_I1ge802VUj9PdUiqa-VgL1r3DQUW_y8PlG8M,6618
|
|
6
|
-
mermaid_trace/core/decorators.py,sha256=13-n6qsmWnInpKgQ0Bgnnn5aQIWkRZ7raTD2xVtKVmU,12303
|
|
7
|
-
mermaid_trace/core/events.py,sha256=TVtarp7IwfTR_C404ZWoyqBZmTtScROz5hWL0uel3G4,2857
|
|
8
|
-
mermaid_trace/core/formatter.py,sha256=6k79eBU09TSCEUcDJN1mfn-_KMld0xXfKtQTKZb8Ogw,3178
|
|
9
|
-
mermaid_trace/handlers/async_handler.py,sha256=uGC27TCgfxyvQQEiJ_7Ir1EFJdsLHBUzHEsLktEaFtM,1893
|
|
10
|
-
mermaid_trace/handlers/mermaid_handler.py,sha256=JUq5gSQepNISreUYkyucS_rk27zGIiwSYFw_Lb8lL28,4314
|
|
11
|
-
mermaid_trace/integrations/fastapi.py,sha256=GJL2H0Ypi4HqiAR-kkV4kSUTitdOj4RkhPi26GGNORM,5515
|
|
12
|
-
mermaid_trace-0.4.0.dist-info/METADATA,sha256=4oszQifzCHhgCEI0Ly1nKAUuvcF-Bs-ejCReGUOsTbo,6287
|
|
13
|
-
mermaid_trace-0.4.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
14
|
-
mermaid_trace-0.4.0.dist-info/entry_points.txt,sha256=WS57KT_870v0A4B87QDjQUqJcddMQxbCQyYeczDAX34,57
|
|
15
|
-
mermaid_trace-0.4.0.dist-info/licenses/LICENSE,sha256=BrBog1Etiq9PdWy0SVQNVByIMD9ss4Edz-R0oXt49zA,1062
|
|
16
|
-
mermaid_trace-0.4.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|