yinzerflow 0.4.4 → 0.5.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.
@@ -1,117 +1,405 @@
1
- # Logging
1
+ # 📖 Logging
2
2
 
3
- YinzerFlow provides a flexible logging system with built-in Pittsburgh personality and performance tracking.
3
+ YinzerFlow provides a flexible logging system with built-in Pittsburgh personality, performance tracking, and support for custom logger implementations.
4
4
 
5
- ## Configuration
5
+ For detailed configuration examples and patterns, see [Configuration Guide](../configuration/configuration.md).
6
+
7
+ # ⚙️ Usage
8
+
9
+ ## 🎛️ Settings
10
+
11
+ ### Log Level — @default <span style="color: #2ecc71">`'info'`</span>
12
+
13
+ Minimum log level to output messages.
6
14
 
7
15
  ```typescript
8
- import { YinzerFlow, createLogger } from 'yinzerflow';
16
+ import { createLogger } from 'yinzerflow';
9
17
 
10
18
  const logger = createLogger({
11
- prefix: 'MYAPP',
12
- logLevel: 'info'
19
+ logLevel: 'info' // 'off', 'error', 'warn', 'info'
13
20
  });
14
21
 
15
- const server = new YinzerFlow({
16
- port: 3000,
17
- logger,
18
- networkLogs: true
19
- });
22
+ logger.info('This will be logged');
23
+ logger.warn('This will be logged');
24
+ logger.error('This will be logged');
20
25
  ```
21
26
 
22
- ### Configuration Options
27
+ <aside>
28
+
29
+ Options: `'off' | 'error' | 'warn' | 'info'`
23
30
 
24
- | Option | Type | Default | Description |
25
- |--------|------|---------|-------------|
26
- | `logLevel` | `'off' \| 'error' \| 'warn' \| 'info'` | `'info'` | Minimum log level to output |
27
- | `prefix` | `string` | `'YINZER'` | Prefix for log messages |
28
- | `logger` | `Logger` | `undefined` | Custom logger implementation (Winston, Pino, etc.) |
29
- | `networkLogs` | `boolean` | `false` | Enable nginx-style network request logging |
30
- | `networkLogger` | `Logger` | `undefined` | Custom logger for network logs (can be same as `logger` or different) |
31
+ - `'off'`: No logging at all
32
+ - `'error'`: Only errors
33
+ - `'warn'`: Warnings and errors
34
+ - `'info'`: All messages (most verbose)
35
+ </aside>
31
36
 
32
- ## Examples
37
+ ### Prefix — @default <span style="color: #2ecc71">`'YINZER'`</span>
33
38
 
34
- ### Basic Example
39
+ Prefix for log messages to identify different components.
35
40
 
36
41
  ```typescript
37
- import { log } from 'yinzerflow';
42
+ import { createLogger } from 'yinzerflow';
43
+
44
+ const dbLogger = createLogger({
45
+ prefix: 'DATABASE',
46
+ logLevel: 'error'
47
+ });
38
48
 
39
- // Use the shared logger (default YINZER prefix)
40
- log.info('Application started');
41
- log.warn('Deprecated feature used');
42
- log.error('Operation failed');
49
+ dbLogger.error('Connection failed');
50
+ // Output: [DATABASE] ❌ [timestamp] [ERROR] Connection failed - aw jeez
43
51
  ```
44
52
 
45
- ### Custom Logger
53
+ <aside>
54
+
55
+ Options: `string`
56
+
57
+ - Default: `'YINZER'`
58
+ - Used to identify different components or modules
59
+ - Appears in all log messages as `[PREFIX]`
60
+ </aside>
61
+
62
+ ### Custom Logger — @default <span style="color: #2ecc71">`undefined`</span>
63
+
64
+ Custom logger implementation for integration with external logging systems.
46
65
 
47
66
  ```typescript
48
- import { createLogger } from 'yinzerflow';
67
+ import { YinzerFlow } from 'yinzerflow';
49
68
 
50
- const dbLogger = createLogger({
51
- prefix: 'DATABASE',
52
- logLevel: 'error'
69
+ // Winston logger implementation
70
+ const winstonLogger = {
71
+ info: (...args) => winston.info(args.join(' ')),
72
+ warn: (...args) => winston.warn(args.join(' ')),
73
+ error: (...args) => winston.error(args.join(' '))
74
+ };
75
+
76
+ const app = new YinzerFlow({
77
+ port: 3000,
78
+ logger: winstonLogger
53
79
  });
80
+ ```
54
81
 
55
- dbLogger.error('Connection failed');
56
- // Output: [DATABASE] ❌ [timestamp] [ERROR] Connection failed - aw jeez
82
+ <aside>
83
+
84
+ Options: `Logger | undefined`
85
+
86
+ - Custom logger must implement `info`, `warn`, `error` methods
87
+ - Each method accepts variable arguments
88
+ - Methods should not return values (void)
89
+ - Falls back to built-in logger if undefined
90
+ </aside>
91
+
92
+ ### Network Logs — @default <span style="color: #e74c3c">`false`</span>
93
+
94
+ Enable nginx-style network request logging.
95
+
96
+ ```typescript
97
+ import { YinzerFlow } from 'yinzerflow';
98
+
99
+ const app = new YinzerFlow({
100
+ port: 3000,
101
+ networkLogs: true // Enable network request logging
102
+ });
57
103
  ```
58
104
 
59
- ### Unified Network and App Logging
105
+ <aside>
106
+
107
+ Options: `boolean`
108
+
109
+ - `false`: No network logging (default)
110
+ - `true`: Enable nginx-style request/response logging
111
+ - Separate from application logging
112
+ - Can use different logger instance
113
+ </aside>
114
+
115
+ # ✨ Best Practices
116
+
117
+ - **Use appropriate log levels** - error for failures, warn for issues, info for status
118
+ - **Create component-specific loggers** - Use different prefixes for different modules
119
+ - **Integrate with external systems** - Use custom loggers for Winston, Pino, etc.
120
+ - **Enable network logs in development** - Use `networkLogs: true` for debugging
121
+ - **Use table logging for structured data** - Use `log.table()` for arrays and objects
122
+ - **Avoid logging sensitive data** - Be careful with passwords, tokens, etc.
123
+
124
+ # 💻 Examples
125
+
126
+ ### Production API
127
+
128
+ **Use Case:** Production API with structured logging and external log management
129
+
130
+ **Description:** Production-ready logging with Winston integration, structured JSON output, and comprehensive error tracking for monitoring and debugging.
60
131
 
61
132
  ```typescript
62
133
  import { YinzerFlow, createLogger } from 'yinzerflow';
134
+ import winston from 'winston';
135
+
136
+ // Production Winston logger
137
+ const winstonLogger = winston.createLogger({
138
+ level: 'info',
139
+ format: winston.format.combine(
140
+ winston.format.timestamp(),
141
+ winston.format.errors({ stack: true }),
142
+ winston.format.json()
143
+ ),
144
+ transports: [
145
+ new winston.transports.File({ filename: 'error.log', level: 'error' }),
146
+ new winston.transports.File({ filename: 'combined.log' }),
147
+ new winston.transports.Console({
148
+ format: winston.format.simple()
149
+ })
150
+ ]
151
+ });
63
152
 
64
- const logger = createLogger({ prefix: 'APP', logLevel: 'info' });
153
+ // Custom logger implementation
154
+ const customLogger = {
155
+ info: (...args) => winstonLogger.info(args.join(' ')),
156
+ warn: (...args) => winstonLogger.warn(args.join(' ')),
157
+ error: (...args) => winstonLogger.error(args.join(' '))
158
+ };
159
+
160
+ // Component-specific loggers
161
+ const dbLogger = createLogger({
162
+ prefix: 'DATABASE',
163
+ logLevel: 'error',
164
+ logger: customLogger
165
+ });
65
166
 
66
- const server = new YinzerFlow({
167
+ const authLogger = createLogger({
168
+ prefix: 'AUTH',
169
+ logLevel: 'warn',
170
+ logger: customLogger
171
+ });
172
+
173
+ const apiLogger = createLogger({
174
+ prefix: 'API',
175
+ logLevel: 'info',
176
+ logger: customLogger
177
+ });
178
+
179
+ const app = new YinzerFlow({
67
180
  port: 3000,
68
- logger,
181
+ logger: customLogger,
69
182
  networkLogs: true,
70
- networkLogger: logger // Route network logs to same logger
183
+ networkLogger: customLogger
184
+ });
185
+
186
+ // Database operations
187
+ const connectToDatabase = async () => {
188
+ try {
189
+ await database.connect();
190
+ dbLogger.info('Database connection established');
191
+ } catch (error) {
192
+ dbLogger.error('Database connection failed', error);
193
+ throw error;
194
+ }
195
+ };
196
+
197
+ // Authentication operations
198
+ const validateToken = async (token: string) => {
199
+ try {
200
+ const user = await jwt.verify(token);
201
+ authLogger.info('Token validated successfully', { userId: user.id });
202
+ return user;
203
+ } catch (error) {
204
+ authLogger.warn('Token validation failed', { token: token.substring(0, 10) + '...' });
205
+ throw new Error('Invalid token');
206
+ }
207
+ };
208
+
209
+ // API operations
210
+ app.get('/api/users', async (ctx) => {
211
+ try {
212
+ apiLogger.info('Fetching users', {
213
+ requestId: ctx.state.requestId,
214
+ ipAddress: ctx.request.ipAddress
215
+ });
216
+
217
+ const users = await getAllUsers();
218
+
219
+ apiLogger.info('Users fetched successfully', {
220
+ count: users.length,
221
+ requestId: ctx.state.requestId
222
+ });
223
+
224
+ return { users };
225
+ } catch (error) {
226
+ apiLogger.error('Failed to fetch users', {
227
+ error: error.message,
228
+ requestId: ctx.state.requestId
229
+ });
230
+
231
+ ctx.response.setStatusCode(500);
232
+ return { error: 'Internal server error' };
233
+ }
71
234
  });
72
235
 
73
- // Both app and network logs go to the same custom logger
236
+ // Error handling with logging
237
+ app.onError(async (ctx, error) => {
238
+ apiLogger.error('Unhandled error', {
239
+ error: error.message,
240
+ stack: error.stack,
241
+ requestId: ctx.state.requestId,
242
+ method: ctx.request.method,
243
+ path: ctx.request.path,
244
+ ipAddress: ctx.request.ipAddress
245
+ });
246
+
247
+ ctx.response.setStatusCode(500);
248
+ return { error: 'Internal server error' };
249
+ });
250
+
251
+ await app.listen();
74
252
  ```
75
253
 
76
- ## Common Use Cases
254
+ ### Dev API
255
+
256
+ **Use Case:** Development server with detailed logging and debugging
77
257
 
78
- - **Debug Development Issues**: Use default logger with `networkLogs: true` for comprehensive debugging
79
- - **Track Application Errors**: Use `logLevel: 'error'` to capture only critical errors
80
- - **Monitor Component Health**: Create isolated loggers per subsystem with custom prefixes
81
- - **Integrate External Logging**: Use custom logger implementation for Winston, Pino, etc.
82
- - **Silent Operation**: Set `logLevel: 'off'` for environments with external log management
83
- - **Script and Utility Logging**: Use shared `log` instance in standalone scripts and database seeds
258
+ **Description:** Development configuration with built-in logger, extensive debugging information, and table logging for easier development and testing.
259
+
260
+ ```typescript
261
+ import { YinzerFlow, log, createLogger } from 'yinzerflow';
84
262
 
85
- ## Methods
263
+ // Development loggers with different prefixes
264
+ const dbLogger = createLogger({
265
+ prefix: 'DATABASE',
266
+ logLevel: 'info'
267
+ });
86
268
 
87
- ### `createLogger(options?): Logger`
269
+ const authLogger = createLogger({
270
+ prefix: 'AUTH',
271
+ logLevel: 'warn'
272
+ });
88
273
 
89
- Creates a logger instance with isolated state.
274
+ const apiLogger = createLogger({
275
+ prefix: 'API',
276
+ logLevel: 'info'
277
+ });
90
278
 
91
- **Parameters:**
92
- - `logLevel?: 'off' | 'error' | 'warn' | 'info'` - Minimum log level (default: 'info')
93
- - `prefix?: string` - Log message prefix (default: 'YINZER')
94
- - `logger?: Logger` - Custom logger implementation
279
+ const app = new YinzerFlow({
280
+ port: 3000,
281
+ logLevel: 'info',
282
+ networkLogs: true // Enable network logging for debugging
283
+ });
95
284
 
96
- **Returns:** Logger with `info`, `warn`, `error`, and `levels` methods.
285
+ // Database operations with detailed logging
286
+ const connectToDatabase = async () => {
287
+ try {
288
+ log.info('Connecting to database...');
289
+ await database.connect();
290
+ dbLogger.info('Database connection established');
291
+
292
+ // Log database configuration (non-sensitive)
293
+ dbLogger.info('Database configuration', {
294
+ host: process.env.DB_HOST,
295
+ port: process.env.DB_PORT,
296
+ database: process.env.DB_NAME
297
+ });
298
+ } catch (error) {
299
+ dbLogger.error('Database connection failed', error);
300
+ throw error;
301
+ }
302
+ };
303
+
304
+ // Authentication with detailed logging
305
+ const validateToken = async (token: string) => {
306
+ try {
307
+ authLogger.info('Validating token', { tokenLength: token.length });
308
+ const user = await jwt.verify(token);
309
+ authLogger.info('Token validated successfully', { userId: user.id });
310
+ return user;
311
+ } catch (error) {
312
+ authLogger.warn('Token validation failed', { error: error.message });
313
+ throw new Error('Invalid token');
314
+ }
315
+ };
316
+
317
+ // API operations with comprehensive logging
318
+ app.get('/api/users', async (ctx) => {
319
+ try {
320
+ apiLogger.info('Fetching users', {
321
+ requestId: ctx.state.requestId,
322
+ ipAddress: ctx.request.ipAddress,
323
+ userAgent: ctx.request.headers['user-agent']
324
+ });
325
+
326
+ const users = await getAllUsers();
327
+
328
+ // Use table logging for structured data
329
+ apiLogger.table(users, 'Users fetched successfully');
330
+
331
+ apiLogger.info('Users fetched successfully', {
332
+ count: users.length,
333
+ requestId: ctx.state.requestId
334
+ });
335
+
336
+ return { users };
337
+ } catch (error) {
338
+ apiLogger.error('Failed to fetch users', {
339
+ error: error.message,
340
+ stack: error.stack,
341
+ requestId: ctx.state.requestId
342
+ });
343
+
344
+ ctx.response.setStatusCode(500);
345
+ return { error: 'Internal server error' };
346
+ }
347
+ });
97
348
 
98
- ### Logger Methods
349
+ // Debug route with extensive logging
350
+ app.get('/debug', async (ctx) => {
351
+ log.info('Debug route accessed');
352
+
353
+ // Log request details
354
+ apiLogger.info('Debug request details', {
355
+ method: ctx.request.method,
356
+ path: ctx.request.path,
357
+ headers: ctx.request.headers,
358
+ query: ctx.request.query,
359
+ params: ctx.request.params,
360
+ body: ctx.request.body,
361
+ ipAddress: ctx.request.ipAddress
362
+ });
363
+
364
+ // Log state information
365
+ apiLogger.table(ctx.state, 'Request state');
366
+
367
+ return {
368
+ message: 'Debug information logged',
369
+ timestamp: new Date().toISOString()
370
+ };
371
+ });
99
372
 
100
- - `info(...args): void` - Log info-level messages
101
- - `warn(...args): void` - Log warning messages
102
- - `error(...args): void` - Log error messages
103
- - `levels` - Access to log level constants
373
+ // Error handling with detailed logging
374
+ app.onError(async (ctx, error) => {
375
+ log.error('Unhandled error occurred', error);
376
+
377
+ apiLogger.error('Unhandled error details', {
378
+ error: error.message,
379
+ stack: error.stack,
380
+ requestId: ctx.state.requestId,
381
+ method: ctx.request.method,
382
+ path: ctx.request.path,
383
+ ipAddress: ctx.request.ipAddress,
384
+ headers: ctx.request.headers,
385
+ body: ctx.request.body
386
+ });
387
+
388
+ ctx.response.setStatusCode(500);
389
+ return { error: 'Internal server error' };
390
+ });
104
391
 
105
- ## Properties
392
+ await app.listen();
393
+ ```
106
394
 
107
- ### Log Levels
395
+ ## 🚀 Performance Notes
108
396
 
109
- - `off` (0): No logging
110
- - `error` (1): Only errors
111
- - `warn` (2): Warnings and errors
112
- - `info` (3): All messages (most verbose)
397
+ - **Early returns**: Log level checks prevent unnecessary processing when logging is disabled
398
+ - **Native console methods**: Uses built-in console methods for optimal performance
399
+ - **Minimal overhead**: Logging adds minimal overhead when disabled
400
+ - **Table optimization**: Table logging uses native console.table for efficient display
113
401
 
114
- ## Security Considerations
402
+ ## 🔒 Security Notes
115
403
 
116
404
  YinzerFlow implements several security measures for safe logging:
117
405
 
@@ -120,11 +408,81 @@ YinzerFlow implements several security measures for safe logging:
120
408
  - **YinzerFlow Solution**: Uses native `console.log` formatting to prevent accidental serialization of sensitive objects
121
409
 
122
410
  ### 🛡️ Log Level Protection
123
- - **Problem**: Verbose logging in production can impact performance and expose internal details
411
+ - **Problem**: Verbose logging in production can impact performance and expose internal details
124
412
  - **YinzerFlow Solution**: Configurable log levels with early returns to minimize overhead when logging is disabled
125
413
 
126
414
  ### 🛡️ Logger Isolation
127
415
  - **Problem**: Custom loggers could interfere with framework logging
128
416
  - **YinzerFlow Solution**: Clean interface boundaries and isolated logger instances prevent conflicts
129
417
 
130
- These security measures ensure YinzerFlow's logging implementation follows security best practices and prevents common attack vectors while maintaining spec compliance.
418
+ ### 🛡️ Network Logging Security
419
+ - **Problem**: Network logs can expose sensitive request data
420
+ - **YinzerFlow Solution**: Network logging is separate and configurable, allowing selective logging
421
+
422
+ ## 🔧 Troubleshooting
423
+
424
+ ### Logs Not Appearing
425
+ - **Problem**: Log messages not showing up
426
+ - **Fix**: Check log level configuration
427
+
428
+ ```typescript
429
+ // ❌ Wrong - log level too high
430
+ const logger = createLogger({ logLevel: 'error' });
431
+ logger.info('This will not appear'); // Blocked by log level
432
+
433
+ // ✅ Correct - appropriate log level
434
+ const logger = createLogger({ logLevel: 'info' });
435
+ logger.info('This will appear'); // Will be logged
436
+ ```
437
+
438
+ ### Custom Logger Not Working
439
+ - **Problem**: Custom logger not being used
440
+ - **Fix**: Check logger interface implementation
441
+
442
+ ```typescript
443
+ // ❌ Wrong - missing required methods
444
+ const customLogger = {
445
+ info: (...args) => console.log(...args)
446
+ // Missing warn and error methods
447
+ };
448
+
449
+ // ✅ Correct - implement all required methods
450
+ const customLogger = {
451
+ info: (...args) => console.log(...args),
452
+ warn: (...args) => console.warn(...args),
453
+ error: (...args) => console.error(...args)
454
+ };
455
+ ```
456
+
457
+ ### Network Logs Not Working
458
+ - **Problem**: Network request logs not appearing
459
+ - **Fix**: Enable network logging in configuration
460
+
461
+ ```typescript
462
+ // ❌ Wrong - network logging disabled
463
+ const app = new YinzerFlow({
464
+ port: 3000,
465
+ networkLogs: false // Disabled
466
+ });
467
+
468
+ // ✅ Correct - enable network logging
469
+ const app = new YinzerFlow({
470
+ port: 3000,
471
+ networkLogs: true // Enabled
472
+ });
473
+ ```
474
+
475
+ ### Table Logging Not Working
476
+ - **Problem**: Table logs not displaying properly
477
+ - **Fix**: Use appropriate data types for table logging
478
+
479
+ ```typescript
480
+ // ❌ Wrong - primitive data
481
+ logger.table('string data'); // Not suitable for table display
482
+
483
+ // ✅ Correct - structured data
484
+ logger.table([
485
+ { id: 1, name: 'John' },
486
+ { id: 2, name: 'Jane' }
487
+ ]); // Will display as table
488
+ ```