

























@@ -1,5 +1,19 @@
1+import crypto from "node:crypto";
2+13const HTTP_STATUS_MIN = 100;
24const HTTP_STATUS_MAX = 599;
5+const REQUEST_ID_HASH_PREFIX_LEN = 12;
6+const PROVIDER_REQUEST_ID_KEYS = [
7+"upstreamRequestId",
8+"providerRequestId",
9+"requestId",
10+"request_id",
11+] as const;
12+const PROVIDER_REQUEST_ID_RE = /^[A-Za-z0-9._:-]{1,128}$/u;
13+const PROVIDER_REQUEST_ID_TEXT_PATTERNS = [
14+/\b(?:x-request-id|request-id|request_id|requestId|trace-id|trace_id)\b["'\s:=([]+([A-Za-z0-9._:-]{1,128})/i,
15+/\((?:request_id|trace_id)\s*:\s*([A-Za-z0-9._:-]{1,128})\)/i,
16+] as const;
317418function isObjectLike(value: unknown): value is object {
519return (typeof value === "object" || typeof value === "function") && value !== null;
@@ -17,6 +31,25 @@ function readOwnDataProperty(value: unknown, key: string): unknown {
1731}
1832}
193334+function findDiagnosticErrorProperty<T>(
35+err: unknown,
36+reader: (candidate: unknown) => T | undefined,
37+seen: Set<object> = new Set(),
38+): T | undefined {
39+const direct = reader(err);
40+if (direct !== undefined) {
41+return direct;
42+}
43+if (!isObjectLike(err) || seen.has(err)) {
44+return undefined;
45+}
46+seen.add(err);
47+return (
48+findDiagnosticErrorProperty(readOwnDataProperty(err, "error"), reader, seen) ??
49+findDiagnosticErrorProperty(readOwnDataProperty(err, "cause"), reader, seen)
50+);
51+}
52+2053function isHttpStatusCode(value: unknown): value is number {
2154return (
2255typeof value === "number" &&
@@ -26,6 +59,61 @@ function isHttpStatusCode(value: unknown): value is number {
2659);
2760}
286162+function normalizeProviderRequestId(value: unknown): string | undefined {
63+if (typeof value === "string") {
64+const trimmed = value.trim();
65+return PROVIDER_REQUEST_ID_RE.test(trimmed) ? trimmed : undefined;
66+}
67+if (typeof value === "number" && Number.isFinite(value)) {
68+const normalized = String(value);
69+return PROVIDER_REQUEST_ID_RE.test(normalized) ? normalized : undefined;
70+}
71+if (typeof value === "bigint") {
72+const normalized = String(value);
73+return PROVIDER_REQUEST_ID_RE.test(normalized) ? normalized : undefined;
74+}
75+return undefined;
76+}
77+78+function hashDiagnosticIdentifier(value: string): string {
79+return `sha256:${crypto
80+ .createHash("sha256")
81+ .update(value)
82+ .digest("hex")
83+ .slice(0, REQUEST_ID_HASH_PREFIX_LEN)}`;
84+}
85+86+function readDirectProviderRequestId(err: unknown): string | undefined {
87+for (const key of PROVIDER_REQUEST_ID_KEYS) {
88+const normalized = normalizeProviderRequestId(readOwnDataProperty(err, key));
89+if (normalized) {
90+return normalized;
91+}
92+}
93+return undefined;
94+}
95+96+function readDirectMessage(err: unknown): string | undefined {
97+if (typeof err === "string") {
98+return err;
99+}
100+const message = readOwnDataProperty(err, "message");
101+return typeof message === "string" ? message : undefined;
102+}
103+104+function extractProviderRequestIdFromText(text: string | undefined): string | undefined {
105+if (!text) {
106+return undefined;
107+}
108+for (const pattern of PROVIDER_REQUEST_ID_TEXT_PATTERNS) {
109+const normalized = normalizeProviderRequestId(text.match(pattern)?.[1]);
110+if (normalized) {
111+return normalized;
112+}
113+}
114+return undefined;
115+}
116+29117export function diagnosticErrorCategory(err: unknown): string {
30118try {
31119if (err instanceof TypeError) {
@@ -69,3 +157,14 @@ export function diagnosticHttpStatusCode(err: unknown): string | undefined {
69157}
70158return undefined;
71159}
160+161+export function diagnosticProviderRequestIdHash(err: unknown): string | undefined {
162+const fromProperty = findDiagnosticErrorProperty(err, readDirectProviderRequestId);
163+if (fromProperty) {
164+return hashDiagnosticIdentifier(fromProperty);
165+}
166+const fromMessage = findDiagnosticErrorProperty(err, (candidate) =>
167+extractProviderRequestIdFromText(readDirectMessage(candidate)),
168+);
169+return fromMessage ? hashDiagnosticIdentifier(fromMessage) : undefined;
170+}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。