@autter/otlp-ingester 1.9.0 → 1.10.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/compat-manifest.json +8 -0
- package/dist/log-promotion.d.ts +36 -5
- package/dist/log-promotion.js +76 -21
- package/dist/server.js +2 -2
- package/package.json +1 -1
|
@@ -169,6 +169,14 @@
|
|
|
169
169
|
"ingester": "1.9.0",
|
|
170
170
|
"migrations": ["0021-occurrence-collapsed-count"],
|
|
171
171
|
"sdks": {}
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
"id": "edge_request_counts",
|
|
175
|
+
"title": "Edge requests counted from their request summaries",
|
|
176
|
+
"ingester": "1.10.0",
|
|
177
|
+
"migrations": [],
|
|
178
|
+
"route": "/v1/logs",
|
|
179
|
+
"sdks": { "@autter/runtime-edge": "1.3.0" }
|
|
172
180
|
}
|
|
173
181
|
]
|
|
174
182
|
}
|
package/dist/log-promotion.d.ts
CHANGED
|
@@ -48,9 +48,40 @@ export interface PromotionLookup {
|
|
|
48
48
|
*/
|
|
49
49
|
export declare function promotionLookups(occurrences: RuntimeOccurrenceInput[], now?: number): PromotionLookup[];
|
|
50
50
|
/**
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
51
|
+
* `autter.request.counted_by = "summary"`: the request this record belongs to
|
|
52
|
+
* is counted in the usage rollups by its request summary (the record of
|
|
53
|
+
* `autter.operation.kind = "request"` carrying the same mark), because no
|
|
54
|
+
* other feed sees it. `@autter/runtime-edge` (1.3.0+) puts it on every
|
|
55
|
+
* record of a request: an edge function has no trace pipeline and no
|
|
56
|
+
* `http.server.duration` histogram, so without it edge services had error
|
|
57
|
+
* counts and no requests. Nothing else sets it: Node and Next.js summaries
|
|
58
|
+
* never carry it (their requests are counted by the histogram or the spans),
|
|
59
|
+
* so a request is counted by its summary only when its sender says the
|
|
60
|
+
* summary is the one count it gets.
|
|
55
61
|
*/
|
|
56
|
-
export declare
|
|
62
|
+
export declare const COUNTED_BY_ATTRIBUTE = "autter.request.counted_by";
|
|
63
|
+
/** On a counted summary: an error of the request was reported (an
|
|
64
|
+
* `autter.capture.mode = "log"` record), which makes it a failed request. */
|
|
65
|
+
export declare const ERROR_REPORTED_ATTRIBUTE = "autter.request.error_reported";
|
|
66
|
+
export declare function countedBySummary(attributes: Record<string, unknown> | null | undefined): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* The usage rollups (`runtime_metrics_1m`) a /v1/logs batch adds, counted the
|
|
69
|
+
* way the trace path counts (normalize-otlp.ts): `request_count` counts
|
|
70
|
+
* requests only, `error_count` counts failed requests once and errors outside
|
|
71
|
+
* a counted request one each.
|
|
72
|
+
*
|
|
73
|
+
* - A request summary marked counted (`countedBySummary`) is one request:
|
|
74
|
+
* `request_count` 1, its duration, on its route and minute; `error_count` 1
|
|
75
|
+
* when it failed — outcome `failed`, a status ≥ 500, or an error reported
|
|
76
|
+
* in it (`autter.request.error_reported`), as an error occurrence recorded
|
|
77
|
+
* in a request fails it on the trace path.
|
|
78
|
+
* - A promoted occurrence (logger-only or edge error record) adds
|
|
79
|
+
* `error_count` 1 — unless its record is marked counted: its request's
|
|
80
|
+
* summary already counts that failure once, however many errors it had.
|
|
81
|
+
*
|
|
82
|
+
* The decision is per record, never by matching records across a batch, so
|
|
83
|
+
* a request whose records an exporter splits over two batches is still
|
|
84
|
+
* counted once. Unmarked summaries add nothing (they are counted elsewhere,
|
|
85
|
+
* or by no one, as before).
|
|
86
|
+
*/
|
|
87
|
+
export declare function logRollups(rows: RuntimeLogRecord[], promoted: RuntimeOccurrence[]): RuntimeMetricPoint[];
|
package/dist/log-promotion.js
CHANGED
|
@@ -81,38 +81,93 @@ export function promotionLookups(occurrences, now = Date.now()) {
|
|
|
81
81
|
return lookups;
|
|
82
82
|
}
|
|
83
83
|
/**
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
84
|
+
* `autter.request.counted_by = "summary"`: the request this record belongs to
|
|
85
|
+
* is counted in the usage rollups by its request summary (the record of
|
|
86
|
+
* `autter.operation.kind = "request"` carrying the same mark), because no
|
|
87
|
+
* other feed sees it. `@autter/runtime-edge` (1.3.0+) puts it on every
|
|
88
|
+
* record of a request: an edge function has no trace pipeline and no
|
|
89
|
+
* `http.server.duration` histogram, so without it edge services had error
|
|
90
|
+
* counts and no requests. Nothing else sets it: Node and Next.js summaries
|
|
91
|
+
* never carry it (their requests are counted by the histogram or the spans),
|
|
92
|
+
* so a request is counted by its summary only when its sender says the
|
|
93
|
+
* summary is the one count it gets.
|
|
88
94
|
*/
|
|
89
|
-
export
|
|
95
|
+
export const COUNTED_BY_ATTRIBUTE = "autter.request.counted_by";
|
|
96
|
+
/** On a counted summary: an error of the request was reported (an
|
|
97
|
+
* `autter.capture.mode = "log"` record), which makes it a failed request. */
|
|
98
|
+
export const ERROR_REPORTED_ATTRIBUTE = "autter.request.error_reported";
|
|
99
|
+
export function countedBySummary(attributes) {
|
|
100
|
+
return attributes?.[COUNTED_BY_ATTRIBUTE] === "summary";
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* The usage rollups (`runtime_metrics_1m`) a /v1/logs batch adds, counted the
|
|
104
|
+
* way the trace path counts (normalize-otlp.ts): `request_count` counts
|
|
105
|
+
* requests only, `error_count` counts failed requests once and errors outside
|
|
106
|
+
* a counted request one each.
|
|
107
|
+
*
|
|
108
|
+
* - A request summary marked counted (`countedBySummary`) is one request:
|
|
109
|
+
* `request_count` 1, its duration, on its route and minute; `error_count` 1
|
|
110
|
+
* when it failed — outcome `failed`, a status ≥ 500, or an error reported
|
|
111
|
+
* in it (`autter.request.error_reported`), as an error occurrence recorded
|
|
112
|
+
* in a request fails it on the trace path.
|
|
113
|
+
* - A promoted occurrence (logger-only or edge error record) adds
|
|
114
|
+
* `error_count` 1 — unless its record is marked counted: its request's
|
|
115
|
+
* summary already counts that failure once, however many errors it had.
|
|
116
|
+
*
|
|
117
|
+
* The decision is per record, never by matching records across a batch, so
|
|
118
|
+
* a request whose records an exporter splits over two batches is still
|
|
119
|
+
* counted once. Unmarked summaries add nothing (they are counted elsewhere,
|
|
120
|
+
* or by no one, as before).
|
|
121
|
+
*/
|
|
122
|
+
export function logRollups(rows, promoted) {
|
|
90
123
|
const rollups = new Map();
|
|
91
|
-
|
|
92
|
-
const
|
|
93
|
-
const
|
|
94
|
-
const key = [
|
|
95
|
-
occ.service,
|
|
96
|
-
occ.environment,
|
|
97
|
-
occ.release ?? "",
|
|
98
|
-
route,
|
|
99
|
-
bucketAt.getTime(),
|
|
100
|
-
].join(" ");
|
|
124
|
+
const add = (point) => {
|
|
125
|
+
const { at, ...rest } = point;
|
|
126
|
+
const bucketAt = new Date(Math.floor(at.getTime() / 60_000) * 60_000);
|
|
127
|
+
const key = [rest.service, rest.environment, rest.release ?? "", rest.route, bucketAt.getTime()].join(" ");
|
|
101
128
|
const existing = rollups.get(key);
|
|
102
129
|
if (existing) {
|
|
103
|
-
existing.
|
|
104
|
-
|
|
130
|
+
existing.requestCount += rest.requestCount;
|
|
131
|
+
existing.errorCount += rest.errorCount;
|
|
132
|
+
existing.durationSumMs += rest.durationSumMs;
|
|
133
|
+
return;
|
|
105
134
|
}
|
|
106
|
-
rollups.set(key, {
|
|
135
|
+
rollups.set(key, { ...rest, bucketAt, sessionCount: 0 });
|
|
136
|
+
};
|
|
137
|
+
for (const row of rows) {
|
|
138
|
+
if (row.kind !== "request" || !countedBySummary(row.attributes))
|
|
139
|
+
continue;
|
|
140
|
+
const failed = row.outcome === "failed" ||
|
|
141
|
+
row.statusCode >= 500 ||
|
|
142
|
+
row.attributes[ERROR_REPORTED_ATTRIBUTE] === true;
|
|
143
|
+
add({
|
|
144
|
+
service: row.service,
|
|
145
|
+
environment: row.environment,
|
|
146
|
+
release: row.release || null,
|
|
147
|
+
// Already normalized (logs.ts), the key promoted errors use too.
|
|
148
|
+
route: row.route,
|
|
149
|
+
at: row.occurredAt,
|
|
150
|
+
requestCount: 1,
|
|
151
|
+
errorCount: failed ? 1 : 0,
|
|
152
|
+
durationSumMs: row.durationMs,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
for (const occ of promoted) {
|
|
156
|
+
// Its request's summary counts this failure.
|
|
157
|
+
if (countedBySummary(occ.attributes))
|
|
158
|
+
continue;
|
|
159
|
+
// One error of its own, in `error_count` only — what the trace path
|
|
160
|
+
// does for an error outside a request: the record names no request
|
|
161
|
+
// the rollups count, so no request is invented.
|
|
162
|
+
add({
|
|
107
163
|
service: occ.service,
|
|
108
164
|
environment: occ.environment,
|
|
109
165
|
release: occ.release,
|
|
110
|
-
route,
|
|
111
|
-
|
|
166
|
+
route: normalizeRoute(occ.route),
|
|
167
|
+
at: occ.occurredAt,
|
|
112
168
|
requestCount: 0,
|
|
113
169
|
errorCount: 1,
|
|
114
170
|
durationSumMs: 0,
|
|
115
|
-
sessionCount: 0,
|
|
116
171
|
});
|
|
117
172
|
}
|
|
118
173
|
return [...rollups.values()];
|
package/dist/server.js
CHANGED
|
@@ -8,7 +8,7 @@ import { deriveFields, occurrenceIdFor } from "./fingerprint.js";
|
|
|
8
8
|
import { occurrenceIdentity } from "./fingerprint-v3.js";
|
|
9
9
|
import { parseStackFrames } from "./stack-frames.js";
|
|
10
10
|
import { SourceMapCache, Symbolicator } from "./symbolicate.js";
|
|
11
|
-
import { logPromotionCandidates, promotionLookups,
|
|
11
|
+
import { logPromotionCandidates, promotionLookups, logRollups, } from "./log-promotion.js";
|
|
12
12
|
import { normalizeBrowserPayload, parseBrowserPayload, } from "./normalize-browser.js";
|
|
13
13
|
import { normalizeMetrics, normalizeTraces, } from "./normalize-otlp.js";
|
|
14
14
|
import { decodeMetricsRequest, decodeTraceRequest, decodeLogsRequest, encodeExportResponse } from "./otlp-proto.js";
|
|
@@ -700,7 +700,7 @@ export function createIngesterApp(config) {
|
|
|
700
700
|
// and those are promoted to occurrences here — see log-promotion.ts.
|
|
701
701
|
const promoted = await promoteLogs(ctx, logs);
|
|
702
702
|
// Rollups count every promoted error, collapsed or suppressed ones too.
|
|
703
|
-
const metricPoints =
|
|
703
|
+
const metricPoints = logRollups(logs, promoted);
|
|
704
704
|
const admitted = admit(ctx, req, promoted);
|
|
705
705
|
try {
|
|
706
706
|
await Promise.all([
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@autter/otlp-ingester",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.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",
|