ntlogger 2.9.1 → 3.0.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/index.d.ts CHANGED
@@ -3,214 +3,218 @@
3
3
  * @file index.d.ts
4
4
  */
5
5
 
6
- /**
7
- * Log levels supported by NightTimeLogger
8
- */
9
- export type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal' | 'internal';
10
-
11
- /**
12
- * Sampling configuration for log levels
13
- */
14
- export interface SamplingConfig {
15
- [level: string]: number; // 0.0 to 1.0, where 1.0 = log all, 0.1 = log 10%
16
- }
17
-
18
- /**
19
- * Rate limit configuration for a log level
20
- */
21
- export interface RateLimitConfig {
22
- max: number; // Maximum number of logs
23
- window: number; // Time window in milliseconds
24
- }
25
-
26
- /**
27
- * Rate limiting configuration for log levels
28
- */
29
- export interface RateLimitConfigMap {
30
- [level: string]: RateLimitConfig;
31
- }
32
-
33
- /**
34
- * Deduplication configuration
35
- */
36
- export interface DeduplicationConfig {
37
- enabled: boolean;
38
- threshold: number; // Number of duplicates before squishing (default: 3)
39
- window: number; // Time window in milliseconds (default: 60000)
40
- }
41
-
42
- /**
43
- * Plugin configuration
44
- */
45
- export interface PluginConfig {
46
- name: string;
47
- enabled?: boolean;
48
- config?: Record<string, any>;
49
- }
50
-
51
- /**
52
- * Logger configuration options
53
- */
54
- export interface LoggerConfig {
55
- /** Minimum log level to be logged */
56
- level?: LogLevel;
57
- /** Enable console logging (default: true) */
58
- console?: boolean;
59
- /** Enable file logging (default: true) */
60
- file?: boolean;
61
- /** Filename for log file (default: `${location}.log`) */
62
- filename?: string;
63
- /** Directory path where log files will be saved (default: './logs') */
64
- path?: string;
65
- /** Maximum size of log file in bytes (default: 1048576 = 1MB) */
66
- maxSize?: number;
67
- /** Maximum number of log files to retain (default: 5) */
68
- maxFiles?: number;
69
- /** Include timestamp in log messages (default: true) */
70
- timestamp?: boolean;
71
- /** Skip cache and create new logger instance (default: false) */
72
- skipCache?: boolean;
73
- /** Enable call site path reporting (default: false) */
74
- reportPath?: boolean;
75
- /** Enable debug mode for logger itself (default: false) */
76
- debug?: boolean;
77
- /** Log sampling rates per level */
78
- sampling?: SamplingConfig;
79
- /** Rate limiting configuration per level */
80
- rateLimit?: RateLimitConfigMap;
81
- /** Log deduplication configuration */
82
- deduplication?: DeduplicationConfig;
83
- /** Enable performance metrics (default: NODE_ENV === 'development') */
84
- performanceMetrics?: boolean;
85
- /** Interval in milliseconds to log statistics (default: 0 = disabled) */
86
- statsInterval?: number;
87
- /** Plugin configurations */
88
- plugins?: PluginConfig[];
89
- }
90
-
91
- /**
92
- * Statistics object returned by getStats()
93
- */
94
- export interface LoggerStats {
95
- sampling: {
96
- total: Record<string, number>;
97
- sampled: Record<string, number>;
98
- rateLimited: Record<string, number>;
99
- } | null;
100
- deduplication: {
101
- totalDeduplicated: number;
102
- uniqueMessages: number;
103
- activeEntries: number;
104
- } | null;
105
- performance: {
106
- enabled: boolean;
107
- avgLogProcessingTime?: number;
108
- avgTransportTime?: number;
109
- logProcessingSamples?: number;
110
- transportSamples?: number;
111
- } | null;
112
- }
113
-
114
- /**
115
- * Logger instance interface
116
- */
117
- export interface Logger {
118
- /**
119
- * Log an informational message
120
- * @param message - The message to log
121
- * @param meta - Optional metadata object
122
- */
123
- info(message: string, meta?: Record<string, any>): void;
124
- info(message: Record<string, any>): void;
125
-
6
+ declare namespace logger {
126
7
  /**
127
- * Log a warning message
128
- * @param message - The message to log
129
- * @param meta - Optional metadata object
8
+ * Log levels supported by NightTimeLogger
130
9
  */
131
- warn(message: string, meta?: Record<string, any>): void;
132
- warn(message: Record<string, any>): void;
10
+ export type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal' | 'internal';
133
11
 
134
12
  /**
135
- * Log an error message
136
- * @param message - The message to log
137
- * @param meta - Optional metadata object
13
+ * Sampling configuration for log levels
138
14
  */
139
- error(message: string, meta?: Record<string, any>): void;
140
- error(message: Record<string, any>): void;
15
+ export interface SamplingConfig {
16
+ [level: string]: number; // 0.0 to 1.0, where 1.0 = log all, 0.1 = log 10%
17
+ }
141
18
 
142
19
  /**
143
- * Log a debug message
144
- * @param message - The message to log
145
- * @param meta - Optional metadata object
20
+ * Rate limit configuration for a log level
146
21
  */
147
- debug(message: string, meta?: Record<string, any>): void;
148
- debug(message: Record<string, any>): void;
22
+ export interface RateLimitConfig {
23
+ max: number; // Maximum number of logs
24
+ window: number; // Time window in milliseconds
25
+ }
149
26
 
150
27
  /**
151
- * Log a trace message
152
- * @param message - The message to log
153
- * @param meta - Optional metadata object
28
+ * Rate limiting configuration for log levels
154
29
  */
155
- trace(message: string, meta?: Record<string, any>): void;
156
- trace(message: Record<string, any>): void;
30
+ export interface RateLimitConfigMap {
31
+ [level: string]: RateLimitConfig;
32
+ }
157
33
 
158
34
  /**
159
- * Log a fatal message
160
- * @param message - The message to log
161
- * @param meta - Optional metadata object
35
+ * Deduplication configuration
162
36
  */
163
- fatal(message: string, meta?: Record<string, any>): void;
164
- fatal(message: Record<string, any>): void;
165
-
166
- /**
167
- * Log an internal message (logger system messages)
168
- * @param message - The message to log
169
- * @param meta - Optional metadata object
170
- */
171
- internal(message: string, meta?: Record<string, any>): void;
172
- internal(message: Record<string, any>): void;
173
-
174
- /**
175
- * Create a child logger with persistent context
176
- * @param context - Context object to merge into all logs
177
- * @returns Child logger instance
178
- */
179
- child(context: Record<string, any>): Logger;
180
-
181
- /**
182
- * Start a performance timer (development mode only)
183
- * @param label - Timer label
184
- */
185
- time?(label: string): void;
37
+ export interface DeduplicationConfig {
38
+ enabled: boolean;
39
+ threshold: number; // Number of duplicates before squishing (default: 3)
40
+ window: number; // Time window in milliseconds (default: 60000)
41
+ }
186
42
 
187
43
  /**
188
- * End a performance timer and log duration (development mode only)
189
- * @param label - Timer label
190
- * @returns Duration in milliseconds or null if timer not found
44
+ * Plugin configuration
191
45
  */
192
- timeEnd?(label: string): number | null;
46
+ export interface PluginConfig {
47
+ name: string;
48
+ enabled?: boolean;
49
+ config?: Record<string, any>;
50
+ }
193
51
 
194
52
  /**
195
- * Get logging statistics
196
- * @returns Statistics object
53
+ * Logger configuration options
197
54
  */
198
- getStats(): LoggerStats;
55
+ export interface LoggerConfig {
56
+ /** Minimum log level to be logged */
57
+ level?: LogLevel;
58
+ /** Enable console logging (default: true) */
59
+ console?: boolean;
60
+ /** Enable file logging (default: true) */
61
+ file?: boolean;
62
+ /** Filename for combined log file (default: combined.log) */
63
+ filename?: string;
64
+ /** Directory path where log files will be saved (default: './logs') */
65
+ path?: string;
66
+ /** Maximum size of log file in bytes (default: 1048576 = 1MB) */
67
+ maxSize?: number;
68
+ /** Maximum number of log files to retain (default: 5) */
69
+ maxFiles?: number;
70
+ /** Include timestamp in log messages (default: true) */
71
+ timestamp?: boolean;
72
+ /** Skip cache and create new logger instance (default: false) */
73
+ skipCache?: boolean;
74
+ /** Enable call site path reporting (default: false) */
75
+ reportPath?: boolean;
76
+ /** Enable debug mode for logger itself (default: false) */
77
+ debug?: boolean;
78
+ /** Log sampling rates per level */
79
+ sampling?: SamplingConfig;
80
+ /** Rate limiting configuration per level */
81
+ rateLimit?: RateLimitConfigMap;
82
+ /** Log deduplication configuration */
83
+ deduplication?: DeduplicationConfig;
84
+ /** Enable performance metrics (default: NODE_ENV === 'development') */
85
+ performanceMetrics?: boolean;
86
+ /** Interval in milliseconds to log statistics (default: 0 = disabled) */
87
+ statsInterval?: number;
88
+ /** Maximum flush/stream shutdown wait in milliseconds (default: 30000). */
89
+ shutdownTimeout?: number;
90
+ /** Plugin configurations */
91
+ plugins?: PluginConfig[];
92
+ }
199
93
 
200
94
  /**
201
- * Flush all pending logs (returns Promise)
202
- * @returns Promise that resolves when all logs are flushed
95
+ * Statistics object returned by getStats()
203
96
  */
204
- flush(): Promise<void>;
97
+ export interface LoggerStats {
98
+ sampling: {
99
+ total: Record<string, number>;
100
+ sampled: Record<string, number>;
101
+ rateLimited: Record<string, number>;
102
+ } | null;
103
+ deduplication: {
104
+ totalDeduplicated: number;
105
+ uniqueMessages: number;
106
+ activeEntries: number;
107
+ } | null;
108
+ performance: {
109
+ enabled: boolean;
110
+ avgLogProcessingTime?: number;
111
+ avgTransportTime?: number;
112
+ logProcessingSamples?: number;
113
+ transportSamples?: number;
114
+ } | null;
115
+ }
205
116
 
206
117
  /**
207
- * Close the logger and flush all pending logs (returns Promise)
208
- * @returns Promise that resolves when logger is closed
118
+ * Logger instance interface
209
119
  */
210
- close(): Promise<void>;
211
-
212
- /** Current log level */
213
- level: string;
120
+ export interface Logger {
121
+ /**
122
+ * Log an informational message
123
+ * @param message - The message to log
124
+ * @param meta - Optional metadata object
125
+ */
126
+ info(message: string, meta?: Record<string, any>): void;
127
+ info(message: Record<string, any>): void;
128
+
129
+ /**
130
+ * Log a warning message
131
+ * @param message - The message to log
132
+ * @param meta - Optional metadata object
133
+ */
134
+ warn(message: string, meta?: Record<string, any>): void;
135
+ warn(message: Record<string, any>): void;
136
+
137
+ /**
138
+ * Log an error message
139
+ * @param message - The message to log
140
+ * @param meta - Optional metadata object
141
+ */
142
+ error(message: string, meta?: Record<string, any>): void;
143
+ error(message: Record<string, any>): void;
144
+
145
+ /**
146
+ * Log a debug message
147
+ * @param message - The message to log
148
+ * @param meta - Optional metadata object
149
+ */
150
+ debug(message: string, meta?: Record<string, any>): void;
151
+ debug(message: Record<string, any>): void;
152
+
153
+ /**
154
+ * Log a trace message
155
+ * @param message - The message to log
156
+ * @param meta - Optional metadata object
157
+ */
158
+ trace(message: string, meta?: Record<string, any>): void;
159
+ trace(message: Record<string, any>): void;
160
+
161
+ /**
162
+ * Log a fatal message
163
+ * @param message - The message to log
164
+ * @param meta - Optional metadata object
165
+ */
166
+ fatal(message: string, meta?: Record<string, any>): void;
167
+ fatal(message: Record<string, any>): void;
168
+
169
+ /**
170
+ * Log an internal message (logger system messages)
171
+ * @param message - The message to log
172
+ * @param meta - Optional metadata object
173
+ */
174
+ internal(message: string, meta?: Record<string, any>): void;
175
+ internal(message: Record<string, any>): void;
176
+
177
+ /**
178
+ * Create a child logger with persistent context
179
+ * @param context - Context object to merge into all logs
180
+ * @returns Child logger instance
181
+ */
182
+ child(context: Record<string, any>): Logger;
183
+
184
+ /**
185
+ * Start a performance timer (development mode only)
186
+ * @param label - Timer label
187
+ */
188
+ time?(label: string): void;
189
+
190
+ /**
191
+ * End a performance timer and log duration (development mode only)
192
+ * @param label - Timer label
193
+ * @returns Duration in milliseconds or null if timer not found
194
+ */
195
+ timeEnd?(label: string): number | null;
196
+
197
+ /**
198
+ * Get logging statistics
199
+ * @returns Statistics object
200
+ */
201
+ getStats(): LoggerStats;
202
+
203
+ /**
204
+ * Flush all pending logs (returns Promise)
205
+ * @returns Promise that resolves when all logs are flushed
206
+ */
207
+ flush(): Promise<void>;
208
+
209
+ /**
210
+ * Close the logger and flush all pending logs (returns Promise)
211
+ * @returns Promise that resolves when logger is closed
212
+ */
213
+ close(): Promise<void>;
214
+
215
+ /** Current log level */
216
+ level: string;
217
+ }
214
218
  }
215
219
 
216
220
  /**
@@ -219,7 +223,12 @@ export interface Logger {
219
223
  * @param config - Configuration options for the logger
220
224
  * @returns Logger instance
221
225
  */
222
- declare function logger(location?: string, config?: LoggerConfig): Logger;
226
+ declare function logger(location?: string, config?: logger.LoggerConfig): logger.Logger;
227
+
228
+ declare namespace logger {
229
+ /** Opt in to process-wide signal handlers; returns an unregister function. */
230
+ function setupSignalHandlers(options?: { timeout?: number }): () => void;
231
+ }
223
232
 
224
233
  export = logger;
225
234
 
@@ -0,0 +1,53 @@
1
+ 'use strict';
2
+
3
+ const delay = () => new Promise(resolve => setTimeout(resolve, 1));
4
+
5
+ function withTimeout(operation, timeout, label) {
6
+ let timer;
7
+ return Promise.race([
8
+ operation,
9
+ new Promise((_, reject) => {
10
+ timer = setTimeout(() => reject(new Error(`${label} timed out after ${timeout}ms`)), timeout);
11
+ }),
12
+ ]).finally(() => clearTimeout(timer));
13
+ }
14
+
15
+ // Winston uses readable-stream, so inspect both its buffers and file sinks.
16
+ function busy(stream) {
17
+ return !!(stream && (stream._writableState?.length || stream._readableState?.length));
18
+ }
19
+
20
+ async function drain(logger, state, timeout = 5000) {
21
+ const deadline = Date.now() + timeout;
22
+ while (state.pending || busy(logger) || logger.transports.some(t =>
23
+ busy(t) || busy(t._stream) || busy(t._dest) || t._opening || t._rotate)) {
24
+ if (state.error) throw state.error;
25
+ if (Date.now() >= deadline) throw new Error('Logger drain timed out');
26
+ await delay();
27
+ }
28
+ if (state.error) throw state.error;
29
+ }
30
+
31
+ // Winston calls close on unpipe but doesn't await the result. Retain that promise.
32
+ function trackClose(transport) {
33
+ if (transport._ntlClose) return;
34
+ const close = transport.close?.bind(transport);
35
+ let promise;
36
+ transport._ntlClose = () => {
37
+ if (!promise) {
38
+ // File._final already ended and drained this stream before unpipe.
39
+ // Calling File.close(callback) on that finished stream never calls back.
40
+ if (transport instanceof require('winston').transports.File && transport._stream?._writableState.finished) {
41
+ return (promise = Promise.resolve());
42
+ }
43
+ promise = close && close.length > 0
44
+ ? new Promise((resolve, reject) => close(err => err ? reject(err) : resolve()))
45
+ : Promise.resolve().then(() => close?.());
46
+ promise.catch(() => {}); // unpipe cannot consume a rejected promise
47
+ }
48
+ return promise;
49
+ };
50
+ transport.close = transport._ntlClose;
51
+ }
52
+
53
+ module.exports = { withTimeout, drain, trackClose };