@pencroff-lab/kore 0.1.1 → 0.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/README.md +40 -1
- package/dist/cjs/src/utils/format_dt.d.ts +71 -1
- package/dist/cjs/src/utils/format_dt.d.ts.map +1 -1
- package/dist/cjs/src/utils/format_dt.js +50 -6
- package/dist/cjs/src/utils/format_dt.js.map +1 -1
- package/dist/cjs/src/utils/index.d.ts +1 -0
- package/dist/cjs/src/utils/index.d.ts.map +1 -1
- package/dist/cjs/src/utils/index.js +1 -0
- package/dist/cjs/src/utils/index.js.map +1 -1
- package/dist/cjs/src/utils/logger.d.ts +271 -0
- package/dist/cjs/src/utils/logger.d.ts.map +1 -0
- package/dist/cjs/src/utils/logger.js +340 -0
- package/dist/cjs/src/utils/logger.js.map +1 -0
- package/dist/esm/src/utils/format_dt.d.ts +71 -1
- package/dist/esm/src/utils/format_dt.d.ts.map +1 -1
- package/dist/esm/src/utils/format_dt.js +50 -6
- package/dist/esm/src/utils/format_dt.js.map +1 -1
- package/dist/esm/src/utils/index.d.ts +1 -0
- package/dist/esm/src/utils/index.d.ts.map +1 -1
- package/dist/esm/src/utils/index.js +1 -0
- package/dist/esm/src/utils/index.js.map +1 -1
- package/dist/esm/src/utils/logger.d.ts +271 -0
- package/dist/esm/src/utils/logger.d.ts.map +1 -0
- package/dist/esm/src/utils/logger.js +335 -0
- package/dist/esm/src/utils/logger.js.map +1 -0
- package/docs/err.md +897 -0
- package/docs/format_dt.md +159 -0
- package/docs/logger.md +342 -0
- package/docs/logging_guide.md +427 -0
- package/docs/outcome.md +831 -0
- package/llms.txt +24 -0
- package/package.json +7 -2
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Structured logging utility with transport DI and Err integration.
|
|
3
|
+
*
|
|
4
|
+
* This module provides a flexible, callable logger with a transport abstraction,
|
|
5
|
+
* built-in pretty console transport, and zero external runtime dependencies
|
|
6
|
+
* beyond `fast-safe-stringify`.
|
|
7
|
+
*
|
|
8
|
+
* ## Design Philosophy
|
|
9
|
+
*
|
|
10
|
+
* The logger is designed as a callable function with overloaded signatures.
|
|
11
|
+
* Transports are injectable, making the logger testable without streams or
|
|
12
|
+
* process-level side effects. The built-in pretty transport renders to stderr
|
|
13
|
+
* with ANSI colors and automatic Err formatting.
|
|
14
|
+
*
|
|
15
|
+
* ## Basic Usage
|
|
16
|
+
*
|
|
17
|
+
* @example Simple logging
|
|
18
|
+
* ```typescript
|
|
19
|
+
* import { log } from './utils/logger';
|
|
20
|
+
*
|
|
21
|
+
* log('Application started'); // INFO level by default
|
|
22
|
+
* log(log.WARN, 'Connection slow'); // Explicit level
|
|
23
|
+
* log(log.ERROR, 'Failed to save', { userId: '123' }); // With context
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @example Logging with Err instances
|
|
27
|
+
* ```typescript
|
|
28
|
+
* import { Err } from './types/err';
|
|
29
|
+
* import { log } from './utils/logger';
|
|
30
|
+
*
|
|
31
|
+
* const [data, err] = fetchData();
|
|
32
|
+
* if (err) {
|
|
33
|
+
* log(log.ERROR, 'Data fetch failed', err);
|
|
34
|
+
* return;
|
|
35
|
+
* }
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* @example Child loggers with module context
|
|
39
|
+
* ```typescript
|
|
40
|
+
* const dbLogger = log.child('database', { version: '1.0' });
|
|
41
|
+
* dbLogger('Connected to postgres');
|
|
42
|
+
* // Output: [database] Connected to postgres
|
|
43
|
+
*
|
|
44
|
+
* const userLogger = dbLogger.child('users');
|
|
45
|
+
* userLogger('User created');
|
|
46
|
+
* // Output: [database] [users] User created
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* @example Custom transport for testing
|
|
50
|
+
* ```typescript
|
|
51
|
+
* import { createLogger, lvl } from './utils/logger';
|
|
52
|
+
* import type { LogEntry, LogTransport } from './utils/logger';
|
|
53
|
+
*
|
|
54
|
+
* const entries: LogEntry[] = [];
|
|
55
|
+
* const spy: LogTransport = { write(e) { entries.push(e); } };
|
|
56
|
+
* const testLogger = createLogger('test', { transports: [spy], level: lvl.TRACE });
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* ## Configuration
|
|
60
|
+
*
|
|
61
|
+
* The logger reads configuration from environment variables:
|
|
62
|
+
* - `LOG_LEVEL`: Minimum level to log (trace|debug|info|warn|error|fatal). Default: 'info'
|
|
63
|
+
*
|
|
64
|
+
* @module logger
|
|
65
|
+
*/
|
|
66
|
+
import { Err } from "../types/err";
|
|
67
|
+
/**
|
|
68
|
+
* Log level constants for type-safe level specification.
|
|
69
|
+
*
|
|
70
|
+
* **Level Hierarchy** (lowest to highest):
|
|
71
|
+
* - `TRACE`: Detailed debugging information
|
|
72
|
+
* - `DEBUG`: Debugging information
|
|
73
|
+
* - `INFO`: General informational messages
|
|
74
|
+
* - `WARN`: Warning messages
|
|
75
|
+
* - `ERROR`: Error messages for failures
|
|
76
|
+
* - `FATAL`: Fatal errors causing termination
|
|
77
|
+
*/
|
|
78
|
+
declare const lvl: {
|
|
79
|
+
readonly TRACE: "trace";
|
|
80
|
+
readonly DEBUG: "debug";
|
|
81
|
+
readonly INFO: "info";
|
|
82
|
+
readonly WARN: "warn";
|
|
83
|
+
readonly ERROR: "error";
|
|
84
|
+
readonly FATAL: "fatal";
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Type representing valid log level values.
|
|
88
|
+
*/
|
|
89
|
+
type LevelValue = (typeof lvl)[keyof typeof lvl];
|
|
90
|
+
/**
|
|
91
|
+
* A single structured log entry passed to transports.
|
|
92
|
+
*/
|
|
93
|
+
interface LogEntry {
|
|
94
|
+
/** Log level */
|
|
95
|
+
level: LevelValue;
|
|
96
|
+
/** Unix timestamp in milliseconds (Date.now()) */
|
|
97
|
+
timestamp: number;
|
|
98
|
+
/** Log message */
|
|
99
|
+
message: string;
|
|
100
|
+
/** Merged bindings + call-site context */
|
|
101
|
+
context: Record<string, unknown>;
|
|
102
|
+
/** Module chain accumulated by child() calls */
|
|
103
|
+
modules: string[];
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Transport interface — receives a `LogEntry` for each log call that passes
|
|
107
|
+
* the level filter. Implement this to integrate any logging backend.
|
|
108
|
+
*
|
|
109
|
+
* @example Pino transport
|
|
110
|
+
* ```typescript
|
|
111
|
+
* import pino from 'pino';
|
|
112
|
+
* import type { LogTransport, LogEntry } from '@pencroff-lab/kore';
|
|
113
|
+
*
|
|
114
|
+
* const pinoInstance = pino();
|
|
115
|
+
* const pinoTransport: LogTransport = {
|
|
116
|
+
* write(entry: LogEntry) {
|
|
117
|
+
* const prefix = entry.modules.map(m => `[${m}] `).join('');
|
|
118
|
+
* pinoInstance[entry.level](entry.context, prefix + entry.message);
|
|
119
|
+
* }
|
|
120
|
+
* };
|
|
121
|
+
* ```
|
|
122
|
+
*/
|
|
123
|
+
interface LogTransport {
|
|
124
|
+
write(entry: LogEntry): void;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Options for the built-in pretty console transport.
|
|
128
|
+
*/
|
|
129
|
+
interface PrettyOptions {
|
|
130
|
+
/** Output stream. Default: `process.stderr` */
|
|
131
|
+
output?: {
|
|
132
|
+
write(data: string): void;
|
|
133
|
+
};
|
|
134
|
+
/**
|
|
135
|
+
* Enable ANSI colors.
|
|
136
|
+
* - `'auto'` (default): enable when output is a TTY
|
|
137
|
+
* - `true`: always enable
|
|
138
|
+
* - `false`: always disable
|
|
139
|
+
*/
|
|
140
|
+
colors?: boolean | "auto";
|
|
141
|
+
/** Override default level colors (ANSI escape sequences) */
|
|
142
|
+
levelColors?: Partial<Record<LevelValue, string>>;
|
|
143
|
+
/**
|
|
144
|
+
* Timestamp format.
|
|
145
|
+
* - `'short'` (default): `HH:MM:SS.mmm` local time
|
|
146
|
+
* - `'iso'`: ISO 8601 string
|
|
147
|
+
* - Custom function receiving `Date.now()` timestamp
|
|
148
|
+
*/
|
|
149
|
+
timestamp?: "short" | "iso" | ((ts: number) => string);
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Options for `createLogger`.
|
|
153
|
+
*/
|
|
154
|
+
interface LoggerOptions {
|
|
155
|
+
/** Minimum log level. Default: from `LOG_LEVEL` env or `'info'` */
|
|
156
|
+
level?: LevelValue;
|
|
157
|
+
/** Transports to write entries to. Default: `[prettyTransport()]` */
|
|
158
|
+
transports?: LogTransport[];
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Callable logger interface with overloaded signatures.
|
|
162
|
+
*
|
|
163
|
+
* The Logger is both a function (for logging) and an object (with level
|
|
164
|
+
* constants and the `child` method).
|
|
165
|
+
*
|
|
166
|
+
* ## Call Signatures
|
|
167
|
+
* 1. `log(message)` - Log at INFO level
|
|
168
|
+
* 2. `log(message, context)` - Log at INFO level with context object or Err
|
|
169
|
+
* 3. `log(message, detail)` - Log at INFO level with detail string
|
|
170
|
+
* 4. `log(level, message)` - Log at specific level
|
|
171
|
+
* 5. `log(level, message, context)` - Log at specific level with context
|
|
172
|
+
*/
|
|
173
|
+
interface Logger {
|
|
174
|
+
/** Trace level constant */
|
|
175
|
+
readonly TRACE: "trace";
|
|
176
|
+
/** Debug level constant */
|
|
177
|
+
readonly DEBUG: "debug";
|
|
178
|
+
/** Info level constant */
|
|
179
|
+
readonly INFO: "info";
|
|
180
|
+
/** Warning level constant */
|
|
181
|
+
readonly WARN: "warn";
|
|
182
|
+
/** Error level constant */
|
|
183
|
+
readonly ERROR: "error";
|
|
184
|
+
/** Fatal level constant */
|
|
185
|
+
readonly FATAL: "fatal";
|
|
186
|
+
/** Log a message at INFO level. */
|
|
187
|
+
(message: string): void;
|
|
188
|
+
/** Log a message at INFO level with context. */
|
|
189
|
+
(message: string, context: object | Err): void;
|
|
190
|
+
/** Log a message at INFO level with detail string. */
|
|
191
|
+
(message: string, detail: string): void;
|
|
192
|
+
/** Log a message at a specific level. */
|
|
193
|
+
(level: LevelValue, message: string): void;
|
|
194
|
+
/** Log a message at a specific level with context. */
|
|
195
|
+
(level: LevelValue, message: string, context: object | Err): void;
|
|
196
|
+
/**
|
|
197
|
+
* Create a child logger with module-specific context.
|
|
198
|
+
*
|
|
199
|
+
* @param module - Module name added to the modules array
|
|
200
|
+
* @param bindings - Optional bindings merged into every log entry's context
|
|
201
|
+
* @returns New Logger instance
|
|
202
|
+
*/
|
|
203
|
+
child(module: string, bindings?: object): Logger;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Create a built-in pretty console transport.
|
|
207
|
+
*
|
|
208
|
+
* Renders log entries to a human-readable format with optional ANSI colors.
|
|
209
|
+
*
|
|
210
|
+
* Output format:
|
|
211
|
+
* ```
|
|
212
|
+
* {dim timestamp} {colored TAG} {[mod] [mod]} {message} {dim context}
|
|
213
|
+
* ```
|
|
214
|
+
*
|
|
215
|
+
* Err instances in context are rendered via `Err.toString()` on their own
|
|
216
|
+
* indented line below the main line.
|
|
217
|
+
*
|
|
218
|
+
* @param options - Optional configuration
|
|
219
|
+
*/
|
|
220
|
+
declare function prettyTransport(options?: PrettyOptions): LogTransport;
|
|
221
|
+
/**
|
|
222
|
+
* Create a logger instance with optional module name and configuration.
|
|
223
|
+
*
|
|
224
|
+
* @param module - Optional module name added as the first entry in `modules`
|
|
225
|
+
* @param options - Optional configuration
|
|
226
|
+
* @returns New Logger instance
|
|
227
|
+
*
|
|
228
|
+
* @example Basic usage
|
|
229
|
+
* ```typescript
|
|
230
|
+
* const logger = createLogger();
|
|
231
|
+
* logger('Application ready');
|
|
232
|
+
* ```
|
|
233
|
+
*
|
|
234
|
+
* @example Module-specific logger
|
|
235
|
+
* ```typescript
|
|
236
|
+
* const dbLogger = createLogger('database');
|
|
237
|
+
* dbLogger('Connected');
|
|
238
|
+
* ```
|
|
239
|
+
*
|
|
240
|
+
* @example Testing with spy transport
|
|
241
|
+
* ```typescript
|
|
242
|
+
* import type { LogEntry, LogTransport } from './utils/logger';
|
|
243
|
+
*
|
|
244
|
+
* const entries: LogEntry[] = [];
|
|
245
|
+
* const spy: LogTransport = { write(e) { entries.push(e); } };
|
|
246
|
+
* const testLogger = createLogger('test', { transports: [spy], level: lvl.TRACE });
|
|
247
|
+
* ```
|
|
248
|
+
*/
|
|
249
|
+
declare function createLogger(module?: string, options?: LoggerOptions): Logger;
|
|
250
|
+
/**
|
|
251
|
+
* Default logger instance for application-wide logging.
|
|
252
|
+
*
|
|
253
|
+
* @example Basic usage
|
|
254
|
+
* ```typescript
|
|
255
|
+
* import { log } from './utils/logger';
|
|
256
|
+
*
|
|
257
|
+
* log('Application started');
|
|
258
|
+
* log(log.INFO, 'Server listening', { port: 3000 });
|
|
259
|
+
* log(log.ERROR, 'Startup failed', err);
|
|
260
|
+
* ```
|
|
261
|
+
*
|
|
262
|
+
* @example Module-specific logging via child
|
|
263
|
+
* ```typescript
|
|
264
|
+
* const dbLogger = log.child('database');
|
|
265
|
+
* dbLogger('Connection pool initialized');
|
|
266
|
+
* ```
|
|
267
|
+
*/
|
|
268
|
+
export declare const log: Logger;
|
|
269
|
+
export { createLogger, prettyTransport, lvl };
|
|
270
|
+
export type { Logger, LevelValue, LogEntry, LogTransport, LoggerOptions, PrettyOptions, };
|
|
271
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../../../src/utils/logger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Structured logging utility with transport DI and Err integration.
|
|
3
|
+
*
|
|
4
|
+
* This module provides a flexible, callable logger with a transport abstraction,
|
|
5
|
+
* built-in pretty console transport, and zero external runtime dependencies
|
|
6
|
+
* beyond `fast-safe-stringify`.
|
|
7
|
+
*
|
|
8
|
+
* ## Design Philosophy
|
|
9
|
+
*
|
|
10
|
+
* The logger is designed as a callable function with overloaded signatures.
|
|
11
|
+
* Transports are injectable, making the logger testable without streams or
|
|
12
|
+
* process-level side effects. The built-in pretty transport renders to stderr
|
|
13
|
+
* with ANSI colors and automatic Err formatting.
|
|
14
|
+
*
|
|
15
|
+
* ## Basic Usage
|
|
16
|
+
*
|
|
17
|
+
* @example Simple logging
|
|
18
|
+
* ```typescript
|
|
19
|
+
* import { log } from './utils/logger';
|
|
20
|
+
*
|
|
21
|
+
* log('Application started'); // INFO level by default
|
|
22
|
+
* log(log.WARN, 'Connection slow'); // Explicit level
|
|
23
|
+
* log(log.ERROR, 'Failed to save', { userId: '123' }); // With context
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @example Logging with Err instances
|
|
27
|
+
* ```typescript
|
|
28
|
+
* import { Err } from './types/err';
|
|
29
|
+
* import { log } from './utils/logger';
|
|
30
|
+
*
|
|
31
|
+
* const [data, err] = fetchData();
|
|
32
|
+
* if (err) {
|
|
33
|
+
* log(log.ERROR, 'Data fetch failed', err);
|
|
34
|
+
* return;
|
|
35
|
+
* }
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* @example Child loggers with module context
|
|
39
|
+
* ```typescript
|
|
40
|
+
* const dbLogger = log.child('database', { version: '1.0' });
|
|
41
|
+
* dbLogger('Connected to postgres');
|
|
42
|
+
* // Output: [database] Connected to postgres
|
|
43
|
+
*
|
|
44
|
+
* const userLogger = dbLogger.child('users');
|
|
45
|
+
* userLogger('User created');
|
|
46
|
+
* // Output: [database] [users] User created
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* @example Custom transport for testing
|
|
50
|
+
* ```typescript
|
|
51
|
+
* import { createLogger, lvl } from './utils/logger';
|
|
52
|
+
* import type { LogEntry, LogTransport } from './utils/logger';
|
|
53
|
+
*
|
|
54
|
+
* const entries: LogEntry[] = [];
|
|
55
|
+
* const spy: LogTransport = { write(e) { entries.push(e); } };
|
|
56
|
+
* const testLogger = createLogger('test', { transports: [spy], level: lvl.TRACE });
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* ## Configuration
|
|
60
|
+
*
|
|
61
|
+
* The logger reads configuration from environment variables:
|
|
62
|
+
* - `LOG_LEVEL`: Minimum level to log (trace|debug|info|warn|error|fatal). Default: 'info'
|
|
63
|
+
*
|
|
64
|
+
* @module logger
|
|
65
|
+
*/
|
|
66
|
+
import stringifySafe from "fast-safe-stringify";
|
|
67
|
+
import { Err } from "../types/err";
|
|
68
|
+
/**
|
|
69
|
+
* Log level constants for type-safe level specification.
|
|
70
|
+
*
|
|
71
|
+
* **Level Hierarchy** (lowest to highest):
|
|
72
|
+
* - `TRACE`: Detailed debugging information
|
|
73
|
+
* - `DEBUG`: Debugging information
|
|
74
|
+
* - `INFO`: General informational messages
|
|
75
|
+
* - `WARN`: Warning messages
|
|
76
|
+
* - `ERROR`: Error messages for failures
|
|
77
|
+
* - `FATAL`: Fatal errors causing termination
|
|
78
|
+
*/
|
|
79
|
+
const lvl = {
|
|
80
|
+
TRACE: "trace",
|
|
81
|
+
DEBUG: "debug",
|
|
82
|
+
INFO: "info",
|
|
83
|
+
WARN: "warn",
|
|
84
|
+
ERROR: "error",
|
|
85
|
+
FATAL: "fatal",
|
|
86
|
+
};
|
|
87
|
+
// ─── Internal constants ───────────────────────────────────────────────────────
|
|
88
|
+
const levelSet = new Set(Object.values(lvl));
|
|
89
|
+
const LEVEL_NUMBERS = {
|
|
90
|
+
trace: 0,
|
|
91
|
+
debug: 1,
|
|
92
|
+
info: 2,
|
|
93
|
+
warn: 3,
|
|
94
|
+
error: 4,
|
|
95
|
+
fatal: 5,
|
|
96
|
+
};
|
|
97
|
+
const LEVEL_TAGS = {
|
|
98
|
+
trace: "TRC",
|
|
99
|
+
debug: "DBG",
|
|
100
|
+
info: "INF",
|
|
101
|
+
warn: "WRN",
|
|
102
|
+
error: "ERR",
|
|
103
|
+
fatal: "FTL",
|
|
104
|
+
};
|
|
105
|
+
const DEFAULT_LEVEL_COLORS = {
|
|
106
|
+
trace: "\x1b[2m",
|
|
107
|
+
debug: "\x1b[36m",
|
|
108
|
+
info: "\x1b[32m",
|
|
109
|
+
warn: "\x1b[38;5;208m",
|
|
110
|
+
error: "\x1b[31m",
|
|
111
|
+
fatal: "\x1b[1m\x1b[31m",
|
|
112
|
+
};
|
|
113
|
+
const RESET = "\x1b[0m";
|
|
114
|
+
const DIM = "\x1b[2m";
|
|
115
|
+
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
116
|
+
function isLevel(val) {
|
|
117
|
+
return (typeof val === "string" &&
|
|
118
|
+
levelSet.has(val.toLocaleLowerCase()));
|
|
119
|
+
}
|
|
120
|
+
function normalizeContext(ctx) {
|
|
121
|
+
if (Err.isErr(ctx))
|
|
122
|
+
return { err: ctx };
|
|
123
|
+
if (typeof ctx === "string")
|
|
124
|
+
return { detail: ctx };
|
|
125
|
+
if (typeof ctx === "object" && ctx !== null)
|
|
126
|
+
return ctx;
|
|
127
|
+
return {};
|
|
128
|
+
}
|
|
129
|
+
function resolveCall(...args) {
|
|
130
|
+
// 1 arg: [msg]
|
|
131
|
+
if (args.length === 1) {
|
|
132
|
+
return { level: lvl.INFO, message: String(args[0]), context: {} };
|
|
133
|
+
}
|
|
134
|
+
// 2 args
|
|
135
|
+
if (args.length === 2) {
|
|
136
|
+
const [first, second] = args;
|
|
137
|
+
if (isLevel(first)) {
|
|
138
|
+
return { level: first, message: String(second), context: {} };
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
level: lvl.INFO,
|
|
142
|
+
message: String(first),
|
|
143
|
+
context: normalizeContext(second),
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
// 3+ args: [lvl, msg, ctx]
|
|
147
|
+
if (args.length >= 3) {
|
|
148
|
+
const [first, second, third] = args;
|
|
149
|
+
if (isLevel(first)) {
|
|
150
|
+
return {
|
|
151
|
+
level: first,
|
|
152
|
+
message: String(second),
|
|
153
|
+
context: normalizeContext(third),
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// Fallback
|
|
158
|
+
return { level: lvl.INFO, message: String(args[0] ?? ""), context: {} };
|
|
159
|
+
}
|
|
160
|
+
function getLogLevel() {
|
|
161
|
+
const envLevel = process.env.LOG_LEVEL?.toLowerCase();
|
|
162
|
+
return isLevel(envLevel) ? envLevel : lvl.INFO;
|
|
163
|
+
}
|
|
164
|
+
// ─── Timestamp formatters ─────────────────────────────────────────────────────
|
|
165
|
+
function formatShortTimestamp(ts) {
|
|
166
|
+
const d = new Date(ts);
|
|
167
|
+
const hh = String(d.getHours()).padStart(2, "0");
|
|
168
|
+
const mm = String(d.getMinutes()).padStart(2, "0");
|
|
169
|
+
const ss = String(d.getSeconds()).padStart(2, "0");
|
|
170
|
+
const ms = String(d.getMilliseconds()).padStart(3, "0");
|
|
171
|
+
return `${hh}:${mm}:${ss}.${ms}`;
|
|
172
|
+
}
|
|
173
|
+
// ─── Pretty transport ─────────────────────────────────────────────────────────
|
|
174
|
+
/**
|
|
175
|
+
* Create a built-in pretty console transport.
|
|
176
|
+
*
|
|
177
|
+
* Renders log entries to a human-readable format with optional ANSI colors.
|
|
178
|
+
*
|
|
179
|
+
* Output format:
|
|
180
|
+
* ```
|
|
181
|
+
* {dim timestamp} {colored TAG} {[mod] [mod]} {message} {dim context}
|
|
182
|
+
* ```
|
|
183
|
+
*
|
|
184
|
+
* Err instances in context are rendered via `Err.toString()` on their own
|
|
185
|
+
* indented line below the main line.
|
|
186
|
+
*
|
|
187
|
+
* @param options - Optional configuration
|
|
188
|
+
*/
|
|
189
|
+
function prettyTransport(options) {
|
|
190
|
+
const output = options?.output ?? process.stderr;
|
|
191
|
+
const colorsOpt = options?.colors ?? "auto";
|
|
192
|
+
const tsOpt = options?.timestamp ?? "short";
|
|
193
|
+
const levelColors = { ...DEFAULT_LEVEL_COLORS, ...options?.levelColors };
|
|
194
|
+
const isTTY = "isTTY" in output && output.isTTY === true;
|
|
195
|
+
const useColors = colorsOpt === "auto" ? isTTY : colorsOpt === true;
|
|
196
|
+
function formatTimestamp(ts) {
|
|
197
|
+
if (typeof tsOpt === "function")
|
|
198
|
+
return tsOpt(ts);
|
|
199
|
+
if (tsOpt === "iso")
|
|
200
|
+
return new Date(ts).toISOString();
|
|
201
|
+
return formatShortTimestamp(ts);
|
|
202
|
+
}
|
|
203
|
+
return {
|
|
204
|
+
write(entry) {
|
|
205
|
+
const ts = formatTimestamp(entry.timestamp);
|
|
206
|
+
const tag = LEVEL_TAGS[entry.level] ?? entry.level.toUpperCase();
|
|
207
|
+
const levelColor = levelColors[entry.level] ?? "";
|
|
208
|
+
// Module prefix
|
|
209
|
+
const modulePrefix = entry.modules.length > 0
|
|
210
|
+
? `${entry.modules.map((m) => `[${m}]`).join(" ")} `
|
|
211
|
+
: "";
|
|
212
|
+
// Split err from rest of context
|
|
213
|
+
const { err: errVal, ...rest } = entry.context;
|
|
214
|
+
const hasErr = errVal !== undefined;
|
|
215
|
+
const hasRest = Object.keys(rest).length > 0;
|
|
216
|
+
let line;
|
|
217
|
+
if (useColors) {
|
|
218
|
+
const ctxStr = hasRest ? ` ${DIM}${stringifySafe(rest)}${RESET}` : "";
|
|
219
|
+
line = `${DIM}${ts}${RESET} ${levelColor}${tag}${RESET} ${modulePrefix}${entry.message}${ctxStr}`;
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
const ctxStr = hasRest ? ` ${stringifySafe(rest)}` : "";
|
|
223
|
+
line = `${ts} ${tag} ${modulePrefix}${entry.message}${ctxStr}`;
|
|
224
|
+
}
|
|
225
|
+
if (hasErr) {
|
|
226
|
+
let errStr;
|
|
227
|
+
if (Err.isErr(errVal)) {
|
|
228
|
+
errStr = errVal.toString({ stack: 3, metadata: true });
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
errStr = stringifySafe(errVal);
|
|
232
|
+
}
|
|
233
|
+
const indented = errStr
|
|
234
|
+
.split("\n")
|
|
235
|
+
.map((l) => ` ${l}`)
|
|
236
|
+
.join("\n");
|
|
237
|
+
line += `\n err: ${indented.trimStart()}`;
|
|
238
|
+
}
|
|
239
|
+
output.write(`${line}\n`);
|
|
240
|
+
},
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
// ─── Core logger builder ──────────────────────────────────────────────────────
|
|
244
|
+
function buildLogger(modules, bindings, level, transports) {
|
|
245
|
+
const configNum = LEVEL_NUMBERS[level];
|
|
246
|
+
const logFn = (...args) => {
|
|
247
|
+
const { level: callLevel, message, context } = resolveCall(...args);
|
|
248
|
+
if ((LEVEL_NUMBERS[callLevel] ?? 0) < configNum)
|
|
249
|
+
return;
|
|
250
|
+
const entry = {
|
|
251
|
+
level: callLevel,
|
|
252
|
+
timestamp: Date.now(),
|
|
253
|
+
message,
|
|
254
|
+
context: { ...bindings, ...context },
|
|
255
|
+
modules,
|
|
256
|
+
};
|
|
257
|
+
for (const transport of transports) {
|
|
258
|
+
transport.write(entry);
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
// Attach level constants
|
|
262
|
+
const keys = Object.keys(lvl);
|
|
263
|
+
for (const key of keys) {
|
|
264
|
+
Object.defineProperty(logFn, key, {
|
|
265
|
+
value: lvl[key],
|
|
266
|
+
writable: false,
|
|
267
|
+
enumerable: true,
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
// Attach child()
|
|
271
|
+
logFn.child = (name, childBindings) => {
|
|
272
|
+
const mergedBindings = {
|
|
273
|
+
...bindings,
|
|
274
|
+
...childBindings,
|
|
275
|
+
};
|
|
276
|
+
return buildLogger([...modules, name], mergedBindings, level, transports);
|
|
277
|
+
};
|
|
278
|
+
return logFn;
|
|
279
|
+
}
|
|
280
|
+
// ─── Public factory ───────────────────────────────────────────────────────────
|
|
281
|
+
/**
|
|
282
|
+
* Create a logger instance with optional module name and configuration.
|
|
283
|
+
*
|
|
284
|
+
* @param module - Optional module name added as the first entry in `modules`
|
|
285
|
+
* @param options - Optional configuration
|
|
286
|
+
* @returns New Logger instance
|
|
287
|
+
*
|
|
288
|
+
* @example Basic usage
|
|
289
|
+
* ```typescript
|
|
290
|
+
* const logger = createLogger();
|
|
291
|
+
* logger('Application ready');
|
|
292
|
+
* ```
|
|
293
|
+
*
|
|
294
|
+
* @example Module-specific logger
|
|
295
|
+
* ```typescript
|
|
296
|
+
* const dbLogger = createLogger('database');
|
|
297
|
+
* dbLogger('Connected');
|
|
298
|
+
* ```
|
|
299
|
+
*
|
|
300
|
+
* @example Testing with spy transport
|
|
301
|
+
* ```typescript
|
|
302
|
+
* import type { LogEntry, LogTransport } from './utils/logger';
|
|
303
|
+
*
|
|
304
|
+
* const entries: LogEntry[] = [];
|
|
305
|
+
* const spy: LogTransport = { write(e) { entries.push(e); } };
|
|
306
|
+
* const testLogger = createLogger('test', { transports: [spy], level: lvl.TRACE });
|
|
307
|
+
* ```
|
|
308
|
+
*/
|
|
309
|
+
function createLogger(module, options) {
|
|
310
|
+
const level = options?.level ?? getLogLevel();
|
|
311
|
+
const transports = options?.transports ?? [prettyTransport()];
|
|
312
|
+
const modules = module ? [module] : [];
|
|
313
|
+
return buildLogger(modules, {}, level, transports);
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Default logger instance for application-wide logging.
|
|
317
|
+
*
|
|
318
|
+
* @example Basic usage
|
|
319
|
+
* ```typescript
|
|
320
|
+
* import { log } from './utils/logger';
|
|
321
|
+
*
|
|
322
|
+
* log('Application started');
|
|
323
|
+
* log(log.INFO, 'Server listening', { port: 3000 });
|
|
324
|
+
* log(log.ERROR, 'Startup failed', err);
|
|
325
|
+
* ```
|
|
326
|
+
*
|
|
327
|
+
* @example Module-specific logging via child
|
|
328
|
+
* ```typescript
|
|
329
|
+
* const dbLogger = log.child('database');
|
|
330
|
+
* dbLogger('Connection pool initialized');
|
|
331
|
+
* ```
|
|
332
|
+
*/
|
|
333
|
+
export const log = createLogger();
|
|
334
|
+
export { createLogger, prettyTransport, lvl };
|
|
335
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../../../src/utils/logger.ts"],"names":[],"mappings":"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"}
|