0
# Advanced Features
1
2
Interactive mode, secrets filtering, stream management, and state control for advanced logging scenarios. These features provide sophisticated capabilities for production applications and complex logging requirements.
3
4
## Capabilities
5
6
### State Control
7
8
Enable, disable, and check the logging state of Signale instances.
9
10
```javascript { .api }
11
/**
12
* Disable logging functionality for this instance
13
*/
14
function disable(): void;
15
16
/**
17
* Enable logging functionality for this instance
18
*/
19
function enable(): void;
20
21
/**
22
* Check if logging is currently enabled
23
* @returns true if logging is enabled, false if disabled
24
*/
25
function isEnabled(): boolean;
26
```
27
28
### Secrets Management
29
30
Add and remove sensitive information filtering from log output.
31
32
```javascript { .api }
33
/**
34
* Add secrets/sensitive information to be filtered from logs
35
* @param secrets - Array of strings or numbers to filter out
36
* @throws TypeError if secrets parameter is not an array
37
*/
38
function addSecrets(secrets: (string | number)[]): void;
39
40
/**
41
* Remove all secrets from the instance
42
*/
43
function clearSecrets(): void;
44
```
45
46
### Instance Properties
47
48
Access current instance state and metadata.
49
50
```javascript { .api }
51
/**
52
* Get current instance configuration and options
53
*/
54
readonly currentOptions: SignaleOptions;
55
56
/**
57
* Get current date string
58
*/
59
readonly date: string;
60
61
/**
62
* Get current timestamp string
63
*/
64
readonly timestamp: string;
65
66
/**
67
* Get the filename of the calling code
68
*/
69
readonly filename: string;
70
71
/**
72
* Get package.json configuration
73
*/
74
readonly packageConfiguration: object;
75
76
interface SignaleOptions {
77
config: ConfigOptions;
78
disabled: boolean;
79
types: Record<string, LoggerType>;
80
interactive: boolean;
81
timers: Map<string, number>;
82
stream: NodeJS.WritableStream | NodeJS.WritableStream[];
83
secrets: (string | number)[];
84
logLevel: LogLevel;
85
}
86
```
87
88
### State Control Usage
89
90
Control logging functionality dynamically.
91
92
**Usage Examples:**
93
94
```javascript
95
const signale = require('signale');
96
97
// Normal logging
98
signale.info('Logging is enabled');
99
// Output: ℹ info Logging is enabled
100
101
console.log(signale.isEnabled()); // true
102
103
// Disable logging
104
signale.disable();
105
console.log(signale.isEnabled()); // false
106
107
signale.success('This will not appear');
108
// No output
109
110
signale.error('This will not appear either');
111
// No output
112
113
// Re-enable logging
114
signale.enable();
115
console.log(signale.isEnabled()); // true
116
117
signale.success('Logging is back!');
118
// Output: ✔ success Logging is back!
119
```
120
121
### Secrets Filtering
122
123
Filter sensitive information from log messages and metadata.
124
125
**Usage Examples:**
126
127
```javascript
128
const { Signale } = require('signale');
129
130
// Initialize with secrets
131
const logger = new Signale({
132
secrets: ['password123', 'secret-api-key']
133
});
134
135
logger.info('User login with password123');
136
// Output: ℹ info User login with [secure]
137
138
logger.warn('API key secret-api-key is expiring');
139
// Output: ⚠ warning API key [secure] is expiring
140
141
// Add more secrets at runtime
142
logger.addSecrets(['session-token-abc', 12345]);
143
144
logger.error('Session session-token-abc invalid for user 12345');
145
// Output: ✖ error Session [secure] invalid for user [secure]
146
147
// Clear all secrets
148
logger.clearSecrets();
149
150
logger.info('Now showing password123 and secret-api-key');
151
// Output: ℹ info Now showing password123 and secret-api-key
152
153
// Secrets in scope names are also filtered
154
const secureLogger = new Signale({
155
secrets: ['production']
156
});
157
158
const scopedLogger = secureLogger.scope('production', 'database');
159
scopedLogger.success('Connected successfully');
160
// Output: [[secure]] [database] › ✔ success Connected successfully
161
```
162
163
### Interactive Mode
164
165
Enable interactive mode for overriding previous log messages.
166
167
**Usage Examples:**
168
169
```javascript
170
const { Signale } = require('signale');
171
172
const interactive = new Signale({
173
interactive: true,
174
scope: 'progress'
175
});
176
177
// Interactive loggers override previous interactive messages
178
interactive.await('Processing step 1/4');
179
// Output: [progress] › ⋯ awaiting Processing step 1/4
180
181
setTimeout(() => {
182
interactive.await('Processing step 2/4');
183
// Previous message is overwritten
184
// Output: [progress] › ⋯ awaiting Processing step 2/4
185
186
setTimeout(() => {
187
interactive.success('Processing step 3/4');
188
// Output: [progress] › ✔ success Processing step 3/4
189
190
setTimeout(() => {
191
interactive.complete('All steps completed!');
192
// Output: [progress] › ☑ complete All steps completed!
193
}, 1000);
194
}, 1000);
195
}, 1000);
196
197
// Regular (non-interactive) messages are not overridden
198
const regular = require('signale');
199
regular.info('This message stays visible');
200
interactive.pending('This overwrites previous interactive message');
201
regular.success('This message also stays visible');
202
```
203
204
### Stream Management
205
206
Configure multiple output streams for flexible logging.
207
208
**Usage Examples:**
209
210
```javascript
211
const { Signale } = require('signale');
212
const fs = require('fs');
213
214
// Create file streams
215
const errorLog = fs.createWriteStream('error.log');
216
const accessLog = fs.createWriteStream('access.log');
217
218
// Global stream configuration
219
const fileLogger = new Signale({
220
stream: [process.stdout, accessLog] // All logs go to console AND file
221
});
222
223
fileLogger.info('This appears in console and access.log');
224
fileLogger.success('This also appears in both places');
225
226
// Per-logger-type stream configuration
227
const mixedLogger = new Signale({
228
stream: process.stdout, // Default stream
229
types: {
230
error: {
231
stream: [process.stderr, errorLog] // Errors to stderr AND error.log
232
},
233
info: {
234
stream: accessLog // Info only to access.log
235
}
236
}
237
});
238
239
mixedLogger.success('To console only'); // Uses default stream
240
mixedLogger.info('To access.log only'); // Uses custom stream
241
mixedLogger.error('To stderr AND error.log'); // Uses custom streams
242
243
// Stream inheritance in scoped loggers
244
const parent = new Signale({
245
stream: fs.createWriteStream('parent.log')
246
});
247
248
const child = parent.scope('child');
249
child.info('This goes to parent.log'); // Inherits parent stream
250
```
251
252
### Instance Inspection
253
254
Access and inspect instance properties and configuration.
255
256
**Usage Examples:**
257
258
```javascript
259
const { Signale } = require('signale');
260
261
const logger = new Signale({
262
scope: 'api',
263
secrets: ['token123'],
264
logLevel: 'warn',
265
types: {
266
custom: { badge: '🔧', color: 'blue', label: 'custom' }
267
}
268
});
269
270
// Inspect current options
271
console.log(logger.currentOptions);
272
// {
273
// config: { displayScope: true, displayBadge: true, ... },
274
// disabled: false,
275
// types: { await: {...}, complete: {...}, custom: {...}, ... },
276
// interactive: false,
277
// timers: Map(0) {},
278
// stream: [object Object],
279
// secrets: ['token123'],
280
// logLevel: 'warn'
281
// }
282
283
// Access metadata properties
284
console.log(logger.date); // "12/7/2023"
285
console.log(logger.timestamp); // "2:30:25 PM"
286
console.log(logger.filename); // "advanced-demo.js"
287
console.log(logger.scopeName); // "api"
288
289
// Package configuration
290
console.log(logger.packageConfiguration);
291
// Configuration loaded from package.json signale section
292
```
293
294
### Error Handling
295
296
Proper error handling for advanced features.
297
298
**Usage Examples:**
299
300
```javascript
301
const { Signale } = require('signale');
302
303
// addSecrets error handling
304
const logger = new Signale();
305
306
try {
307
logger.addSecrets('not-an-array'); // TypeError
308
} catch (error) {
309
console.error(error.message); // "Argument must be an array."
310
}
311
312
// Valid secrets addition
313
logger.addSecrets(['valid', 'secrets']);
314
logger.info('These valid secrets are filtered');
315
316
// Stream error handling
317
const invalidStream = { write: 'not-a-function' };
318
319
try {
320
const badLogger = new Signale({ stream: invalidStream });
321
badLogger.info('This may cause issues');
322
} catch (error) {
323
console.error('Stream configuration error:', error.message);
324
}
325
326
// Filename access with anonymous execution
327
const anonymousLogger = new Signale();
328
console.log(anonymousLogger.filename); // "anonymous" if no file context
329
```
330
331
### Performance Considerations
332
333
Optimize logging performance for production use.
334
335
**Usage Examples:**
336
337
```javascript
338
const { Signale } = require('signale');
339
340
// Disable logging in production for performance
341
const logger = new Signale({
342
disabled: process.env.NODE_ENV === 'production'
343
});
344
345
// Or use log levels to filter
346
const prodLogger = new Signale({
347
logLevel: process.env.NODE_ENV === 'production' ? 'error' : 'info'
348
});
349
350
// Lazy evaluation with isEnabled check
351
if (logger.isEnabled()) {
352
const expensiveData = computeExpensiveLogData();
353
logger.debug('Expensive debug data: %j', expensiveData);
354
}
355
356
// Stream buffering for high-volume logging
357
const bufferedStream = new (require('stream').PassThrough)();
358
const highVolumeLogger = new Signale({
359
stream: bufferedStream
360
});
361
362
// Batch write to file periodically
363
setInterval(() => {
364
const fs = require('fs');
365
if (bufferedStream.readable) {
366
const data = bufferedStream.read();
367
if (data) {
368
fs.appendFileSync('high-volume.log', data);
369
}
370
}
371
}, 1000);
372
```
373
374
### Advanced Configuration Patterns
375
376
Combine multiple advanced features for sophisticated logging setups.
377
378
**Usage Examples:**
379
380
```javascript
381
const { Signale } = require('signale');
382
const fs = require('fs');
383
384
// Production-ready logger with all advanced features
385
class ProductionLogger {
386
constructor(options = {}) {
387
const {
388
environment = 'development',
389
logLevel = 'info',
390
secrets = [],
391
logFile = null
392
} = options;
393
394
const streams = [process.stdout];
395
if (logFile) {
396
streams.push(fs.createWriteStream(logFile, { flags: 'a' }));
397
}
398
399
this.logger = new Signale({
400
disabled: environment === 'test',
401
logLevel: environment === 'production' ? 'warn' : logLevel,
402
secrets: [...secrets, process.env.API_SECRET].filter(Boolean),
403
stream: streams,
404
config: {
405
displayTimestamp: true,
406
displayDate: environment === 'production',
407
displayFilename: environment === 'development'
408
}
409
});
410
411
// Add environment-specific secrets
412
if (environment === 'production') {
413
this.logger.addSecrets([
414
process.env.DATABASE_URL,
415
process.env.JWT_SECRET
416
].filter(Boolean));
417
}
418
}
419
420
// Expose logger methods
421
get info() { return this.logger.info.bind(this.logger); }
422
get warn() { return this.logger.warn.bind(this.logger); }
423
get error() { return this.logger.error.bind(this.logger); }
424
get success() { return this.logger.success.bind(this.logger); }
425
426
// Advanced methods
427
scope(...names) { return this.logger.scope(...names); }
428
time(label) { return this.logger.time(label); }
429
timeEnd(label) { return this.logger.timeEnd(label); }
430
}
431
432
// Usage
433
const prodLogger = new ProductionLogger({
434
environment: 'production',
435
logLevel: 'warn',
436
secrets: ['user-session-key'],
437
logFile: 'production.log'
438
});
439
440
prodLogger.warn('Production warning'); // Appears in console and file
441
prodLogger.info('Development info'); // Filtered out in production
442
```