0
# Debugging and Logging
1
2
Debugging system with namespaced loggers and configurable output for development and troubleshooting. Metalsmith uses the `debug` module with enhanced features for plugin development and build monitoring.
3
4
## Capabilities
5
6
### Debug Logger Creation
7
8
Create namespaced debug loggers for plugins and custom code.
9
10
```javascript { .api }
11
/**
12
* Create a namespaced debug logger
13
* @param namespace - Debug namespace (typically plugin name)
14
* @returns Enhanced debugger with multiple log levels
15
*/
16
debug(namespace: string): Debugger;
17
18
interface Debugger {
19
/** Main debug function for general messages */
20
(message: string, ...args: any[]): void;
21
/** Info-level logging (namespace:info) */
22
info(message: string, ...args: any[]): void;
23
/** Warning-level logging (namespace:warn) */
24
warn(message: string, ...args: any[]): void;
25
/** Error-level logging (namespace:error) */
26
error(message: string, ...args: any[]): void;
27
}
28
```
29
30
**Usage Examples:**
31
32
```javascript
33
import Metalsmith from "metalsmith";
34
35
const metalsmith = Metalsmith(__dirname);
36
37
// Create debug logger for a plugin
38
function myPlugin(files, metalsmith, done) {
39
const debug = metalsmith.debug('metalsmith-myplugin');
40
41
debug('Starting plugin execution');
42
debug('Processing %d files', Object.keys(files).length);
43
44
Object.keys(files).forEach(filepath => {
45
debug('Processing file: %s', filepath);
46
47
try {
48
// Process file...
49
debug.info('Successfully processed: %s', filepath);
50
} catch (error) {
51
debug.error('Failed to process %s: %s', filepath, error.message);
52
}
53
});
54
55
debug('Plugin execution completed');
56
done();
57
}
58
59
// Use different log levels
60
function detailedPlugin(files, metalsmith, done) {
61
const debug = metalsmith.debug('detailed-plugin');
62
63
debug('Plugin started'); // General debug
64
debug.info('Configuration loaded'); // Info level
65
debug.warn('Deprecated option used'); // Warning level
66
debug.error('Critical error occurred'); // Error level
67
68
done();
69
}
70
```
71
72
### Debug Configuration
73
74
Control debug output through environment variables and Metalsmith settings.
75
76
```javascript { .api }
77
/**
78
* Debug configuration properties (available on metalsmith.debug)
79
*/
80
interface DebugConfig {
81
/** Enable debug output for specific namespaces */
82
enable(namespaces: string): void;
83
/** Disable debug output */
84
disable(): void;
85
/** Set custom log handler function */
86
handle: (...args: any[]) => void;
87
/** Enable/disable color output */
88
colors: boolean;
89
/** Check if debug is currently enabled */
90
enabled: boolean;
91
}
92
```
93
94
**Environment Variable Control:**
95
96
```javascript
97
// Enable debug output via environment
98
metalsmith.env('DEBUG', '@metalsmith/*'); // All metalsmith plugins
99
metalsmith.env('DEBUG', 'metalsmith-markdown'); // Specific plugin
100
metalsmith.env('DEBUG', '*'); // All debug output
101
102
// Enable in code
103
metalsmith.debug.enable('@metalsmith/*');
104
105
// Disable debug output
106
metalsmith.debug.disable();
107
108
// Check if debug is enabled
109
if (metalsmith.debug.enabled) {
110
console.log('Debug mode is active');
111
}
112
```
113
114
**Color Configuration:**
115
116
```javascript
117
// Enable colors (default for terminals)
118
metalsmith.debug.colors = true;
119
120
// Disable colors (useful for log files)
121
metalsmith.debug.colors = false;
122
```
123
124
### Custom Log Handling
125
126
Configure custom log handlers for debug output.
127
128
```javascript { .api }
129
/**
130
* Set custom debug log handler
131
* @param handler - Function to handle debug output
132
*/
133
debug.handle = (message: string) => void;
134
```
135
136
**Usage Examples:**
137
138
```javascript
139
import fs from 'fs';
140
141
// Log to file
142
const logStream = fs.createWriteStream('debug.log', { flags: 'a' });
143
metalsmith.debug.handle = (message) => {
144
logStream.write(message + '\n');
145
};
146
147
// Custom formatted logging
148
metalsmith.debug.handle = (message) => {
149
const timestamp = new Date().toISOString();
150
console.log(`[${timestamp}] ${message}`);
151
};
152
153
// Multiple handlers
154
const originalHandler = metalsmith.debug.handle;
155
metalsmith.debug.handle = (message) => {
156
originalHandler(message); // Console output
157
logStream.write(`${new Date().toISOString()}: ${message}\n`); // File output
158
};
159
```
160
161
### Built-in Debug Features
162
163
Metalsmith includes enhanced debug features beyond standard debug module.
164
165
**Buffer Formatter:**
166
167
```javascript
168
// Debug includes a %b formatter for buffers
169
function plugin(files, metalsmith, done) {
170
const debug = metalsmith.debug('my-plugin');
171
172
Object.keys(files).forEach(filepath => {
173
const file = files[filepath];
174
175
// %b formatter shows buffer content preview
176
debug('File contents: %b', file.contents);
177
// Output: "File contents: <Buffer contents preview...>"
178
});
179
180
done();
181
}
182
```
183
184
**Performance Monitoring:**
185
186
```javascript
187
function performancePlugin(files, metalsmith, done) {
188
const debug = metalsmith.debug('performance');
189
190
const startTime = Date.now();
191
192
// Process files...
193
194
const duration = Date.now() - startTime;
195
debug('Processing completed in %dms', duration);
196
debug.info('Processed %d files', Object.keys(files).length);
197
198
done();
199
}
200
```
201
202
### Debug-enabled Build Process
203
204
Using debug output to monitor the build process.
205
206
```javascript
207
// Enable comprehensive debugging
208
metalsmith
209
.env('DEBUG', '*')
210
.env('DEBUG_LOG', 'build.log') // Optional: log to file
211
.build((error, files) => {
212
if (error) {
213
console.error('Build failed:', error);
214
return;
215
}
216
console.log('Build completed successfully');
217
});
218
```
219
220
### Plugin Debug Patterns
221
222
Best practices for debugging in plugins.
223
224
```javascript
225
function robustPlugin(options = {}) {
226
return function plugin(files, metalsmith, done) {
227
const debug = metalsmith.debug('robust-plugin');
228
229
// Log plugin start with configuration
230
debug('Plugin starting with options: %o', options);
231
232
const startTime = process.hrtime();
233
const fileCount = Object.keys(files).length;
234
235
debug('Processing %d files', fileCount);
236
237
try {
238
let processed = 0;
239
240
Object.keys(files).forEach(filepath => {
241
debug('Processing file %d/%d: %s', ++processed, fileCount, filepath);
242
243
const file = files[filepath];
244
245
// Detailed file information
246
debug('File size: %d bytes', file.contents.length);
247
debug('File metadata: %o', {
248
title: file.title,
249
date: file.date,
250
tags: file.tags
251
});
252
253
// Process file with error handling
254
try {
255
// File processing logic...
256
debug.info('Successfully processed: %s', filepath);
257
} catch (fileError) {
258
debug.error('Error processing %s: %s', filepath, fileError.message);
259
throw fileError; // Re-throw to stop build
260
}
261
});
262
263
const [seconds, nanoseconds] = process.hrtime(startTime);
264
const duration = (seconds * 1000) + (nanoseconds / 1000000);
265
266
debug('Plugin completed in %dms', duration.toFixed(2));
267
debug.info('Successfully processed %d files', processed);
268
269
done();
270
} catch (error) {
271
debug.error('Plugin failed: %s', error.message);
272
debug.error('Stack trace: %s', error.stack);
273
done(error);
274
}
275
};
276
}
277
```
278
279
### Environment-specific Debug Configuration
280
281
Configure debugging based on environment settings.
282
283
```javascript
284
// Development environment with verbose debugging
285
if (process.env.NODE_ENV === 'development') {
286
metalsmith
287
.env('DEBUG', '@metalsmith/*,my-plugin*')
288
.env('DEBUG_LOG', 'logs/debug.log');
289
290
metalsmith.debug.colors = true;
291
}
292
293
// Production environment with error-only logging
294
if (process.env.NODE_ENV === 'production') {
295
metalsmith.env('DEBUG', false);
296
297
// Custom error-only handler
298
metalsmith.debug.handle = (message) => {
299
if (message.includes(':error')) {
300
console.error(message);
301
}
302
};
303
}
304
305
// Conditional debugging in plugins
306
function conditionalPlugin(files, metalsmith, done) {
307
const debug = metalsmith.debug('conditional-plugin');
308
const verbose = metalsmith.env('VERBOSE');
309
310
if (verbose) {
311
debug('Verbose mode enabled');
312
debug('File list: %o', Object.keys(files));
313
}
314
315
// Process files...
316
done();
317
}
318
```
319
320
### Debugging File Processing Issues
321
322
Common debugging scenarios for file processing problems.
323
324
```javascript
325
function diagnosticPlugin(files, metalsmith, done) {
326
const debug = metalsmith.debug('diagnostics');
327
328
debug('=== DIAGNOSTIC INFORMATION ===');
329
debug('Working directory: %s', metalsmith.directory());
330
debug('Source directory: %s', metalsmith.source());
331
debug('Destination directory: %s', metalsmith.destination());
332
debug('Global metadata: %o', metalsmith.metadata());
333
debug('Environment: %o', metalsmith.env());
334
335
debug('=== FILE ANALYSIS ===');
336
debug('Total files: %d', Object.keys(files).length);
337
338
Object.keys(files).forEach(filepath => {
339
const file = files[filepath];
340
341
debug('File: %s', filepath);
342
debug(' Size: %d bytes', file.contents.length);
343
debug(' Mode: %s', file.mode);
344
debug(' Stats: %o', file.stats);
345
debug(' Metadata keys: %o', Object.keys(file).filter(k => !['contents', 'stats', 'mode'].includes(k)));
346
347
// Check for front-matter parsing issues
348
if (file.contents.toString().startsWith('---')) {
349
debug.warn(' Potential front-matter parsing issue detected');
350
}
351
});
352
353
done();
354
}
355
```