Setting the file. One moment. Extract Span · Exploring APM Traces · PostHog/skills · Skills Docs(opens in a new tab)
scripts/extract_span.py
Python·86 lines·3 KB
_common
import
SPAN_KIND
,
STATUS_CODE
, fmt_duration, is_zero_id, load_trace_file, truncate
17
18
19def format_span_line(span):
20 name = span.get("name", "?")
21 return f"[{span.get('service_name', '?')}] {name} ({fmt_duration(span.get('duration_nano'))}) <{SPAN_KIND.get(span.get('kind'), span.get('kind'))}>"
22
23
24span_filter = os.environ.get("SPAN", "").lower()
25if not span_filter:
26 print("Usage: SPAN='span_name' python3 extract_span.py FILE", file=sys.stderr)
27 sys.exit(1)
28
29max_len = int(os.environ.get("MAX_LEN", "0"))
30
31spans = load_trace_file(sys.argv[1])
32if not spans:
33 print("No spans in payload.", file=sys.stderr)
34 sys.exit(1)
35
36by_id = {s.get("span_id"): s for s in spans if s.get("span_id")}
37children = {}
38for span in spans:
39 pid = span.get("parent_span_id") or ""
40 children.setdefault(pid, []).append(span)
41
42matches = [s for s in spans if span_filter in (s.get("name", "") or "").lower()]
43
44if not matches:
45 print(f"No spans matching '{span_filter}' found ({len(spans)} spans scanned).", file=sys.stderr)
46 sys.exit(1)
47
48print(f"Matched {len(matches)} span(s) for '{span_filter}'.\n")
49
50for span in matches:
51 print("=" * 80)
52 print(format_span_line(span))
53 err = " [ERROR]" if span.get("status_code") == 2 else ""
54 print(f" status: {STATUS_CODE.get(span.get('status_code'), span.get('status_code'))}{err}")
55 print(f" span_id: {span.get('span_id', '?')}")
56 print(f" parent_span_id: {span.get('parent_span_id', '?')}")
57 print(f" trace_id: {span.get('trace_id', '?')}")
58 print(f" timestamp: {span.get('timestamp', '?')}")
59 print(f" end_time: {span.get('end_time', '?')}")
60 print(f" is_root_span: {span.get('is_root_span', False)}")
61 print("=" * 80)
62
63 formatted = json.dumps(span, indent=2, default=str)
64 print("\n--- FULL ROW ---")
65 print(truncate(formatted, max_len, show_total=True))
66
67 parent_id = span.get("parent_span_id") or ""
68 parent = by_id.get(parent_id) if parent_id and not is_zero_id(parent_id) else None
69 print("\n--- PARENT ---")
70 if parent:
71 print(f" {format_span_line(parent)}")
72 print(f" span_id={parent.get('span_id', '?')}")
73 elif is_zero_id(parent_id):
74 print(" (this is a root span)")
75 else:
76 print(f" (parent {parent_id} not in payload)")
77
78 sid = span.get("span_id")
79 kids = children.get(sid, []) if sid else []
80 print(f"\n--- CHILDREN ({len(kids)}) ---")
81 for kid in sorted(kids, key=lambda s: s.get("timestamp", "")):
82 print(f" {format_span_line(kid)}")
83 print(f" span_id={kid.get('span_id', '?')}")
84 if not kids:
85 print(" (none)")
86 print()