@autter/otlp-ingester 1.6.1 → 1.8.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 +31 -5
- package/dist/auth.d.ts +16 -1
- package/dist/auth.js +34 -10
- package/dist/clickhouse.d.ts +3 -0
- package/dist/clickhouse.js +38 -1
- package/dist/compat-manifest.json +37 -0
- package/dist/config.d.ts +23 -2
- package/dist/config.js +33 -8
- package/dist/context.d.ts +5 -0
- package/dist/context.js +49 -10
- package/dist/index.d.ts +2 -1
- package/dist/index.js +8 -2
- package/dist/ingest-drops.d.ts +308 -0
- package/dist/ingest-drops.js +448 -0
- package/dist/log-promotion.d.ts +4 -3
- package/dist/log-promotion.js +5 -5
- package/dist/logs.d.ts +16 -1
- package/dist/logs.js +17 -3
- package/dist/memory.d.ts +9 -1
- package/dist/memory.js +28 -7
- package/dist/migrations.d.ts +8 -0
- package/dist/migrations.js +29 -1
- package/dist/normalize-browser.d.ts +53 -25
- package/dist/normalize-browser.js +56 -10
- package/dist/normalize-otlp.d.ts +6 -0
- package/dist/normalize-otlp.js +275 -108
- package/dist/otlp-proto.d.ts +14 -0
- package/dist/otlp-proto.js +25 -0
- package/dist/profiles.d.ts +4 -0
- package/dist/profiles.js +6 -2
- package/dist/request-spans.d.ts +45 -0
- package/dist/request-spans.js +91 -0
- package/dist/sdk-versions.d.ts +39 -2
- package/dist/sdk-versions.js +49 -8
- package/dist/server.d.ts +10 -0
- package/dist/server.js +345 -105
- package/dist/sink.d.ts +14 -0
- package/dist/sink.js +15 -0
- package/dist/source-maps-lookup.d.ts +6 -3
- package/dist/source-maps-lookup.js +35 -13
- package/dist/source-maps.d.ts +6 -2
- package/dist/source-maps.js +12 -4
- package/dist/stack-frames.d.ts +5 -2
- package/dist/stack-frames.js +55 -9
- package/dist/symbolicate.d.ts +13 -0
- package/dist/symbolicate.js +22 -0
- package/dist/trace-dedupe.d.ts +98 -0
- package/dist/trace-dedupe.js +385 -0
- package/dist/types.d.ts +5 -1
- package/package.json +1 -1
package/dist/migrations.js
CHANGED
|
@@ -37,7 +37,8 @@ import { profileTableDDL } from "./profiles.js";
|
|
|
37
37
|
import { SOURCE_MAP_DEBUG_COLUMNS, SOURCE_MAP_DEBUG_ID_INDEX, sourceMapTableDDL, } from "./source-maps.js";
|
|
38
38
|
import { LOG_REQUEST_COLUMNS, LOG_REQUEST_ID_INDEX, logTableDDL, requestRollupTableDDL, requestRollupViewDDL, } from "./logs.js";
|
|
39
39
|
import { memoryTableDDL, platformEventTableDDL } from "./memory.js";
|
|
40
|
-
import { ingesterInfoTableDDL, sdkVersionTableDDL } from "./sdk-versions.js";
|
|
40
|
+
import { ingesterInfoTableDDL, SDK_VERSION_VIA_COLUMN, sdkVersionTableDDL } from "./sdk-versions.js";
|
|
41
|
+
import { ingestDropsTableDDL } from "./ingest-drops.js";
|
|
41
42
|
/** Migration 0013 columns — shared with the baseline DDL in clickhouse.ts. */
|
|
42
43
|
export const OCCURRENCE_CODE_COLUMNS = [
|
|
43
44
|
"error_code String DEFAULT ''",
|
|
@@ -62,6 +63,17 @@ export const OCCURRENCE_GROUPING_COLUMNS = [
|
|
|
62
63
|
"frames String DEFAULT '' CODEC(ZSTD(3))",
|
|
63
64
|
"fingerprints Array(String) DEFAULT []",
|
|
64
65
|
];
|
|
66
|
+
/**
|
|
67
|
+
* Migration 0020 columns — shared with the baseline DDL in clickhouse.ts.
|
|
68
|
+
* In-app browser JS frames a source map resolved / left unresolved at
|
|
69
|
+
* ingest (symbolicate.ts inAppFrameResolution); 0 and 0 for server
|
|
70
|
+
* occurrences, browser ones with no in-app JS frame, and rows written
|
|
71
|
+
* before 0020.
|
|
72
|
+
*/
|
|
73
|
+
export const OCCURRENCE_FRAME_RESOLUTION_COLUMNS = [
|
|
74
|
+
"in_app_frames_resolved UInt16 DEFAULT 0",
|
|
75
|
+
"in_app_frames_unresolved UInt16 DEFAULT 0",
|
|
76
|
+
];
|
|
65
77
|
export const MIGRATIONS = [
|
|
66
78
|
// 0001 intentionally reserved as the baseline marker: databases created
|
|
67
79
|
// before the migration runner existed record it as applied without
|
|
@@ -202,6 +214,22 @@ export const MIGRATIONS = [
|
|
|
202
214
|
`ALTER TABLE {db}.runtime_source_maps ADD ${SOURCE_MAP_DEBUG_ID_INDEX.replace("INDEX ", "INDEX IF NOT EXISTS ")}`,
|
|
203
215
|
],
|
|
204
216
|
},
|
|
217
|
+
// Rejections and drops per tenant, minute, route and reason (EI-27):
|
|
218
|
+
// what the ingester refused or did not store, so a repository's missing
|
|
219
|
+
// telemetry has a reason (ingest-drops.ts).
|
|
220
|
+
{ id: "0018-runtime-ingest-drops", statements: [ingestDropsTableDDL("{db}")] },
|
|
221
|
+
// How each service's telemetry arrived: an OpenTelemetry Collector, an
|
|
222
|
+
// SDK exporter directly, or the browser relay (sdk-versions.ts).
|
|
223
|
+
{
|
|
224
|
+
id: "0019-sdk-versions-via",
|
|
225
|
+
statements: [`ALTER TABLE {db}.runtime_sdk_versions ADD COLUMN IF NOT EXISTS ${SDK_VERSION_VIA_COLUMN}`],
|
|
226
|
+
},
|
|
227
|
+
// Resolved and unresolved in-app browser frames per occurrence, after
|
|
228
|
+
// symbolication — the share the EI-14 source map rule reads.
|
|
229
|
+
{
|
|
230
|
+
id: "0020-occurrence-frame-resolution",
|
|
231
|
+
statements: OCCURRENCE_FRAME_RESOLUTION_COLUMNS.map((column) => `ALTER TABLE {db}.runtime_error_occurrences ADD COLUMN IF NOT EXISTS ${column}`),
|
|
232
|
+
},
|
|
205
233
|
];
|
|
206
234
|
/** The tracking table itself — created by the runner before anything else. */
|
|
207
235
|
export function migrationsTableDDL(db) {
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { type RuntimeMetricPoint, type RuntimeOccurrenceInput } from "./types.js";
|
|
3
|
+
/** Events past this in one payload are dropped and counted (events_over_limit). */
|
|
4
|
+
export declare const MAX_BROWSER_EVENTS = 50;
|
|
5
|
+
/** A whole payload, every event valid: what normalizeBrowserPayload takes. */
|
|
3
6
|
export declare const browserPayloadSchema: z.ZodObject<{
|
|
4
|
-
version: z.ZodLiteral<1>;
|
|
5
|
-
sessionId: z.ZodOptional<z.ZodString>;
|
|
6
|
-
service: z.ZodString;
|
|
7
|
-
environment: z.ZodString;
|
|
8
|
-
release: z.ZodOptional<z.ZodString>;
|
|
9
|
-
/** @autter/runtime-browser version (1.4+); recorded for compatibility checks. */
|
|
10
|
-
sdk: z.ZodCatch<z.ZodOptional<z.ZodString>>;
|
|
11
7
|
events: z.ZodArray<z.ZodObject<{
|
|
12
8
|
id: z.ZodOptional<z.ZodString>;
|
|
13
9
|
type: z.ZodEnum<["exception", "unhandled_rejection", "message", "session_start", "track_event", "outcome", "request_failure", "csp_violation", "timing"]>;
|
|
@@ -52,64 +48,71 @@ export declare const browserPayloadSchema: z.ZodObject<{
|
|
|
52
48
|
*/
|
|
53
49
|
traceId: z.ZodCatch<z.ZodOptional<z.ZodString>>;
|
|
54
50
|
}, "strip", z.ZodTypeAny, {
|
|
51
|
+
type: "request_failure" | "timing" | "outcome" | "csp_violation" | "message" | "exception" | "unhandled_rejection" | "session_start" | "track_event";
|
|
55
52
|
message: string;
|
|
56
|
-
type: "message" | "exception" | "request_failure" | "timing" | "outcome" | "csp_violation" | "unhandled_rejection" | "session_start" | "track_event";
|
|
57
53
|
timestamp: string;
|
|
54
|
+
breadcrumbs?: unknown[] | undefined;
|
|
55
|
+
route?: string | undefined;
|
|
58
56
|
severity?: "info" | "warning" | "error" | "fatal" | undefined;
|
|
59
57
|
errorType?: string | undefined;
|
|
60
58
|
stack?: string | undefined;
|
|
61
|
-
route?: string | undefined;
|
|
62
59
|
traceId?: string | undefined;
|
|
63
|
-
breadcrumbs?: unknown[] | undefined;
|
|
64
60
|
debugIds?: Record<string, unknown> | undefined;
|
|
65
61
|
durationMs?: number | undefined;
|
|
66
62
|
filename?: string | undefined;
|
|
63
|
+
name?: string | undefined;
|
|
67
64
|
column?: number | undefined;
|
|
68
65
|
line?: number | undefined;
|
|
69
|
-
name?: string | undefined;
|
|
70
66
|
id?: string | undefined;
|
|
71
67
|
context?: Record<string, unknown> | undefined;
|
|
72
68
|
fingerprint?: string | string[] | undefined;
|
|
73
69
|
}, {
|
|
74
|
-
type: "
|
|
70
|
+
type: "request_failure" | "timing" | "outcome" | "csp_violation" | "message" | "exception" | "unhandled_rejection" | "session_start" | "track_event";
|
|
75
71
|
timestamp: string;
|
|
72
|
+
breadcrumbs?: unknown;
|
|
73
|
+
route?: string | undefined;
|
|
76
74
|
message?: string | undefined;
|
|
77
75
|
severity?: "info" | "warning" | "error" | "fatal" | undefined;
|
|
78
76
|
errorType?: string | undefined;
|
|
79
77
|
stack?: string | undefined;
|
|
80
|
-
route?: string | undefined;
|
|
81
78
|
traceId?: unknown;
|
|
82
|
-
breadcrumbs?: unknown;
|
|
83
79
|
debugIds?: unknown;
|
|
84
80
|
durationMs?: number | undefined;
|
|
85
81
|
filename?: string | undefined;
|
|
82
|
+
name?: string | undefined;
|
|
86
83
|
column?: number | undefined;
|
|
87
84
|
line?: number | undefined;
|
|
88
|
-
name?: string | undefined;
|
|
89
85
|
id?: string | undefined;
|
|
90
86
|
context?: Record<string, unknown> | undefined;
|
|
91
87
|
fingerprint?: unknown;
|
|
92
88
|
}>, "many">;
|
|
89
|
+
version: z.ZodLiteral<1>;
|
|
90
|
+
sessionId: z.ZodOptional<z.ZodString>;
|
|
91
|
+
service: z.ZodString;
|
|
92
|
+
environment: z.ZodString;
|
|
93
|
+
release: z.ZodOptional<z.ZodString>;
|
|
94
|
+
/** @autter/runtime-browser version (1.4+); recorded for compatibility checks. */
|
|
95
|
+
sdk: z.ZodCatch<z.ZodOptional<z.ZodString>>;
|
|
93
96
|
}, "strip", z.ZodTypeAny, {
|
|
97
|
+
version: 1;
|
|
94
98
|
service: string;
|
|
95
99
|
environment: string;
|
|
96
|
-
version: 1;
|
|
97
100
|
events: {
|
|
101
|
+
type: "request_failure" | "timing" | "outcome" | "csp_violation" | "message" | "exception" | "unhandled_rejection" | "session_start" | "track_event";
|
|
98
102
|
message: string;
|
|
99
|
-
type: "message" | "exception" | "request_failure" | "timing" | "outcome" | "csp_violation" | "unhandled_rejection" | "session_start" | "track_event";
|
|
100
103
|
timestamp: string;
|
|
104
|
+
breadcrumbs?: unknown[] | undefined;
|
|
105
|
+
route?: string | undefined;
|
|
101
106
|
severity?: "info" | "warning" | "error" | "fatal" | undefined;
|
|
102
107
|
errorType?: string | undefined;
|
|
103
108
|
stack?: string | undefined;
|
|
104
|
-
route?: string | undefined;
|
|
105
109
|
traceId?: string | undefined;
|
|
106
|
-
breadcrumbs?: unknown[] | undefined;
|
|
107
110
|
debugIds?: Record<string, unknown> | undefined;
|
|
108
111
|
durationMs?: number | undefined;
|
|
109
112
|
filename?: string | undefined;
|
|
113
|
+
name?: string | undefined;
|
|
110
114
|
column?: number | undefined;
|
|
111
115
|
line?: number | undefined;
|
|
112
|
-
name?: string | undefined;
|
|
113
116
|
id?: string | undefined;
|
|
114
117
|
context?: Record<string, unknown> | undefined;
|
|
115
118
|
fingerprint?: string | string[] | undefined;
|
|
@@ -118,25 +121,25 @@ export declare const browserPayloadSchema: z.ZodObject<{
|
|
|
118
121
|
sessionId?: string | undefined;
|
|
119
122
|
sdk?: string | undefined;
|
|
120
123
|
}, {
|
|
124
|
+
version: 1;
|
|
121
125
|
service: string;
|
|
122
126
|
environment: string;
|
|
123
|
-
version: 1;
|
|
124
127
|
events: {
|
|
125
|
-
type: "
|
|
128
|
+
type: "request_failure" | "timing" | "outcome" | "csp_violation" | "message" | "exception" | "unhandled_rejection" | "session_start" | "track_event";
|
|
126
129
|
timestamp: string;
|
|
130
|
+
breadcrumbs?: unknown;
|
|
131
|
+
route?: string | undefined;
|
|
127
132
|
message?: string | undefined;
|
|
128
133
|
severity?: "info" | "warning" | "error" | "fatal" | undefined;
|
|
129
134
|
errorType?: string | undefined;
|
|
130
135
|
stack?: string | undefined;
|
|
131
|
-
route?: string | undefined;
|
|
132
136
|
traceId?: unknown;
|
|
133
|
-
breadcrumbs?: unknown;
|
|
134
137
|
debugIds?: unknown;
|
|
135
138
|
durationMs?: number | undefined;
|
|
136
139
|
filename?: string | undefined;
|
|
140
|
+
name?: string | undefined;
|
|
137
141
|
column?: number | undefined;
|
|
138
142
|
line?: number | undefined;
|
|
139
|
-
name?: string | undefined;
|
|
140
143
|
id?: string | undefined;
|
|
141
144
|
context?: Record<string, unknown> | undefined;
|
|
142
145
|
fingerprint?: unknown;
|
|
@@ -146,6 +149,31 @@ export declare const browserPayloadSchema: z.ZodObject<{
|
|
|
146
149
|
sdk?: unknown;
|
|
147
150
|
}>;
|
|
148
151
|
export type BrowserPayload = z.infer<typeof browserPayloadSchema>;
|
|
152
|
+
export interface ParsedBrowserPayload {
|
|
153
|
+
/** The envelope with its valid events (at most MAX_BROWSER_EVENTS). */
|
|
154
|
+
payload: BrowserPayload;
|
|
155
|
+
/** Events dropped because they failed validation (invalid_event). */
|
|
156
|
+
invalidEvents: number;
|
|
157
|
+
/** Events past MAX_BROWSER_EVENTS, not looked at (events_over_limit). */
|
|
158
|
+
overLimitEvents: number;
|
|
159
|
+
/** The first validation issues of the dropped events; `path` starts with ["events", index]. */
|
|
160
|
+
issues: z.ZodIssue[];
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Validate a browser payload event by event (1.8.0). The envelope (version,
|
|
164
|
+
* service, environment) must be valid or the payload is refused; an event
|
|
165
|
+
* that fails validation — a type this ingester doesn't know, a bad
|
|
166
|
+
* timestamp, an oversized field — is dropped on its own and counted, so it
|
|
167
|
+
* no longer costs the errors sent in the same beacon. Events past
|
|
168
|
+
* MAX_BROWSER_EVENTS are dropped and counted unread.
|
|
169
|
+
*/
|
|
170
|
+
export declare function parseBrowserPayload(body: unknown): {
|
|
171
|
+
success: true;
|
|
172
|
+
data: ParsedBrowserPayload;
|
|
173
|
+
} | {
|
|
174
|
+
success: false;
|
|
175
|
+
issues: z.ZodIssue[];
|
|
176
|
+
};
|
|
149
177
|
export interface NormalizedBrowser {
|
|
150
178
|
occurrences: RuntimeOccurrenceInput[];
|
|
151
179
|
metricPoints: RuntimeMetricPoint[];
|
|
@@ -67,7 +67,9 @@ const browserEventSchema = z.object({
|
|
|
67
67
|
*/
|
|
68
68
|
traceId: z.string().regex(/^(?!0{32})[0-9a-f]{32}$/).optional().catch(undefined),
|
|
69
69
|
});
|
|
70
|
-
|
|
70
|
+
/** Events past this in one payload are dropped and counted (events_over_limit). */
|
|
71
|
+
export const MAX_BROWSER_EVENTS = 50;
|
|
72
|
+
const browserEnvelope = {
|
|
71
73
|
version: z.literal(1),
|
|
72
74
|
sessionId: z.string().max(100).optional(),
|
|
73
75
|
service: z.string().min(1).max(200),
|
|
@@ -75,8 +77,53 @@ export const browserPayloadSchema = z.object({
|
|
|
75
77
|
release: z.string().max(200).optional(),
|
|
76
78
|
/** @autter/runtime-browser version (1.4+); recorded for compatibility checks. */
|
|
77
79
|
sdk: z.string().regex(/^\d{1,6}\.\d{1,6}\.\d{1,6}[0-9A-Za-z.+-]{0,20}$/).optional().catch(undefined),
|
|
78
|
-
|
|
80
|
+
};
|
|
81
|
+
/** A whole payload, every event valid: what normalizeBrowserPayload takes. */
|
|
82
|
+
export const browserPayloadSchema = z.object({
|
|
83
|
+
...browserEnvelope,
|
|
84
|
+
events: z.array(browserEventSchema).max(MAX_BROWSER_EVENTS),
|
|
79
85
|
});
|
|
86
|
+
const browserEnvelopeSchema = z.object({ ...browserEnvelope, events: z.array(z.unknown()) });
|
|
87
|
+
/**
|
|
88
|
+
* Validate a browser payload event by event (1.8.0). The envelope (version,
|
|
89
|
+
* service, environment) must be valid or the payload is refused; an event
|
|
90
|
+
* that fails validation — a type this ingester doesn't know, a bad
|
|
91
|
+
* timestamp, an oversized field — is dropped on its own and counted, so it
|
|
92
|
+
* no longer costs the errors sent in the same beacon. Events past
|
|
93
|
+
* MAX_BROWSER_EVENTS are dropped and counted unread.
|
|
94
|
+
*/
|
|
95
|
+
export function parseBrowserPayload(body) {
|
|
96
|
+
const envelope = browserEnvelopeSchema.safeParse(body);
|
|
97
|
+
if (!envelope.success)
|
|
98
|
+
return { success: false, issues: envelope.error.issues.slice(0, 5) };
|
|
99
|
+
const raw = envelope.data.events;
|
|
100
|
+
const considered = raw.slice(0, MAX_BROWSER_EVENTS);
|
|
101
|
+
const events = [];
|
|
102
|
+
const issues = [];
|
|
103
|
+
let invalidEvents = 0;
|
|
104
|
+
considered.forEach((candidate, index) => {
|
|
105
|
+
const parsed = browserEventSchema.safeParse(candidate);
|
|
106
|
+
if (parsed.success) {
|
|
107
|
+
events.push(parsed.data);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
invalidEvents += 1;
|
|
111
|
+
for (const issue of parsed.error.issues) {
|
|
112
|
+
if (issues.length >= 5)
|
|
113
|
+
break;
|
|
114
|
+
issues.push({ ...issue, path: ["events", index, ...issue.path] });
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
return {
|
|
118
|
+
success: true,
|
|
119
|
+
data: {
|
|
120
|
+
payload: { ...envelope.data, events },
|
|
121
|
+
invalidEvents,
|
|
122
|
+
overLimitEvents: raw.length - considered.length,
|
|
123
|
+
issues,
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
}
|
|
80
127
|
const TYPE_TO_ERROR_TYPE = {
|
|
81
128
|
exception: "Error",
|
|
82
129
|
unhandled_rejection: "UnhandledRejection",
|
|
@@ -154,14 +201,13 @@ export function normalizeBrowserPayload(payload) {
|
|
|
154
201
|
continue;
|
|
155
202
|
}
|
|
156
203
|
const severity = asSeverity(event.severity, TYPE_TO_SEVERITY[event.type] ?? "error");
|
|
157
|
-
//
|
|
158
|
-
// only
|
|
159
|
-
//
|
|
160
|
-
//
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
});
|
|
204
|
+
// A browser error belongs to no server request: it counts in
|
|
205
|
+
// `error_count` only (fatal/error severity), never `request_count`,
|
|
206
|
+
// so a page that only reports errors still shows them without
|
|
207
|
+
// inventing requests. Warnings and info messages count nothing.
|
|
208
|
+
if (severity === "fatal" || severity === "error") {
|
|
209
|
+
bumpRollup(event.route ? (event.route.split("?")[0] ?? "") : "", occurredAt, { errorCount: 1 });
|
|
210
|
+
}
|
|
165
211
|
occurrences.push({
|
|
166
212
|
source: "browser",
|
|
167
213
|
severity,
|
package/dist/normalize-otlp.d.ts
CHANGED
|
@@ -78,7 +78,13 @@ export interface OtlpMetricsRequest {
|
|
|
78
78
|
}>;
|
|
79
79
|
}
|
|
80
80
|
export interface NormalizedTraces {
|
|
81
|
+
/** One per thrown error: duplicate recordings across a trace's spans are
|
|
82
|
+
* merged and redundant status-only occurrences dropped (trace-dedupe.ts). */
|
|
81
83
|
occurrences: RuntimeOccurrenceInput[];
|
|
84
|
+
/** Each occurrence's position among every signal the batch recorded,
|
|
85
|
+
* before deduplication: the batch index its deterministic id is derived
|
|
86
|
+
* from, so a merge or a drop never shifts another occurrence's id. */
|
|
87
|
+
occurrenceBatchIndexes: number[];
|
|
82
88
|
spans: RuntimeSpanRow[];
|
|
83
89
|
metricPoints: RuntimeMetricPoint[];
|
|
84
90
|
llmCalls: RuntimeLlmCall[];
|