Repository navigation
Expand file tree
/
Copy pathlogging.ts
More file actions
68 lines (63 loc) · 2.18 KB
/
Copy pathlogging.ts
File metadata and controls
68 lines (63 loc) · 2.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
type LogValue = string | number | boolean | null | undefined;
export type SafeErrorCode =
| "TIMEOUT"
| "CONCURRENT_SCAN"
| "RPC_RATE_LIMITED"
| "RPC_QUORUM"
| "RPC_NETWORK"
| "STORAGE_LOCKED"
| "STORAGE_CORRUPT"
| "PPOI_FAILED"
| "SCAN_FAILED";
export const classifyError = (error: unknown): SafeErrorCode => {
if (!(error instanceof Error)) return "SCAN_FAILED";
const message = error.message.toLowerCase();
const systemCode = String((error as NodeJS.ErrnoException).code ?? "").toLowerCase();
if (message.includes("timed out") || systemCode === "etimedout") return "TIMEOUT";
if (message.includes("already in progress") || message.includes("scan in progress")) {
return "CONCURRENT_SCAN";
}
if (message.includes("429") || message.includes("rate limit")) return "RPC_RATE_LIMITED";
if (message.startsWith("rpc quorum") || message.startsWith("rpc omitted")) {
return "RPC_QUORUM";
}
if (/\block(?:ed|ing)?\b/.test(message) || systemCode === "eagain" || systemCode === "ebusy") {
return "STORAGE_LOCKED";
}
if (message.includes("corrupt") || message.includes("checksum")) return "STORAGE_CORRUPT";
if (message.includes("ppoi") || message.includes("proof of innocence")) return "PPOI_FAILED";
if (
message.includes("network") ||
message.includes("fetch") ||
message.includes("socket") ||
systemCode === "econnreset" ||
systemCode === "enotfound"
) {
return "RPC_NETWORK";
}
return "SCAN_FAILED";
};
const writeLog = (
level: "info" | "warn" | "error",
event: string,
fields: Record<string, LogValue> = {},
): void => {
const safeFields = Object.fromEntries(
Object.entries(fields).filter(([, value]) => value !== undefined),
);
process.stdout.write(
`${JSON.stringify({
timestamp: new Date().toISOString(),
level,
event,
...safeFields,
})}\n`,
);
};
export const logInfo = (event: string, fields?: Record<string, LogValue>): void =>
writeLog("info", event, fields);
export const logError = (event: string, error: unknown): void =>
writeLog("error", event, {
errorType: error instanceof Error ? error.constructor.name : "UnknownError",
errorCode: classifyError(error),
});