@kortyx/usage-telemetry 0.3.0 → 0.4.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/CHANGELOG.md +8 -0
- package/README.md +86 -4
- package/dist/browser-node.d.ts +11 -3
- package/dist/browser-node.js +432 -23
- package/dist/browser-node.js.map +1 -1
- package/dist/{client-rVwo4XAO.d.ts → client-BPjAx5oh.d.ts} +8 -5
- package/dist/index.d.ts +12 -3
- package/dist/index.js +426 -23
- package/dist/index.js.map +1 -1
- package/dist/node.d.ts +10 -4
- package/dist/node.js +445 -24
- package/dist/node.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
classifyUsageError: () => classifyUsageError,
|
|
24
|
+
classifyUsageHttpStatus: () => classifyUsageHttpStatus,
|
|
24
25
|
createCollectorTransport: () => createCollectorTransport,
|
|
25
26
|
createPostHogTransport: () => createPostHogTransport,
|
|
26
27
|
createUsageTelemetry: () => createUsageTelemetry,
|
|
@@ -72,6 +73,10 @@ var operations = [
|
|
|
72
73
|
"studio.settings",
|
|
73
74
|
"studio.update",
|
|
74
75
|
"studio.ingest",
|
|
76
|
+
"cli.command",
|
|
77
|
+
"studio.eval.execution",
|
|
78
|
+
"studio.diagnostic",
|
|
79
|
+
"studio.table.layout",
|
|
75
80
|
"cli.topology",
|
|
76
81
|
"cli.eval"
|
|
77
82
|
];
|
|
@@ -86,9 +91,143 @@ var outcomes = [
|
|
|
86
91
|
"ungraded"
|
|
87
92
|
];
|
|
88
93
|
var publicCatalog = {
|
|
89
|
-
products: ["sdk", "oss_studio"],
|
|
94
|
+
products: ["sdk", "oss_studio", "cli"],
|
|
90
95
|
operations,
|
|
91
96
|
properties: {
|
|
97
|
+
measurement_version: ["2"],
|
|
98
|
+
measurement_kind: [
|
|
99
|
+
"invocation",
|
|
100
|
+
"stage",
|
|
101
|
+
"execution",
|
|
102
|
+
"attempt",
|
|
103
|
+
"chunk",
|
|
104
|
+
"output",
|
|
105
|
+
"update",
|
|
106
|
+
"poll",
|
|
107
|
+
"request",
|
|
108
|
+
"call",
|
|
109
|
+
"feature",
|
|
110
|
+
"observation"
|
|
111
|
+
],
|
|
112
|
+
traffic_source: ["internal", "synthetic", "external", "unknown"],
|
|
113
|
+
layout_action: [
|
|
114
|
+
"visibility",
|
|
115
|
+
"show_all",
|
|
116
|
+
"reset",
|
|
117
|
+
"apply",
|
|
118
|
+
"reset_width",
|
|
119
|
+
"pin",
|
|
120
|
+
"unpin",
|
|
121
|
+
"resize",
|
|
122
|
+
"reorder"
|
|
123
|
+
],
|
|
124
|
+
eval_phase: [
|
|
125
|
+
"params",
|
|
126
|
+
"setup",
|
|
127
|
+
"execute",
|
|
128
|
+
"responder",
|
|
129
|
+
"reference",
|
|
130
|
+
"grading",
|
|
131
|
+
"verification",
|
|
132
|
+
"cleanup",
|
|
133
|
+
"reporting"
|
|
134
|
+
],
|
|
135
|
+
cli_resource: ["evals.runs", "evals.suites"],
|
|
136
|
+
retryable: "boolean",
|
|
137
|
+
retried: "boolean",
|
|
138
|
+
recovered: "boolean",
|
|
139
|
+
retry_attempt: ["1", "2-5", "6-20", "21-100", "101+"],
|
|
140
|
+
batch_size: ["1", "2-5", "6-20", "21-100", "101+"],
|
|
141
|
+
http_status_class: ["1xx", "2xx", "3xx", "4xx", "5xx"],
|
|
142
|
+
cause_category: [
|
|
143
|
+
"configuration",
|
|
144
|
+
"provider",
|
|
145
|
+
"validation",
|
|
146
|
+
"domain",
|
|
147
|
+
"workflow",
|
|
148
|
+
"persistence",
|
|
149
|
+
"request",
|
|
150
|
+
"transport",
|
|
151
|
+
"internal",
|
|
152
|
+
"unknown"
|
|
153
|
+
],
|
|
154
|
+
cli_command: [
|
|
155
|
+
"studio.start",
|
|
156
|
+
"studio.stop",
|
|
157
|
+
"studio.restart",
|
|
158
|
+
"studio.status",
|
|
159
|
+
"studio.logs",
|
|
160
|
+
"studio.credentials",
|
|
161
|
+
"studio.reset",
|
|
162
|
+
"studio.prompts",
|
|
163
|
+
"studio.evals",
|
|
164
|
+
"studio.runs",
|
|
165
|
+
"studio.sessions",
|
|
166
|
+
"studio.interrupts",
|
|
167
|
+
"studio.workflows",
|
|
168
|
+
"studio.diagnostics",
|
|
169
|
+
"studio.inspect",
|
|
170
|
+
"studio.doctor",
|
|
171
|
+
"studio.catalogs",
|
|
172
|
+
"connections",
|
|
173
|
+
"evals.run",
|
|
174
|
+
"evals.list",
|
|
175
|
+
"topology.push",
|
|
176
|
+
"help",
|
|
177
|
+
"unknown"
|
|
178
|
+
],
|
|
179
|
+
cli_action: [
|
|
180
|
+
"start",
|
|
181
|
+
"stop",
|
|
182
|
+
"restart",
|
|
183
|
+
"status",
|
|
184
|
+
"logs",
|
|
185
|
+
"credentials",
|
|
186
|
+
"reset",
|
|
187
|
+
"run",
|
|
188
|
+
"list",
|
|
189
|
+
"get",
|
|
190
|
+
"show",
|
|
191
|
+
"inspect",
|
|
192
|
+
"analyze",
|
|
193
|
+
"download",
|
|
194
|
+
"doctor",
|
|
195
|
+
"cancel",
|
|
196
|
+
"compare",
|
|
197
|
+
"create",
|
|
198
|
+
"update",
|
|
199
|
+
"delete",
|
|
200
|
+
"import",
|
|
201
|
+
"export",
|
|
202
|
+
"pull",
|
|
203
|
+
"push",
|
|
204
|
+
"add",
|
|
205
|
+
"remove",
|
|
206
|
+
"use",
|
|
207
|
+
"verify",
|
|
208
|
+
"versions",
|
|
209
|
+
"diff",
|
|
210
|
+
"validate",
|
|
211
|
+
"action",
|
|
212
|
+
"tag",
|
|
213
|
+
"untag",
|
|
214
|
+
"rollback",
|
|
215
|
+
"promote",
|
|
216
|
+
"archive",
|
|
217
|
+
"restore",
|
|
218
|
+
"test",
|
|
219
|
+
"copy",
|
|
220
|
+
"apply",
|
|
221
|
+
"wait",
|
|
222
|
+
"catalogs",
|
|
223
|
+
"help",
|
|
224
|
+
"unknown"
|
|
225
|
+
],
|
|
226
|
+
dry_run: "boolean",
|
|
227
|
+
json_output: "boolean",
|
|
228
|
+
settings_override: "boolean",
|
|
229
|
+
case_timeout_override: "boolean",
|
|
230
|
+
run_timeout_override: "boolean",
|
|
92
231
|
phase: [
|
|
93
232
|
"admission",
|
|
94
233
|
"execution",
|
|
@@ -233,6 +372,7 @@ var publicCatalog = {
|
|
|
233
372
|
"pending",
|
|
234
373
|
"expired"
|
|
235
374
|
],
|
|
375
|
+
match: ["all", "any"],
|
|
236
376
|
filter: [
|
|
237
377
|
"search",
|
|
238
378
|
"status",
|
|
@@ -265,6 +405,7 @@ var publicCatalog = {
|
|
|
265
405
|
"401",
|
|
266
406
|
"403",
|
|
267
407
|
"404",
|
|
408
|
+
"408",
|
|
268
409
|
"409",
|
|
269
410
|
"413",
|
|
270
411
|
"422",
|
|
@@ -288,6 +429,47 @@ var publicCatalog = {
|
|
|
288
429
|
},
|
|
289
430
|
// Built-in contracts only; application codes and provider response text are excluded.
|
|
290
431
|
errorCodes: [
|
|
432
|
+
"UNCLASSIFIED_FAILURE",
|
|
433
|
+
"HTTP_UNAUTHORIZED",
|
|
434
|
+
"HTTP_FORBIDDEN",
|
|
435
|
+
"HTTP_NOT_FOUND",
|
|
436
|
+
"HTTP_TIMEOUT",
|
|
437
|
+
"HTTP_CONFLICT",
|
|
438
|
+
"HTTP_TOO_LARGE",
|
|
439
|
+
"HTTP_RATE_LIMITED",
|
|
440
|
+
"HTTP_SERVER_ERROR",
|
|
441
|
+
"HTTP_INVALID_REQUEST",
|
|
442
|
+
"NETWORK_DNS_FAILED",
|
|
443
|
+
"NETWORK_CONNECTION_REFUSED",
|
|
444
|
+
"NETWORK_CONNECTION_RESET",
|
|
445
|
+
"NETWORK_TIMEOUT",
|
|
446
|
+
"NETWORK_TLS_FAILED",
|
|
447
|
+
"CLI_ARGUMENT_INVALID",
|
|
448
|
+
"CLI_EXIT_FAILED",
|
|
449
|
+
"STUDIO_NOT_CONFIGURED",
|
|
450
|
+
"STUDIO_RESPONSE_INVALID",
|
|
451
|
+
"EVAL_CONCURRENCY_CHANGED",
|
|
452
|
+
"EVAL_CONSUMER_FAILED",
|
|
453
|
+
"EVAL_CONTRACT_CHANGED",
|
|
454
|
+
"EVAL_DISCOVERY_REJECTED",
|
|
455
|
+
"EVAL_EXECUTION_CONFLICT",
|
|
456
|
+
"EVAL_EXECUTION_STORE_CHANGED",
|
|
457
|
+
"EVAL_EXECUTION_UNKNOWN",
|
|
458
|
+
"EVAL_EXECUTOR_BUSY",
|
|
459
|
+
"EVAL_EXECUTOR_FAILED",
|
|
460
|
+
"EVAL_EXECUTOR_REJECTED",
|
|
461
|
+
"EVAL_EXECUTOR_UNAUTHORIZED",
|
|
462
|
+
"EVAL_GRADING_FAILED",
|
|
463
|
+
"EVAL_GRADING_TIMEOUT",
|
|
464
|
+
"EVAL_JUDGE_UNAVAILABLE",
|
|
465
|
+
"EVAL_LEASE_LOST",
|
|
466
|
+
"EVAL_RETRY_DELAY_EXCEEDED",
|
|
467
|
+
"EVAL_SETUP_TIMEOUT",
|
|
468
|
+
"EVAL_TRANSPORT_UNAVAILABLE",
|
|
469
|
+
"EVAL_VERIFICATION_TIMEOUT",
|
|
470
|
+
"EVAL_RESULT_INVALID",
|
|
471
|
+
"EVAL_RUN_TIMEOUT",
|
|
472
|
+
"EVAL_SETTINGS_INVALID",
|
|
291
473
|
"EXECUTION_FAILED",
|
|
292
474
|
"INVALID_REQUEST",
|
|
293
475
|
"INVALID_RESUME",
|
|
@@ -355,8 +537,8 @@ function scale(value) {
|
|
|
355
537
|
return value <= 1 ? "1" : value <= 5 ? "2-5" : value <= 20 ? "6-20" : value <= 100 ? "21-100" : "101+";
|
|
356
538
|
}
|
|
357
539
|
|
|
358
|
-
// src/
|
|
359
|
-
function
|
|
540
|
+
// src/failure.ts
|
|
541
|
+
function usageErrorProperty(value, key) {
|
|
360
542
|
try {
|
|
361
543
|
if (!value || typeof value !== "object") return void 0;
|
|
362
544
|
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
@@ -365,40 +547,201 @@ function property(value, key) {
|
|
|
365
547
|
return void 0;
|
|
366
548
|
}
|
|
367
549
|
}
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
550
|
+
var networkCodes = {
|
|
551
|
+
ENOTFOUND: "NETWORK_DNS_FAILED",
|
|
552
|
+
EAI_AGAIN: "NETWORK_DNS_FAILED",
|
|
553
|
+
ECONNREFUSED: "NETWORK_CONNECTION_REFUSED",
|
|
554
|
+
ECONNRESET: "NETWORK_CONNECTION_RESET",
|
|
555
|
+
EPIPE: "NETWORK_CONNECTION_RESET",
|
|
556
|
+
ETIMEDOUT: "NETWORK_TIMEOUT",
|
|
557
|
+
UND_ERR_CONNECT_TIMEOUT: "NETWORK_TIMEOUT",
|
|
558
|
+
UND_ERR_HEADERS_TIMEOUT: "NETWORK_TIMEOUT",
|
|
559
|
+
UND_ERR_BODY_TIMEOUT: "NETWORK_TIMEOUT",
|
|
560
|
+
CERT_HAS_EXPIRED: "NETWORK_TLS_FAILED",
|
|
561
|
+
DEPTH_ZERO_SELF_SIGNED_CERT: "NETWORK_TLS_FAILED",
|
|
562
|
+
UNABLE_TO_VERIFY_LEAF_SIGNATURE: "NETWORK_TLS_FAILED"
|
|
563
|
+
};
|
|
564
|
+
function classifyUsageHttpStatus(status) {
|
|
565
|
+
if (!Number.isInteger(status) || status < 100 || status > 599)
|
|
566
|
+
return {
|
|
567
|
+
outcome: "failed",
|
|
568
|
+
properties: {
|
|
569
|
+
error_code: "UNCLASSIFIED_FAILURE",
|
|
570
|
+
error_category: "unknown"
|
|
571
|
+
}
|
|
572
|
+
};
|
|
573
|
+
if (status < 400)
|
|
574
|
+
return {
|
|
575
|
+
outcome: "success",
|
|
576
|
+
properties: { http_status_class: `${Math.floor(status / 100)}xx` }
|
|
577
|
+
};
|
|
578
|
+
const code = status === 401 ? "HTTP_UNAUTHORIZED" : status === 403 ? "HTTP_FORBIDDEN" : status === 404 ? "HTTP_NOT_FOUND" : status === 408 || status === 504 ? "HTTP_TIMEOUT" : status === 409 ? "HTTP_CONFLICT" : status === 413 ? "HTTP_TOO_LARGE" : status === 429 ? "HTTP_RATE_LIMITED" : status >= 500 ? "HTTP_SERVER_ERROR" : "HTTP_INVALID_REQUEST";
|
|
579
|
+
return {
|
|
580
|
+
outcome: "failed",
|
|
581
|
+
properties: {
|
|
582
|
+
error_code: code,
|
|
583
|
+
error_category: status >= 500 || status === 408 ? "transport" : "request",
|
|
584
|
+
http_status: String(status),
|
|
585
|
+
http_status_class: `${Math.floor(status / 100)}xx`,
|
|
586
|
+
retryable: status === 408 || status === 429 || status >= 500
|
|
587
|
+
}
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
function nativeExceptionName(value) {
|
|
591
|
+
try {
|
|
592
|
+
if (typeof DOMException !== "undefined")
|
|
593
|
+
return Object.getOwnPropertyDescriptor(
|
|
594
|
+
DOMException.prototype,
|
|
595
|
+
"name"
|
|
596
|
+
)?.get?.call(value);
|
|
597
|
+
} catch {
|
|
598
|
+
}
|
|
599
|
+
return void 0;
|
|
600
|
+
}
|
|
601
|
+
function classifyOne(error, catalog) {
|
|
602
|
+
const read = (key) => usageErrorProperty(error, key);
|
|
603
|
+
let name = read("name") ?? nativeExceptionName(error);
|
|
604
|
+
try {
|
|
605
|
+
if (name === void 0 && error instanceof SyntaxError)
|
|
606
|
+
name = "SyntaxError";
|
|
607
|
+
} catch {
|
|
608
|
+
}
|
|
609
|
+
const code = read("code");
|
|
610
|
+
if (name === "AbortError" || code === "EXECUTION_CANCELLED" || code === "ABORT_ERR")
|
|
372
611
|
return { outcome: "cancelled", properties: {} };
|
|
373
612
|
if (code === "EXECUTION_LIMIT_REACHED" || name === "ExecutionLimitReached")
|
|
374
613
|
return { outcome: "limit_reached", properties: {} };
|
|
375
|
-
if (
|
|
614
|
+
if (typeof name === "string" && [
|
|
615
|
+
"GraphInterrupt",
|
|
616
|
+
"NodeInterrupt",
|
|
617
|
+
"Interrupt",
|
|
618
|
+
"ParallelChildWaiting"
|
|
619
|
+
].includes(name))
|
|
376
620
|
return { outcome: "suspended", properties: {} };
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
621
|
+
if (name === "EvalConfigurationError")
|
|
622
|
+
return {
|
|
623
|
+
outcome: "failed",
|
|
624
|
+
properties: {
|
|
625
|
+
error_code: "EVAL_SETTINGS_INVALID",
|
|
626
|
+
error_category: "configuration",
|
|
627
|
+
retryable: false
|
|
628
|
+
}
|
|
629
|
+
};
|
|
630
|
+
if (name === "TimeoutError")
|
|
631
|
+
return {
|
|
632
|
+
outcome: "failed",
|
|
633
|
+
properties: {
|
|
634
|
+
error_code: "NETWORK_TIMEOUT",
|
|
635
|
+
error_category: "transport",
|
|
636
|
+
retryable: true
|
|
637
|
+
}
|
|
638
|
+
};
|
|
639
|
+
if (typeof code === "string" && Object.hasOwn(networkCodes, code))
|
|
640
|
+
return {
|
|
641
|
+
outcome: "failed",
|
|
642
|
+
properties: {
|
|
643
|
+
error_code: networkCodes[code] ?? "UNCLASSIFIED_FAILURE",
|
|
644
|
+
error_category: "transport",
|
|
645
|
+
retryable: true
|
|
646
|
+
}
|
|
647
|
+
};
|
|
648
|
+
if (typeof code === "string" && catalog.errorCodes.includes(code)) {
|
|
649
|
+
const failure = usageErrorProperty(error, "failure");
|
|
650
|
+
const category = read("category") ?? usageErrorProperty(failure, "category");
|
|
651
|
+
const retryable = read("retryable") ?? usageErrorProperty(failure, "retryable");
|
|
652
|
+
const status2 = read("status") ?? usageErrorProperty(failure, "status");
|
|
653
|
+
return {
|
|
654
|
+
outcome: "failed",
|
|
655
|
+
properties: {
|
|
656
|
+
...typeof status2 === "number" ? classifyUsageHttpStatus(status2).properties : {},
|
|
657
|
+
// The framework code is more specific than its HTTP projection.
|
|
658
|
+
error_code: code,
|
|
659
|
+
error_category: code !== "EXECUTION_FAILED" && typeof category === "string" && Array.isArray(catalog.properties.error_category) && catalog.properties.error_category.includes(category) ? category : "unknown",
|
|
660
|
+
...typeof retryable === "boolean" ? { retryable } : {}
|
|
661
|
+
}
|
|
662
|
+
};
|
|
663
|
+
}
|
|
664
|
+
const status = read("status") ?? read("statusCode");
|
|
665
|
+
if (typeof status === "number" && Number.isInteger(status) && status >= 400 && status <= 599)
|
|
666
|
+
return classifyUsageHttpStatus(status);
|
|
667
|
+
if (name === "ZodError" || name === "SyntaxError")
|
|
668
|
+
return {
|
|
669
|
+
outcome: "failed",
|
|
670
|
+
properties: {
|
|
671
|
+
error_code: "SCHEMA_VALIDATION",
|
|
672
|
+
error_category: "validation"
|
|
673
|
+
}
|
|
674
|
+
};
|
|
675
|
+
return void 0;
|
|
676
|
+
}
|
|
677
|
+
function classifyUsageError(error, catalog = publicCatalog) {
|
|
678
|
+
const seen = /* @__PURE__ */ new Set();
|
|
679
|
+
const pending = [{ value: error, depth: 0 }];
|
|
680
|
+
let result;
|
|
681
|
+
while (pending.length && seen.size < 8) {
|
|
682
|
+
const current = pending.shift();
|
|
683
|
+
if (!current || seen.has(current.value)) continue;
|
|
684
|
+
seen.add(current.value);
|
|
685
|
+
const found = classifyOne(current.value, catalog);
|
|
686
|
+
if (found) {
|
|
687
|
+
if (!result) result = found;
|
|
688
|
+
else if (found.properties.error_code && found.outcome === "failed" && found.properties.error_code !== result.properties.error_code) {
|
|
689
|
+
result.properties.cause_code = found.properties.error_code;
|
|
690
|
+
result.properties.cause_category = found.properties.error_category ?? "unknown";
|
|
691
|
+
if (result.properties.retryable === void 0 && typeof found.properties.retryable === "boolean")
|
|
692
|
+
result.properties.retryable = found.properties.retryable;
|
|
693
|
+
break;
|
|
694
|
+
}
|
|
695
|
+
if (result === found && found.outcome !== "failed") return found;
|
|
386
696
|
}
|
|
697
|
+
if (current.depth < 3)
|
|
698
|
+
for (const key of ["failure", "cause", "error"]) {
|
|
699
|
+
const value = usageErrorProperty(current.value, key);
|
|
700
|
+
if (value && typeof value === "object")
|
|
701
|
+
pending.push({ value, depth: current.depth + 1 });
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
return result ?? {
|
|
705
|
+
outcome: "failed",
|
|
706
|
+
properties: { error_code: "other", error_category: "unknown" }
|
|
387
707
|
};
|
|
388
708
|
}
|
|
709
|
+
|
|
710
|
+
// src/measurement.ts
|
|
711
|
+
function usageMeasurement(event, operation, input) {
|
|
712
|
+
if (event === "usage.feature")
|
|
713
|
+
return usageErrorProperty(input, "origin") === "background" || usageErrorProperty(input, "origin") === "server" ? "observation" : "feature";
|
|
714
|
+
if (operation === "cli.command" || operation === "sdk.eval")
|
|
715
|
+
return "invocation";
|
|
716
|
+
if (operation === "studio.setup") return "stage";
|
|
717
|
+
if (operation === "sdk.execution" || operation === "studio.eval.execution")
|
|
718
|
+
return "execution";
|
|
719
|
+
if (operation === "sdk.export" || operation === "sdk.model") return "attempt";
|
|
720
|
+
if (operation === "sdk.structured") {
|
|
721
|
+
const format = usageErrorProperty(input, "format");
|
|
722
|
+
return format === "text-delta" ? "chunk" : format === "final" ? "output" : "update";
|
|
723
|
+
}
|
|
724
|
+
if (usageErrorProperty(input, "origin") === "background") return "poll";
|
|
725
|
+
if (operation.startsWith("studio.")) return "request";
|
|
726
|
+
return "call";
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
// src/client.ts
|
|
389
730
|
function sanitizeProperties(input, catalog = publicCatalog) {
|
|
390
731
|
const safe = {};
|
|
391
732
|
for (const [key, rule] of Object.entries(catalog.properties)) {
|
|
392
|
-
const value =
|
|
733
|
+
const value = usageErrorProperty(input, key);
|
|
393
734
|
if (value === void 0) continue;
|
|
394
735
|
if (rule === "boolean") {
|
|
395
736
|
if (typeof value === "boolean") safe[key] = value;
|
|
396
737
|
} else if (typeof value === "string")
|
|
397
738
|
safe[key] = rule.includes(value) ? value : "other";
|
|
398
739
|
}
|
|
399
|
-
const
|
|
400
|
-
|
|
401
|
-
|
|
740
|
+
for (const key of ["error_code", "cause_code"]) {
|
|
741
|
+
const code = usageErrorProperty(input, key);
|
|
742
|
+
if (typeof code === "string")
|
|
743
|
+
safe[key] = catalog.errorCodes.includes(code) ? code : "other";
|
|
744
|
+
}
|
|
402
745
|
return safe;
|
|
403
746
|
}
|
|
404
747
|
var durationBounds = [10, 100, 1e3, 1e4, 6e4];
|
|
@@ -419,6 +762,16 @@ function createUsageTelemetry(options) {
|
|
|
419
762
|
let disposed = false;
|
|
420
763
|
let dropped = 0;
|
|
421
764
|
let delivered = 0;
|
|
765
|
+
let lostObservations = 0;
|
|
766
|
+
let failedBatches = 0;
|
|
767
|
+
let reportedLoss = 0;
|
|
768
|
+
let reportedFailures = 0;
|
|
769
|
+
const lose = (count) => {
|
|
770
|
+
lostObservations = Math.min(
|
|
771
|
+
Number.MAX_SAFE_INTEGER,
|
|
772
|
+
lostObservations + count
|
|
773
|
+
);
|
|
774
|
+
};
|
|
422
775
|
let hour = Math.floor(now() / 36e5);
|
|
423
776
|
let sent = 0;
|
|
424
777
|
const active = () => {
|
|
@@ -454,6 +807,10 @@ function createUsageTelemetry(options) {
|
|
|
454
807
|
pending.clear();
|
|
455
808
|
if (!records.length) return;
|
|
456
809
|
let attempted = records.length;
|
|
810
|
+
let attemptedObservations = records.reduce(
|
|
811
|
+
(total, record2) => total + record2.count,
|
|
812
|
+
0
|
|
813
|
+
);
|
|
457
814
|
flight = (async () => {
|
|
458
815
|
try {
|
|
459
816
|
if (options.debug?.()) {
|
|
@@ -471,7 +828,14 @@ function createUsageTelemetry(options) {
|
|
|
471
828
|
);
|
|
472
829
|
const batch = records.slice(0, allowance);
|
|
473
830
|
dropped += records.length - batch.length;
|
|
831
|
+
lose(
|
|
832
|
+
records.slice(allowance).reduce((total, record2) => total + record2.count, 0)
|
|
833
|
+
);
|
|
474
834
|
attempted = batch.length;
|
|
835
|
+
attemptedObservations = batch.reduce(
|
|
836
|
+
(total, record2) => total + record2.count,
|
|
837
|
+
0
|
|
838
|
+
);
|
|
475
839
|
if (!batch.length || !active()) return;
|
|
476
840
|
const identified = await options.identity();
|
|
477
841
|
const identity = typeof identified === "string" ? identified : identified.id;
|
|
@@ -482,13 +846,25 @@ function createUsageTelemetry(options) {
|
|
|
482
846
|
identity
|
|
483
847
|
)) {
|
|
484
848
|
dropped += batch.length;
|
|
849
|
+
lose(attemptedObservations);
|
|
485
850
|
return;
|
|
486
851
|
}
|
|
487
852
|
sent += batch.length;
|
|
853
|
+
const lossSnapshot = lostObservations;
|
|
854
|
+
const failureSnapshot = failedBatches;
|
|
855
|
+
if (batch[0] && (lossSnapshot > reportedLoss || failureSnapshot > reportedFailures))
|
|
856
|
+
batch[0].delivery_health = {
|
|
857
|
+
dropped_observations: lossSnapshot - reportedLoss,
|
|
858
|
+
failed_batches: failureSnapshot - reportedFailures
|
|
859
|
+
};
|
|
488
860
|
await options.transport(batch, identity);
|
|
861
|
+
reportedLoss = lossSnapshot;
|
|
862
|
+
reportedFailures = failureSnapshot;
|
|
489
863
|
delivered += batch.length;
|
|
490
864
|
} catch {
|
|
491
865
|
dropped += attempted;
|
|
866
|
+
lose(attemptedObservations);
|
|
867
|
+
failedBatches = Math.min(Number.MAX_SAFE_INTEGER, failedBatches + 1);
|
|
492
868
|
}
|
|
493
869
|
})().finally(() => {
|
|
494
870
|
flight = void 0;
|
|
@@ -512,12 +888,29 @@ function createUsageTelemetry(options) {
|
|
|
512
888
|
}
|
|
513
889
|
if (!configured || !catalog.operations.includes(operation) || !outcomes.includes(outcome))
|
|
514
890
|
return;
|
|
515
|
-
const
|
|
891
|
+
const failed = outcome === "failed";
|
|
892
|
+
const status = usageErrorProperty(input, "http_status");
|
|
893
|
+
const http = typeof status === "string" && /^\d{3}$/.test(status) ? classifyUsageHttpStatus(Number(status)).properties : {};
|
|
894
|
+
const properties = sanitizeProperties(
|
|
895
|
+
{
|
|
896
|
+
measurement_version: "2",
|
|
897
|
+
measurement_kind: usageMeasurement(event, operation, input),
|
|
898
|
+
...failed ? {
|
|
899
|
+
error_code: "UNCLASSIFIED_FAILURE",
|
|
900
|
+
error_category: "unknown",
|
|
901
|
+
...http
|
|
902
|
+
} : {},
|
|
903
|
+
...sanitizeProperties(input, catalog),
|
|
904
|
+
traffic_source: options.context.trafficSource ?? "unknown"
|
|
905
|
+
},
|
|
906
|
+
catalog
|
|
907
|
+
);
|
|
516
908
|
const key = JSON.stringify([event, operation, outcome, properties]);
|
|
517
909
|
let existing = pending.get(key);
|
|
518
910
|
if (!existing) {
|
|
519
911
|
if (pending.size >= (options.maxGroups ?? 64)) {
|
|
520
912
|
dropped++;
|
|
913
|
+
lose(1);
|
|
521
914
|
return;
|
|
522
915
|
}
|
|
523
916
|
existing = {
|
|
@@ -529,7 +922,9 @@ function createUsageTelemetry(options) {
|
|
|
529
922
|
component: options.context.component,
|
|
530
923
|
version: options.context.version,
|
|
531
924
|
analytics_environment: options.context.environment ?? "production",
|
|
532
|
-
runtime_mode:
|
|
925
|
+
runtime_mode: ["development", "production", "ci"].includes(
|
|
926
|
+
options.context.runtimeMode ?? ""
|
|
927
|
+
) ? options.context.runtimeMode ?? "unknown" : "unknown",
|
|
533
928
|
identity_scope: options.context.identityScope ?? "installation",
|
|
534
929
|
operation,
|
|
535
930
|
outcome,
|
|
@@ -574,8 +969,11 @@ function createUsageTelemetry(options) {
|
|
|
574
969
|
if (ended) return;
|
|
575
970
|
ended = true;
|
|
576
971
|
try {
|
|
972
|
+
const status = usageErrorProperty(extra, "http_status");
|
|
973
|
+
const http = outcome === "failed" && typeof status === "string" && /^\d{3}$/.test(status) ? classifyUsageHttpStatus(Number(status)).properties : {};
|
|
577
974
|
record("usage.operation", operation, outcome, now() - began, {
|
|
578
975
|
...initial,
|
|
976
|
+
...http,
|
|
579
977
|
...sanitizeProperties(extra, catalog)
|
|
580
978
|
});
|
|
581
979
|
} catch {
|
|
@@ -658,6 +1056,10 @@ function createPostHogTransport(options) {
|
|
|
658
1056
|
count: record.count,
|
|
659
1057
|
duration_total_ms: record.duration_total_ms,
|
|
660
1058
|
duration_buckets: record.duration_buckets,
|
|
1059
|
+
...record.delivery_health ? {
|
|
1060
|
+
usage_dropped_observations: record.delivery_health.dropped_observations,
|
|
1061
|
+
usage_failed_batches: record.delivery_health.failed_batches
|
|
1062
|
+
} : {},
|
|
661
1063
|
$process_person_profile: false,
|
|
662
1064
|
$geoip_disable: true,
|
|
663
1065
|
$ip: null
|
|
@@ -712,6 +1114,7 @@ function createCollectorTransport(options) {
|
|
|
712
1114
|
// Annotate the CommonJS export names for ESM import in node:
|
|
713
1115
|
0 && (module.exports = {
|
|
714
1116
|
classifyUsageError,
|
|
1117
|
+
classifyUsageHttpStatus,
|
|
715
1118
|
createCollectorTransport,
|
|
716
1119
|
createPostHogTransport,
|
|
717
1120
|
createUsageTelemetry,
|