@rawnodes/logger 1.1.0 → 1.2.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/{index.d.cts → index.d.mts} +16 -22
- package/dist/index.d.ts +16 -22
- package/dist/index.js +195 -149
- package/dist/index.js.map +1 -1
- package/dist/{index.cjs → index.mjs} +181 -166
- package/dist/index.mjs.map +1 -0
- package/package.json +11 -7
- package/dist/index.cjs.map +0 -1
|
@@ -29,24 +29,6 @@ declare class LoggerStore<TContext extends LoggerContext = LoggerContext> {
|
|
|
29
29
|
run<T>(context: TContext, fn: () => T): T;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
interface TimingResult {
|
|
33
|
-
label: string;
|
|
34
|
-
durationMs: number;
|
|
35
|
-
durationFormatted: string;
|
|
36
|
-
}
|
|
37
|
-
interface Timer {
|
|
38
|
-
end: () => TimingResult;
|
|
39
|
-
}
|
|
40
|
-
declare function createTimer(label: string): Timer;
|
|
41
|
-
declare function measureAsync<T>(label: string, fn: () => Promise<T>): Promise<{
|
|
42
|
-
result: T;
|
|
43
|
-
timing: TimingResult;
|
|
44
|
-
}>;
|
|
45
|
-
declare function measureSync<T>(label: string, fn: () => T): {
|
|
46
|
-
result: T;
|
|
47
|
-
timing: TimingResult;
|
|
48
|
-
};
|
|
49
|
-
|
|
50
32
|
declare class BaseLogger<TContext extends LoggerContext = LoggerContext> {
|
|
51
33
|
private winstonLogger;
|
|
52
34
|
private defaultLevel;
|
|
@@ -62,9 +44,7 @@ declare class BaseLogger<TContext extends LoggerContext = LoggerContext> {
|
|
|
62
44
|
private matchesContext;
|
|
63
45
|
private shouldLog;
|
|
64
46
|
getChildLogger(context: string): Logger;
|
|
65
|
-
|
|
66
|
-
timeEnd(timer: Timer, context?: string): TimingResult;
|
|
67
|
-
timeAsync<T>(label: string, fn: () => Promise<T>, context?: string): Promise<T>;
|
|
47
|
+
profile(id: string, meta?: object): void;
|
|
68
48
|
log(message: string, context?: string, meta?: object): void;
|
|
69
49
|
error(message: string, error?: Error | unknown, context?: string): void;
|
|
70
50
|
warn(message: string, context?: string, meta?: object): void;
|
|
@@ -84,6 +64,20 @@ interface SingletonLogger<TContext extends LoggerContext> {
|
|
|
84
64
|
}
|
|
85
65
|
declare function createSingletonLogger<TContext extends LoggerContext>(): SingletonLogger<TContext>;
|
|
86
66
|
|
|
67
|
+
interface TimingResult {
|
|
68
|
+
label: string;
|
|
69
|
+
durationMs: number;
|
|
70
|
+
durationFormatted: string;
|
|
71
|
+
}
|
|
72
|
+
declare function measureAsync<T>(label: string, fn: () => Promise<T>): Promise<{
|
|
73
|
+
result: T;
|
|
74
|
+
timing: TimingResult;
|
|
75
|
+
}>;
|
|
76
|
+
declare function measureSync<T>(label: string, fn: () => T): {
|
|
77
|
+
result: T;
|
|
78
|
+
timing: TimingResult;
|
|
79
|
+
};
|
|
80
|
+
|
|
87
81
|
interface RequestIdOptions {
|
|
88
82
|
prefix?: string;
|
|
89
83
|
short?: boolean;
|
|
@@ -100,4 +94,4 @@ interface MaskSecretsOptions {
|
|
|
100
94
|
declare function maskSecrets(obj: unknown, options?: MaskSecretsOptions): unknown;
|
|
101
95
|
declare function createMasker(options?: MaskSecretsOptions): (obj: unknown) => unknown;
|
|
102
96
|
|
|
103
|
-
export { BaseLogger, type ConsoleConfig, type FileConfig, type LevelOverride, type LoggerConfig, type LoggerContext, LoggerStore, type MaskSecretsOptions, type RequestIdOptions, type SingletonLogger, type
|
|
97
|
+
export { BaseLogger, type ConsoleConfig, type FileConfig, type LevelOverride, type LoggerConfig, type LoggerContext, LoggerStore, type MaskSecretsOptions, type RequestIdOptions, type SingletonLogger, type TimingResult, createMasker, createSingletonLogger, extractRequestId, generateRequestId, getOrGenerateRequestId, maskSecrets, measureAsync, measureSync };
|
package/dist/index.d.ts
CHANGED
|
@@ -29,24 +29,6 @@ declare class LoggerStore<TContext extends LoggerContext = LoggerContext> {
|
|
|
29
29
|
run<T>(context: TContext, fn: () => T): T;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
interface TimingResult {
|
|
33
|
-
label: string;
|
|
34
|
-
durationMs: number;
|
|
35
|
-
durationFormatted: string;
|
|
36
|
-
}
|
|
37
|
-
interface Timer {
|
|
38
|
-
end: () => TimingResult;
|
|
39
|
-
}
|
|
40
|
-
declare function createTimer(label: string): Timer;
|
|
41
|
-
declare function measureAsync<T>(label: string, fn: () => Promise<T>): Promise<{
|
|
42
|
-
result: T;
|
|
43
|
-
timing: TimingResult;
|
|
44
|
-
}>;
|
|
45
|
-
declare function measureSync<T>(label: string, fn: () => T): {
|
|
46
|
-
result: T;
|
|
47
|
-
timing: TimingResult;
|
|
48
|
-
};
|
|
49
|
-
|
|
50
32
|
declare class BaseLogger<TContext extends LoggerContext = LoggerContext> {
|
|
51
33
|
private winstonLogger;
|
|
52
34
|
private defaultLevel;
|
|
@@ -62,9 +44,7 @@ declare class BaseLogger<TContext extends LoggerContext = LoggerContext> {
|
|
|
62
44
|
private matchesContext;
|
|
63
45
|
private shouldLog;
|
|
64
46
|
getChildLogger(context: string): Logger;
|
|
65
|
-
|
|
66
|
-
timeEnd(timer: Timer, context?: string): TimingResult;
|
|
67
|
-
timeAsync<T>(label: string, fn: () => Promise<T>, context?: string): Promise<T>;
|
|
47
|
+
profile(id: string, meta?: object): void;
|
|
68
48
|
log(message: string, context?: string, meta?: object): void;
|
|
69
49
|
error(message: string, error?: Error | unknown, context?: string): void;
|
|
70
50
|
warn(message: string, context?: string, meta?: object): void;
|
|
@@ -84,6 +64,20 @@ interface SingletonLogger<TContext extends LoggerContext> {
|
|
|
84
64
|
}
|
|
85
65
|
declare function createSingletonLogger<TContext extends LoggerContext>(): SingletonLogger<TContext>;
|
|
86
66
|
|
|
67
|
+
interface TimingResult {
|
|
68
|
+
label: string;
|
|
69
|
+
durationMs: number;
|
|
70
|
+
durationFormatted: string;
|
|
71
|
+
}
|
|
72
|
+
declare function measureAsync<T>(label: string, fn: () => Promise<T>): Promise<{
|
|
73
|
+
result: T;
|
|
74
|
+
timing: TimingResult;
|
|
75
|
+
}>;
|
|
76
|
+
declare function measureSync<T>(label: string, fn: () => T): {
|
|
77
|
+
result: T;
|
|
78
|
+
timing: TimingResult;
|
|
79
|
+
};
|
|
80
|
+
|
|
87
81
|
interface RequestIdOptions {
|
|
88
82
|
prefix?: string;
|
|
89
83
|
short?: boolean;
|
|
@@ -100,4 +94,4 @@ interface MaskSecretsOptions {
|
|
|
100
94
|
declare function maskSecrets(obj: unknown, options?: MaskSecretsOptions): unknown;
|
|
101
95
|
declare function createMasker(options?: MaskSecretsOptions): (obj: unknown) => unknown;
|
|
102
96
|
|
|
103
|
-
export { BaseLogger, type ConsoleConfig, type FileConfig, type LevelOverride, type LoggerConfig, type LoggerContext, LoggerStore, type MaskSecretsOptions, type RequestIdOptions, type SingletonLogger, type
|
|
97
|
+
export { BaseLogger, type ConsoleConfig, type FileConfig, type LevelOverride, type LoggerConfig, type LoggerContext, LoggerStore, type MaskSecretsOptions, type RequestIdOptions, type SingletonLogger, type TimingResult, createMasker, createSingletonLogger, extractRequestId, generateRequestId, getOrGenerateRequestId, maskSecrets, measureAsync, measureSync };
|
package/dist/index.js
CHANGED
|
@@ -1,15 +1,110 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var winston = require('winston');
|
|
4
|
+
var util = require('util');
|
|
5
|
+
var DailyRotateFile = require('winston-daily-rotate-file');
|
|
6
|
+
var async_hooks = require('async_hooks');
|
|
7
|
+
var crypto = require('crypto');
|
|
8
|
+
|
|
9
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
|
+
|
|
11
|
+
var DailyRotateFile__default = /*#__PURE__*/_interopDefault(DailyRotateFile);
|
|
6
12
|
|
|
7
13
|
// src/logger.ts
|
|
14
|
+
|
|
15
|
+
// src/utils/mask-secrets.ts
|
|
16
|
+
var DEFAULT_SECRET_PATTERNS = [
|
|
17
|
+
"password",
|
|
18
|
+
"secret",
|
|
19
|
+
"token",
|
|
20
|
+
"apikey",
|
|
21
|
+
"api_key",
|
|
22
|
+
"api-key",
|
|
23
|
+
"auth",
|
|
24
|
+
"credential",
|
|
25
|
+
"private"
|
|
26
|
+
];
|
|
27
|
+
var DEFAULT_MASK = "***";
|
|
28
|
+
function isSecretKey(key, patterns) {
|
|
29
|
+
const lowerKey = key.toLowerCase();
|
|
30
|
+
return patterns.some((pattern) => lowerKey.includes(pattern.toLowerCase()));
|
|
31
|
+
}
|
|
32
|
+
function maskUrlCredentials(url, mask) {
|
|
33
|
+
try {
|
|
34
|
+
const parsed = new URL(url);
|
|
35
|
+
if (parsed.password) {
|
|
36
|
+
parsed.password = mask;
|
|
37
|
+
}
|
|
38
|
+
if (parsed.username && parsed.password) {
|
|
39
|
+
parsed.username = mask;
|
|
40
|
+
}
|
|
41
|
+
return parsed.toString();
|
|
42
|
+
} catch {
|
|
43
|
+
return url;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function maskSecrets(obj, options = {}) {
|
|
47
|
+
const { patterns = DEFAULT_SECRET_PATTERNS, mask = DEFAULT_MASK, deep = true } = options;
|
|
48
|
+
if (obj === null || obj === void 0) {
|
|
49
|
+
return obj;
|
|
50
|
+
}
|
|
51
|
+
if (typeof obj === "string") {
|
|
52
|
+
if (obj.startsWith("http://") || obj.startsWith("https://")) {
|
|
53
|
+
return maskUrlCredentials(obj, mask);
|
|
54
|
+
}
|
|
55
|
+
return obj;
|
|
56
|
+
}
|
|
57
|
+
if (Array.isArray(obj)) {
|
|
58
|
+
return deep ? obj.map((item) => maskSecrets(item, options)) : obj;
|
|
59
|
+
}
|
|
60
|
+
if (typeof obj === "object") {
|
|
61
|
+
const result = {};
|
|
62
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
63
|
+
if (isSecretKey(key, patterns)) {
|
|
64
|
+
result[key] = mask;
|
|
65
|
+
} else if (deep && typeof value === "object" && value !== null) {
|
|
66
|
+
result[key] = maskSecrets(value, options);
|
|
67
|
+
} else if (typeof value === "string") {
|
|
68
|
+
result[key] = maskSecrets(value, options);
|
|
69
|
+
} else {
|
|
70
|
+
result[key] = value;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return result;
|
|
74
|
+
}
|
|
75
|
+
return obj;
|
|
76
|
+
}
|
|
77
|
+
function createMasker(options = {}) {
|
|
78
|
+
return (obj) => maskSecrets(obj, options);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// src/formatters.ts
|
|
8
82
|
var DEFAULT_CONTEXT = "APP";
|
|
83
|
+
var LEVEL_COLORS = {
|
|
84
|
+
error: "\x1B[31m",
|
|
85
|
+
// red
|
|
86
|
+
warn: "\x1B[33m",
|
|
87
|
+
// yellow
|
|
88
|
+
info: "\x1B[32m",
|
|
89
|
+
// green
|
|
90
|
+
http: "\x1B[35m",
|
|
91
|
+
// magenta
|
|
92
|
+
verbose: "\x1B[36m",
|
|
93
|
+
// cyan
|
|
94
|
+
debug: "\x1B[34m",
|
|
95
|
+
// blue
|
|
96
|
+
silly: "\x1B[90m"
|
|
97
|
+
// grey
|
|
98
|
+
};
|
|
99
|
+
var RESET = "\x1B[0m";
|
|
100
|
+
function colorizeLevel(level) {
|
|
101
|
+
const color = LEVEL_COLORS[level] || "";
|
|
102
|
+
return color ? `${color}${level}${RESET}` : level;
|
|
103
|
+
}
|
|
9
104
|
function formatMeta(meta, colors) {
|
|
10
105
|
return Object.entries(meta).filter(([, value]) => value !== void 0 && value !== null).map(([key, value]) => {
|
|
11
106
|
if (typeof value === "object") {
|
|
12
|
-
const inspected = inspect(value, { depth: 4, colors, compact: false });
|
|
107
|
+
const inspected = util.inspect(value, { depth: 4, colors, compact: false });
|
|
13
108
|
return `
|
|
14
109
|
${key}: ${inspected.split("\n").join("\n ")}`;
|
|
15
110
|
}
|
|
@@ -18,7 +113,7 @@ function formatMeta(meta, colors) {
|
|
|
18
113
|
}).join("");
|
|
19
114
|
}
|
|
20
115
|
function addStoreContext(store) {
|
|
21
|
-
return format((info) => {
|
|
116
|
+
return winston.format((info) => {
|
|
22
117
|
const storeContext = store.getStore();
|
|
23
118
|
if (storeContext) {
|
|
24
119
|
return { ...info, ...storeContext };
|
|
@@ -26,24 +121,31 @@ function addStoreContext(store) {
|
|
|
26
121
|
return info;
|
|
27
122
|
})();
|
|
28
123
|
}
|
|
124
|
+
function maskSecretsFormat(options) {
|
|
125
|
+
return winston.format((info) => {
|
|
126
|
+
return maskSecrets(info, options);
|
|
127
|
+
})();
|
|
128
|
+
}
|
|
29
129
|
function createLocalFormat(store) {
|
|
30
|
-
return format.combine(
|
|
31
|
-
format.errors({ stack: true }),
|
|
32
|
-
format.timestamp(),
|
|
130
|
+
return winston.format.combine(
|
|
131
|
+
winston.format.errors({ stack: true }),
|
|
132
|
+
winston.format.timestamp(),
|
|
33
133
|
addStoreContext(store),
|
|
34
|
-
|
|
35
|
-
format.printf(({ timestamp, level, context, message, ...meta }) => {
|
|
134
|
+
maskSecretsFormat(),
|
|
135
|
+
winston.format.printf(({ timestamp, level, context, message, ...meta }) => {
|
|
36
136
|
const formattedMeta = formatMeta(meta, true);
|
|
37
|
-
|
|
137
|
+
const coloredLevel = colorizeLevel(level);
|
|
138
|
+
return `[${timestamp}] ${coloredLevel} [${context || DEFAULT_CONTEXT}] ${message}${formattedMeta}`;
|
|
38
139
|
})
|
|
39
140
|
);
|
|
40
141
|
}
|
|
41
142
|
function createProductionFormat(store) {
|
|
42
|
-
return format.combine(
|
|
43
|
-
format.errors({ stack: true }),
|
|
44
|
-
format.timestamp(),
|
|
143
|
+
return winston.format.combine(
|
|
144
|
+
winston.format.errors({ stack: true }),
|
|
145
|
+
winston.format.timestamp(),
|
|
45
146
|
addStoreContext(store),
|
|
46
|
-
|
|
147
|
+
maskSecretsFormat(),
|
|
148
|
+
winston.format.json()
|
|
47
149
|
);
|
|
48
150
|
}
|
|
49
151
|
function createFormat(isLocal, store) {
|
|
@@ -51,13 +153,13 @@ function createFormat(isLocal, store) {
|
|
|
51
153
|
}
|
|
52
154
|
function createTransports(config) {
|
|
53
155
|
const result = [
|
|
54
|
-
new transports.Console({
|
|
156
|
+
new winston.transports.Console({
|
|
55
157
|
level: config.console.level
|
|
56
158
|
})
|
|
57
159
|
];
|
|
58
160
|
if (config.file) {
|
|
59
161
|
result.push(
|
|
60
|
-
new
|
|
162
|
+
new DailyRotateFile__default.default({
|
|
61
163
|
dirname: config.file.dirname,
|
|
62
164
|
filename: config.file.filename,
|
|
63
165
|
level: config.file.level,
|
|
@@ -70,8 +172,24 @@ function createTransports(config) {
|
|
|
70
172
|
}
|
|
71
173
|
return result;
|
|
72
174
|
}
|
|
175
|
+
function createExceptionHandlers(config) {
|
|
176
|
+
const result = [new winston.transports.Console()];
|
|
177
|
+
if (config.file) {
|
|
178
|
+
result.push(
|
|
179
|
+
new DailyRotateFile__default.default({
|
|
180
|
+
dirname: config.file.dirname,
|
|
181
|
+
filename: config.file.filename,
|
|
182
|
+
datePattern: config.file.datePattern,
|
|
183
|
+
zippedArchive: config.file.zippedArchive,
|
|
184
|
+
maxSize: config.file.maxSize,
|
|
185
|
+
maxFiles: config.file.maxFiles
|
|
186
|
+
})
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
return result;
|
|
190
|
+
}
|
|
73
191
|
var LoggerStore = class {
|
|
74
|
-
storage = new AsyncLocalStorage();
|
|
192
|
+
storage = new async_hooks.AsyncLocalStorage();
|
|
75
193
|
getStore() {
|
|
76
194
|
return this.storage.getStore();
|
|
77
195
|
}
|
|
@@ -80,44 +198,6 @@ var LoggerStore = class {
|
|
|
80
198
|
}
|
|
81
199
|
};
|
|
82
200
|
|
|
83
|
-
// src/utils/timing.ts
|
|
84
|
-
function formatDuration(ms) {
|
|
85
|
-
if (ms < 1e3) {
|
|
86
|
-
return `${ms.toFixed(2)}ms`;
|
|
87
|
-
}
|
|
88
|
-
if (ms < 6e4) {
|
|
89
|
-
return `${(ms / 1e3).toFixed(2)}s`;
|
|
90
|
-
}
|
|
91
|
-
const minutes = Math.floor(ms / 6e4);
|
|
92
|
-
const seconds = (ms % 6e4 / 1e3).toFixed(1);
|
|
93
|
-
return `${minutes}m ${seconds}s`;
|
|
94
|
-
}
|
|
95
|
-
function createTimer(label) {
|
|
96
|
-
const start = performance.now();
|
|
97
|
-
return {
|
|
98
|
-
end() {
|
|
99
|
-
const durationMs = performance.now() - start;
|
|
100
|
-
return {
|
|
101
|
-
label,
|
|
102
|
-
durationMs,
|
|
103
|
-
durationFormatted: formatDuration(durationMs)
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
async function measureAsync(label, fn) {
|
|
109
|
-
const timer = createTimer(label);
|
|
110
|
-
const result = await fn();
|
|
111
|
-
const timing = timer.end();
|
|
112
|
-
return { result, timing };
|
|
113
|
-
}
|
|
114
|
-
function measureSync(label, fn) {
|
|
115
|
-
const timer = createTimer(label);
|
|
116
|
-
const result = fn();
|
|
117
|
-
const timing = timer.end();
|
|
118
|
-
return { result, timing };
|
|
119
|
-
}
|
|
120
|
-
|
|
121
201
|
// src/logger.ts
|
|
122
202
|
var DEFAULT_CONTEXT2 = "APP";
|
|
123
203
|
var LOG_LEVELS = {
|
|
@@ -138,11 +218,15 @@ var BaseLogger = class {
|
|
|
138
218
|
const isLocal = process.env.NODE_ENV !== "production";
|
|
139
219
|
this.defaultLevel = config.level;
|
|
140
220
|
this.store = store ?? new LoggerStore();
|
|
141
|
-
|
|
221
|
+
const exceptionHandlers = createExceptionHandlers(config);
|
|
222
|
+
this.winstonLogger = winston.createLogger({
|
|
142
223
|
level: "silly",
|
|
143
224
|
// Allow all, we filter manually
|
|
144
225
|
format: createFormat(isLocal, this.store),
|
|
145
|
-
transports: createTransports(config)
|
|
226
|
+
transports: createTransports(config),
|
|
227
|
+
exceptionHandlers,
|
|
228
|
+
rejectionHandlers: exceptionHandlers,
|
|
229
|
+
exitOnError: false
|
|
146
230
|
});
|
|
147
231
|
}
|
|
148
232
|
getStore() {
|
|
@@ -182,27 +266,8 @@ var BaseLogger = class {
|
|
|
182
266
|
getChildLogger(context) {
|
|
183
267
|
return this.winstonLogger.child({ context });
|
|
184
268
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
}
|
|
188
|
-
timeEnd(timer, context) {
|
|
189
|
-
const result = timer.end();
|
|
190
|
-
this.debug(`${result.label} completed in ${result.durationFormatted}`, context, {
|
|
191
|
-
timing: result
|
|
192
|
-
});
|
|
193
|
-
return result;
|
|
194
|
-
}
|
|
195
|
-
async timeAsync(label, fn, context) {
|
|
196
|
-
const timer = this.time(label);
|
|
197
|
-
try {
|
|
198
|
-
const result = await fn();
|
|
199
|
-
this.timeEnd(timer, context);
|
|
200
|
-
return result;
|
|
201
|
-
} catch (error) {
|
|
202
|
-
const timing = timer.end();
|
|
203
|
-
this.error(`${label} failed after ${timing.durationFormatted}`, error, context);
|
|
204
|
-
throw error;
|
|
205
|
-
}
|
|
269
|
+
profile(id, meta) {
|
|
270
|
+
this.winstonLogger.profile(id, meta);
|
|
206
271
|
}
|
|
207
272
|
log(message, context, meta) {
|
|
208
273
|
if (!this.shouldLog("info")) return;
|
|
@@ -276,9 +341,47 @@ function createSingletonLogger() {
|
|
|
276
341
|
}
|
|
277
342
|
};
|
|
278
343
|
}
|
|
344
|
+
|
|
345
|
+
// src/utils/timing.ts
|
|
346
|
+
function formatDuration(ms) {
|
|
347
|
+
if (ms < 1e3) {
|
|
348
|
+
return `${ms.toFixed(2)}ms`;
|
|
349
|
+
}
|
|
350
|
+
if (ms < 6e4) {
|
|
351
|
+
return `${(ms / 1e3).toFixed(2)}s`;
|
|
352
|
+
}
|
|
353
|
+
const minutes = Math.floor(ms / 6e4);
|
|
354
|
+
const seconds = (ms % 6e4 / 1e3).toFixed(1);
|
|
355
|
+
return `${minutes}m ${seconds}s`;
|
|
356
|
+
}
|
|
357
|
+
function createTimer(label) {
|
|
358
|
+
const start = performance.now();
|
|
359
|
+
return {
|
|
360
|
+
end() {
|
|
361
|
+
const durationMs = performance.now() - start;
|
|
362
|
+
return {
|
|
363
|
+
label,
|
|
364
|
+
durationMs,
|
|
365
|
+
durationFormatted: formatDuration(durationMs)
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
async function measureAsync(label, fn) {
|
|
371
|
+
const timer = createTimer(label);
|
|
372
|
+
const result = await fn();
|
|
373
|
+
const timing = timer.end();
|
|
374
|
+
return { result, timing };
|
|
375
|
+
}
|
|
376
|
+
function measureSync(label, fn) {
|
|
377
|
+
const timer = createTimer(label);
|
|
378
|
+
const result = fn();
|
|
379
|
+
const timing = timer.end();
|
|
380
|
+
return { result, timing };
|
|
381
|
+
}
|
|
279
382
|
function generateRequestId(options = {}) {
|
|
280
383
|
const { prefix, short = false } = options;
|
|
281
|
-
const uuid = randomUUID();
|
|
384
|
+
const uuid = crypto.randomUUID();
|
|
282
385
|
const id = short ? uuid.split("-")[0] : uuid;
|
|
283
386
|
return prefix ? `${prefix}-${id}` : id;
|
|
284
387
|
}
|
|
@@ -299,72 +402,15 @@ function getOrGenerateRequestId(headers, options = {}) {
|
|
|
299
402
|
return extractRequestId(headers) ?? generateRequestId(options);
|
|
300
403
|
}
|
|
301
404
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
"private"
|
|
313
|
-
];
|
|
314
|
-
var DEFAULT_MASK = "***";
|
|
315
|
-
function isSecretKey(key, patterns) {
|
|
316
|
-
const lowerKey = key.toLowerCase();
|
|
317
|
-
return patterns.some((pattern) => lowerKey.includes(pattern.toLowerCase()));
|
|
318
|
-
}
|
|
319
|
-
function maskUrlCredentials(url, mask) {
|
|
320
|
-
try {
|
|
321
|
-
const parsed = new URL(url);
|
|
322
|
-
if (parsed.password) {
|
|
323
|
-
parsed.password = mask;
|
|
324
|
-
}
|
|
325
|
-
if (parsed.username && parsed.password) {
|
|
326
|
-
parsed.username = mask;
|
|
327
|
-
}
|
|
328
|
-
return parsed.toString();
|
|
329
|
-
} catch {
|
|
330
|
-
return url;
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
function maskSecrets(obj, options = {}) {
|
|
334
|
-
const { patterns = DEFAULT_SECRET_PATTERNS, mask = DEFAULT_MASK, deep = true } = options;
|
|
335
|
-
if (obj === null || obj === void 0) {
|
|
336
|
-
return obj;
|
|
337
|
-
}
|
|
338
|
-
if (typeof obj === "string") {
|
|
339
|
-
if (obj.startsWith("http://") || obj.startsWith("https://")) {
|
|
340
|
-
return maskUrlCredentials(obj, mask);
|
|
341
|
-
}
|
|
342
|
-
return obj;
|
|
343
|
-
}
|
|
344
|
-
if (Array.isArray(obj)) {
|
|
345
|
-
return deep ? obj.map((item) => maskSecrets(item, options)) : obj;
|
|
346
|
-
}
|
|
347
|
-
if (typeof obj === "object") {
|
|
348
|
-
const result = {};
|
|
349
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
350
|
-
if (isSecretKey(key, patterns)) {
|
|
351
|
-
result[key] = mask;
|
|
352
|
-
} else if (deep && typeof value === "object" && value !== null) {
|
|
353
|
-
result[key] = maskSecrets(value, options);
|
|
354
|
-
} else if (typeof value === "string") {
|
|
355
|
-
result[key] = maskSecrets(value, options);
|
|
356
|
-
} else {
|
|
357
|
-
result[key] = value;
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
return result;
|
|
361
|
-
}
|
|
362
|
-
return obj;
|
|
363
|
-
}
|
|
364
|
-
function createMasker(options = {}) {
|
|
365
|
-
return (obj) => maskSecrets(obj, options);
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
export { BaseLogger, LoggerStore, createMasker, createSingletonLogger, createTimer, extractRequestId, generateRequestId, getOrGenerateRequestId, maskSecrets, measureAsync, measureSync };
|
|
405
|
+
exports.BaseLogger = BaseLogger;
|
|
406
|
+
exports.LoggerStore = LoggerStore;
|
|
407
|
+
exports.createMasker = createMasker;
|
|
408
|
+
exports.createSingletonLogger = createSingletonLogger;
|
|
409
|
+
exports.extractRequestId = extractRequestId;
|
|
410
|
+
exports.generateRequestId = generateRequestId;
|
|
411
|
+
exports.getOrGenerateRequestId = getOrGenerateRequestId;
|
|
412
|
+
exports.maskSecrets = maskSecrets;
|
|
413
|
+
exports.measureAsync = measureAsync;
|
|
414
|
+
exports.measureSync = measureSync;
|
|
369
415
|
//# sourceMappingURL=index.js.map
|
|
370
416
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/formatters.ts","../src/transports.ts","../src/store.ts","../src/utils/timing.ts","../src/logger.ts","../src/singleton.ts","../src/utils/request-id.ts","../src/utils/mask-secrets.ts"],"names":["DEFAULT_CONTEXT"],"mappings":"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","file":"index.js","sourcesContent":["import { inspect } from 'util';\nimport { format, Logform } from 'winston';\nimport { LoggerStore } from './store.js';\nimport type { LoggerContext } from './types.js';\n\nconst DEFAULT_CONTEXT = 'APP';\n\nfunction formatMeta(meta: Record<string, unknown>, colors: boolean): string {\n return Object.entries(meta)\n .filter(([, value]) => value !== undefined && value !== null)\n .map(([key, value]) => {\n if (typeof value === 'object') {\n const inspected = inspect(value, { depth: 4, colors, compact: false });\n return `\\n ${key}: ${inspected.split('\\n').join('\\n ')}`;\n }\n return `\\n ${key}: ${value}`;\n })\n .join('');\n}\n\nfunction addStoreContext<TContext extends LoggerContext>(store: LoggerStore<TContext>): Logform.Format {\n return format((info) => {\n const storeContext = store.getStore();\n if (storeContext) {\n return { ...info, ...storeContext };\n }\n return info;\n })();\n}\n\nexport function createLocalFormat<TContext extends LoggerContext>(store: LoggerStore<TContext>): Logform.Format {\n return format.combine(\n format.errors({ stack: true }),\n format.timestamp(),\n addStoreContext(store),\n format.colorize(),\n format.printf(({ timestamp, level, context, message, ...meta }) => {\n const formattedMeta = formatMeta(meta, true);\n return `[${timestamp}] ${level} [${context || DEFAULT_CONTEXT}] ${message}${formattedMeta}`;\n }),\n );\n}\n\nexport function createProductionFormat<TContext extends LoggerContext>(store: LoggerStore<TContext>): Logform.Format {\n return format.combine(\n format.errors({ stack: true }),\n format.timestamp(),\n addStoreContext(store),\n format.json(),\n );\n}\n\nexport function createFormat<TContext extends LoggerContext>(isLocal: boolean, store: LoggerStore<TContext>): Logform.Format {\n return isLocal ? createLocalFormat(store) : createProductionFormat(store);\n}\n","import { transports } from 'winston';\nimport DailyRotateFile from 'winston-daily-rotate-file';\nimport { LoggerConfig } from './types.js';\n\ntype Transport = transports.ConsoleTransportInstance | DailyRotateFile;\n\nexport function createTransports(config: LoggerConfig): Transport[] {\n const result: Transport[] = [\n new transports.Console({\n level: config.console.level,\n }),\n ];\n\n if (config.file) {\n result.push(\n new DailyRotateFile({\n dirname: config.file.dirname,\n filename: config.file.filename,\n level: config.file.level,\n datePattern: config.file.datePattern,\n zippedArchive: config.file.zippedArchive,\n maxSize: config.file.maxSize,\n maxFiles: config.file.maxFiles,\n }),\n );\n }\n\n return result;\n}\n","import { AsyncLocalStorage } from 'async_hooks';\nimport type { LoggerContext } from './types.js';\n\nexport class LoggerStore<TContext extends LoggerContext = LoggerContext> {\n private storage = new AsyncLocalStorage<TContext>();\n\n getStore(): TContext | undefined {\n return this.storage.getStore();\n }\n\n run<T>(context: TContext, fn: () => T): T {\n return this.storage.run(context, fn);\n }\n}\n","export interface TimingResult {\n label: string;\n durationMs: number;\n durationFormatted: string;\n}\n\nexport interface Timer {\n end: () => TimingResult;\n}\n\nfunction formatDuration(ms: number): string {\n if (ms < 1000) {\n return `${ms.toFixed(2)}ms`;\n }\n if (ms < 60000) {\n return `${(ms / 1000).toFixed(2)}s`;\n }\n const minutes = Math.floor(ms / 60000);\n const seconds = ((ms % 60000) / 1000).toFixed(1);\n return `${minutes}m ${seconds}s`;\n}\n\nexport function createTimer(label: string): Timer {\n const start = performance.now();\n\n return {\n end(): TimingResult {\n const durationMs = performance.now() - start;\n return {\n label,\n durationMs,\n durationFormatted: formatDuration(durationMs),\n };\n },\n };\n}\n\nexport async function measureAsync<T>(\n label: string,\n fn: () => Promise<T>,\n): Promise<{ result: T; timing: TimingResult }> {\n const timer = createTimer(label);\n const result = await fn();\n const timing = timer.end();\n return { result, timing };\n}\n\nexport function measureSync<T>(\n label: string,\n fn: () => T,\n): { result: T; timing: TimingResult } {\n const timer = createTimer(label);\n const result = fn();\n const timing = timer.end();\n return { result, timing };\n}\n","import { createLogger, Logger } from 'winston';\nimport type { LoggerConfig, LoggerContext, LevelOverride } from './types.js';\nimport { createFormat } from './formatters.js';\nimport { createTransports } from './transports.js';\nimport { LoggerStore } from './store.js';\nimport { createTimer, type Timer, type TimingResult } from './utils/timing.js';\n\nconst DEFAULT_CONTEXT = 'APP';\n\nconst LOG_LEVELS: Record<string, number> = {\n error: 0,\n warn: 1,\n info: 2,\n http: 3,\n verbose: 4,\n debug: 5,\n silly: 6,\n};\n\nexport class BaseLogger<TContext extends LoggerContext = LoggerContext> {\n private winstonLogger: Logger;\n private defaultLevel: string;\n private store: LoggerStore<TContext>;\n private levelOverrides: Map<string, LevelOverride<TContext>> = new Map();\n\n constructor(config: LoggerConfig, store?: LoggerStore<TContext>) {\n const isLocal = process.env.NODE_ENV !== 'production';\n\n this.defaultLevel = config.level;\n this.store = store ?? new LoggerStore<TContext>();\n\n this.winstonLogger = createLogger({\n level: 'silly', // Allow all, we filter manually\n format: createFormat(isLocal, this.store),\n transports: createTransports(config),\n });\n }\n\n getStore(): LoggerStore<TContext> {\n return this.store;\n }\n\n setLevelOverride(match: Partial<TContext>, level: string): void {\n const key = JSON.stringify(match);\n this.levelOverrides.set(key, { match, level });\n }\n\n removeLevelOverride(match: Partial<TContext>): void {\n const key = JSON.stringify(match);\n this.levelOverrides.delete(key);\n }\n\n clearLevelOverrides(): void {\n this.levelOverrides.clear();\n }\n\n getLevelOverrides(): LevelOverride<TContext>[] {\n return Array.from(this.levelOverrides.values());\n }\n\n private getEffectiveLevel(): string {\n const context = this.store.getStore();\n if (!context) return this.defaultLevel;\n\n for (const { match, level } of this.levelOverrides.values()) {\n if (this.matchesContext(context, match)) {\n return level;\n }\n }\n return this.defaultLevel;\n }\n\n private matchesContext(context: TContext, match: Partial<TContext>): boolean {\n return Object.entries(match).every(([key, value]) => context[key] === value);\n }\n\n private shouldLog(level: string): boolean {\n const effectiveLevel = this.getEffectiveLevel();\n return LOG_LEVELS[level] <= LOG_LEVELS[effectiveLevel];\n }\n\n getChildLogger(context: string): Logger {\n return this.winstonLogger.child({ context });\n }\n\n time(label: string): Timer {\n return createTimer(label);\n }\n\n timeEnd(timer: Timer, context?: string): TimingResult {\n const result = timer.end();\n this.debug(`${result.label} completed in ${result.durationFormatted}`, context, {\n timing: result,\n });\n return result;\n }\n\n async timeAsync<T>(label: string, fn: () => Promise<T>, context?: string): Promise<T> {\n const timer = this.time(label);\n try {\n const result = await fn();\n this.timeEnd(timer, context);\n return result;\n } catch (error) {\n const timing = timer.end();\n this.error(`${label} failed after ${timing.durationFormatted}`, error, context);\n throw error;\n }\n }\n\n log(message: string, context?: string, meta?: object): void {\n if (!this.shouldLog('info')) return;\n this.winstonLogger.info(message, { context: context || DEFAULT_CONTEXT, ...meta });\n }\n\n error(message: string, error?: Error | unknown, context?: string): void {\n if (!this.shouldLog('error')) return;\n const meta: Record<string, unknown> = { context: context || DEFAULT_CONTEXT };\n if (error instanceof Error) {\n meta.errorMessage = error.message;\n meta.errorStack = error.stack;\n } else if (error) {\n meta.error = error;\n }\n this.winstonLogger.error(message, meta);\n }\n\n warn(message: string, context?: string, meta?: object): void {\n if (!this.shouldLog('warn')) return;\n this.winstonLogger.warn(message, { context: context || DEFAULT_CONTEXT, ...meta });\n }\n\n debug(message: string, context?: string, meta?: object): void {\n if (!this.shouldLog('debug')) return;\n this.winstonLogger.debug(message, { context: context || DEFAULT_CONTEXT, ...meta });\n }\n\n info(message: string, context?: string, meta?: object): void {\n if (!this.shouldLog('info')) return;\n this.winstonLogger.info(message, { context: context || DEFAULT_CONTEXT, ...meta });\n }\n\n verbose(message: string, context?: string, meta?: object): void {\n if (!this.shouldLog('verbose')) return;\n this.winstonLogger.verbose(message, { context: context || DEFAULT_CONTEXT, ...meta });\n }\n}\n","import { Logger } from 'winston';\nimport { BaseLogger } from './logger.js';\nimport { LoggerStore } from './store.js';\nimport type { LoggerConfig, LoggerContext, LevelOverride } from './types.js';\n\nexport interface SingletonLogger<TContext extends LoggerContext> {\n getInstance(config?: LoggerConfig): BaseLogger<TContext>;\n getStore(): LoggerStore<TContext>;\n for(context: string): Logger;\n setLevelOverride(match: Partial<TContext>, level: string): void;\n removeLevelOverride(match: Partial<TContext>): void;\n getLevelOverrides(): LevelOverride<TContext>[];\n clearLevelOverrides(): void;\n}\n\nexport function createSingletonLogger<TContext extends LoggerContext>(): SingletonLogger<TContext> {\n let instance: BaseLogger<TContext> | null = null;\n\n const ensureInstance = (): BaseLogger<TContext> => {\n if (!instance) {\n throw new Error('Logger not initialized. Call getInstance(config) first.');\n }\n return instance;\n };\n\n return {\n getInstance(config?: LoggerConfig): BaseLogger<TContext> {\n if (!instance) {\n if (!config) {\n throw new Error('Logger config is required for first initialization');\n }\n instance = new BaseLogger<TContext>(config);\n }\n return instance;\n },\n\n getStore(): LoggerStore<TContext> {\n return ensureInstance().getStore();\n },\n\n for(context: string): Logger {\n return ensureInstance().getChildLogger(context);\n },\n\n setLevelOverride(match: Partial<TContext>, level: string): void {\n ensureInstance().setLevelOverride(match, level);\n },\n\n removeLevelOverride(match: Partial<TContext>): void {\n ensureInstance().removeLevelOverride(match);\n },\n\n getLevelOverrides(): LevelOverride<TContext>[] {\n return ensureInstance().getLevelOverrides();\n },\n\n clearLevelOverrides(): void {\n ensureInstance().clearLevelOverrides();\n },\n };\n}\n","import { randomUUID } from 'crypto';\n\nexport interface RequestIdOptions {\n prefix?: string;\n short?: boolean;\n}\n\nexport function generateRequestId(options: RequestIdOptions = {}): string {\n const { prefix, short = false } = options;\n const uuid = randomUUID();\n const id = short ? uuid.split('-')[0] : uuid;\n return prefix ? `${prefix}-${id}` : id;\n}\n\nexport function extractRequestId(headers: Record<string, string | string[] | undefined>): string | undefined {\n const headerNames = ['x-request-id', 'x-correlation-id', 'x-trace-id'];\n\n for (const name of headerNames) {\n const value = headers[name];\n if (typeof value === 'string' && value.length > 0) {\n return value;\n }\n if (Array.isArray(value) && value.length > 0) {\n return value[0];\n }\n }\n\n return undefined;\n}\n\nexport function getOrGenerateRequestId(\n headers: Record<string, string | string[] | undefined>,\n options: RequestIdOptions = {},\n): string {\n return extractRequestId(headers) ?? generateRequestId(options);\n}\n","const DEFAULT_SECRET_PATTERNS = [\n 'password',\n 'secret',\n 'token',\n 'apikey',\n 'api_key',\n 'api-key',\n 'auth',\n 'credential',\n 'private',\n];\n\nconst DEFAULT_MASK = '***';\n\nexport interface MaskSecretsOptions {\n patterns?: string[];\n mask?: string;\n deep?: boolean;\n}\n\nfunction isSecretKey(key: string, patterns: string[]): boolean {\n const lowerKey = key.toLowerCase();\n return patterns.some((pattern) => lowerKey.includes(pattern.toLowerCase()));\n}\n\nfunction maskUrlCredentials(url: string, mask: string): string {\n try {\n const parsed = new URL(url);\n if (parsed.password) {\n parsed.password = mask;\n }\n if (parsed.username && parsed.password) {\n parsed.username = mask;\n }\n return parsed.toString();\n } catch {\n return url;\n }\n}\n\nexport function maskSecrets(\n obj: unknown,\n options: MaskSecretsOptions = {},\n): unknown {\n const { patterns = DEFAULT_SECRET_PATTERNS, mask = DEFAULT_MASK, deep = true } = options;\n\n if (obj === null || obj === undefined) {\n return obj;\n }\n\n if (typeof obj === 'string') {\n if (obj.startsWith('http://') || obj.startsWith('https://')) {\n return maskUrlCredentials(obj, mask);\n }\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return deep ? obj.map((item) => maskSecrets(item, options)) : obj;\n }\n\n if (typeof obj === 'object') {\n const result: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(obj)) {\n if (isSecretKey(key, patterns)) {\n result[key] = mask;\n } else if (deep && typeof value === 'object' && value !== null) {\n result[key] = maskSecrets(value, options);\n } else if (typeof value === 'string') {\n result[key] = maskSecrets(value, options);\n } else {\n result[key] = value;\n }\n }\n\n return result;\n }\n\n return obj;\n}\n\nexport function createMasker(options: MaskSecretsOptions = {}) {\n return (obj: unknown): unknown => maskSecrets(obj, options);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/utils/mask-secrets.ts","../src/formatters.ts","../src/transports.ts","../src/store.ts","../src/logger.ts","../src/singleton.ts","../src/utils/timing.ts","../src/utils/request-id.ts"],"names":["inspect","format","transports","DailyRotateFile","AsyncLocalStorage","DEFAULT_CONTEXT","createLogger","randomUUID"],"mappings":"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","file":"index.js","sourcesContent":["const DEFAULT_SECRET_PATTERNS = [\n 'password',\n 'secret',\n 'token',\n 'apikey',\n 'api_key',\n 'api-key',\n 'auth',\n 'credential',\n 'private',\n];\n\nconst DEFAULT_MASK = '***';\n\nexport interface MaskSecretsOptions {\n patterns?: string[];\n mask?: string;\n deep?: boolean;\n}\n\nfunction isSecretKey(key: string, patterns: string[]): boolean {\n const lowerKey = key.toLowerCase();\n return patterns.some((pattern) => lowerKey.includes(pattern.toLowerCase()));\n}\n\nfunction maskUrlCredentials(url: string, mask: string): string {\n try {\n const parsed = new URL(url);\n if (parsed.password) {\n parsed.password = mask;\n }\n if (parsed.username && parsed.password) {\n parsed.username = mask;\n }\n return parsed.toString();\n } catch {\n return url;\n }\n}\n\nexport function maskSecrets(\n obj: unknown,\n options: MaskSecretsOptions = {},\n): unknown {\n const { patterns = DEFAULT_SECRET_PATTERNS, mask = DEFAULT_MASK, deep = true } = options;\n\n if (obj === null || obj === undefined) {\n return obj;\n }\n\n if (typeof obj === 'string') {\n if (obj.startsWith('http://') || obj.startsWith('https://')) {\n return maskUrlCredentials(obj, mask);\n }\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return deep ? obj.map((item) => maskSecrets(item, options)) : obj;\n }\n\n if (typeof obj === 'object') {\n const result: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(obj)) {\n if (isSecretKey(key, patterns)) {\n result[key] = mask;\n } else if (deep && typeof value === 'object' && value !== null) {\n result[key] = maskSecrets(value, options);\n } else if (typeof value === 'string') {\n result[key] = maskSecrets(value, options);\n } else {\n result[key] = value;\n }\n }\n\n return result;\n }\n\n return obj;\n}\n\nexport function createMasker(options: MaskSecretsOptions = {}) {\n return (obj: unknown): unknown => maskSecrets(obj, options);\n}\n","import { inspect } from 'util';\nimport { format, Logform } from 'winston';\nimport { LoggerStore } from './store.js';\nimport type { LoggerContext } from './types.js';\nimport { maskSecrets, type MaskSecretsOptions } from './utils/mask-secrets.js';\n\nconst DEFAULT_CONTEXT = 'APP';\n\nconst LEVEL_COLORS: Record<string, string> = {\n error: '\\x1b[31m', // red\n warn: '\\x1b[33m', // yellow\n info: '\\x1b[32m', // green\n http: '\\x1b[35m', // magenta\n verbose: '\\x1b[36m', // cyan\n debug: '\\x1b[34m', // blue\n silly: '\\x1b[90m', // grey\n};\nconst RESET = '\\x1b[0m';\n\nfunction colorizeLevel(level: string): string {\n const color = LEVEL_COLORS[level] || '';\n return color ? `${color}${level}${RESET}` : level;\n}\n\nfunction formatMeta(meta: Record<string, unknown>, colors: boolean): string {\n return Object.entries(meta)\n .filter(([, value]) => value !== undefined && value !== null)\n .map(([key, value]) => {\n if (typeof value === 'object') {\n const inspected = inspect(value, { depth: 4, colors, compact: false });\n return `\\n ${key}: ${inspected.split('\\n').join('\\n ')}`;\n }\n return `\\n ${key}: ${value}`;\n })\n .join('');\n}\n\nfunction addStoreContext<TContext extends LoggerContext>(store: LoggerStore<TContext>): Logform.Format {\n return format((info) => {\n const storeContext = store.getStore();\n if (storeContext) {\n return { ...info, ...storeContext };\n }\n return info;\n })();\n}\n\nfunction maskSecretsFormat(options?: MaskSecretsOptions): Logform.Format {\n return format((info) => {\n return maskSecrets(info, options) as Logform.TransformableInfo;\n })();\n}\n\nexport function createLocalFormat<TContext extends LoggerContext>(store: LoggerStore<TContext>): Logform.Format {\n return format.combine(\n format.errors({ stack: true }),\n format.timestamp(),\n addStoreContext(store),\n maskSecretsFormat(),\n format.printf(({ timestamp, level, context, message, ...meta }) => {\n const formattedMeta = formatMeta(meta, true);\n const coloredLevel = colorizeLevel(level);\n return `[${timestamp}] ${coloredLevel} [${context || DEFAULT_CONTEXT}] ${message}${formattedMeta}`;\n }),\n );\n}\n\nexport function createProductionFormat<TContext extends LoggerContext>(store: LoggerStore<TContext>): Logform.Format {\n return format.combine(\n format.errors({ stack: true }),\n format.timestamp(),\n addStoreContext(store),\n maskSecretsFormat(),\n format.json(),\n );\n}\n\nexport function createFormat<TContext extends LoggerContext>(isLocal: boolean, store: LoggerStore<TContext>): Logform.Format {\n return isLocal ? createLocalFormat(store) : createProductionFormat(store);\n}\n","import { transports } from 'winston';\nimport DailyRotateFile from 'winston-daily-rotate-file';\nimport { LoggerConfig } from './types.js';\n\ntype Transport = transports.ConsoleTransportInstance | DailyRotateFile;\n\nexport function createTransports(config: LoggerConfig): Transport[] {\n const result: Transport[] = [\n new transports.Console({\n level: config.console.level,\n }),\n ];\n\n if (config.file) {\n result.push(\n new DailyRotateFile({\n dirname: config.file.dirname,\n filename: config.file.filename,\n level: config.file.level,\n datePattern: config.file.datePattern,\n zippedArchive: config.file.zippedArchive,\n maxSize: config.file.maxSize,\n maxFiles: config.file.maxFiles,\n }),\n );\n }\n\n return result;\n}\n\nexport function createExceptionHandlers(config: LoggerConfig): Transport[] {\n const result: Transport[] = [new transports.Console()];\n\n if (config.file) {\n result.push(\n new DailyRotateFile({\n dirname: config.file.dirname,\n filename: config.file.filename,\n datePattern: config.file.datePattern,\n zippedArchive: config.file.zippedArchive,\n maxSize: config.file.maxSize,\n maxFiles: config.file.maxFiles,\n }),\n );\n }\n\n return result;\n}\n","import { AsyncLocalStorage } from 'async_hooks';\nimport type { LoggerContext } from './types.js';\n\nexport class LoggerStore<TContext extends LoggerContext = LoggerContext> {\n private storage = new AsyncLocalStorage<TContext>();\n\n getStore(): TContext | undefined {\n return this.storage.getStore();\n }\n\n run<T>(context: TContext, fn: () => T): T {\n return this.storage.run(context, fn);\n }\n}\n","import { createLogger, Logger } from 'winston';\nimport type { LoggerConfig, LoggerContext, LevelOverride } from './types.js';\nimport { createFormat } from './formatters.js';\nimport { createTransports, createExceptionHandlers } from './transports.js';\nimport { LoggerStore } from './store.js';\n\nconst DEFAULT_CONTEXT = 'APP';\n\nconst LOG_LEVELS: Record<string, number> = {\n error: 0,\n warn: 1,\n info: 2,\n http: 3,\n verbose: 4,\n debug: 5,\n silly: 6,\n};\n\nexport class BaseLogger<TContext extends LoggerContext = LoggerContext> {\n private winstonLogger: Logger;\n private defaultLevel: string;\n private store: LoggerStore<TContext>;\n private levelOverrides: Map<string, LevelOverride<TContext>> = new Map();\n\n constructor(config: LoggerConfig, store?: LoggerStore<TContext>) {\n const isLocal = process.env.NODE_ENV !== 'production';\n\n this.defaultLevel = config.level;\n this.store = store ?? new LoggerStore<TContext>();\n\n const exceptionHandlers = createExceptionHandlers(config);\n\n this.winstonLogger = createLogger({\n level: 'silly', // Allow all, we filter manually\n format: createFormat(isLocal, this.store),\n transports: createTransports(config),\n exceptionHandlers,\n rejectionHandlers: exceptionHandlers,\n exitOnError: false,\n });\n }\n\n getStore(): LoggerStore<TContext> {\n return this.store;\n }\n\n setLevelOverride(match: Partial<TContext>, level: string): void {\n const key = JSON.stringify(match);\n this.levelOverrides.set(key, { match, level });\n }\n\n removeLevelOverride(match: Partial<TContext>): void {\n const key = JSON.stringify(match);\n this.levelOverrides.delete(key);\n }\n\n clearLevelOverrides(): void {\n this.levelOverrides.clear();\n }\n\n getLevelOverrides(): LevelOverride<TContext>[] {\n return Array.from(this.levelOverrides.values());\n }\n\n private getEffectiveLevel(): string {\n const context = this.store.getStore();\n if (!context) return this.defaultLevel;\n\n for (const { match, level } of this.levelOverrides.values()) {\n if (this.matchesContext(context, match)) {\n return level;\n }\n }\n return this.defaultLevel;\n }\n\n private matchesContext(context: TContext, match: Partial<TContext>): boolean {\n return Object.entries(match).every(([key, value]) => context[key] === value);\n }\n\n private shouldLog(level: string): boolean {\n const effectiveLevel = this.getEffectiveLevel();\n return LOG_LEVELS[level] <= LOG_LEVELS[effectiveLevel];\n }\n\n getChildLogger(context: string): Logger {\n return this.winstonLogger.child({ context });\n }\n\n profile(id: string, meta?: object): void {\n this.winstonLogger.profile(id, meta);\n }\n\n log(message: string, context?: string, meta?: object): void {\n if (!this.shouldLog('info')) return;\n this.winstonLogger.info(message, { context: context || DEFAULT_CONTEXT, ...meta });\n }\n\n error(message: string, error?: Error | unknown, context?: string): void {\n if (!this.shouldLog('error')) return;\n const meta: Record<string, unknown> = { context: context || DEFAULT_CONTEXT };\n if (error instanceof Error) {\n meta.errorMessage = error.message;\n meta.errorStack = error.stack;\n } else if (error) {\n meta.error = error;\n }\n this.winstonLogger.error(message, meta);\n }\n\n warn(message: string, context?: string, meta?: object): void {\n if (!this.shouldLog('warn')) return;\n this.winstonLogger.warn(message, { context: context || DEFAULT_CONTEXT, ...meta });\n }\n\n debug(message: string, context?: string, meta?: object): void {\n if (!this.shouldLog('debug')) return;\n this.winstonLogger.debug(message, { context: context || DEFAULT_CONTEXT, ...meta });\n }\n\n info(message: string, context?: string, meta?: object): void {\n if (!this.shouldLog('info')) return;\n this.winstonLogger.info(message, { context: context || DEFAULT_CONTEXT, ...meta });\n }\n\n verbose(message: string, context?: string, meta?: object): void {\n if (!this.shouldLog('verbose')) return;\n this.winstonLogger.verbose(message, { context: context || DEFAULT_CONTEXT, ...meta });\n }\n}\n","import { Logger } from 'winston';\nimport { BaseLogger } from './logger.js';\nimport { LoggerStore } from './store.js';\nimport type { LoggerConfig, LoggerContext, LevelOverride } from './types.js';\n\nexport interface SingletonLogger<TContext extends LoggerContext> {\n getInstance(config?: LoggerConfig): BaseLogger<TContext>;\n getStore(): LoggerStore<TContext>;\n for(context: string): Logger;\n setLevelOverride(match: Partial<TContext>, level: string): void;\n removeLevelOverride(match: Partial<TContext>): void;\n getLevelOverrides(): LevelOverride<TContext>[];\n clearLevelOverrides(): void;\n}\n\nexport function createSingletonLogger<TContext extends LoggerContext>(): SingletonLogger<TContext> {\n let instance: BaseLogger<TContext> | null = null;\n\n const ensureInstance = (): BaseLogger<TContext> => {\n if (!instance) {\n throw new Error('Logger not initialized. Call getInstance(config) first.');\n }\n return instance;\n };\n\n return {\n getInstance(config?: LoggerConfig): BaseLogger<TContext> {\n if (!instance) {\n if (!config) {\n throw new Error('Logger config is required for first initialization');\n }\n instance = new BaseLogger<TContext>(config);\n }\n return instance;\n },\n\n getStore(): LoggerStore<TContext> {\n return ensureInstance().getStore();\n },\n\n for(context: string): Logger {\n return ensureInstance().getChildLogger(context);\n },\n\n setLevelOverride(match: Partial<TContext>, level: string): void {\n ensureInstance().setLevelOverride(match, level);\n },\n\n removeLevelOverride(match: Partial<TContext>): void {\n ensureInstance().removeLevelOverride(match);\n },\n\n getLevelOverrides(): LevelOverride<TContext>[] {\n return ensureInstance().getLevelOverrides();\n },\n\n clearLevelOverrides(): void {\n ensureInstance().clearLevelOverrides();\n },\n };\n}\n","export interface TimingResult {\n label: string;\n durationMs: number;\n durationFormatted: string;\n}\n\nexport interface Timer {\n end: () => TimingResult;\n}\n\nfunction formatDuration(ms: number): string {\n if (ms < 1000) {\n return `${ms.toFixed(2)}ms`;\n }\n if (ms < 60000) {\n return `${(ms / 1000).toFixed(2)}s`;\n }\n const minutes = Math.floor(ms / 60000);\n const seconds = ((ms % 60000) / 1000).toFixed(1);\n return `${minutes}m ${seconds}s`;\n}\n\nexport function createTimer(label: string): Timer {\n const start = performance.now();\n\n return {\n end(): TimingResult {\n const durationMs = performance.now() - start;\n return {\n label,\n durationMs,\n durationFormatted: formatDuration(durationMs),\n };\n },\n };\n}\n\nexport async function measureAsync<T>(\n label: string,\n fn: () => Promise<T>,\n): Promise<{ result: T; timing: TimingResult }> {\n const timer = createTimer(label);\n const result = await fn();\n const timing = timer.end();\n return { result, timing };\n}\n\nexport function measureSync<T>(\n label: string,\n fn: () => T,\n): { result: T; timing: TimingResult } {\n const timer = createTimer(label);\n const result = fn();\n const timing = timer.end();\n return { result, timing };\n}\n","import { randomUUID } from 'crypto';\n\nexport interface RequestIdOptions {\n prefix?: string;\n short?: boolean;\n}\n\nexport function generateRequestId(options: RequestIdOptions = {}): string {\n const { prefix, short = false } = options;\n const uuid = randomUUID();\n const id = short ? uuid.split('-')[0] : uuid;\n return prefix ? `${prefix}-${id}` : id;\n}\n\nexport function extractRequestId(headers: Record<string, string | string[] | undefined>): string | undefined {\n const headerNames = ['x-request-id', 'x-correlation-id', 'x-trace-id'];\n\n for (const name of headerNames) {\n const value = headers[name];\n if (typeof value === 'string' && value.length > 0) {\n return value;\n }\n if (Array.isArray(value) && value.length > 0) {\n return value[0];\n }\n }\n\n return undefined;\n}\n\nexport function getOrGenerateRequestId(\n headers: Record<string, string | string[] | undefined>,\n options: RequestIdOptions = {},\n): string {\n return extractRequestId(headers) ?? generateRequestId(options);\n}\n"]}
|
|
@@ -1,21 +1,104 @@
|
|
|
1
|
-
|
|
1
|
+
import { createLogger, transports, format } from 'winston';
|
|
2
|
+
import { inspect } from 'util';
|
|
3
|
+
import DailyRotateFile from 'winston-daily-rotate-file';
|
|
4
|
+
import { AsyncLocalStorage } from 'async_hooks';
|
|
5
|
+
import { randomUUID } from 'crypto';
|
|
2
6
|
|
|
3
|
-
|
|
4
|
-
var util = require('util');
|
|
5
|
-
var DailyRotateFile = require('winston-daily-rotate-file');
|
|
6
|
-
var async_hooks = require('async_hooks');
|
|
7
|
-
var crypto = require('crypto');
|
|
8
|
-
|
|
9
|
-
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
7
|
+
// src/logger.ts
|
|
10
8
|
|
|
11
|
-
|
|
9
|
+
// src/utils/mask-secrets.ts
|
|
10
|
+
var DEFAULT_SECRET_PATTERNS = [
|
|
11
|
+
"password",
|
|
12
|
+
"secret",
|
|
13
|
+
"token",
|
|
14
|
+
"apikey",
|
|
15
|
+
"api_key",
|
|
16
|
+
"api-key",
|
|
17
|
+
"auth",
|
|
18
|
+
"credential",
|
|
19
|
+
"private"
|
|
20
|
+
];
|
|
21
|
+
var DEFAULT_MASK = "***";
|
|
22
|
+
function isSecretKey(key, patterns) {
|
|
23
|
+
const lowerKey = key.toLowerCase();
|
|
24
|
+
return patterns.some((pattern) => lowerKey.includes(pattern.toLowerCase()));
|
|
25
|
+
}
|
|
26
|
+
function maskUrlCredentials(url, mask) {
|
|
27
|
+
try {
|
|
28
|
+
const parsed = new URL(url);
|
|
29
|
+
if (parsed.password) {
|
|
30
|
+
parsed.password = mask;
|
|
31
|
+
}
|
|
32
|
+
if (parsed.username && parsed.password) {
|
|
33
|
+
parsed.username = mask;
|
|
34
|
+
}
|
|
35
|
+
return parsed.toString();
|
|
36
|
+
} catch {
|
|
37
|
+
return url;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function maskSecrets(obj, options = {}) {
|
|
41
|
+
const { patterns = DEFAULT_SECRET_PATTERNS, mask = DEFAULT_MASK, deep = true } = options;
|
|
42
|
+
if (obj === null || obj === void 0) {
|
|
43
|
+
return obj;
|
|
44
|
+
}
|
|
45
|
+
if (typeof obj === "string") {
|
|
46
|
+
if (obj.startsWith("http://") || obj.startsWith("https://")) {
|
|
47
|
+
return maskUrlCredentials(obj, mask);
|
|
48
|
+
}
|
|
49
|
+
return obj;
|
|
50
|
+
}
|
|
51
|
+
if (Array.isArray(obj)) {
|
|
52
|
+
return deep ? obj.map((item) => maskSecrets(item, options)) : obj;
|
|
53
|
+
}
|
|
54
|
+
if (typeof obj === "object") {
|
|
55
|
+
const result = {};
|
|
56
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
57
|
+
if (isSecretKey(key, patterns)) {
|
|
58
|
+
result[key] = mask;
|
|
59
|
+
} else if (deep && typeof value === "object" && value !== null) {
|
|
60
|
+
result[key] = maskSecrets(value, options);
|
|
61
|
+
} else if (typeof value === "string") {
|
|
62
|
+
result[key] = maskSecrets(value, options);
|
|
63
|
+
} else {
|
|
64
|
+
result[key] = value;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
return obj;
|
|
70
|
+
}
|
|
71
|
+
function createMasker(options = {}) {
|
|
72
|
+
return (obj) => maskSecrets(obj, options);
|
|
73
|
+
}
|
|
12
74
|
|
|
13
|
-
// src/
|
|
75
|
+
// src/formatters.ts
|
|
14
76
|
var DEFAULT_CONTEXT = "APP";
|
|
77
|
+
var LEVEL_COLORS = {
|
|
78
|
+
error: "\x1B[31m",
|
|
79
|
+
// red
|
|
80
|
+
warn: "\x1B[33m",
|
|
81
|
+
// yellow
|
|
82
|
+
info: "\x1B[32m",
|
|
83
|
+
// green
|
|
84
|
+
http: "\x1B[35m",
|
|
85
|
+
// magenta
|
|
86
|
+
verbose: "\x1B[36m",
|
|
87
|
+
// cyan
|
|
88
|
+
debug: "\x1B[34m",
|
|
89
|
+
// blue
|
|
90
|
+
silly: "\x1B[90m"
|
|
91
|
+
// grey
|
|
92
|
+
};
|
|
93
|
+
var RESET = "\x1B[0m";
|
|
94
|
+
function colorizeLevel(level) {
|
|
95
|
+
const color = LEVEL_COLORS[level] || "";
|
|
96
|
+
return color ? `${color}${level}${RESET}` : level;
|
|
97
|
+
}
|
|
15
98
|
function formatMeta(meta, colors) {
|
|
16
99
|
return Object.entries(meta).filter(([, value]) => value !== void 0 && value !== null).map(([key, value]) => {
|
|
17
100
|
if (typeof value === "object") {
|
|
18
|
-
const inspected =
|
|
101
|
+
const inspected = inspect(value, { depth: 4, colors, compact: false });
|
|
19
102
|
return `
|
|
20
103
|
${key}: ${inspected.split("\n").join("\n ")}`;
|
|
21
104
|
}
|
|
@@ -24,7 +107,7 @@ function formatMeta(meta, colors) {
|
|
|
24
107
|
}).join("");
|
|
25
108
|
}
|
|
26
109
|
function addStoreContext(store) {
|
|
27
|
-
return
|
|
110
|
+
return format((info) => {
|
|
28
111
|
const storeContext = store.getStore();
|
|
29
112
|
if (storeContext) {
|
|
30
113
|
return { ...info, ...storeContext };
|
|
@@ -32,24 +115,31 @@ function addStoreContext(store) {
|
|
|
32
115
|
return info;
|
|
33
116
|
})();
|
|
34
117
|
}
|
|
118
|
+
function maskSecretsFormat(options) {
|
|
119
|
+
return format((info) => {
|
|
120
|
+
return maskSecrets(info, options);
|
|
121
|
+
})();
|
|
122
|
+
}
|
|
35
123
|
function createLocalFormat(store) {
|
|
36
|
-
return
|
|
37
|
-
|
|
38
|
-
|
|
124
|
+
return format.combine(
|
|
125
|
+
format.errors({ stack: true }),
|
|
126
|
+
format.timestamp(),
|
|
39
127
|
addStoreContext(store),
|
|
40
|
-
|
|
41
|
-
|
|
128
|
+
maskSecretsFormat(),
|
|
129
|
+
format.printf(({ timestamp, level, context, message, ...meta }) => {
|
|
42
130
|
const formattedMeta = formatMeta(meta, true);
|
|
43
|
-
|
|
131
|
+
const coloredLevel = colorizeLevel(level);
|
|
132
|
+
return `[${timestamp}] ${coloredLevel} [${context || DEFAULT_CONTEXT}] ${message}${formattedMeta}`;
|
|
44
133
|
})
|
|
45
134
|
);
|
|
46
135
|
}
|
|
47
136
|
function createProductionFormat(store) {
|
|
48
|
-
return
|
|
49
|
-
|
|
50
|
-
|
|
137
|
+
return format.combine(
|
|
138
|
+
format.errors({ stack: true }),
|
|
139
|
+
format.timestamp(),
|
|
51
140
|
addStoreContext(store),
|
|
52
|
-
|
|
141
|
+
maskSecretsFormat(),
|
|
142
|
+
format.json()
|
|
53
143
|
);
|
|
54
144
|
}
|
|
55
145
|
function createFormat(isLocal, store) {
|
|
@@ -57,13 +147,13 @@ function createFormat(isLocal, store) {
|
|
|
57
147
|
}
|
|
58
148
|
function createTransports(config) {
|
|
59
149
|
const result = [
|
|
60
|
-
new
|
|
150
|
+
new transports.Console({
|
|
61
151
|
level: config.console.level
|
|
62
152
|
})
|
|
63
153
|
];
|
|
64
154
|
if (config.file) {
|
|
65
155
|
result.push(
|
|
66
|
-
new
|
|
156
|
+
new DailyRotateFile({
|
|
67
157
|
dirname: config.file.dirname,
|
|
68
158
|
filename: config.file.filename,
|
|
69
159
|
level: config.file.level,
|
|
@@ -76,8 +166,24 @@ function createTransports(config) {
|
|
|
76
166
|
}
|
|
77
167
|
return result;
|
|
78
168
|
}
|
|
169
|
+
function createExceptionHandlers(config) {
|
|
170
|
+
const result = [new transports.Console()];
|
|
171
|
+
if (config.file) {
|
|
172
|
+
result.push(
|
|
173
|
+
new DailyRotateFile({
|
|
174
|
+
dirname: config.file.dirname,
|
|
175
|
+
filename: config.file.filename,
|
|
176
|
+
datePattern: config.file.datePattern,
|
|
177
|
+
zippedArchive: config.file.zippedArchive,
|
|
178
|
+
maxSize: config.file.maxSize,
|
|
179
|
+
maxFiles: config.file.maxFiles
|
|
180
|
+
})
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
return result;
|
|
184
|
+
}
|
|
79
185
|
var LoggerStore = class {
|
|
80
|
-
storage = new
|
|
186
|
+
storage = new AsyncLocalStorage();
|
|
81
187
|
getStore() {
|
|
82
188
|
return this.storage.getStore();
|
|
83
189
|
}
|
|
@@ -86,44 +192,6 @@ var LoggerStore = class {
|
|
|
86
192
|
}
|
|
87
193
|
};
|
|
88
194
|
|
|
89
|
-
// src/utils/timing.ts
|
|
90
|
-
function formatDuration(ms) {
|
|
91
|
-
if (ms < 1e3) {
|
|
92
|
-
return `${ms.toFixed(2)}ms`;
|
|
93
|
-
}
|
|
94
|
-
if (ms < 6e4) {
|
|
95
|
-
return `${(ms / 1e3).toFixed(2)}s`;
|
|
96
|
-
}
|
|
97
|
-
const minutes = Math.floor(ms / 6e4);
|
|
98
|
-
const seconds = (ms % 6e4 / 1e3).toFixed(1);
|
|
99
|
-
return `${minutes}m ${seconds}s`;
|
|
100
|
-
}
|
|
101
|
-
function createTimer(label) {
|
|
102
|
-
const start = performance.now();
|
|
103
|
-
return {
|
|
104
|
-
end() {
|
|
105
|
-
const durationMs = performance.now() - start;
|
|
106
|
-
return {
|
|
107
|
-
label,
|
|
108
|
-
durationMs,
|
|
109
|
-
durationFormatted: formatDuration(durationMs)
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
async function measureAsync(label, fn) {
|
|
115
|
-
const timer = createTimer(label);
|
|
116
|
-
const result = await fn();
|
|
117
|
-
const timing = timer.end();
|
|
118
|
-
return { result, timing };
|
|
119
|
-
}
|
|
120
|
-
function measureSync(label, fn) {
|
|
121
|
-
const timer = createTimer(label);
|
|
122
|
-
const result = fn();
|
|
123
|
-
const timing = timer.end();
|
|
124
|
-
return { result, timing };
|
|
125
|
-
}
|
|
126
|
-
|
|
127
195
|
// src/logger.ts
|
|
128
196
|
var DEFAULT_CONTEXT2 = "APP";
|
|
129
197
|
var LOG_LEVELS = {
|
|
@@ -144,11 +212,15 @@ var BaseLogger = class {
|
|
|
144
212
|
const isLocal = process.env.NODE_ENV !== "production";
|
|
145
213
|
this.defaultLevel = config.level;
|
|
146
214
|
this.store = store ?? new LoggerStore();
|
|
147
|
-
|
|
215
|
+
const exceptionHandlers = createExceptionHandlers(config);
|
|
216
|
+
this.winstonLogger = createLogger({
|
|
148
217
|
level: "silly",
|
|
149
218
|
// Allow all, we filter manually
|
|
150
219
|
format: createFormat(isLocal, this.store),
|
|
151
|
-
transports: createTransports(config)
|
|
220
|
+
transports: createTransports(config),
|
|
221
|
+
exceptionHandlers,
|
|
222
|
+
rejectionHandlers: exceptionHandlers,
|
|
223
|
+
exitOnError: false
|
|
152
224
|
});
|
|
153
225
|
}
|
|
154
226
|
getStore() {
|
|
@@ -188,27 +260,8 @@ var BaseLogger = class {
|
|
|
188
260
|
getChildLogger(context) {
|
|
189
261
|
return this.winstonLogger.child({ context });
|
|
190
262
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
}
|
|
194
|
-
timeEnd(timer, context) {
|
|
195
|
-
const result = timer.end();
|
|
196
|
-
this.debug(`${result.label} completed in ${result.durationFormatted}`, context, {
|
|
197
|
-
timing: result
|
|
198
|
-
});
|
|
199
|
-
return result;
|
|
200
|
-
}
|
|
201
|
-
async timeAsync(label, fn, context) {
|
|
202
|
-
const timer = this.time(label);
|
|
203
|
-
try {
|
|
204
|
-
const result = await fn();
|
|
205
|
-
this.timeEnd(timer, context);
|
|
206
|
-
return result;
|
|
207
|
-
} catch (error) {
|
|
208
|
-
const timing = timer.end();
|
|
209
|
-
this.error(`${label} failed after ${timing.durationFormatted}`, error, context);
|
|
210
|
-
throw error;
|
|
211
|
-
}
|
|
263
|
+
profile(id, meta) {
|
|
264
|
+
this.winstonLogger.profile(id, meta);
|
|
212
265
|
}
|
|
213
266
|
log(message, context, meta) {
|
|
214
267
|
if (!this.shouldLog("info")) return;
|
|
@@ -282,9 +335,47 @@ function createSingletonLogger() {
|
|
|
282
335
|
}
|
|
283
336
|
};
|
|
284
337
|
}
|
|
338
|
+
|
|
339
|
+
// src/utils/timing.ts
|
|
340
|
+
function formatDuration(ms) {
|
|
341
|
+
if (ms < 1e3) {
|
|
342
|
+
return `${ms.toFixed(2)}ms`;
|
|
343
|
+
}
|
|
344
|
+
if (ms < 6e4) {
|
|
345
|
+
return `${(ms / 1e3).toFixed(2)}s`;
|
|
346
|
+
}
|
|
347
|
+
const minutes = Math.floor(ms / 6e4);
|
|
348
|
+
const seconds = (ms % 6e4 / 1e3).toFixed(1);
|
|
349
|
+
return `${minutes}m ${seconds}s`;
|
|
350
|
+
}
|
|
351
|
+
function createTimer(label) {
|
|
352
|
+
const start = performance.now();
|
|
353
|
+
return {
|
|
354
|
+
end() {
|
|
355
|
+
const durationMs = performance.now() - start;
|
|
356
|
+
return {
|
|
357
|
+
label,
|
|
358
|
+
durationMs,
|
|
359
|
+
durationFormatted: formatDuration(durationMs)
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
async function measureAsync(label, fn) {
|
|
365
|
+
const timer = createTimer(label);
|
|
366
|
+
const result = await fn();
|
|
367
|
+
const timing = timer.end();
|
|
368
|
+
return { result, timing };
|
|
369
|
+
}
|
|
370
|
+
function measureSync(label, fn) {
|
|
371
|
+
const timer = createTimer(label);
|
|
372
|
+
const result = fn();
|
|
373
|
+
const timing = timer.end();
|
|
374
|
+
return { result, timing };
|
|
375
|
+
}
|
|
285
376
|
function generateRequestId(options = {}) {
|
|
286
377
|
const { prefix, short = false } = options;
|
|
287
|
-
const uuid =
|
|
378
|
+
const uuid = randomUUID();
|
|
288
379
|
const id = short ? uuid.split("-")[0] : uuid;
|
|
289
380
|
return prefix ? `${prefix}-${id}` : id;
|
|
290
381
|
}
|
|
@@ -305,82 +396,6 @@ function getOrGenerateRequestId(headers, options = {}) {
|
|
|
305
396
|
return extractRequestId(headers) ?? generateRequestId(options);
|
|
306
397
|
}
|
|
307
398
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
"secret",
|
|
312
|
-
"token",
|
|
313
|
-
"apikey",
|
|
314
|
-
"api_key",
|
|
315
|
-
"api-key",
|
|
316
|
-
"auth",
|
|
317
|
-
"credential",
|
|
318
|
-
"private"
|
|
319
|
-
];
|
|
320
|
-
var DEFAULT_MASK = "***";
|
|
321
|
-
function isSecretKey(key, patterns) {
|
|
322
|
-
const lowerKey = key.toLowerCase();
|
|
323
|
-
return patterns.some((pattern) => lowerKey.includes(pattern.toLowerCase()));
|
|
324
|
-
}
|
|
325
|
-
function maskUrlCredentials(url, mask) {
|
|
326
|
-
try {
|
|
327
|
-
const parsed = new URL(url);
|
|
328
|
-
if (parsed.password) {
|
|
329
|
-
parsed.password = mask;
|
|
330
|
-
}
|
|
331
|
-
if (parsed.username && parsed.password) {
|
|
332
|
-
parsed.username = mask;
|
|
333
|
-
}
|
|
334
|
-
return parsed.toString();
|
|
335
|
-
} catch {
|
|
336
|
-
return url;
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
function maskSecrets(obj, options = {}) {
|
|
340
|
-
const { patterns = DEFAULT_SECRET_PATTERNS, mask = DEFAULT_MASK, deep = true } = options;
|
|
341
|
-
if (obj === null || obj === void 0) {
|
|
342
|
-
return obj;
|
|
343
|
-
}
|
|
344
|
-
if (typeof obj === "string") {
|
|
345
|
-
if (obj.startsWith("http://") || obj.startsWith("https://")) {
|
|
346
|
-
return maskUrlCredentials(obj, mask);
|
|
347
|
-
}
|
|
348
|
-
return obj;
|
|
349
|
-
}
|
|
350
|
-
if (Array.isArray(obj)) {
|
|
351
|
-
return deep ? obj.map((item) => maskSecrets(item, options)) : obj;
|
|
352
|
-
}
|
|
353
|
-
if (typeof obj === "object") {
|
|
354
|
-
const result = {};
|
|
355
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
356
|
-
if (isSecretKey(key, patterns)) {
|
|
357
|
-
result[key] = mask;
|
|
358
|
-
} else if (deep && typeof value === "object" && value !== null) {
|
|
359
|
-
result[key] = maskSecrets(value, options);
|
|
360
|
-
} else if (typeof value === "string") {
|
|
361
|
-
result[key] = maskSecrets(value, options);
|
|
362
|
-
} else {
|
|
363
|
-
result[key] = value;
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
return result;
|
|
367
|
-
}
|
|
368
|
-
return obj;
|
|
369
|
-
}
|
|
370
|
-
function createMasker(options = {}) {
|
|
371
|
-
return (obj) => maskSecrets(obj, options);
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
exports.BaseLogger = BaseLogger;
|
|
375
|
-
exports.LoggerStore = LoggerStore;
|
|
376
|
-
exports.createMasker = createMasker;
|
|
377
|
-
exports.createSingletonLogger = createSingletonLogger;
|
|
378
|
-
exports.createTimer = createTimer;
|
|
379
|
-
exports.extractRequestId = extractRequestId;
|
|
380
|
-
exports.generateRequestId = generateRequestId;
|
|
381
|
-
exports.getOrGenerateRequestId = getOrGenerateRequestId;
|
|
382
|
-
exports.maskSecrets = maskSecrets;
|
|
383
|
-
exports.measureAsync = measureAsync;
|
|
384
|
-
exports.measureSync = measureSync;
|
|
385
|
-
//# sourceMappingURL=index.cjs.map
|
|
386
|
-
//# sourceMappingURL=index.cjs.map
|
|
399
|
+
export { BaseLogger, LoggerStore, createMasker, createSingletonLogger, extractRequestId, generateRequestId, getOrGenerateRequestId, maskSecrets, measureAsync, measureSync };
|
|
400
|
+
//# sourceMappingURL=index.mjs.map
|
|
401
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/mask-secrets.ts","../src/formatters.ts","../src/transports.ts","../src/store.ts","../src/logger.ts","../src/singleton.ts","../src/utils/timing.ts","../src/utils/request-id.ts"],"names":["DEFAULT_CONTEXT"],"mappings":"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","file":"index.mjs","sourcesContent":["const DEFAULT_SECRET_PATTERNS = [\n 'password',\n 'secret',\n 'token',\n 'apikey',\n 'api_key',\n 'api-key',\n 'auth',\n 'credential',\n 'private',\n];\n\nconst DEFAULT_MASK = '***';\n\nexport interface MaskSecretsOptions {\n patterns?: string[];\n mask?: string;\n deep?: boolean;\n}\n\nfunction isSecretKey(key: string, patterns: string[]): boolean {\n const lowerKey = key.toLowerCase();\n return patterns.some((pattern) => lowerKey.includes(pattern.toLowerCase()));\n}\n\nfunction maskUrlCredentials(url: string, mask: string): string {\n try {\n const parsed = new URL(url);\n if (parsed.password) {\n parsed.password = mask;\n }\n if (parsed.username && parsed.password) {\n parsed.username = mask;\n }\n return parsed.toString();\n } catch {\n return url;\n }\n}\n\nexport function maskSecrets(\n obj: unknown,\n options: MaskSecretsOptions = {},\n): unknown {\n const { patterns = DEFAULT_SECRET_PATTERNS, mask = DEFAULT_MASK, deep = true } = options;\n\n if (obj === null || obj === undefined) {\n return obj;\n }\n\n if (typeof obj === 'string') {\n if (obj.startsWith('http://') || obj.startsWith('https://')) {\n return maskUrlCredentials(obj, mask);\n }\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return deep ? obj.map((item) => maskSecrets(item, options)) : obj;\n }\n\n if (typeof obj === 'object') {\n const result: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(obj)) {\n if (isSecretKey(key, patterns)) {\n result[key] = mask;\n } else if (deep && typeof value === 'object' && value !== null) {\n result[key] = maskSecrets(value, options);\n } else if (typeof value === 'string') {\n result[key] = maskSecrets(value, options);\n } else {\n result[key] = value;\n }\n }\n\n return result;\n }\n\n return obj;\n}\n\nexport function createMasker(options: MaskSecretsOptions = {}) {\n return (obj: unknown): unknown => maskSecrets(obj, options);\n}\n","import { inspect } from 'util';\nimport { format, Logform } from 'winston';\nimport { LoggerStore } from './store.js';\nimport type { LoggerContext } from './types.js';\nimport { maskSecrets, type MaskSecretsOptions } from './utils/mask-secrets.js';\n\nconst DEFAULT_CONTEXT = 'APP';\n\nconst LEVEL_COLORS: Record<string, string> = {\n error: '\\x1b[31m', // red\n warn: '\\x1b[33m', // yellow\n info: '\\x1b[32m', // green\n http: '\\x1b[35m', // magenta\n verbose: '\\x1b[36m', // cyan\n debug: '\\x1b[34m', // blue\n silly: '\\x1b[90m', // grey\n};\nconst RESET = '\\x1b[0m';\n\nfunction colorizeLevel(level: string): string {\n const color = LEVEL_COLORS[level] || '';\n return color ? `${color}${level}${RESET}` : level;\n}\n\nfunction formatMeta(meta: Record<string, unknown>, colors: boolean): string {\n return Object.entries(meta)\n .filter(([, value]) => value !== undefined && value !== null)\n .map(([key, value]) => {\n if (typeof value === 'object') {\n const inspected = inspect(value, { depth: 4, colors, compact: false });\n return `\\n ${key}: ${inspected.split('\\n').join('\\n ')}`;\n }\n return `\\n ${key}: ${value}`;\n })\n .join('');\n}\n\nfunction addStoreContext<TContext extends LoggerContext>(store: LoggerStore<TContext>): Logform.Format {\n return format((info) => {\n const storeContext = store.getStore();\n if (storeContext) {\n return { ...info, ...storeContext };\n }\n return info;\n })();\n}\n\nfunction maskSecretsFormat(options?: MaskSecretsOptions): Logform.Format {\n return format((info) => {\n return maskSecrets(info, options) as Logform.TransformableInfo;\n })();\n}\n\nexport function createLocalFormat<TContext extends LoggerContext>(store: LoggerStore<TContext>): Logform.Format {\n return format.combine(\n format.errors({ stack: true }),\n format.timestamp(),\n addStoreContext(store),\n maskSecretsFormat(),\n format.printf(({ timestamp, level, context, message, ...meta }) => {\n const formattedMeta = formatMeta(meta, true);\n const coloredLevel = colorizeLevel(level);\n return `[${timestamp}] ${coloredLevel} [${context || DEFAULT_CONTEXT}] ${message}${formattedMeta}`;\n }),\n );\n}\n\nexport function createProductionFormat<TContext extends LoggerContext>(store: LoggerStore<TContext>): Logform.Format {\n return format.combine(\n format.errors({ stack: true }),\n format.timestamp(),\n addStoreContext(store),\n maskSecretsFormat(),\n format.json(),\n );\n}\n\nexport function createFormat<TContext extends LoggerContext>(isLocal: boolean, store: LoggerStore<TContext>): Logform.Format {\n return isLocal ? createLocalFormat(store) : createProductionFormat(store);\n}\n","import { transports } from 'winston';\nimport DailyRotateFile from 'winston-daily-rotate-file';\nimport { LoggerConfig } from './types.js';\n\ntype Transport = transports.ConsoleTransportInstance | DailyRotateFile;\n\nexport function createTransports(config: LoggerConfig): Transport[] {\n const result: Transport[] = [\n new transports.Console({\n level: config.console.level,\n }),\n ];\n\n if (config.file) {\n result.push(\n new DailyRotateFile({\n dirname: config.file.dirname,\n filename: config.file.filename,\n level: config.file.level,\n datePattern: config.file.datePattern,\n zippedArchive: config.file.zippedArchive,\n maxSize: config.file.maxSize,\n maxFiles: config.file.maxFiles,\n }),\n );\n }\n\n return result;\n}\n\nexport function createExceptionHandlers(config: LoggerConfig): Transport[] {\n const result: Transport[] = [new transports.Console()];\n\n if (config.file) {\n result.push(\n new DailyRotateFile({\n dirname: config.file.dirname,\n filename: config.file.filename,\n datePattern: config.file.datePattern,\n zippedArchive: config.file.zippedArchive,\n maxSize: config.file.maxSize,\n maxFiles: config.file.maxFiles,\n }),\n );\n }\n\n return result;\n}\n","import { AsyncLocalStorage } from 'async_hooks';\nimport type { LoggerContext } from './types.js';\n\nexport class LoggerStore<TContext extends LoggerContext = LoggerContext> {\n private storage = new AsyncLocalStorage<TContext>();\n\n getStore(): TContext | undefined {\n return this.storage.getStore();\n }\n\n run<T>(context: TContext, fn: () => T): T {\n return this.storage.run(context, fn);\n }\n}\n","import { createLogger, Logger } from 'winston';\nimport type { LoggerConfig, LoggerContext, LevelOverride } from './types.js';\nimport { createFormat } from './formatters.js';\nimport { createTransports, createExceptionHandlers } from './transports.js';\nimport { LoggerStore } from './store.js';\n\nconst DEFAULT_CONTEXT = 'APP';\n\nconst LOG_LEVELS: Record<string, number> = {\n error: 0,\n warn: 1,\n info: 2,\n http: 3,\n verbose: 4,\n debug: 5,\n silly: 6,\n};\n\nexport class BaseLogger<TContext extends LoggerContext = LoggerContext> {\n private winstonLogger: Logger;\n private defaultLevel: string;\n private store: LoggerStore<TContext>;\n private levelOverrides: Map<string, LevelOverride<TContext>> = new Map();\n\n constructor(config: LoggerConfig, store?: LoggerStore<TContext>) {\n const isLocal = process.env.NODE_ENV !== 'production';\n\n this.defaultLevel = config.level;\n this.store = store ?? new LoggerStore<TContext>();\n\n const exceptionHandlers = createExceptionHandlers(config);\n\n this.winstonLogger = createLogger({\n level: 'silly', // Allow all, we filter manually\n format: createFormat(isLocal, this.store),\n transports: createTransports(config),\n exceptionHandlers,\n rejectionHandlers: exceptionHandlers,\n exitOnError: false,\n });\n }\n\n getStore(): LoggerStore<TContext> {\n return this.store;\n }\n\n setLevelOverride(match: Partial<TContext>, level: string): void {\n const key = JSON.stringify(match);\n this.levelOverrides.set(key, { match, level });\n }\n\n removeLevelOverride(match: Partial<TContext>): void {\n const key = JSON.stringify(match);\n this.levelOverrides.delete(key);\n }\n\n clearLevelOverrides(): void {\n this.levelOverrides.clear();\n }\n\n getLevelOverrides(): LevelOverride<TContext>[] {\n return Array.from(this.levelOverrides.values());\n }\n\n private getEffectiveLevel(): string {\n const context = this.store.getStore();\n if (!context) return this.defaultLevel;\n\n for (const { match, level } of this.levelOverrides.values()) {\n if (this.matchesContext(context, match)) {\n return level;\n }\n }\n return this.defaultLevel;\n }\n\n private matchesContext(context: TContext, match: Partial<TContext>): boolean {\n return Object.entries(match).every(([key, value]) => context[key] === value);\n }\n\n private shouldLog(level: string): boolean {\n const effectiveLevel = this.getEffectiveLevel();\n return LOG_LEVELS[level] <= LOG_LEVELS[effectiveLevel];\n }\n\n getChildLogger(context: string): Logger {\n return this.winstonLogger.child({ context });\n }\n\n profile(id: string, meta?: object): void {\n this.winstonLogger.profile(id, meta);\n }\n\n log(message: string, context?: string, meta?: object): void {\n if (!this.shouldLog('info')) return;\n this.winstonLogger.info(message, { context: context || DEFAULT_CONTEXT, ...meta });\n }\n\n error(message: string, error?: Error | unknown, context?: string): void {\n if (!this.shouldLog('error')) return;\n const meta: Record<string, unknown> = { context: context || DEFAULT_CONTEXT };\n if (error instanceof Error) {\n meta.errorMessage = error.message;\n meta.errorStack = error.stack;\n } else if (error) {\n meta.error = error;\n }\n this.winstonLogger.error(message, meta);\n }\n\n warn(message: string, context?: string, meta?: object): void {\n if (!this.shouldLog('warn')) return;\n this.winstonLogger.warn(message, { context: context || DEFAULT_CONTEXT, ...meta });\n }\n\n debug(message: string, context?: string, meta?: object): void {\n if (!this.shouldLog('debug')) return;\n this.winstonLogger.debug(message, { context: context || DEFAULT_CONTEXT, ...meta });\n }\n\n info(message: string, context?: string, meta?: object): void {\n if (!this.shouldLog('info')) return;\n this.winstonLogger.info(message, { context: context || DEFAULT_CONTEXT, ...meta });\n }\n\n verbose(message: string, context?: string, meta?: object): void {\n if (!this.shouldLog('verbose')) return;\n this.winstonLogger.verbose(message, { context: context || DEFAULT_CONTEXT, ...meta });\n }\n}\n","import { Logger } from 'winston';\nimport { BaseLogger } from './logger.js';\nimport { LoggerStore } from './store.js';\nimport type { LoggerConfig, LoggerContext, LevelOverride } from './types.js';\n\nexport interface SingletonLogger<TContext extends LoggerContext> {\n getInstance(config?: LoggerConfig): BaseLogger<TContext>;\n getStore(): LoggerStore<TContext>;\n for(context: string): Logger;\n setLevelOverride(match: Partial<TContext>, level: string): void;\n removeLevelOverride(match: Partial<TContext>): void;\n getLevelOverrides(): LevelOverride<TContext>[];\n clearLevelOverrides(): void;\n}\n\nexport function createSingletonLogger<TContext extends LoggerContext>(): SingletonLogger<TContext> {\n let instance: BaseLogger<TContext> | null = null;\n\n const ensureInstance = (): BaseLogger<TContext> => {\n if (!instance) {\n throw new Error('Logger not initialized. Call getInstance(config) first.');\n }\n return instance;\n };\n\n return {\n getInstance(config?: LoggerConfig): BaseLogger<TContext> {\n if (!instance) {\n if (!config) {\n throw new Error('Logger config is required for first initialization');\n }\n instance = new BaseLogger<TContext>(config);\n }\n return instance;\n },\n\n getStore(): LoggerStore<TContext> {\n return ensureInstance().getStore();\n },\n\n for(context: string): Logger {\n return ensureInstance().getChildLogger(context);\n },\n\n setLevelOverride(match: Partial<TContext>, level: string): void {\n ensureInstance().setLevelOverride(match, level);\n },\n\n removeLevelOverride(match: Partial<TContext>): void {\n ensureInstance().removeLevelOverride(match);\n },\n\n getLevelOverrides(): LevelOverride<TContext>[] {\n return ensureInstance().getLevelOverrides();\n },\n\n clearLevelOverrides(): void {\n ensureInstance().clearLevelOverrides();\n },\n };\n}\n","export interface TimingResult {\n label: string;\n durationMs: number;\n durationFormatted: string;\n}\n\nexport interface Timer {\n end: () => TimingResult;\n}\n\nfunction formatDuration(ms: number): string {\n if (ms < 1000) {\n return `${ms.toFixed(2)}ms`;\n }\n if (ms < 60000) {\n return `${(ms / 1000).toFixed(2)}s`;\n }\n const minutes = Math.floor(ms / 60000);\n const seconds = ((ms % 60000) / 1000).toFixed(1);\n return `${minutes}m ${seconds}s`;\n}\n\nexport function createTimer(label: string): Timer {\n const start = performance.now();\n\n return {\n end(): TimingResult {\n const durationMs = performance.now() - start;\n return {\n label,\n durationMs,\n durationFormatted: formatDuration(durationMs),\n };\n },\n };\n}\n\nexport async function measureAsync<T>(\n label: string,\n fn: () => Promise<T>,\n): Promise<{ result: T; timing: TimingResult }> {\n const timer = createTimer(label);\n const result = await fn();\n const timing = timer.end();\n return { result, timing };\n}\n\nexport function measureSync<T>(\n label: string,\n fn: () => T,\n): { result: T; timing: TimingResult } {\n const timer = createTimer(label);\n const result = fn();\n const timing = timer.end();\n return { result, timing };\n}\n","import { randomUUID } from 'crypto';\n\nexport interface RequestIdOptions {\n prefix?: string;\n short?: boolean;\n}\n\nexport function generateRequestId(options: RequestIdOptions = {}): string {\n const { prefix, short = false } = options;\n const uuid = randomUUID();\n const id = short ? uuid.split('-')[0] : uuid;\n return prefix ? `${prefix}-${id}` : id;\n}\n\nexport function extractRequestId(headers: Record<string, string | string[] | undefined>): string | undefined {\n const headerNames = ['x-request-id', 'x-correlation-id', 'x-trace-id'];\n\n for (const name of headerNames) {\n const value = headers[name];\n if (typeof value === 'string' && value.length > 0) {\n return value;\n }\n if (Array.isArray(value) && value.length > 0) {\n return value[0];\n }\n }\n\n return undefined;\n}\n\nexport function getOrGenerateRequestId(\n headers: Record<string, string | string[] | undefined>,\n options: RequestIdOptions = {},\n): string {\n return extractRequestId(headers) ?? generateRequestId(options);\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rawnodes/logger",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Flexible Winston-based logger with AsyncLocalStorage context, level overrides, and timing utilities",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"module": "./dist/index.js",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
8
7
|
"types": "./dist/index.d.ts",
|
|
9
8
|
"exports": {
|
|
10
9
|
".": {
|
|
11
|
-
"
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
"import": {
|
|
11
|
+
"types": "./dist/index.d.mts",
|
|
12
|
+
"default": "./dist/index.mjs"
|
|
13
|
+
},
|
|
14
|
+
"require": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"default": "./dist/index.js"
|
|
17
|
+
}
|
|
14
18
|
}
|
|
15
19
|
},
|
|
16
20
|
"files": [
|
package/dist/index.cjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/formatters.ts","../src/transports.ts","../src/store.ts","../src/utils/timing.ts","../src/logger.ts","../src/singleton.ts","../src/utils/request-id.ts","../src/utils/mask-secrets.ts"],"names":["inspect","format","transports","DailyRotateFile","AsyncLocalStorage","DEFAULT_CONTEXT","createLogger","randomUUID"],"mappings":"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","file":"index.cjs","sourcesContent":["import { inspect } from 'util';\nimport { format, Logform } from 'winston';\nimport { LoggerStore } from './store.js';\nimport type { LoggerContext } from './types.js';\n\nconst DEFAULT_CONTEXT = 'APP';\n\nfunction formatMeta(meta: Record<string, unknown>, colors: boolean): string {\n return Object.entries(meta)\n .filter(([, value]) => value !== undefined && value !== null)\n .map(([key, value]) => {\n if (typeof value === 'object') {\n const inspected = inspect(value, { depth: 4, colors, compact: false });\n return `\\n ${key}: ${inspected.split('\\n').join('\\n ')}`;\n }\n return `\\n ${key}: ${value}`;\n })\n .join('');\n}\n\nfunction addStoreContext<TContext extends LoggerContext>(store: LoggerStore<TContext>): Logform.Format {\n return format((info) => {\n const storeContext = store.getStore();\n if (storeContext) {\n return { ...info, ...storeContext };\n }\n return info;\n })();\n}\n\nexport function createLocalFormat<TContext extends LoggerContext>(store: LoggerStore<TContext>): Logform.Format {\n return format.combine(\n format.errors({ stack: true }),\n format.timestamp(),\n addStoreContext(store),\n format.colorize(),\n format.printf(({ timestamp, level, context, message, ...meta }) => {\n const formattedMeta = formatMeta(meta, true);\n return `[${timestamp}] ${level} [${context || DEFAULT_CONTEXT}] ${message}${formattedMeta}`;\n }),\n );\n}\n\nexport function createProductionFormat<TContext extends LoggerContext>(store: LoggerStore<TContext>): Logform.Format {\n return format.combine(\n format.errors({ stack: true }),\n format.timestamp(),\n addStoreContext(store),\n format.json(),\n );\n}\n\nexport function createFormat<TContext extends LoggerContext>(isLocal: boolean, store: LoggerStore<TContext>): Logform.Format {\n return isLocal ? createLocalFormat(store) : createProductionFormat(store);\n}\n","import { transports } from 'winston';\nimport DailyRotateFile from 'winston-daily-rotate-file';\nimport { LoggerConfig } from './types.js';\n\ntype Transport = transports.ConsoleTransportInstance | DailyRotateFile;\n\nexport function createTransports(config: LoggerConfig): Transport[] {\n const result: Transport[] = [\n new transports.Console({\n level: config.console.level,\n }),\n ];\n\n if (config.file) {\n result.push(\n new DailyRotateFile({\n dirname: config.file.dirname,\n filename: config.file.filename,\n level: config.file.level,\n datePattern: config.file.datePattern,\n zippedArchive: config.file.zippedArchive,\n maxSize: config.file.maxSize,\n maxFiles: config.file.maxFiles,\n }),\n );\n }\n\n return result;\n}\n","import { AsyncLocalStorage } from 'async_hooks';\nimport type { LoggerContext } from './types.js';\n\nexport class LoggerStore<TContext extends LoggerContext = LoggerContext> {\n private storage = new AsyncLocalStorage<TContext>();\n\n getStore(): TContext | undefined {\n return this.storage.getStore();\n }\n\n run<T>(context: TContext, fn: () => T): T {\n return this.storage.run(context, fn);\n }\n}\n","export interface TimingResult {\n label: string;\n durationMs: number;\n durationFormatted: string;\n}\n\nexport interface Timer {\n end: () => TimingResult;\n}\n\nfunction formatDuration(ms: number): string {\n if (ms < 1000) {\n return `${ms.toFixed(2)}ms`;\n }\n if (ms < 60000) {\n return `${(ms / 1000).toFixed(2)}s`;\n }\n const minutes = Math.floor(ms / 60000);\n const seconds = ((ms % 60000) / 1000).toFixed(1);\n return `${minutes}m ${seconds}s`;\n}\n\nexport function createTimer(label: string): Timer {\n const start = performance.now();\n\n return {\n end(): TimingResult {\n const durationMs = performance.now() - start;\n return {\n label,\n durationMs,\n durationFormatted: formatDuration(durationMs),\n };\n },\n };\n}\n\nexport async function measureAsync<T>(\n label: string,\n fn: () => Promise<T>,\n): Promise<{ result: T; timing: TimingResult }> {\n const timer = createTimer(label);\n const result = await fn();\n const timing = timer.end();\n return { result, timing };\n}\n\nexport function measureSync<T>(\n label: string,\n fn: () => T,\n): { result: T; timing: TimingResult } {\n const timer = createTimer(label);\n const result = fn();\n const timing = timer.end();\n return { result, timing };\n}\n","import { createLogger, Logger } from 'winston';\nimport type { LoggerConfig, LoggerContext, LevelOverride } from './types.js';\nimport { createFormat } from './formatters.js';\nimport { createTransports } from './transports.js';\nimport { LoggerStore } from './store.js';\nimport { createTimer, type Timer, type TimingResult } from './utils/timing.js';\n\nconst DEFAULT_CONTEXT = 'APP';\n\nconst LOG_LEVELS: Record<string, number> = {\n error: 0,\n warn: 1,\n info: 2,\n http: 3,\n verbose: 4,\n debug: 5,\n silly: 6,\n};\n\nexport class BaseLogger<TContext extends LoggerContext = LoggerContext> {\n private winstonLogger: Logger;\n private defaultLevel: string;\n private store: LoggerStore<TContext>;\n private levelOverrides: Map<string, LevelOverride<TContext>> = new Map();\n\n constructor(config: LoggerConfig, store?: LoggerStore<TContext>) {\n const isLocal = process.env.NODE_ENV !== 'production';\n\n this.defaultLevel = config.level;\n this.store = store ?? new LoggerStore<TContext>();\n\n this.winstonLogger = createLogger({\n level: 'silly', // Allow all, we filter manually\n format: createFormat(isLocal, this.store),\n transports: createTransports(config),\n });\n }\n\n getStore(): LoggerStore<TContext> {\n return this.store;\n }\n\n setLevelOverride(match: Partial<TContext>, level: string): void {\n const key = JSON.stringify(match);\n this.levelOverrides.set(key, { match, level });\n }\n\n removeLevelOverride(match: Partial<TContext>): void {\n const key = JSON.stringify(match);\n this.levelOverrides.delete(key);\n }\n\n clearLevelOverrides(): void {\n this.levelOverrides.clear();\n }\n\n getLevelOverrides(): LevelOverride<TContext>[] {\n return Array.from(this.levelOverrides.values());\n }\n\n private getEffectiveLevel(): string {\n const context = this.store.getStore();\n if (!context) return this.defaultLevel;\n\n for (const { match, level } of this.levelOverrides.values()) {\n if (this.matchesContext(context, match)) {\n return level;\n }\n }\n return this.defaultLevel;\n }\n\n private matchesContext(context: TContext, match: Partial<TContext>): boolean {\n return Object.entries(match).every(([key, value]) => context[key] === value);\n }\n\n private shouldLog(level: string): boolean {\n const effectiveLevel = this.getEffectiveLevel();\n return LOG_LEVELS[level] <= LOG_LEVELS[effectiveLevel];\n }\n\n getChildLogger(context: string): Logger {\n return this.winstonLogger.child({ context });\n }\n\n time(label: string): Timer {\n return createTimer(label);\n }\n\n timeEnd(timer: Timer, context?: string): TimingResult {\n const result = timer.end();\n this.debug(`${result.label} completed in ${result.durationFormatted}`, context, {\n timing: result,\n });\n return result;\n }\n\n async timeAsync<T>(label: string, fn: () => Promise<T>, context?: string): Promise<T> {\n const timer = this.time(label);\n try {\n const result = await fn();\n this.timeEnd(timer, context);\n return result;\n } catch (error) {\n const timing = timer.end();\n this.error(`${label} failed after ${timing.durationFormatted}`, error, context);\n throw error;\n }\n }\n\n log(message: string, context?: string, meta?: object): void {\n if (!this.shouldLog('info')) return;\n this.winstonLogger.info(message, { context: context || DEFAULT_CONTEXT, ...meta });\n }\n\n error(message: string, error?: Error | unknown, context?: string): void {\n if (!this.shouldLog('error')) return;\n const meta: Record<string, unknown> = { context: context || DEFAULT_CONTEXT };\n if (error instanceof Error) {\n meta.errorMessage = error.message;\n meta.errorStack = error.stack;\n } else if (error) {\n meta.error = error;\n }\n this.winstonLogger.error(message, meta);\n }\n\n warn(message: string, context?: string, meta?: object): void {\n if (!this.shouldLog('warn')) return;\n this.winstonLogger.warn(message, { context: context || DEFAULT_CONTEXT, ...meta });\n }\n\n debug(message: string, context?: string, meta?: object): void {\n if (!this.shouldLog('debug')) return;\n this.winstonLogger.debug(message, { context: context || DEFAULT_CONTEXT, ...meta });\n }\n\n info(message: string, context?: string, meta?: object): void {\n if (!this.shouldLog('info')) return;\n this.winstonLogger.info(message, { context: context || DEFAULT_CONTEXT, ...meta });\n }\n\n verbose(message: string, context?: string, meta?: object): void {\n if (!this.shouldLog('verbose')) return;\n this.winstonLogger.verbose(message, { context: context || DEFAULT_CONTEXT, ...meta });\n }\n}\n","import { Logger } from 'winston';\nimport { BaseLogger } from './logger.js';\nimport { LoggerStore } from './store.js';\nimport type { LoggerConfig, LoggerContext, LevelOverride } from './types.js';\n\nexport interface SingletonLogger<TContext extends LoggerContext> {\n getInstance(config?: LoggerConfig): BaseLogger<TContext>;\n getStore(): LoggerStore<TContext>;\n for(context: string): Logger;\n setLevelOverride(match: Partial<TContext>, level: string): void;\n removeLevelOverride(match: Partial<TContext>): void;\n getLevelOverrides(): LevelOverride<TContext>[];\n clearLevelOverrides(): void;\n}\n\nexport function createSingletonLogger<TContext extends LoggerContext>(): SingletonLogger<TContext> {\n let instance: BaseLogger<TContext> | null = null;\n\n const ensureInstance = (): BaseLogger<TContext> => {\n if (!instance) {\n throw new Error('Logger not initialized. Call getInstance(config) first.');\n }\n return instance;\n };\n\n return {\n getInstance(config?: LoggerConfig): BaseLogger<TContext> {\n if (!instance) {\n if (!config) {\n throw new Error('Logger config is required for first initialization');\n }\n instance = new BaseLogger<TContext>(config);\n }\n return instance;\n },\n\n getStore(): LoggerStore<TContext> {\n return ensureInstance().getStore();\n },\n\n for(context: string): Logger {\n return ensureInstance().getChildLogger(context);\n },\n\n setLevelOverride(match: Partial<TContext>, level: string): void {\n ensureInstance().setLevelOverride(match, level);\n },\n\n removeLevelOverride(match: Partial<TContext>): void {\n ensureInstance().removeLevelOverride(match);\n },\n\n getLevelOverrides(): LevelOverride<TContext>[] {\n return ensureInstance().getLevelOverrides();\n },\n\n clearLevelOverrides(): void {\n ensureInstance().clearLevelOverrides();\n },\n };\n}\n","import { randomUUID } from 'crypto';\n\nexport interface RequestIdOptions {\n prefix?: string;\n short?: boolean;\n}\n\nexport function generateRequestId(options: RequestIdOptions = {}): string {\n const { prefix, short = false } = options;\n const uuid = randomUUID();\n const id = short ? uuid.split('-')[0] : uuid;\n return prefix ? `${prefix}-${id}` : id;\n}\n\nexport function extractRequestId(headers: Record<string, string | string[] | undefined>): string | undefined {\n const headerNames = ['x-request-id', 'x-correlation-id', 'x-trace-id'];\n\n for (const name of headerNames) {\n const value = headers[name];\n if (typeof value === 'string' && value.length > 0) {\n return value;\n }\n if (Array.isArray(value) && value.length > 0) {\n return value[0];\n }\n }\n\n return undefined;\n}\n\nexport function getOrGenerateRequestId(\n headers: Record<string, string | string[] | undefined>,\n options: RequestIdOptions = {},\n): string {\n return extractRequestId(headers) ?? generateRequestId(options);\n}\n","const DEFAULT_SECRET_PATTERNS = [\n 'password',\n 'secret',\n 'token',\n 'apikey',\n 'api_key',\n 'api-key',\n 'auth',\n 'credential',\n 'private',\n];\n\nconst DEFAULT_MASK = '***';\n\nexport interface MaskSecretsOptions {\n patterns?: string[];\n mask?: string;\n deep?: boolean;\n}\n\nfunction isSecretKey(key: string, patterns: string[]): boolean {\n const lowerKey = key.toLowerCase();\n return patterns.some((pattern) => lowerKey.includes(pattern.toLowerCase()));\n}\n\nfunction maskUrlCredentials(url: string, mask: string): string {\n try {\n const parsed = new URL(url);\n if (parsed.password) {\n parsed.password = mask;\n }\n if (parsed.username && parsed.password) {\n parsed.username = mask;\n }\n return parsed.toString();\n } catch {\n return url;\n }\n}\n\nexport function maskSecrets(\n obj: unknown,\n options: MaskSecretsOptions = {},\n): unknown {\n const { patterns = DEFAULT_SECRET_PATTERNS, mask = DEFAULT_MASK, deep = true } = options;\n\n if (obj === null || obj === undefined) {\n return obj;\n }\n\n if (typeof obj === 'string') {\n if (obj.startsWith('http://') || obj.startsWith('https://')) {\n return maskUrlCredentials(obj, mask);\n }\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return deep ? obj.map((item) => maskSecrets(item, options)) : obj;\n }\n\n if (typeof obj === 'object') {\n const result: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(obj)) {\n if (isSecretKey(key, patterns)) {\n result[key] = mask;\n } else if (deep && typeof value === 'object' && value !== null) {\n result[key] = maskSecrets(value, options);\n } else if (typeof value === 'string') {\n result[key] = maskSecrets(value, options);\n } else {\n result[key] = value;\n }\n }\n\n return result;\n }\n\n return obj;\n}\n\nexport function createMasker(options: MaskSecretsOptions = {}) {\n return (obj: unknown): unknown => maskSecrets(obj, options);\n}\n"]}
|