forked from ritik4ever/stellar-goal-vault
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlogger.ts
More file actions
134 lines (118 loc) · 3.06 KB
/
Copy pathlogger.ts
File metadata and controls
134 lines (118 loc) · 3.06 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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
export const LOG_LEVELS = ['debug', 'info', 'warn', 'error'] as const;
export type LogLevel = (typeof LOG_LEVELS)[number];
type LogFields = Record<string, unknown>;
const LOG_LEVEL_PRIORITY: Record<LogLevel, number> = {
debug: 10,
info: 20,
warn: 30,
error: 40,
};
export function normalizeLogLevel(rawLevel: string | undefined): LogLevel {
const normalized = rawLevel?.trim().toLowerCase();
return LOG_LEVELS.includes(normalized as LogLevel) ? (normalized as LogLevel) : 'info';
}
export function shouldLog(level: LogLevel, configuredLevel: LogLevel): boolean {
return LOG_LEVEL_PRIORITY[level] >= LOG_LEVEL_PRIORITY[configuredLevel];
}
export function createLogLine(
level: LogLevel,
event: string,
fields: LogFields,
now: Date = new Date(),
): string {
return JSON.stringify({
timestamp: now.toISOString(),
level,
event,
...fields,
});
}
/* eslint-disable no-console */
function getConsoleMethod(
level: LogLevel,
): (message?: unknown, ...optionalParams: unknown[]) => void {
switch (level) {
case 'debug':
return console.debug;
case 'warn':
return console.warn;
case 'error':
return console.error;
case 'info':
default:
return console.info;
}
}
/* eslint-enable no-console */
import { getRequestId } from './requestContext';
function withRequestContext(fields: LogFields): LogFields {
const requestId = getRequestId();
if (requestId && fields.requestId === undefined) {
return { requestId, ...fields };
}
return fields;
}
export function logLine(
level: LogLevel,
event: string,
fields: LogFields,
configuredLevel: LogLevel,
): void {
if (!shouldLog(level, configuredLevel)) {
return;
}
getConsoleMethod(level)(createLogLine(level, event, withRequestContext(fields)));
}
export function logInfo(event: string, fields: LogFields, configuredLevel: LogLevel): void {
logLine('info', event, fields, configuredLevel);
}
export function logRequest(
request: {
requestId?: string;
method: string;
path: string;
status: number;
durationMs: number;
},
configuredLevel: LogLevel,
): void {
const durationMs = Number(request.durationMs.toFixed(2));
logInfo(
'http_request',
{
message: `${request.method} ${request.path} ${request.status} ${durationMs}ms`,
requestId: request.requestId,
method: request.method,
path: request.path,
status: request.status,
durationMs,
},
configuredLevel,
);
}
export function logError(
error: unknown,
context: {
event?: string;
requestId?: string;
method?: string;
path?: string;
status?: number;
[key: string]: unknown;
},
configuredLevel: LogLevel,
): void {
const normalizedError =
error instanceof Error ? error : new Error(typeof error === 'string' ? error : 'Unknown error');
logLine(
'error',
typeof context.event === 'string' ? context.event : 'error',
{
...context,
message: normalizedError.message,
stack: normalizedError.stack,
errorName: normalizedError.name,
},
configuredLevel,
);
}