@kopai/ui 0.0.5 → 0.1.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.
Files changed (125) hide show
  1. package/README.md +137 -0
  2. package/dist/index.cjs +5069 -3
  3. package/dist/index.d.cts +301 -3
  4. package/dist/index.d.cts.map +1 -1
  5. package/dist/index.d.mts +302 -3
  6. package/dist/index.d.mts.map +1 -1
  7. package/dist/index.mjs +5010 -3
  8. package/dist/index.mjs.map +1 -1
  9. package/package.json +25 -7
  10. package/src/components/KeyboardShortcuts/KeyboardShortcutsProvider.tsx +113 -0
  11. package/src/components/KeyboardShortcuts/ShortcutsHelpDialog.tsx +82 -0
  12. package/src/components/KeyboardShortcuts/context.ts +23 -0
  13. package/src/components/KeyboardShortcuts/index.ts +8 -0
  14. package/src/components/KeyboardShortcuts/types.ts +11 -0
  15. package/src/components/dashboard/Badge/Badge.stories.tsx +29 -0
  16. package/src/components/dashboard/Badge/index.tsx +32 -0
  17. package/src/components/dashboard/Button/Button.stories.tsx +107 -0
  18. package/src/components/dashboard/Button/index.tsx +63 -0
  19. package/src/components/dashboard/Card/Card.stories.tsx +81 -0
  20. package/src/components/dashboard/Card/index.tsx +58 -0
  21. package/src/components/dashboard/Chart/Chart.stories.tsx +48 -0
  22. package/src/components/dashboard/Chart/index.tsx +74 -0
  23. package/src/components/dashboard/DatePicker/DatePicker.stories.tsx +33 -0
  24. package/src/components/dashboard/DatePicker/index.tsx +41 -0
  25. package/src/components/dashboard/Divider/Divider.stories.tsx +17 -0
  26. package/src/components/dashboard/Divider/index.tsx +49 -0
  27. package/src/components/dashboard/Empty/Empty.stories.tsx +48 -0
  28. package/src/components/dashboard/Empty/index.tsx +46 -0
  29. package/src/components/dashboard/Grid/Grid.stories.tsx +52 -0
  30. package/src/components/dashboard/Grid/index.tsx +26 -0
  31. package/src/components/dashboard/Heading/Heading.stories.tsx +25 -0
  32. package/src/components/dashboard/Heading/index.tsx +27 -0
  33. package/src/components/dashboard/List/List.stories.tsx +37 -0
  34. package/src/components/dashboard/List/index.tsx +24 -0
  35. package/src/components/dashboard/Metric/Metric.stories.tsx +65 -0
  36. package/src/components/dashboard/Metric/index.tsx +36 -0
  37. package/src/components/dashboard/Stack/Stack.stories.tsx +61 -0
  38. package/src/components/dashboard/Stack/index.tsx +33 -0
  39. package/src/components/dashboard/Table/Table.stories.tsx +38 -0
  40. package/src/components/dashboard/Table/index.tsx +104 -0
  41. package/src/components/dashboard/Text/Text.stories.tsx +53 -0
  42. package/src/components/dashboard/Text/index.tsx +18 -0
  43. package/src/components/dashboard/index.ts +46 -0
  44. package/src/components/index.ts +17 -0
  45. package/src/components/observability/LogTimeline/LogDetailPane/AttributesTab.tsx +56 -0
  46. package/src/components/observability/LogTimeline/LogDetailPane/JsonTreeView.tsx +139 -0
  47. package/src/components/observability/LogTimeline/LogDetailPane/index.tsx +271 -0
  48. package/src/components/observability/LogTimeline/LogFilter.stories.tsx +66 -0
  49. package/src/components/observability/LogTimeline/LogFilter.test.tsx +696 -0
  50. package/src/components/observability/LogTimeline/LogFilter.tsx +674 -0
  51. package/src/components/observability/LogTimeline/LogRow.tsx +174 -0
  52. package/src/components/observability/LogTimeline/LogTimeline.stories.tsx +154 -0
  53. package/src/components/observability/LogTimeline/index.tsx +542 -0
  54. package/src/components/observability/LogTimeline/shortcuts.ts +18 -0
  55. package/src/components/observability/MetricHistogram/MetricHistogram.stories.tsx +20 -0
  56. package/src/components/observability/MetricHistogram/index.tsx +303 -0
  57. package/src/components/observability/MetricStat/MetricStat.stories.tsx +30 -0
  58. package/src/components/observability/MetricStat/index.tsx +281 -0
  59. package/src/components/observability/MetricTable/MetricTable.stories.tsx +20 -0
  60. package/src/components/observability/MetricTable/index.tsx +194 -0
  61. package/src/components/observability/MetricTimeSeries/MetricTimeSeries.stories.tsx +28 -0
  62. package/src/components/observability/MetricTimeSeries/index.tsx +462 -0
  63. package/src/components/observability/RawDataTable/RawDataTable.stories.tsx +27 -0
  64. package/src/components/observability/RawDataTable/index.tsx +131 -0
  65. package/src/components/observability/ServiceList/ServiceList.stories.tsx +20 -0
  66. package/src/components/observability/ServiceList/index.tsx +60 -0
  67. package/src/components/observability/ServiceList/shortcuts.ts +6 -0
  68. package/src/components/observability/TabBar/TabBar.stories.tsx +34 -0
  69. package/src/components/observability/TabBar/index.tsx +46 -0
  70. package/src/components/observability/TraceDetail/TraceDetail.stories.tsx +51 -0
  71. package/src/components/observability/TraceDetail/index.tsx +53 -0
  72. package/src/components/observability/TraceSearch/TraceSearch.stories.tsx +49 -0
  73. package/src/components/observability/TraceSearch/index.tsx +292 -0
  74. package/src/components/observability/TraceTimeline/DetailPane/AttributesTab.tsx +152 -0
  75. package/src/components/observability/TraceTimeline/DetailPane/EventsTab.tsx +128 -0
  76. package/src/components/observability/TraceTimeline/DetailPane/LinksTab.tsx +210 -0
  77. package/src/components/observability/TraceTimeline/DetailPane/index.tsx +174 -0
  78. package/src/components/observability/TraceTimeline/SpanRow.tsx +173 -0
  79. package/src/components/observability/TraceTimeline/TimelineBar.tsx +41 -0
  80. package/src/components/observability/TraceTimeline/Tooltip.tsx +42 -0
  81. package/src/components/observability/TraceTimeline/TraceHeader.tsx +88 -0
  82. package/src/components/observability/TraceTimeline/TraceTimeline.stories.tsx +25 -0
  83. package/src/components/observability/TraceTimeline/index.tsx +478 -0
  84. package/src/components/observability/TraceTimeline/shortcuts.ts +16 -0
  85. package/src/components/observability/__fixtures__/logs.ts +476 -0
  86. package/src/components/observability/__fixtures__/metrics.ts +216 -0
  87. package/src/components/observability/__fixtures__/raw-table.ts +204 -0
  88. package/src/components/observability/__fixtures__/services.ts +8 -0
  89. package/src/components/observability/__fixtures__/trace-summaries.ts +81 -0
  90. package/src/components/observability/__fixtures__/traces.ts +396 -0
  91. package/src/components/observability/index.ts +66 -0
  92. package/src/components/observability/renderers/OtelMetricDiscovery.tsx +77 -0
  93. package/src/components/observability/renderers/OtelMetricHistogram.tsx +29 -0
  94. package/src/components/observability/renderers/OtelMetricStat.tsx +44 -0
  95. package/src/components/observability/renderers/OtelMetricTable.tsx +29 -0
  96. package/src/components/observability/renderers/OtelMetricTimeSeries.tsx +30 -0
  97. package/src/components/observability/renderers/index.ts +5 -0
  98. package/src/components/observability/shared/LoadingSkeleton.tsx +43 -0
  99. package/src/components/observability/types.ts +113 -0
  100. package/src/components/observability/utils/attributes.ts +17 -0
  101. package/src/components/observability/utils/colors.ts +29 -0
  102. package/src/components/observability/utils/flatten-tree.ts +53 -0
  103. package/src/components/observability/utils/lttb.ts +121 -0
  104. package/src/components/observability/utils/time.ts +46 -0
  105. package/src/hooks/use-kopai-data.test.ts +296 -0
  106. package/src/hooks/use-kopai-data.ts +64 -0
  107. package/src/hooks/use-live-logs.test.ts +193 -0
  108. package/src/hooks/use-live-logs.ts +113 -0
  109. package/src/index.ts +15 -0
  110. package/src/lib/__snapshots__/generate-prompt-instructions.test.ts.snap +33 -0
  111. package/src/lib/catalog.ts +165 -0
  112. package/src/lib/component-catalog.test.ts +357 -0
  113. package/src/lib/component-catalog.ts +171 -0
  114. package/src/lib/dashboard-datasource.ts +76 -0
  115. package/src/lib/generate-prompt-instructions.test.ts +27 -0
  116. package/src/lib/generate-prompt-instructions.ts +185 -0
  117. package/src/lib/log-buffer.test.ts +88 -0
  118. package/src/lib/log-buffer.ts +62 -0
  119. package/src/lib/observability-catalog.ts +143 -0
  120. package/src/lib/renderer.test.tsx +693 -0
  121. package/src/lib/renderer.tsx +276 -0
  122. package/src/pages/observability.tsx +828 -0
  123. package/src/providers/kopai-provider.tsx +51 -0
  124. package/src/styles/globals.css +46 -0
  125. package/src/vite-env.d.ts +1 -0
@@ -0,0 +1,204 @@
1
+ import type { RawTableData } from "../types.js";
2
+
3
+ export const mockRawTableData: RawTableData = {
4
+ columns: [
5
+ "timestamp",
6
+ "service",
7
+ "method",
8
+ "path",
9
+ "status_code",
10
+ "duration_ms",
11
+ "bytes_sent",
12
+ ],
13
+ types: [
14
+ "DateTime64",
15
+ "String",
16
+ "String",
17
+ "String",
18
+ "UInt16",
19
+ "Float64",
20
+ "UInt64",
21
+ ],
22
+ rows: [
23
+ [
24
+ "2023-11-14 22:13:20.000",
25
+ "api-gateway",
26
+ "GET",
27
+ "/api/users",
28
+ 200,
29
+ 45.2,
30
+ 4096,
31
+ ],
32
+ [
33
+ "2023-11-14 22:13:20.150",
34
+ "api-gateway",
35
+ "GET",
36
+ "/api/users/123",
37
+ 200,
38
+ 32.8,
39
+ 1024,
40
+ ],
41
+ [
42
+ "2023-11-14 22:13:20.300",
43
+ "api-gateway",
44
+ "POST",
45
+ "/api/users",
46
+ 201,
47
+ 78.5,
48
+ 512,
49
+ ],
50
+ [
51
+ "2023-11-14 22:13:20.500",
52
+ "api-gateway",
53
+ "GET",
54
+ "/api/health",
55
+ 200,
56
+ 2.1,
57
+ 128,
58
+ ],
59
+ [
60
+ "2023-11-14 22:13:20.700",
61
+ "user-service",
62
+ "GET",
63
+ "/internal/users",
64
+ 200,
65
+ 28.4,
66
+ 8192,
67
+ ],
68
+ [
69
+ "2023-11-14 22:13:21.000",
70
+ "api-gateway",
71
+ "PUT",
72
+ "/api/users/456",
73
+ 200,
74
+ 65.3,
75
+ 256,
76
+ ],
77
+ [
78
+ "2023-11-14 22:13:21.200",
79
+ "auth-service",
80
+ "POST",
81
+ "/auth/validate",
82
+ 200,
83
+ 12.7,
84
+ 64,
85
+ ],
86
+ [
87
+ "2023-11-14 22:13:21.500",
88
+ "api-gateway",
89
+ "DELETE",
90
+ "/api/users/789",
91
+ 204,
92
+ 41.9,
93
+ 0,
94
+ ],
95
+ [
96
+ "2023-11-14 22:13:21.800",
97
+ "api-gateway",
98
+ "GET",
99
+ "/api/users?page=2",
100
+ 200,
101
+ 52.6,
102
+ 4096,
103
+ ],
104
+ [
105
+ "2023-11-14 22:13:22.000",
106
+ "user-service",
107
+ "GET",
108
+ "/internal/users/search",
109
+ 200,
110
+ 120.4,
111
+ 16384,
112
+ ],
113
+ [
114
+ "2023-11-14 22:13:22.300",
115
+ "api-gateway",
116
+ "POST",
117
+ "/api/users/bulk",
118
+ 400,
119
+ 15.8,
120
+ 256,
121
+ ],
122
+ [
123
+ "2023-11-14 22:13:22.500",
124
+ "auth-service",
125
+ "POST",
126
+ "/auth/token/refresh",
127
+ 200,
128
+ 8.3,
129
+ 512,
130
+ ],
131
+ [
132
+ "2023-11-14 22:13:22.800",
133
+ "api-gateway",
134
+ "GET",
135
+ "/api/users/123/orders",
136
+ 200,
137
+ 89.7,
138
+ 12288,
139
+ ],
140
+ [
141
+ "2023-11-14 22:13:23.000",
142
+ "api-gateway",
143
+ "PATCH",
144
+ "/api/users/123",
145
+ 200,
146
+ 34.2,
147
+ 128,
148
+ ],
149
+ [
150
+ "2023-11-14 22:13:23.300",
151
+ "user-service",
152
+ "POST",
153
+ "/internal/users/notify",
154
+ 202,
155
+ 5.6,
156
+ 64,
157
+ ],
158
+ [
159
+ "2023-11-14 22:13:23.500",
160
+ "api-gateway",
161
+ "GET",
162
+ "/api/users/export",
163
+ 500,
164
+ 250.1,
165
+ 0,
166
+ ],
167
+ [
168
+ "2023-11-14 22:13:23.800",
169
+ "auth-service",
170
+ "POST",
171
+ "/auth/validate",
172
+ 401,
173
+ 3.4,
174
+ 128,
175
+ ],
176
+ [
177
+ "2023-11-14 22:13:24.000",
178
+ "api-gateway",
179
+ "GET",
180
+ "/api/users",
181
+ 200,
182
+ 48.9,
183
+ 4096,
184
+ ],
185
+ [
186
+ "2023-11-14 22:13:24.200",
187
+ "api-gateway",
188
+ "POST",
189
+ "/api/users",
190
+ 422,
191
+ 11.2,
192
+ 256,
193
+ ],
194
+ [
195
+ "2023-11-14 22:13:24.500",
196
+ "user-service",
197
+ "GET",
198
+ "/internal/users/count",
199
+ 200,
200
+ 6.8,
201
+ 32,
202
+ ],
203
+ ],
204
+ };
@@ -0,0 +1,8 @@
1
+ export const mockServices = [
2
+ { name: "api-gateway" },
3
+ { name: "user-service" },
4
+ { name: "auth-service" },
5
+ { name: "cache-service" },
6
+ { name: "notification-service" },
7
+ { name: "billing-service" },
8
+ ];
@@ -0,0 +1,81 @@
1
+ import type { TraceSummary } from "../TraceSearch/index.js";
2
+
3
+ const BASE_MS = 1700000000000; // 2023-11-14T22:13:20Z
4
+
5
+ export const mockTraceSummaries: TraceSummary[] = [
6
+ {
7
+ traceId: "0af7651916cd43dd8448eb211c80319c",
8
+ rootSpanName: "GET /api/users",
9
+ serviceName: "api-gateway",
10
+ durationMs: 320,
11
+ statusCode: "OK",
12
+ timestampMs: BASE_MS,
13
+ spanCount: 8,
14
+ services: [
15
+ { name: "api-gateway", count: 3, hasError: false },
16
+ { name: "user-service", count: 3, hasError: false },
17
+ { name: "auth-service", count: 1, hasError: false },
18
+ { name: "cache-service", count: 1, hasError: false },
19
+ ],
20
+ errorCount: 0,
21
+ },
22
+ {
23
+ traceId: "1bf8762027de54ee9559fc322d91420d",
24
+ rootSpanName: "POST /api/users",
25
+ serviceName: "api-gateway",
26
+ durationMs: 95,
27
+ statusCode: "ERROR",
28
+ timestampMs: BASE_MS + 10_000,
29
+ spanCount: 4,
30
+ services: [
31
+ { name: "api-gateway", count: 3, hasError: true },
32
+ { name: "auth-service", count: 1, hasError: false },
33
+ ],
34
+ errorCount: 2,
35
+ },
36
+ {
37
+ traceId: "2cf9873138ef65ff0660ad433ea2531e",
38
+ rootSpanName: "GET /api/products",
39
+ serviceName: "api-gateway",
40
+ durationMs: 450,
41
+ statusCode: "OK",
42
+ timestampMs: BASE_MS + 25_000,
43
+ spanCount: 12,
44
+ services: [
45
+ { name: "api-gateway", count: 2, hasError: false },
46
+ { name: "product-service", count: 5, hasError: false },
47
+ { name: "cache-service", count: 3, hasError: false },
48
+ { name: "search-service", count: 2, hasError: false },
49
+ ],
50
+ errorCount: 0,
51
+ },
52
+ {
53
+ traceId: "3da0984249fa76aa1771be544fb3642f",
54
+ rootSpanName: "PUT /api/users/42",
55
+ serviceName: "api-gateway",
56
+ durationMs: 180,
57
+ statusCode: "OK",
58
+ timestampMs: BASE_MS + 42_000,
59
+ spanCount: 6,
60
+ services: [
61
+ { name: "api-gateway", count: 2, hasError: false },
62
+ { name: "user-service", count: 3, hasError: false },
63
+ { name: "notification-service", count: 1, hasError: false },
64
+ ],
65
+ errorCount: 0,
66
+ },
67
+ {
68
+ traceId: "4eb1a9535aab87bb2882cf655ac4753a",
69
+ rootSpanName: "DELETE /api/sessions",
70
+ serviceName: "api-gateway",
71
+ durationMs: 45,
72
+ statusCode: "OK",
73
+ timestampMs: BASE_MS + 60_000,
74
+ spanCount: 3,
75
+ services: [
76
+ { name: "api-gateway", count: 1, hasError: false },
77
+ { name: "auth-service", count: 2, hasError: false },
78
+ ],
79
+ errorCount: 0,
80
+ },
81
+ ];
@@ -0,0 +1,396 @@
1
+ import type { denormalizedSignals } from "@kopai/core";
2
+
3
+ type OtelTracesRow = denormalizedSignals.OtelTracesRow;
4
+
5
+ // Shared trace ID for the main trace
6
+ const TRACE_ID = "0af7651916cd43dd8448eb211c80319c";
7
+
8
+ // Span IDs (8-byte hex = 16 hex chars)
9
+ const ROOT_SPAN = "b7ad6b7169203331";
10
+ const CHILD_AUTH = "5cc999522982f714";
11
+ const CHILD_USERS = "0e0a2b1c7f4d3e5a";
12
+ const CHILD_DB = "1a2b3c4d5e6f7a8b";
13
+ const CHILD_CACHE = "9f8e7d6c5b4a3210";
14
+ const CHILD_SERIALIZE = "aa11bb22cc33dd44";
15
+ const CHILD_LOGGING = "ee55ff6600771188";
16
+ const CHILD_RESPONSE = "2233445566778899";
17
+
18
+ // Base timestamp: 2023-11-14T22:13:20Z in nanoseconds
19
+ const BASE_NS = 1700000000000000000n;
20
+ const ts = (offsetMs: number) =>
21
+ (BASE_NS + BigInt(offsetMs) * 1000000n).toString();
22
+ const dur = (ms: number) => (BigInt(ms) * 1000000n).toString();
23
+
24
+ export const mockTraceRows: OtelTracesRow[] = [
25
+ // Root span: api-gateway GET /api/users
26
+ {
27
+ SpanId: ROOT_SPAN,
28
+ TraceId: TRACE_ID,
29
+ Timestamp: ts(0),
30
+ Duration: dur(320),
31
+ ParentSpanId: "",
32
+ ServiceName: "api-gateway",
33
+ SpanName: "GET /api/users",
34
+ SpanKind: "SERVER",
35
+ StatusCode: "OK",
36
+ StatusMessage: "",
37
+ ScopeName: "opentelemetry.instrumentation.http",
38
+ ScopeVersion: "0.44.0",
39
+ SpanAttributes: {
40
+ "http.method": "GET",
41
+ "http.url": "https://api.example.com/api/users",
42
+ "http.status_code": 200,
43
+ "http.route": "/api/users",
44
+ "net.host.name": "api.example.com",
45
+ "net.host.port": 443,
46
+ "http.request_content_length": 0,
47
+ "http.response_content_length": 4096,
48
+ },
49
+ ResourceAttributes: {
50
+ "service.name": "api-gateway",
51
+ "service.version": "1.4.2",
52
+ "deployment.environment": "production",
53
+ "host.name": "api-gw-prod-01",
54
+ },
55
+ "Events.Name": ["request.received", "response.sent"],
56
+ "Events.Timestamp": [ts(0), ts(319)],
57
+ "Events.Attributes": [
58
+ { "http.method": "GET", "client.address": "192.168.1.42" },
59
+ { "http.status_code": 200, "response.size_bytes": 4096 },
60
+ ],
61
+ },
62
+
63
+ // Child 1: auth-service AuthService.validate
64
+ {
65
+ SpanId: CHILD_AUTH,
66
+ TraceId: TRACE_ID,
67
+ Timestamp: ts(2),
68
+ Duration: dur(35),
69
+ ParentSpanId: ROOT_SPAN,
70
+ ServiceName: "auth-service",
71
+ SpanName: "AuthService.validate",
72
+ SpanKind: "CLIENT",
73
+ StatusCode: "OK",
74
+ StatusMessage: "",
75
+ ScopeName: "opentelemetry.instrumentation.grpc",
76
+ ScopeVersion: "0.44.0",
77
+ SpanAttributes: {
78
+ "rpc.system": "grpc",
79
+ "rpc.service": "AuthService",
80
+ "rpc.method": "validate",
81
+ "rpc.grpc.status_code": 0,
82
+ "auth.token_type": "Bearer",
83
+ },
84
+ ResourceAttributes: {
85
+ "service.name": "auth-service",
86
+ "service.version": "2.1.0",
87
+ "deployment.environment": "production",
88
+ "host.name": "auth-prod-01",
89
+ },
90
+ },
91
+
92
+ // Child 2: user-service UserService.getUsers
93
+ {
94
+ SpanId: CHILD_USERS,
95
+ TraceId: TRACE_ID,
96
+ Timestamp: ts(40),
97
+ Duration: dur(250),
98
+ ParentSpanId: ROOT_SPAN,
99
+ ServiceName: "user-service",
100
+ SpanName: "UserService.getUsers",
101
+ SpanKind: "INTERNAL",
102
+ StatusCode: "OK",
103
+ StatusMessage: "",
104
+ ScopeName: "opentelemetry.instrumentation.express",
105
+ ScopeVersion: "0.44.0",
106
+ SpanAttributes: {
107
+ "code.function": "getUsers",
108
+ "code.namespace": "UserService",
109
+ "app.users.limit": 50,
110
+ "app.users.offset": 0,
111
+ },
112
+ ResourceAttributes: {
113
+ "service.name": "user-service",
114
+ "service.version": "3.0.1",
115
+ "deployment.environment": "production",
116
+ "host.name": "user-svc-prod-02",
117
+ },
118
+ },
119
+
120
+ // Child 2a: user-service PostgresDB.query (child of UserService.getUsers)
121
+ {
122
+ SpanId: CHILD_DB,
123
+ TraceId: TRACE_ID,
124
+ Timestamp: ts(45),
125
+ Duration: dur(180),
126
+ ParentSpanId: CHILD_USERS,
127
+ ServiceName: "user-service",
128
+ SpanName: "PostgresDB.query",
129
+ SpanKind: "CLIENT",
130
+ StatusCode: "OK",
131
+ StatusMessage: "",
132
+ ScopeName: "opentelemetry.instrumentation.pg",
133
+ ScopeVersion: "0.44.0",
134
+ SpanAttributes: {
135
+ "db.system": "postgresql",
136
+ "db.name": "users_db",
137
+ "db.statement": "SELECT id, name, email FROM users LIMIT $1 OFFSET $2",
138
+ "db.operation": "SELECT",
139
+ "db.sql.table": "users",
140
+ "net.peer.name": "pg-primary.internal",
141
+ "net.peer.port": 5432,
142
+ },
143
+ ResourceAttributes: {
144
+ "service.name": "user-service",
145
+ "service.version": "3.0.1",
146
+ "deployment.environment": "production",
147
+ "host.name": "user-svc-prod-02",
148
+ },
149
+ "Links.TraceId": ["abcdef0123456789abcdef0123456789"],
150
+ "Links.SpanId": ["1122334455667788"],
151
+ "Links.TraceState": [""],
152
+ "Links.Attributes": [{ "link.reason": "batch_parent" }],
153
+ },
154
+
155
+ // Child 3: cache-service Redis.get
156
+ {
157
+ SpanId: CHILD_CACHE,
158
+ TraceId: TRACE_ID,
159
+ Timestamp: ts(38),
160
+ Duration: dur(5),
161
+ ParentSpanId: ROOT_SPAN,
162
+ ServiceName: "cache-service",
163
+ SpanName: "Redis.get",
164
+ SpanKind: "CLIENT",
165
+ StatusCode: "OK",
166
+ StatusMessage: "",
167
+ ScopeName: "opentelemetry.instrumentation.redis",
168
+ ScopeVersion: "0.44.0",
169
+ SpanAttributes: {
170
+ "db.system": "redis",
171
+ "db.operation": "GET",
172
+ "db.statement": "GET users:list:page:0",
173
+ "net.peer.name": "redis-primary.internal",
174
+ "net.peer.port": 6379,
175
+ "cache.hit": false,
176
+ },
177
+ ResourceAttributes: {
178
+ "service.name": "cache-service",
179
+ "service.version": "1.0.5",
180
+ "deployment.environment": "production",
181
+ "host.name": "cache-prod-01",
182
+ },
183
+ },
184
+
185
+ // Child 4: user-service serialize response
186
+ {
187
+ SpanId: CHILD_SERIALIZE,
188
+ TraceId: TRACE_ID,
189
+ Timestamp: ts(292),
190
+ Duration: dur(15),
191
+ ParentSpanId: CHILD_USERS,
192
+ ServiceName: "user-service",
193
+ SpanName: "UserService.serialize",
194
+ SpanKind: "INTERNAL",
195
+ StatusCode: "OK",
196
+ StatusMessage: "",
197
+ ScopeName: "opentelemetry.instrumentation.express",
198
+ ScopeVersion: "0.44.0",
199
+ SpanAttributes: {
200
+ "code.function": "serialize",
201
+ "code.namespace": "UserService",
202
+ "app.serialization.format": "json",
203
+ "app.records.count": 42,
204
+ },
205
+ ResourceAttributes: {
206
+ "service.name": "user-service",
207
+ "service.version": "3.0.1",
208
+ "deployment.environment": "production",
209
+ "host.name": "user-svc-prod-02",
210
+ },
211
+ },
212
+
213
+ // Child 5: api-gateway logging middleware
214
+ {
215
+ SpanId: CHILD_LOGGING,
216
+ TraceId: TRACE_ID,
217
+ Timestamp: ts(1),
218
+ Duration: dur(1),
219
+ ParentSpanId: ROOT_SPAN,
220
+ ServiceName: "api-gateway",
221
+ SpanName: "Middleware.logging",
222
+ SpanKind: "INTERNAL",
223
+ StatusCode: "UNSET",
224
+ ScopeName: "opentelemetry.instrumentation.express",
225
+ ScopeVersion: "0.44.0",
226
+ SpanAttributes: {
227
+ "express.type": "middleware",
228
+ "express.name": "loggingMiddleware",
229
+ },
230
+ ResourceAttributes: {
231
+ "service.name": "api-gateway",
232
+ "service.version": "1.4.2",
233
+ "deployment.environment": "production",
234
+ "host.name": "api-gw-prod-01",
235
+ },
236
+ },
237
+
238
+ // Child 6: api-gateway response formatting
239
+ {
240
+ SpanId: CHILD_RESPONSE,
241
+ TraceId: TRACE_ID,
242
+ Timestamp: ts(310),
243
+ Duration: dur(8),
244
+ ParentSpanId: ROOT_SPAN,
245
+ ServiceName: "api-gateway",
246
+ SpanName: "Response.format",
247
+ SpanKind: "INTERNAL",
248
+ StatusCode: "OK",
249
+ ScopeName: "opentelemetry.instrumentation.express",
250
+ ScopeVersion: "0.44.0",
251
+ SpanAttributes: {
252
+ "http.response_content_length": 4096,
253
+ "http.content_type": "application/json",
254
+ },
255
+ ResourceAttributes: {
256
+ "service.name": "api-gateway",
257
+ "service.version": "1.4.2",
258
+ "deployment.environment": "production",
259
+ "host.name": "api-gw-prod-01",
260
+ },
261
+ },
262
+ ];
263
+
264
+ // ── Error trace ──
265
+
266
+ const ERROR_TRACE_ID = "1bf8762027de54ee9559fc322d91420d";
267
+ const ERR_ROOT = "c8ae7e8270314442";
268
+ const ERR_CHILD_AUTH = "d9bf8f9381425553";
269
+ const ERR_CHILD_PARSE = "eac0a0a492536664";
270
+ const ERR_CHILD_LOG = "fbd1b1b5a3647775";
271
+
272
+ const ERR_BASE_NS = 1700000010000000000n; // 10s after main trace
273
+ const ets = (offsetMs: number) =>
274
+ (ERR_BASE_NS + BigInt(offsetMs) * 1000000n).toString();
275
+
276
+ export const mockErrorTraceRows: OtelTracesRow[] = [
277
+ // Root span: api-gateway POST /api/users
278
+ {
279
+ SpanId: ERR_ROOT,
280
+ TraceId: ERROR_TRACE_ID,
281
+ Timestamp: ets(0),
282
+ Duration: dur(95),
283
+ ParentSpanId: "",
284
+ ServiceName: "api-gateway",
285
+ SpanName: "POST /api/users",
286
+ SpanKind: "SERVER",
287
+ StatusCode: "ERROR",
288
+ StatusMessage: "Internal server error",
289
+ ScopeName: "opentelemetry.instrumentation.http",
290
+ ScopeVersion: "0.44.0",
291
+ SpanAttributes: {
292
+ "http.method": "POST",
293
+ "http.url": "https://api.example.com/api/users",
294
+ "http.status_code": 500,
295
+ "http.route": "/api/users",
296
+ "net.host.name": "api.example.com",
297
+ },
298
+ ResourceAttributes: {
299
+ "service.name": "api-gateway",
300
+ "service.version": "1.4.2",
301
+ "deployment.environment": "production",
302
+ "host.name": "api-gw-prod-01",
303
+ },
304
+ "Events.Name": ["exception"],
305
+ "Events.Timestamp": [ets(90)],
306
+ "Events.Attributes": [
307
+ {
308
+ "exception.type": "InternalServerError",
309
+ "exception.message": "Failed to parse request body: invalid JSON",
310
+ "exception.stacktrace":
311
+ "Error: Failed to parse request body: invalid JSON\n at parseBody (/app/src/middleware/body-parser.ts:42:11)\n at Layer.handle (/app/node_modules/express/lib/router/layer.js:95:5)",
312
+ },
313
+ ],
314
+ },
315
+
316
+ // Child: auth-service validate (OK)
317
+ {
318
+ SpanId: ERR_CHILD_AUTH,
319
+ TraceId: ERROR_TRACE_ID,
320
+ Timestamp: ets(1),
321
+ Duration: dur(30),
322
+ ParentSpanId: ERR_ROOT,
323
+ ServiceName: "auth-service",
324
+ SpanName: "AuthService.validate",
325
+ SpanKind: "CLIENT",
326
+ StatusCode: "OK",
327
+ StatusMessage: "",
328
+ ScopeName: "opentelemetry.instrumentation.grpc",
329
+ ScopeVersion: "0.44.0",
330
+ SpanAttributes: {
331
+ "rpc.system": "grpc",
332
+ "rpc.service": "AuthService",
333
+ "rpc.method": "validate",
334
+ "rpc.grpc.status_code": 0,
335
+ },
336
+ ResourceAttributes: {
337
+ "service.name": "auth-service",
338
+ "service.version": "2.1.0",
339
+ "deployment.environment": "production",
340
+ "host.name": "auth-prod-01",
341
+ },
342
+ },
343
+
344
+ // Child: api-gateway body parsing (ERROR)
345
+ {
346
+ SpanId: ERR_CHILD_PARSE,
347
+ TraceId: ERROR_TRACE_ID,
348
+ Timestamp: ets(35),
349
+ Duration: dur(50),
350
+ ParentSpanId: ERR_ROOT,
351
+ ServiceName: "api-gateway",
352
+ SpanName: "Middleware.bodyParser",
353
+ SpanKind: "INTERNAL",
354
+ StatusCode: "ERROR",
355
+ StatusMessage: "Failed to parse request body: invalid JSON",
356
+ ScopeName: "opentelemetry.instrumentation.express",
357
+ ScopeVersion: "0.44.0",
358
+ SpanAttributes: {
359
+ "express.type": "middleware",
360
+ "express.name": "bodyParser",
361
+ "http.request_content_length": 156,
362
+ "http.content_type": "application/json",
363
+ },
364
+ ResourceAttributes: {
365
+ "service.name": "api-gateway",
366
+ "service.version": "1.4.2",
367
+ "deployment.environment": "production",
368
+ "host.name": "api-gw-prod-01",
369
+ },
370
+ },
371
+
372
+ // Child: api-gateway error logging
373
+ {
374
+ SpanId: ERR_CHILD_LOG,
375
+ TraceId: ERROR_TRACE_ID,
376
+ Timestamp: ets(86),
377
+ Duration: dur(3),
378
+ ParentSpanId: ERR_ROOT,
379
+ ServiceName: "api-gateway",
380
+ SpanName: "ErrorHandler.log",
381
+ SpanKind: "INTERNAL",
382
+ StatusCode: "UNSET",
383
+ ScopeName: "opentelemetry.instrumentation.express",
384
+ ScopeVersion: "0.44.0",
385
+ SpanAttributes: {
386
+ "error.logged": true,
387
+ "error.type": "InternalServerError",
388
+ },
389
+ ResourceAttributes: {
390
+ "service.name": "api-gateway",
391
+ "service.version": "1.4.2",
392
+ "deployment.environment": "production",
393
+ "host.name": "api-gw-prod-01",
394
+ },
395
+ },
396
+ ];