@autter/otlp-ingester 1.1.0 → 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/dist/fingerprint.js +170 -5
- package/dist/stack-fixtures.d.ts +25 -0
- package/dist/stack-fixtures.js +231 -0
- package/package.json +1 -1
package/dist/fingerprint.js
CHANGED
|
@@ -54,11 +54,125 @@ export function normalizeRoute(route) {
|
|
|
54
54
|
.join("/");
|
|
55
55
|
}
|
|
56
56
|
const FRAME_LOCATION_RE = /:\d+(:\d+)?\)?$/;
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
57
|
+
// A Go location line: "\t<file>.go:<line> +0x<off>" (offset optional).
|
|
58
|
+
const GO_LOCATION_RE = /^\s*(.+\.go):\d+(?:\s+\+0x[0-9a-f]+)?\s*$/;
|
|
59
|
+
const GO_GOROUTINE_RE = /\bgoroutine \d+ \[/;
|
|
60
|
+
// A .NET frame with a source location: "at <method>(...) in <file>:line <n>".
|
|
61
|
+
const DOTNET_FRAME_RE = /^\s*at\s+.+\)\s+in\s+.+:line\s+\d+\s*$/i;
|
|
62
|
+
const DOTNET_CS_RE = /\.cs:line\s+\d+/i;
|
|
63
|
+
// A JVM frame: "at <fqmethod>(<File>.java:<line>)" / "(Native Method)".
|
|
64
|
+
const JVM_FRAME_RE = /^\s*at\s+[\w$.]+(?:\/[\w$.]+)?\(.*\.(?:java|kt|scala|groovy):\d+\)\s*$/;
|
|
65
|
+
const JVM_NATIVE_RE = /\((?:Native Method|Unknown Source)\)\s*$/;
|
|
66
|
+
// A Rust backtrace frame (" 3: my::mod::func") or its "at <file>.rs:<n>" line.
|
|
67
|
+
const RUST_FRAME_RE = /^\s*\d+:\s+(?:0x[0-9a-f]+\s+-\s+)?\S+::\S/;
|
|
68
|
+
const RUST_AT_RS_RE = /^\s*at\s+\S+\.rs:\d+/;
|
|
69
|
+
/**
|
|
70
|
+
* Classify a whole stack by language. Signatures are chosen to be unique to
|
|
71
|
+
* each runtime so a JS or Python stack always falls through to "script".
|
|
72
|
+
*/
|
|
73
|
+
function detectStackLanguage(lines) {
|
|
74
|
+
let hasDotnet = false;
|
|
75
|
+
let hasJvm = false;
|
|
76
|
+
let hasRust = false;
|
|
77
|
+
for (const line of lines) {
|
|
78
|
+
if (GO_LOCATION_RE.test(line) || GO_GOROUTINE_RE.test(line))
|
|
79
|
+
return "go";
|
|
80
|
+
if (DOTNET_FRAME_RE.test(line) || DOTNET_CS_RE.test(line))
|
|
81
|
+
hasDotnet = true;
|
|
82
|
+
if (JVM_FRAME_RE.test(line) || JVM_NATIVE_RE.test(line))
|
|
83
|
+
hasJvm = true;
|
|
84
|
+
if (RUST_FRAME_RE.test(line) ||
|
|
85
|
+
RUST_AT_RS_RE.test(line) ||
|
|
86
|
+
line.trim() === "stack backtrace:")
|
|
87
|
+
hasRust = true;
|
|
88
|
+
}
|
|
89
|
+
// .NET and JVM frames both start with "at"; decide by the location marker
|
|
90
|
+
// each detector matched (`.cs`/`:line` vs `.java`/Native Method).
|
|
91
|
+
if (hasDotnet)
|
|
92
|
+
return "dotnet";
|
|
93
|
+
if (hasJvm)
|
|
94
|
+
return "jvm";
|
|
95
|
+
if (hasRust)
|
|
96
|
+
return "rust";
|
|
97
|
+
return "script";
|
|
98
|
+
}
|
|
99
|
+
/** Drop the trailing call-argument group, e.g. "f(0x1, 0x2)" → "f". */
|
|
100
|
+
function stripTrailingArgs(fn) {
|
|
101
|
+
return fn.replace(/\([^()]*\)\s*$/, "").trim();
|
|
102
|
+
}
|
|
103
|
+
function cleanGoFunc(fn) {
|
|
104
|
+
return stripTrailingArgs(fn.replace(/^created by\s+/, "").replace(/\s+in goroutine \d+\s*$/, ""));
|
|
105
|
+
}
|
|
106
|
+
/** Go: a function line followed by a "\t<file>.go:<line> +0x<off>" location. */
|
|
107
|
+
function parseGoFrames(lines, topN) {
|
|
108
|
+
const frames = [];
|
|
109
|
+
let prevFunc = "";
|
|
110
|
+
for (const line of lines) {
|
|
111
|
+
const loc = GO_LOCATION_RE.exec(line);
|
|
112
|
+
if (loc && prevFunc) {
|
|
113
|
+
frames.push(`${cleanGoFunc(prevFunc)} (${loc[1].trim()})`);
|
|
114
|
+
if (frames.length >= topN)
|
|
115
|
+
break;
|
|
116
|
+
prevFunc = "";
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
const trimmed = line.trim();
|
|
120
|
+
if (trimmed && !GO_GOROUTINE_RE.test(trimmed))
|
|
121
|
+
prevFunc = trimmed;
|
|
122
|
+
}
|
|
123
|
+
return frames;
|
|
124
|
+
}
|
|
125
|
+
/** Rust: " N: module::func" optionally followed by " at <file>:<line>:<col>". */
|
|
126
|
+
function parseRustFrames(lines, topN) {
|
|
127
|
+
const frames = [];
|
|
128
|
+
for (let i = 0; i < lines.length && frames.length < topN; i++) {
|
|
129
|
+
const m = /^\s*\d+:\s+(?:0x[0-9a-f]+\s+-\s+)?(.+?)\s*$/.exec(lines[i]);
|
|
130
|
+
if (!m)
|
|
131
|
+
continue;
|
|
132
|
+
const fn = m[1].replace(/::h[0-9a-f]{6,}$/, "").trim();
|
|
133
|
+
if (!fn)
|
|
134
|
+
continue;
|
|
135
|
+
const at = /^\s*at\s+(\S+?):\d+(?::\d+)?\s*$/.exec(lines[i + 1] ?? "");
|
|
136
|
+
if (at)
|
|
137
|
+
i++;
|
|
138
|
+
frames.push(at ? `${fn} (${at[1]})` : fn);
|
|
139
|
+
}
|
|
140
|
+
return frames;
|
|
141
|
+
}
|
|
142
|
+
/** JVM (Java/Kotlin/Scala): "\tat <fqmethod>(<File>:<line>)". */
|
|
143
|
+
function parseJvmFrames(lines, topN) {
|
|
144
|
+
const frames = [];
|
|
145
|
+
for (const line of lines) {
|
|
146
|
+
const m = /^\s*at\s+(.+?)\((.*)\)\s*$/.exec(line);
|
|
147
|
+
if (!m)
|
|
148
|
+
continue;
|
|
149
|
+
frames.push(`${m[1].trim()}(${m[2].trim().replace(/:\d+$/, "")})`);
|
|
150
|
+
if (frames.length >= topN)
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
return frames;
|
|
154
|
+
}
|
|
155
|
+
/** .NET: " at <method>(<params>) in <file>:line <n>" (location optional). */
|
|
156
|
+
function parseDotnetFrames(lines, topN) {
|
|
157
|
+
const frames = [];
|
|
158
|
+
for (const line of lines) {
|
|
159
|
+
const m = /^\s*at\s+(.+?)(?:\s+in\s+(.+?):line\s+\d+)?\s*$/.exec(line);
|
|
160
|
+
if (!m)
|
|
161
|
+
continue;
|
|
162
|
+
const method = stripTrailingArgs(m[1]);
|
|
163
|
+
const file = m[2]?.trim() ?? "";
|
|
164
|
+
frames.push(file ? `${method} (${file})` : method);
|
|
165
|
+
if (frames.length >= topN)
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
return frames;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Historical JS/TS/Firefox/Python normalisation — output is intentionally
|
|
172
|
+
* unchanged so pre-existing issues in those runtimes keep their fingerprints.
|
|
173
|
+
*/
|
|
174
|
+
function parseScriptFrames(lines, topN) {
|
|
175
|
+
return lines
|
|
62
176
|
.map((line) => line.trim())
|
|
63
177
|
.filter((line) => /^at\s|@|^\s*File\s/.test(line) || /\.[jt]sx?/.test(line))
|
|
64
178
|
.slice(0, topN)
|
|
@@ -68,6 +182,57 @@ export function normalizeStackFrames(stack, topN = 5) {
|
|
|
68
182
|
.replace(/\s+/g, " ")
|
|
69
183
|
.trim());
|
|
70
184
|
}
|
|
185
|
+
/**
|
|
186
|
+
* Safe fallback for a non-empty stack we could not parse into frames (an
|
|
187
|
+
* unsupported runtime, or a malformed one). Rather than discard everything —
|
|
188
|
+
* which collapses every same-message error into one issue — derive a stable
|
|
189
|
+
* signature from any structurally frame-like lines, with volatile tokens
|
|
190
|
+
* (addresses, offsets, line/column numbers) templated out so the SAME defect
|
|
191
|
+
* still groups across occurrences. When there is no frame-like structure at
|
|
192
|
+
* all we return nothing, exactly as before, and grouping falls back to the
|
|
193
|
+
* message + service + error type.
|
|
194
|
+
*/
|
|
195
|
+
function fallbackFrames(lines, topN) {
|
|
196
|
+
const framey = lines
|
|
197
|
+
.map((line) => line.trim())
|
|
198
|
+
.filter((line) => /(?:[/\\]|\.\w+)\S*[:(]\d+/.test(line) ||
|
|
199
|
+
/\b0x[0-9a-f]+/i.test(line) ||
|
|
200
|
+
/^(?:at|from)\b/.test(line) ||
|
|
201
|
+
/^\d+:\s/.test(line));
|
|
202
|
+
if (framey.length === 0)
|
|
203
|
+
return [];
|
|
204
|
+
return framey
|
|
205
|
+
.map((line) => line
|
|
206
|
+
.replace(/0x[0-9a-f]+/gi, "0x")
|
|
207
|
+
.replace(/:\d+(:\d+)?\b/g, "")
|
|
208
|
+
.replace(/\s+/g, " ")
|
|
209
|
+
.trim())
|
|
210
|
+
.filter(Boolean)
|
|
211
|
+
.slice(0, topN);
|
|
212
|
+
}
|
|
213
|
+
export function normalizeStackFrames(stack, topN = 5) {
|
|
214
|
+
if (!stack)
|
|
215
|
+
return [];
|
|
216
|
+
const lines = stack.split("\n");
|
|
217
|
+
let frames;
|
|
218
|
+
switch (detectStackLanguage(lines)) {
|
|
219
|
+
case "go":
|
|
220
|
+
frames = parseGoFrames(lines, topN);
|
|
221
|
+
break;
|
|
222
|
+
case "rust":
|
|
223
|
+
frames = parseRustFrames(lines, topN);
|
|
224
|
+
break;
|
|
225
|
+
case "jvm":
|
|
226
|
+
frames = parseJvmFrames(lines, topN);
|
|
227
|
+
break;
|
|
228
|
+
case "dotnet":
|
|
229
|
+
frames = parseDotnetFrames(lines, topN);
|
|
230
|
+
break;
|
|
231
|
+
default:
|
|
232
|
+
frames = parseScriptFrames(lines, topN);
|
|
233
|
+
}
|
|
234
|
+
return frames.length > 0 ? frames : fallbackFrames(lines, topN);
|
|
235
|
+
}
|
|
71
236
|
export function fingerprintOccurrence(input) {
|
|
72
237
|
const parts = [
|
|
73
238
|
input.source,
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Representative raw stack traces for every officially-supported runtime,
|
|
3
|
+
* exactly as their OpenTelemetry SDKs put them on the `exception.stacktrace`
|
|
4
|
+
* span attribute (or the browser relay's `stack` field). These drive the
|
|
5
|
+
* golden fingerprint tests in fingerprint.test.ts.
|
|
6
|
+
*
|
|
7
|
+
* Each language provides three variants of the SAME family of errors:
|
|
8
|
+
* - `primary` — the defect under test.
|
|
9
|
+
* - `sibling` — a DIFFERENT defect (different top function/file) that
|
|
10
|
+
* carries the SAME error message. It must fingerprint separately: this is
|
|
11
|
+
* the regression the pipeline exists to prevent (before per-language
|
|
12
|
+
* parsing, Go/Rust frames were dropped and these collided into one issue).
|
|
13
|
+
* - `redeploy` — the primary defect after a rebuild that shifted every line
|
|
14
|
+
* number (and, for Go, pointer offsets/addresses/goroutine ids). It must
|
|
15
|
+
* fingerprint IDENTICALLY to `primary`, proving grouping is stable across
|
|
16
|
+
* re-deploys and repeated ingestion.
|
|
17
|
+
*/
|
|
18
|
+
export interface StackFixture {
|
|
19
|
+
primary: string;
|
|
20
|
+
sibling: string;
|
|
21
|
+
redeploy: string;
|
|
22
|
+
/** Golden normalised top frames for `primary` (locks the parser output). */
|
|
23
|
+
primaryFrames: string[];
|
|
24
|
+
}
|
|
25
|
+
export declare const STACK_FIXTURES: Record<string, StackFixture>;
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Representative raw stack traces for every officially-supported runtime,
|
|
3
|
+
* exactly as their OpenTelemetry SDKs put them on the `exception.stacktrace`
|
|
4
|
+
* span attribute (or the browser relay's `stack` field). These drive the
|
|
5
|
+
* golden fingerprint tests in fingerprint.test.ts.
|
|
6
|
+
*
|
|
7
|
+
* Each language provides three variants of the SAME family of errors:
|
|
8
|
+
* - `primary` — the defect under test.
|
|
9
|
+
* - `sibling` — a DIFFERENT defect (different top function/file) that
|
|
10
|
+
* carries the SAME error message. It must fingerprint separately: this is
|
|
11
|
+
* the regression the pipeline exists to prevent (before per-language
|
|
12
|
+
* parsing, Go/Rust frames were dropped and these collided into one issue).
|
|
13
|
+
* - `redeploy` — the primary defect after a rebuild that shifted every line
|
|
14
|
+
* number (and, for Go, pointer offsets/addresses/goroutine ids). It must
|
|
15
|
+
* fingerprint IDENTICALLY to `primary`, proving grouping is stable across
|
|
16
|
+
* re-deploys and repeated ingestion.
|
|
17
|
+
*/
|
|
18
|
+
// ── Go ──────────────────────────────────────────────────────────────────────
|
|
19
|
+
const GO_PRIMARY = `panic: runtime error: invalid memory address or nil pointer dereference
|
|
20
|
+
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x1a2b3c]
|
|
21
|
+
|
|
22
|
+
goroutine 42 [running]:
|
|
23
|
+
main.(*OrderService).Process(0xc0000b4000, 0xc0000d2000)
|
|
24
|
+
/app/orders/service.go:128 +0x1a5
|
|
25
|
+
main.(*Handler).ServeHTTP(0xc0000a2000, {0x8f2a40, 0xc0000b0000})
|
|
26
|
+
/app/web/handler.go:64 +0x2c8
|
|
27
|
+
net/http.(*conn).serve(0xc0001a4000, {0x8f2b20, 0xc0000c2000})
|
|
28
|
+
/usr/local/go/src/net/http/server.go:2092 +0x1a5
|
|
29
|
+
created by net/http.(*Server).Serve in goroutine 1
|
|
30
|
+
/usr/local/go/src/net/http/server.go:3285 +0x33e`;
|
|
31
|
+
const GO_SIBLING = `panic: runtime error: invalid memory address or nil pointer dereference
|
|
32
|
+
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x4d5e6f]
|
|
33
|
+
|
|
34
|
+
goroutine 88 [running]:
|
|
35
|
+
main.(*PaymentService).Charge(0xc0000f4000, 0xc000102000)
|
|
36
|
+
/app/payments/service.go:212 +0x9c
|
|
37
|
+
main.(*Handler).ServeHTTP(0xc0000a2000, {0x8f2a40, 0xc0000b0000})
|
|
38
|
+
/app/web/handler.go:64 +0x2c8
|
|
39
|
+
net/http.(*conn).serve(0xc0001a4000, {0x8f2b20, 0xc0000c2000})
|
|
40
|
+
/usr/local/go/src/net/http/server.go:2092 +0x1a5`;
|
|
41
|
+
const GO_REDEPLOY = `panic: runtime error: invalid memory address or nil pointer dereference
|
|
42
|
+
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x7a8b9c]
|
|
43
|
+
|
|
44
|
+
goroutine 15 [running]:
|
|
45
|
+
main.(*OrderService).Process(0xc000200000, 0xc000210000)
|
|
46
|
+
/app/orders/service.go:140 +0x1f2
|
|
47
|
+
main.(*Handler).ServeHTTP(0xc000202000, {0x8f2a40, 0xc000208000})
|
|
48
|
+
/app/web/handler.go:71 +0x300
|
|
49
|
+
net/http.(*conn).serve(0xc000300000, {0x8f2b20, 0xc000310000})
|
|
50
|
+
/usr/local/go/src/net/http/server.go:2092 +0x1a5
|
|
51
|
+
created by net/http.(*Server).Serve in goroutine 1
|
|
52
|
+
/usr/local/go/src/net/http/server.go:3285 +0x33e`;
|
|
53
|
+
// ── Rust ────────────────────────────────────────────────────────────────────
|
|
54
|
+
const RUST_PRIMARY = `thread 'actix-rt|system:0|arbiter:1' panicked at src/orders/service.rs:88:21:
|
|
55
|
+
called \`Result::unwrap()\` on an \`Err\` value: PoolTimedOut
|
|
56
|
+
stack backtrace:
|
|
57
|
+
0: rust_begin_unwind
|
|
58
|
+
at /rustc/abc123/library/std/src/panicking.rs:665:5
|
|
59
|
+
1: core::panicking::panic_fmt
|
|
60
|
+
at /rustc/abc123/library/core/src/panicking.rs:74:14
|
|
61
|
+
2: core::result::unwrap_failed
|
|
62
|
+
at /rustc/abc123/library/core/src/result.rs:1679:5
|
|
63
|
+
3: myapp::orders::service::OrderService::process
|
|
64
|
+
at ./src/orders/service.rs:88:21
|
|
65
|
+
4: myapp::web::handler::handle_request
|
|
66
|
+
at ./src/web/handler.rs:42:9`;
|
|
67
|
+
const RUST_SIBLING = `thread 'main' panicked at src/payments/service.rs:143:10:
|
|
68
|
+
called \`Result::unwrap()\` on an \`Err\` value: PoolTimedOut
|
|
69
|
+
stack backtrace:
|
|
70
|
+
0: rust_begin_unwind
|
|
71
|
+
at /rustc/abc123/library/std/src/panicking.rs:665:5
|
|
72
|
+
1: core::panicking::panic_fmt
|
|
73
|
+
at /rustc/abc123/library/core/src/panicking.rs:74:14
|
|
74
|
+
2: core::result::unwrap_failed
|
|
75
|
+
at /rustc/abc123/library/core/src/result.rs:1679:5
|
|
76
|
+
3: myapp::payments::service::PaymentService::charge
|
|
77
|
+
at ./src/payments/service.rs:143:10
|
|
78
|
+
4: myapp::web::handler::handle_request
|
|
79
|
+
at ./src/web/handler.rs:42:9`;
|
|
80
|
+
const RUST_REDEPLOY = `thread 'main' panicked at src/orders/service.rs:95:21:
|
|
81
|
+
called \`Result::unwrap()\` on an \`Err\` value: PoolTimedOut
|
|
82
|
+
stack backtrace:
|
|
83
|
+
0: rust_begin_unwind
|
|
84
|
+
at /rustc/abc123/library/std/src/panicking.rs:665:5
|
|
85
|
+
1: core::panicking::panic_fmt
|
|
86
|
+
at /rustc/abc123/library/core/src/panicking.rs:74:14
|
|
87
|
+
2: core::result::unwrap_failed
|
|
88
|
+
at /rustc/abc123/library/core/src/result.rs:1679:5
|
|
89
|
+
3: myapp::orders::service::OrderService::process
|
|
90
|
+
at ./src/orders/service.rs:95:21
|
|
91
|
+
4: myapp::web::handler::handle_request
|
|
92
|
+
at ./src/web/handler.rs:47:9`;
|
|
93
|
+
// ── Java / JVM ──────────────────────────────────────────────────────────────
|
|
94
|
+
const JAVA_PRIMARY = `java.lang.NullPointerException: Cannot invoke "com.example.model.Order.total()" because "order" is null
|
|
95
|
+
at com.example.orders.OrderService.process(OrderService.java:88)
|
|
96
|
+
at com.example.web.RequestHandler.handle(RequestHandler.java:42)
|
|
97
|
+
at com.example.web.RequestHandler.doGet(RequestHandler.java:31)
|
|
98
|
+
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:687)
|
|
99
|
+
at java.base/java.lang.Thread.run(Thread.java:1583)
|
|
100
|
+
Caused by: java.lang.IllegalStateException: order not loaded
|
|
101
|
+
at com.example.orders.OrderLoader.require(OrderLoader.java:55)
|
|
102
|
+
... 4 more`;
|
|
103
|
+
const JAVA_SIBLING = `java.lang.NullPointerException: Cannot invoke "com.example.model.Order.total()" because "order" is null
|
|
104
|
+
at com.example.billing.InvoiceService.render(InvoiceService.java:140)
|
|
105
|
+
at com.example.web.RequestHandler.handle(RequestHandler.java:42)
|
|
106
|
+
at com.example.web.RequestHandler.doGet(RequestHandler.java:31)
|
|
107
|
+
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:687)
|
|
108
|
+
at java.base/java.lang.Thread.run(Thread.java:1583)`;
|
|
109
|
+
const JAVA_REDEPLOY = `java.lang.NullPointerException: Cannot invoke "com.example.model.Order.total()" because "order" is null
|
|
110
|
+
at com.example.orders.OrderService.process(OrderService.java:92)
|
|
111
|
+
at com.example.web.RequestHandler.handle(RequestHandler.java:45)
|
|
112
|
+
at com.example.web.RequestHandler.doGet(RequestHandler.java:33)
|
|
113
|
+
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:690)
|
|
114
|
+
at java.base/java.lang.Thread.run(Thread.java:1589)`;
|
|
115
|
+
// ── .NET ────────────────────────────────────────────────────────────────────
|
|
116
|
+
const DOTNET_PRIMARY = `System.NullReferenceException: Object reference not set to an instance of an object.
|
|
117
|
+
at MyApp.Orders.OrderService.Process(Order order) in C:\\src\\MyApp\\Orders\\OrderService.cs:line 88
|
|
118
|
+
at MyApp.Web.RequestHandler.HandleAsync(HttpContext context) in C:\\src\\MyApp\\Web\\RequestHandler.cs:line 42
|
|
119
|
+
at MyApp.Web.RequestHandler.<HandleAsync>d__4.MoveNext() in C:\\src\\MyApp\\Web\\RequestHandler.cs:line 39
|
|
120
|
+
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](ref TStateMachine stateMachine)
|
|
121
|
+
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(ref Task currentTaskSlot)`;
|
|
122
|
+
const DOTNET_SIBLING = `System.NullReferenceException: Object reference not set to an instance of an object.
|
|
123
|
+
at MyApp.Billing.InvoiceService.Render(Invoice invoice) in C:\\src\\MyApp\\Billing\\InvoiceService.cs:line 205
|
|
124
|
+
at MyApp.Web.RequestHandler.HandleAsync(HttpContext context) in C:\\src\\MyApp\\Web\\RequestHandler.cs:line 42
|
|
125
|
+
at MyApp.Web.RequestHandler.<HandleAsync>d__4.MoveNext() in C:\\src\\MyApp\\Web\\RequestHandler.cs:line 39
|
|
126
|
+
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](ref TStateMachine stateMachine)
|
|
127
|
+
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(ref Task currentTaskSlot)`;
|
|
128
|
+
const DOTNET_REDEPLOY = `System.NullReferenceException: Object reference not set to an instance of an object.
|
|
129
|
+
at MyApp.Orders.OrderService.Process(Order order) in C:\\src\\MyApp\\Orders\\OrderService.cs:line 94
|
|
130
|
+
at MyApp.Web.RequestHandler.HandleAsync(HttpContext context) in C:\\src\\MyApp\\Web\\RequestHandler.cs:line 47
|
|
131
|
+
at MyApp.Web.RequestHandler.<HandleAsync>d__4.MoveNext() in C:\\src\\MyApp\\Web\\RequestHandler.cs:line 44
|
|
132
|
+
at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](ref TStateMachine stateMachine)
|
|
133
|
+
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(ref Task currentTaskSlot)`;
|
|
134
|
+
// ── JavaScript / Node (V8) ──────────────────────────────────────────────────
|
|
135
|
+
const NODE_PRIMARY = `TypeError: Cannot read properties of undefined (reading 'total')
|
|
136
|
+
at OrderService.process (/app/dist/orders/service.js:128:35)
|
|
137
|
+
at RequestHandler.handle (/app/dist/web/handler.js:64:20)
|
|
138
|
+
at /app/dist/web/router.js:22:9
|
|
139
|
+
at processTicksAndRejections (node:internal/process/task_queues:95:5)`;
|
|
140
|
+
const NODE_SIBLING = `TypeError: Cannot read properties of undefined (reading 'total')
|
|
141
|
+
at PaymentService.charge (/app/dist/payments/service.js:212:18)
|
|
142
|
+
at RequestHandler.handle (/app/dist/web/handler.js:64:20)
|
|
143
|
+
at /app/dist/web/router.js:22:9
|
|
144
|
+
at processTicksAndRejections (node:internal/process/task_queues:95:5)`;
|
|
145
|
+
const NODE_REDEPLOY = `TypeError: Cannot read properties of undefined (reading 'total')
|
|
146
|
+
at OrderService.process (/app/dist/orders/service.js:131:35)
|
|
147
|
+
at RequestHandler.handle (/app/dist/web/handler.js:70:20)
|
|
148
|
+
at /app/dist/web/router.js:25:9
|
|
149
|
+
at processTicksAndRejections (node:internal/process/task_queues:95:5)`;
|
|
150
|
+
// ── Python ──────────────────────────────────────────────────────────────────
|
|
151
|
+
const PYTHON_PRIMARY = `Traceback (most recent call last):
|
|
152
|
+
File "/app/web/handler.py", line 42, in handle
|
|
153
|
+
return self.service.process(order)
|
|
154
|
+
File "/app/orders/service.py", line 88, in process
|
|
155
|
+
raise ValueError(f"order {order_id} is invalid")
|
|
156
|
+
ValueError: order 4821 is invalid`;
|
|
157
|
+
const PYTHON_SIBLING = `Traceback (most recent call last):
|
|
158
|
+
File "/app/web/handler.py", line 42, in handle
|
|
159
|
+
return self.service.process(order)
|
|
160
|
+
File "/app/billing/invoice.py", line 205, in render
|
|
161
|
+
raise ValueError(f"order {order_id} is invalid")
|
|
162
|
+
ValueError: order 7734 is invalid`;
|
|
163
|
+
export const STACK_FIXTURES = {
|
|
164
|
+
go: {
|
|
165
|
+
primary: GO_PRIMARY,
|
|
166
|
+
sibling: GO_SIBLING,
|
|
167
|
+
redeploy: GO_REDEPLOY,
|
|
168
|
+
primaryFrames: [
|
|
169
|
+
"main.(*OrderService).Process (/app/orders/service.go)",
|
|
170
|
+
"main.(*Handler).ServeHTTP (/app/web/handler.go)",
|
|
171
|
+
"net/http.(*conn).serve (/usr/local/go/src/net/http/server.go)",
|
|
172
|
+
"net/http.(*Server).Serve (/usr/local/go/src/net/http/server.go)",
|
|
173
|
+
],
|
|
174
|
+
},
|
|
175
|
+
rust: {
|
|
176
|
+
primary: RUST_PRIMARY,
|
|
177
|
+
sibling: RUST_SIBLING,
|
|
178
|
+
redeploy: RUST_REDEPLOY,
|
|
179
|
+
primaryFrames: [
|
|
180
|
+
"rust_begin_unwind (/rustc/abc123/library/std/src/panicking.rs)",
|
|
181
|
+
"core::panicking::panic_fmt (/rustc/abc123/library/core/src/panicking.rs)",
|
|
182
|
+
"core::result::unwrap_failed (/rustc/abc123/library/core/src/result.rs)",
|
|
183
|
+
"myapp::orders::service::OrderService::process (./src/orders/service.rs)",
|
|
184
|
+
"myapp::web::handler::handle_request (./src/web/handler.rs)",
|
|
185
|
+
],
|
|
186
|
+
},
|
|
187
|
+
java: {
|
|
188
|
+
primary: JAVA_PRIMARY,
|
|
189
|
+
sibling: JAVA_SIBLING,
|
|
190
|
+
redeploy: JAVA_REDEPLOY,
|
|
191
|
+
primaryFrames: [
|
|
192
|
+
"com.example.orders.OrderService.process(OrderService.java)",
|
|
193
|
+
"com.example.web.RequestHandler.handle(RequestHandler.java)",
|
|
194
|
+
"com.example.web.RequestHandler.doGet(RequestHandler.java)",
|
|
195
|
+
"jakarta.servlet.http.HttpServlet.service(HttpServlet.java)",
|
|
196
|
+
"java.base/java.lang.Thread.run(Thread.java)",
|
|
197
|
+
],
|
|
198
|
+
},
|
|
199
|
+
dotnet: {
|
|
200
|
+
primary: DOTNET_PRIMARY,
|
|
201
|
+
sibling: DOTNET_SIBLING,
|
|
202
|
+
redeploy: DOTNET_REDEPLOY,
|
|
203
|
+
primaryFrames: [
|
|
204
|
+
"MyApp.Orders.OrderService.Process (C:\\src\\MyApp\\Orders\\OrderService.cs)",
|
|
205
|
+
"MyApp.Web.RequestHandler.HandleAsync (C:\\src\\MyApp\\Web\\RequestHandler.cs)",
|
|
206
|
+
"MyApp.Web.RequestHandler.<HandleAsync>d__4.MoveNext (C:\\src\\MyApp\\Web\\RequestHandler.cs)",
|
|
207
|
+
"System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine]",
|
|
208
|
+
"System.Threading.Tasks.Task.ExecuteWithThreadLocal",
|
|
209
|
+
],
|
|
210
|
+
},
|
|
211
|
+
node: {
|
|
212
|
+
primary: NODE_PRIMARY,
|
|
213
|
+
sibling: NODE_SIBLING,
|
|
214
|
+
redeploy: NODE_REDEPLOY,
|
|
215
|
+
primaryFrames: [
|
|
216
|
+
"at OrderService.process (/app/dist/orders/service.js",
|
|
217
|
+
"at RequestHandler.handle (/app/dist/web/handler.js",
|
|
218
|
+
"at /app/dist/web/router.js",
|
|
219
|
+
"at processTicksAndRejections (node:internal/process/task_queues",
|
|
220
|
+
],
|
|
221
|
+
},
|
|
222
|
+
python: {
|
|
223
|
+
primary: PYTHON_PRIMARY,
|
|
224
|
+
sibling: PYTHON_SIBLING,
|
|
225
|
+
redeploy: PYTHON_PRIMARY,
|
|
226
|
+
primaryFrames: [
|
|
227
|
+
'File "/app/web/handler.py", line 42, in handle',
|
|
228
|
+
'File "/app/orders/service.py", line 88, in process',
|
|
229
|
+
],
|
|
230
|
+
},
|
|
231
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@autter/otlp-ingester",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Self-hostable OTLP + browser-error ingest service for Autter Runtime: normalises telemetry into a per-repo ClickHouse data model",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|