0
# Plugin System
1
2
Extend loglevel with custom logging behavior through the method factory system, enabling advanced features like remote logging, custom formatting, and output redirection.
3
4
## Capabilities
5
6
### methodFactory
7
8
```javascript { .api }
9
/**
10
* Plugin API entry point for custom method factories
11
* Called for each enabled method when level is set
12
* @type {MethodFactory}
13
*/
14
methodFactory: MethodFactory;
15
16
/**
17
* Method factory function type
18
* @param {string} methodName - Log method name ('trace', 'debug', 'info', 'warn', 'error')
19
* @param {number} level - Current logging level (0-5)
20
* @param {string | symbol} loggerName - Name of the logger (undefined for root logger)
21
* @returns {Function} Logging method implementation
22
*/
23
type MethodFactory = (
24
methodName: 'trace' | 'debug' | 'info' | 'warn' | 'error',
25
level: number,
26
loggerName: string | symbol | undefined
27
) => (...message: any[]) => void;
28
```
29
30
**Usage Examples:**
31
32
```javascript
33
import log from 'loglevel';
34
35
// Basic method factory override
36
const originalFactory = log.methodFactory;
37
log.methodFactory = function(methodName, level, loggerName) {
38
const rawMethod = originalFactory(methodName, level, loggerName);
39
40
return function(...args) {
41
// Add timestamp prefix
42
const timestamp = new Date().toISOString();
43
rawMethod(`[${timestamp}]`, ...args);
44
};
45
};
46
47
// Apply the factory
48
log.setLevel(log.getLevel()); // Rebuilds methods with new factory
49
log.info('This message has a timestamp'); // [2023-10-01T12:00:00.000Z] This message has a timestamp
50
```
51
52
### rebuild
53
54
```javascript { .api }
55
/**
56
* Rebuild logging methods using current methodFactory
57
* Forces regeneration of all logging methods
58
* Updates child loggers if called on root logger
59
*/
60
rebuild(): void;
61
```
62
63
**Usage Examples:**
64
65
```javascript
66
import log from 'loglevel';
67
68
// Change method factory
69
log.methodFactory = customFactory;
70
71
// Rebuild methods to apply changes
72
log.rebuild();
73
74
// For root logger, also rebuilds all child loggers
75
const childLogger = log.getLogger('child');
76
log.rebuild(); // Updates both root and child logger methods
77
```
78
79
## Plugin Examples
80
81
### Prefix Plugin
82
83
Add prefixes to all log messages:
84
85
```javascript
86
import log from 'loglevel';
87
88
function createPrefixPlugin(prefix) {
89
const originalFactory = log.methodFactory;
90
91
log.methodFactory = function(methodName, level, loggerName) {
92
const rawMethod = originalFactory(methodName, level, loggerName);
93
94
return function(...args) {
95
const loggerPrefix = loggerName ? `[${String(loggerName)}]` : '';
96
rawMethod(`${prefix}${loggerPrefix}`, ...args);
97
};
98
};
99
100
log.rebuild();
101
}
102
103
// Usage
104
createPrefixPlugin('[MyApp] ');
105
106
const dbLogger = log.getLogger('DB');
107
log.info('Application started'); // [MyApp] Application started
108
dbLogger.warn('Connection slow'); // [MyApp] [DB] Connection slow
109
```
110
111
### Remote Logging Plugin
112
113
Send logs to a remote server:
114
115
```javascript
116
import log from 'loglevel';
117
118
function createRemotePlugin(endpoint) {
119
const originalFactory = log.methodFactory;
120
121
log.methodFactory = function(methodName, level, loggerName) {
122
const rawMethod = originalFactory(methodName, level, loggerName);
123
124
return function(...args) {
125
// Local logging
126
rawMethod(...args);
127
128
// Remote logging for errors and warnings
129
if (level >= log.levels.WARN) {
130
fetch(endpoint, {
131
method: 'POST',
132
headers: { 'Content-Type': 'application/json' },
133
body: JSON.stringify({
134
level: methodName,
135
logger: loggerName,
136
message: args.join(' '),
137
timestamp: Date.now(),
138
url: window.location?.href
139
})
140
}).catch(err => {
141
// Fail silently to avoid logging loops
142
});
143
}
144
};
145
};
146
147
log.rebuild();
148
}
149
150
// Usage
151
createRemotePlugin('/api/logs');
152
log.error('Critical error'); // Logs locally AND sends to server
153
```
154
155
### Conditional Logging Plugin
156
157
Add conditional logging based on environment or feature flags:
158
159
```javascript
160
import log from 'loglevel';
161
162
function createConditionalPlugin(shouldLog) {
163
const originalFactory = log.methodFactory;
164
165
log.methodFactory = function(methodName, level, loggerName) {
166
const rawMethod = originalFactory(methodName, level, loggerName);
167
168
return function(...args) {
169
// Check condition before logging
170
if (shouldLog(methodName, level, loggerName, args)) {
171
rawMethod(...args);
172
}
173
};
174
};
175
176
log.rebuild();
177
}
178
179
// Usage examples
180
// Only log in development
181
createConditionalPlugin(() => process.env.NODE_ENV === 'development');
182
183
// Only log specific modules
184
createConditionalPlugin((method, level, logger) => {
185
return !logger || logger === 'database' || logger === 'api';
186
});
187
188
// Rate limiting
189
const logCounts = new Map();
190
createConditionalPlugin((method, level, logger, args) => {
191
const key = `${logger}-${method}`;
192
const count = logCounts.get(key) || 0;
193
logCounts.set(key, count + 1);
194
return count < 100; // Max 100 logs per method per logger
195
});
196
```
197
198
### Formatting Plugin
199
200
Custom message formatting and structured logging:
201
202
```javascript
203
import log from 'loglevel';
204
205
function createFormattingPlugin() {
206
const originalFactory = log.methodFactory;
207
208
log.methodFactory = function(methodName, level, loggerName) {
209
const rawMethod = originalFactory(methodName, level, loggerName);
210
211
return function(...args) {
212
// Structured logging format
213
const logEntry = {
214
timestamp: new Date().toISOString(),
215
level: methodName.toUpperCase(),
216
logger: loggerName || 'root',
217
message: args.length === 1 && typeof args[0] === 'string'
218
? args[0]
219
: args.map(arg => typeof arg === 'object' ? JSON.stringify(arg) : String(arg)).join(' ')
220
};
221
222
// Format as JSON for structured logging
223
rawMethod(JSON.stringify(logEntry));
224
};
225
};
226
227
log.rebuild();
228
}
229
230
// Usage
231
createFormattingPlugin();
232
log.info('User logged in', { userId: 123 });
233
// {"timestamp":"2023-10-01T12:00:00.000Z","level":"INFO","logger":"root","message":"User logged in {\"userId\":123}"}
234
```
235
236
## Plugin Best Practices
237
238
### Preserve Original Functionality
239
240
Always wrap the original method factory to maintain loglevel's reliability:
241
242
```javascript
243
const originalFactory = log.methodFactory;
244
log.methodFactory = function(methodName, level, loggerName) {
245
const rawMethod = originalFactory(methodName, level, loggerName);
246
247
return function(...args) {
248
// Your custom logic here
249
try {
250
// Custom processing
251
processCustomLogic(methodName, args);
252
} catch (error) {
253
// Don't break logging if plugin fails
254
}
255
256
// Always call original method
257
return rawMethod(...args);
258
};
259
};
260
```
261
262
### Handle Errors Gracefully
263
264
Plugin failures shouldn't break logging:
265
266
```javascript
267
log.methodFactory = function(methodName, level, loggerName) {
268
const rawMethod = originalFactory(methodName, level, loggerName);
269
270
return function(...args) {
271
try {
272
// Plugin logic
273
customBehavior(...args);
274
} catch (error) {
275
// Silently fail or use fallback
276
console.error('Logging plugin error:', error);
277
}
278
279
return rawMethod(...args);
280
};
281
};
282
```
283
284
### Support All Loggers
285
286
Ensure plugins work with both root and named loggers:
287
288
```javascript
289
log.methodFactory = function(methodName, level, loggerName) {
290
const rawMethod = originalFactory(methodName, level, loggerName);
291
292
return function(...args) {
293
// Handle both root logger (loggerName === undefined) and named loggers
294
const prefix = loggerName ? `[${String(loggerName)}]` : '[ROOT]';
295
return rawMethod(prefix, ...args);
296
};
297
};
298
299
// Rebuild all loggers
300
log.rebuild();
301
```
302
303
### Memory Management
304
305
Be aware of memory usage in plugins:
306
307
```javascript
308
// Avoid memory leaks in stateful plugins
309
const logCache = new Map();
310
311
log.methodFactory = function(methodName, level, loggerName) {
312
const rawMethod = originalFactory(methodName, level, loggerName);
313
314
return function(...args) {
315
// Limit cache size
316
if (logCache.size > 1000) {
317
logCache.clear();
318
}
319
320
// Cache logic here
321
return rawMethod(...args);
322
};
323
};
324
```