flow-debugger 1.0.2 → 1.2.0
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.
- package/README.md +14 -2
- package/assets/DASHBOARD.png +1 -0
- package/dashboard/app.js +12 -0
- package/dashboard/style.css +46 -0
- package/dist/cjs/core/TraceEngine.js +5 -0
- package/dist/cjs/core/TraceEngine.js.map +1 -1
- package/dist/cjs/core/types.js.map +1 -1
- package/dist/cjs/integrations/axios.js +6 -4
- package/dist/cjs/integrations/axios.js.map +1 -1
- package/dist/cjs/integrations/fetch.js +6 -4
- package/dist/cjs/integrations/fetch.js.map +1 -1
- package/dist/cjs/integrations/mongo.js +6 -4
- package/dist/cjs/integrations/mongo.js.map +1 -1
- package/dist/cjs/integrations/mysql.js +18 -12
- package/dist/cjs/integrations/mysql.js.map +1 -1
- package/dist/cjs/integrations/postgres.js +3 -2
- package/dist/cjs/integrations/postgres.js.map +1 -1
- package/dist/cjs/integrations/redis.js +6 -4
- package/dist/cjs/integrations/redis.js.map +1 -1
- package/dist/cjs/middleware/express.js +15 -2
- package/dist/cjs/middleware/express.js.map +1 -1
- package/dist/esm/core/TraceEngine.js +5 -0
- package/dist/esm/core/TraceEngine.js.map +1 -1
- package/dist/esm/core/types.js.map +1 -1
- package/dist/esm/integrations/axios.js +6 -4
- package/dist/esm/integrations/axios.js.map +1 -1
- package/dist/esm/integrations/fetch.js +6 -4
- package/dist/esm/integrations/fetch.js.map +1 -1
- package/dist/esm/integrations/mongo.js +6 -4
- package/dist/esm/integrations/mongo.js.map +1 -1
- package/dist/esm/integrations/mysql.js +18 -12
- package/dist/esm/integrations/mysql.js.map +1 -1
- package/dist/esm/integrations/postgres.js +3 -2
- package/dist/esm/integrations/postgres.js.map +1 -1
- package/dist/esm/integrations/redis.js +6 -4
- package/dist/esm/integrations/redis.js.map +1 -1
- package/dist/esm/middleware/express.js +15 -2
- package/dist/esm/middleware/express.js.map +1 -1
- package/dist/types/core/TraceEngine.d.ts +1 -0
- package/dist/types/core/TraceEngine.d.ts.map +1 -1
- package/dist/types/core/types.d.ts +1 -0
- package/dist/types/core/types.d.ts.map +1 -1
- package/dist/types/integrations/axios.d.ts.map +1 -1
- package/dist/types/integrations/fetch.d.ts.map +1 -1
- package/dist/types/integrations/mongo.d.ts.map +1 -1
- package/dist/types/integrations/mysql.d.ts.map +1 -1
- package/dist/types/integrations/redis.d.ts.map +1 -1
- package/flowdebuger.png +0 -0
- package/package.json +5 -5
- package/python-sdk/flow_debugger_core.py +83 -0
- package/python-sdk/middleware.py +32 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import uuid
|
|
3
|
+
from typing import List, Dict, Any, Optional, Union
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
|
|
6
|
+
class TraceStep:
|
|
7
|
+
def __init__(self, name: str, service: str = 'internal', status: str = 'success'):
|
|
8
|
+
self.name = name
|
|
9
|
+
self.service = service
|
|
10
|
+
self.status = status
|
|
11
|
+
self.classification = 'INFO'
|
|
12
|
+
self.start_time = time.time() * 1000 # ms
|
|
13
|
+
self.end_time = 0
|
|
14
|
+
self.duration = 0
|
|
15
|
+
self.offset = 0
|
|
16
|
+
self.error = None
|
|
17
|
+
self.metadata = {}
|
|
18
|
+
|
|
19
|
+
def end(self):
|
|
20
|
+
self.end_time = time.time() * 1000
|
|
21
|
+
self.duration = self.end_time - self.start_time
|
|
22
|
+
|
|
23
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
24
|
+
return {
|
|
25
|
+
'name': self.name,
|
|
26
|
+
'service': self.service,
|
|
27
|
+
'status': self.status,
|
|
28
|
+
'classification': self.classification,
|
|
29
|
+
'startTime': self.start_time,
|
|
30
|
+
'endTime': self.end_time,
|
|
31
|
+
'duration': self.duration,
|
|
32
|
+
'offset': self.offset,
|
|
33
|
+
'error': self.error,
|
|
34
|
+
'metadata': self.metadata
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
class RequestTracer:
|
|
38
|
+
def __init__(self, endpoint: str, method: str, trace_id: str = None):
|
|
39
|
+
self.trace_id = trace_id or f"py_{uuid.uuid4().hex[:12]}"
|
|
40
|
+
self.endpoint = endpoint
|
|
41
|
+
self.method = method
|
|
42
|
+
self.start_time = time.time() * 1000
|
|
43
|
+
self.steps: List[TraceStep] = []
|
|
44
|
+
self.ended = False
|
|
45
|
+
self.total_duration = 0
|
|
46
|
+
self.status_code = None
|
|
47
|
+
|
|
48
|
+
def step(self, name: str, service: str = 'internal'):
|
|
49
|
+
new_step = TraceStep(name, service)
|
|
50
|
+
new_step.offset = new_step.start_time - self.start_time
|
|
51
|
+
self.steps.append(new_step)
|
|
52
|
+
return new_step
|
|
53
|
+
|
|
54
|
+
def end(self, status_code: int = 200):
|
|
55
|
+
if self.ended:
|
|
56
|
+
return
|
|
57
|
+
self.ended = True
|
|
58
|
+
self.status_code = status_code
|
|
59
|
+
end_time = time.time() * 1000
|
|
60
|
+
self.total_duration = end_time - self.start_time
|
|
61
|
+
|
|
62
|
+
# Build final trace object
|
|
63
|
+
return self.to_dict()
|
|
64
|
+
|
|
65
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
66
|
+
return {
|
|
67
|
+
'traceId': self.trace_id,
|
|
68
|
+
'endpoint': self.endpoint,
|
|
69
|
+
'method': self.method,
|
|
70
|
+
'statusCode': self.status_code,
|
|
71
|
+
'steps': [s.to_dict() for s in self.steps],
|
|
72
|
+
'totalDuration': self.total_duration,
|
|
73
|
+
'classification': self._classify_trace(),
|
|
74
|
+
'timestamp': datetime.now().isoformat(),
|
|
75
|
+
'language': 'python'
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
def _classify_trace(self) -> str:
|
|
79
|
+
if any(s.status != 'success' for s in self.steps):
|
|
80
|
+
return 'ERROR'
|
|
81
|
+
if self.total_duration > 500:
|
|
82
|
+
return 'WARN'
|
|
83
|
+
return 'INFO'
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
import time
|
|
3
|
+
from .flow_debugger_core import RequestTracer
|
|
4
|
+
|
|
5
|
+
class FlowDebuggerFlask:
|
|
6
|
+
def __init__(self, app=None, debugger_url="http://localhost:3500/__debugger"):
|
|
7
|
+
self.debugger_url = debugger_url
|
|
8
|
+
if app is not None:
|
|
9
|
+
self.init_app(app)
|
|
10
|
+
|
|
11
|
+
def init_app(self, app):
|
|
12
|
+
@app.before_request
|
|
13
|
+
def before_request():
|
|
14
|
+
import flask
|
|
15
|
+
# Start trace
|
|
16
|
+
tracer = RequestTracer(endpoint=flask.request.path, method=flask.request.method)
|
|
17
|
+
flask.g.tracer = tracer
|
|
18
|
+
|
|
19
|
+
@app.after_request
|
|
20
|
+
def after_request(response):
|
|
21
|
+
import flask
|
|
22
|
+
tracer = getattr(flask.g, 'tracer', None)
|
|
23
|
+
if tracer:
|
|
24
|
+
trace_data = tracer.end(status_code=response.status_code)
|
|
25
|
+
# Send to Node.js dashboard API in background (sync for simple version)
|
|
26
|
+
try:
|
|
27
|
+
# In a real version, this would be buffered or async
|
|
28
|
+
# For this demo/SDK, we send it directly to the local debugger
|
|
29
|
+
requests.post(self.debugger_url, json=trace_data, timeout=0.1)
|
|
30
|
+
except:
|
|
31
|
+
pass
|
|
32
|
+
return response
|