scribelog 1.0.1 → 1.0.2

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.
Files changed (2) hide show
  1. package/README.md +103 -79
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Scribelog 🪵📝
2
2
 
3
- [![npm version](https://img.shields.io/npm/v/scribelog.svg)](https://www.npmjs.com/package/scribelog) <!-- This should update automatically -->
3
+ [![npm version](https://img.shields.io/npm/v/scribelog.svg)](https://www.npmjs.com/package/scribelog)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
- [![Build Status](https://github.com/tolongames/scribelog/actions/workflows/node.js.yml/badge.svg)](https://github.com/tolongames/scribelog/actions/workflows/node.js.yml) <!-- Add your GitHub Actions badge URL -->
5
+ [![Build Status](https://github.com/tolongames/scribelog/actions/workflows/node.js.yml/badge.svg)](https://github.com/tolongames/scribelog/actions/workflows/node.js.yml)
6
6
  <!-- Add other badges if you have them (e.g., coverage) -->
7
7
 
8
8
  **Scribelog** is an advanced, highly configurable logging library for Node.js applications, written in TypeScript. It offers flexible formatting, support for multiple destinations (transports), child loggers, and automatic error catching, aiming for a great developer experience.
@@ -36,40 +36,56 @@ pnpm add scribelog
36
36
  ## 🚀 Basic Usage
37
37
 
38
38
  ```ts
39
- import { createLogger } from 'scribelog';
39
+ // Import necessary functions and types
40
+ import { createLogger, format, transports } from 'scribelog';
40
41
 
41
42
  // Create a logger with default settings:
42
43
  // - Level: 'info'
43
- // - Format: Simple, colored output to console
44
+ // - Format: Simple, colored output to console (defaultSimpleFormat)
44
45
  // - Transport: Console
45
46
  const logger = createLogger();
46
47
 
47
48
  // Log messages at different levels
48
49
  logger.info('Application started successfully.');
49
- logger.warn('Warning: Cache memory usage high.', { usage: '85%' });
50
+ logger.warn('Warning: Cache memory usage high.', { usage: '85%' }); // Add metadata
50
51
 
51
- // Pass an Error object directly or in metadata
52
+ // --- Correct way to log Errors ---
53
+ // Pass a message string as the first argument,
54
+ // and the Error object in the metadata (typically under the 'error' key).
55
+ // The `format.errors()` formatter (included in defaults) will handle it.
52
56
  const dbError = new Error('Database connection timeout');
53
- (dbError as any).code = 'DB_TIMEOUT'; // Add custom properties
54
- logger.error(dbError); // Logs the error message and stack trace
57
+ (dbError as any).code = 'DB_TIMEOUT'; // You can add custom properties to errors
58
+ logger.error('Database Error Occurred', { error: dbError });
59
+
55
60
  logger.info('Operation completed', { user: 'admin', durationMs: 120 });
56
61
 
57
- // Debug logs won't appear by default (level 'info')
62
+ // Debug logs won't appear with the default 'info' level
58
63
  logger.debug('Detailed step for debugging.');
64
+
65
+ // --- Example with JSON format and debug level ---
66
+ const jsonLogger = createLogger({
67
+ level: 'debug', // Log 'debug' and higher levels
68
+ format: format.defaultJsonFormat, // Use predefined JSON format (includes errors, timestamp, etc.)
69
+ });
70
+
71
+ jsonLogger.debug('Debugging operation X', { operationId: 'op-xyz' });
72
+ // Example JSON Output:
73
+ // {"level":"debug","message":"Debugging operation X","timestamp":"...ISO_STRING...","operationId":"op-xyz"}
59
74
  ```
60
75
 
61
- **Example Output (Simple Format with Colors):**
76
+ **Example Output (Default Simple Format with Colors):**
62
77
 
63
78
  ```bash
64
79
  # (Timestamp will be gray, [INFO] green, [WARN] yellow, [ERROR] red)
65
80
  2024-05-01T10:00:00.123Z [INFO]: Application started successfully.
66
81
  2024-05-01T10:00:01.456Z [WARN]: Warning: Cache memory usage high. { usage: '85%' }
67
- 2024-05-01T10:00:02.789Z [ERROR]: Database connection timeout { errorName: 'Error', code: 'DB_TIMEOUT' }
82
+ 2024-05-01T10:00:02.789Z [ERROR]: Database connection timeout { exception: true, eventType: undefined, errorName: 'Error', code: 'DB_TIMEOUT' }
68
83
  Error: Database connection timeout
69
84
  at <anonymous>:10:17
70
85
  ... (stack trace) ...
71
86
  2024-05-01T10:00:03.111Z [INFO]: Operation completed { user: 'admin', durationMs: 120 }
72
87
  ```
88
+ *(Note: `eventType` is undefined here because the error wasn't logged via `handleExceptions`/`handleRejections`)*
73
89
 
74
90
  ---
75
91
 
@@ -95,28 +111,35 @@ Create and configure your logger using `createLogger(options?: LoggerOptions)`.
95
111
  import { createLogger, format, transports } from 'scribelog';
96
112
 
97
113
  const prodLogger = createLogger({
98
- level: 'info', // Only log info and above in production
99
- format: format.defaultJsonFormat, // Use the predefined JSON format
114
+ level: process.env.LOG_LEVEL || 'info', // Read level from environment or default to info
115
+ format: format.defaultJsonFormat, // Use predefined JSON format
100
116
  transports: [
101
117
  new transports.Console({
102
- // Console specific options can go here if needed
103
- // e.g., level: 'info' (though logger level already covers this)
118
+ // Console specific options if needed
104
119
  }),
105
- // In the future, you might add a FileTransport here:
106
- // new transports.File({ filename: 'app.log', level: 'warn' })
120
+ // Future: new transports.File({ filename: '/var/log/app.log', level: 'warn' })
107
121
  ],
108
122
  defaultMeta: {
109
- environment: 'production',
110
- region: process.env.AWS_REGION || 'unknown',
123
+ service: 'my-prod-service',
124
+ pid: process.pid,
125
+ // You can add more static metadata here
111
126
  },
112
- // Handle critical errors in production
113
- handleExceptions: true,
114
- handleRejections: true,
115
- // exitOnError: true // Default is true, ensures app exits on fatal errors
127
+ handleExceptions: true, // Recommended for production
128
+ handleRejections: true, // Recommended for production
129
+ // exitOnError: true // Default, recommended for production
116
130
  });
117
131
 
118
132
  prodLogger.info('Production logger initialized.');
119
- prodLogger.error(new Error('Critical configuration error!'));
133
+ try {
134
+ // Simulate an operation that might fail
135
+ throw new Error('Critical configuration error!');
136
+ } catch (error) {
137
+ // Log the caught error correctly
138
+ prodLogger.error('Failed to apply configuration', { error: error as Error });
139
+ }
140
+
141
+ // Example of an unhandled rejection that would be caught if not caught here
142
+ // Promise.reject('Something failed asynchronously');
120
143
  ```
121
144
 
122
145
  ---
@@ -126,13 +149,7 @@ prodLogger.error(new Error('Critical configuration error!'));
126
149
  Scribelog uses standard `npm` logging levels (ordered from most to least severe):
127
150
 
128
151
  ```text
129
- error: 0
130
- warn: 1
131
- info: 2
132
- http: 3
133
- verbose: 4
134
- debug: 5
135
- silly: 6
152
+ error: 0, warn: 1, info: 2, http: 3, verbose: 4, debug: 5, silly: 6
136
153
  ```
137
154
 
138
155
  Setting the `level` option filters messages *at or above* the specified severity. `level: 'info'` logs `info`, `warn`, and `error`. `level: 'debug'` logs everything.
@@ -144,7 +161,7 @@ Setting the `level` option filters messages *at or above* the specified severity
144
161
  Formatters transform the log `info` object before it reaches transports. Use `format.combine(...)` to chain them.
145
162
 
146
163
  **How it Works:**
147
- `createLogger` -> `log()`/`logEntry()` -> Creates `LogInfo` object -> Passes to `format` function -> `format` function applies its chain -> Result (string or object) passed to `transport.log()`.
164
+ `createLogger` -> `log()`/`logEntry()` -> Creates `LogInfo` object -> Passes to `format` function -> `format` function applies its chain (`combine`) -> Result (string or object) passed to `transport.log()`.
148
165
 
149
166
  ### Available Formatters
150
167
 
@@ -152,60 +169,66 @@ Formatters transform the log `info` object before it reaches transports. Use `fo
152
169
  * `alias?: string`: Key for the formatted timestamp (default: `'timestamp'`).
153
170
  * `format?: string | ((date: Date) => string)`: `date-fns` format string or custom function (default: ISO 8601).
154
171
  ```ts
155
- format.timestamp({ format: 'yyyy-MM-dd HH:mm:ss' }) // -> '2024-05-01 10:30:00'
156
- format.timestamp({ alias: '@timestamp' }) // -> Adds {'@timestamp': '...'}
172
+ format.timestamp({ format: 'yyyy-MM-dd HH:mm:ss' }) // -> Adds { timestamp: '2024-05-01 10:30:00' }
173
+ format.timestamp({ alias: '@timestamp' }) // -> Adds { '@timestamp': '...ISO...' }
157
174
  ```
158
175
  * **`format.level(options?)`**: Adds the log level string.
159
176
  * `alias?: string`: Key for the level (default: `'level'`).
160
177
  * **`format.message(options?)`**: Adds the log message string.
161
178
  * `alias?: string`: Key for the message (default: `'message'`).
162
- * **`format.errors(options?)`**: Extracts info from an `Error` object (expected at `info.error`). Adds `errorName`, `stack?`, `originalReason?` and potentially other error properties. Sets `info.message` to `error.message` if `info.message` was empty. Removes the original `info.error`.
179
+ * **`format.errors(options?)`**: Extracts info from an `Error` object (expected at `info.error`). Adds `errorName`, `stack?`, `originalReason?` and potentially other error properties to the `info` object. Sets `info.message` to `error.message` if `info.message` was empty. Removes the original `info.error` field. **Place this early in your `combine` chain.**
163
180
  * `stack?: boolean`: Include stack trace (default: `true`).
164
- * **`format.metadata(options?)`**: Gathers all remaining properties into the main object or under an alias. Excludes standard fields (`level`, `message`, `timestamp`, etc.) and error fields (`stack`, `errorName`, etc.).
165
- * `alias?: string`: If provided, nest metadata under this key.
166
- * `exclude?: string[]`: Array of additional keys to exclude from metadata.
181
+ * **`format.metadata(options?)`**: Gathers all remaining properties into the main object or under an alias. Excludes standard fields added by other formatters (`level`, `message`, `timestamp`, `errorName`, `stack`, `exception`, `eventType` etc.).
182
+ * `alias?: string`: If provided, nest metadata under this key and remove original keys.
183
+ * `exclude?: string[]`: Array of additional keys to exclude from metadata collection.
167
184
  * **`format.json(options?)`**: **Terminal Formatter.** Serializes the final `info` object to a JSON string.
168
185
  * `space?: string | number`: Pretty-printing spaces for `JSON.stringify`.
169
- * **`format.simple(options?)`**: **Terminal Formatter.** Creates a human-readable, colored (if TTY) string. Includes `timestamp`, `level`, `message`, `{ metadata }`, and `stack` (on a new line).
170
- * `colors?: boolean`: Force colors on or off (default: auto-detect).
186
+ * **`format.simple(options?)`**: **Terminal Formatter.** Creates a human-readable, colored (if TTY) string. Includes `timestamp`, `level`, `message`, `{ metadata }`, and `stack` (on a new line if present).
187
+ * `colors?: boolean`: Force colors on or off (default: auto-detect based on TTY).
171
188
 
172
189
  ### Combining Formatters (`format.combine`)
173
190
 
174
- The order matters! Formatters run sequentially, modifying the `info` object. Terminal formatters (`json`, `simple`) should usually be last.
191
+ The order matters! Formatters run sequentially. Terminal formatters (`json`, `simple`) should be last.
175
192
 
176
193
  ```ts
177
194
  import { createLogger, format } from 'scribelog';
178
195
 
179
- // Example: Log only level, message, and custom timestamp
196
+ // Example: Log only level, message, and custom timestamp in simple format
180
197
  const minimalFormat = format.combine(
198
+ // Note: errors() is not included here
181
199
  format.timestamp({ format: 'HH:mm:ss.SSS' }),
182
200
  format.level(),
183
201
  format.message(),
184
- // No metadata() or errors()
185
- format.simple() // Simple will only use timestamp, level, message
202
+ // No metadata() - ignores other fields like { extra: '...' }
203
+ format.simple() // simple() will only use timestamp, level, message
186
204
  );
187
205
  const minimalLogger = createLogger({ format: minimalFormat });
188
- minimalLogger.info('Minimal log', { extra: 'this will be ignored'});
206
+ minimalLogger.info('Minimal log', { extra: 'this is ignored'});
189
207
  // Output: 10:45:00.123 [INFO]: Minimal log
190
208
 
191
209
  // Example: JSON output with specific fields and nested metadata
192
210
  const customJsonFormat = format.combine(
193
- format.errors({ stack: false }), // Include basic error info, no stack
194
- format.timestamp({ alias: '@ts' }),
195
- format.level({ alias: 'severity' }),
196
- format.message(),
197
- format.metadata({ alias: 'data' }), // Nest other data under 'data'
198
- format.json()
211
+ format.errors({ stack: false }), // Include basic error info, no stack
212
+ format.timestamp({ alias: '@ts' }), // Rename timestamp field
213
+ format.level({ alias: 'severity' }), // Rename level field
214
+ format.message(), // Keep message field
215
+ format.metadata({ alias: 'data' }), // Nest other data under 'data'
216
+ format.json() // Output as JSON
199
217
  );
200
218
  const customJsonLogger = createLogger({ format: customJsonFormat });
201
219
  customJsonLogger.warn('Warning with nested meta', { user: 'test', id: 1 });
202
220
  // Output: {"@ts":"...","severity":"warn","message":"Warning with nested meta","data":{"user":"test","id":1}}
221
+
222
+ const errorExample = new Error("Failed task");
223
+ (errorExample as any).details = { code: 500 };
224
+ customJsonLogger.error("Task failed", { error: errorExample });
225
+ // Output: {"@ts":"...", "severity":"error", "message":"Failed task", "errorName":"Error", "originalReason":undefined, "data":{"details":{"code":500}}}
203
226
  ```
204
227
 
205
228
  ### Predefined Formats
206
229
 
207
- * `format.defaultSimpleFormat`: Equivalent to `combine(errors(), timestamp(), level(), message(), metadata(), simple())`. **This is the default format for `createLogger`.**
208
- * `format.defaultJsonFormat`: Equivalent to `combine(errors(), timestamp(), level(), message(), metadata(), json())`.
230
+ * `format.defaultSimpleFormat`: Equivalent to `combine(errors({ stack: true }), timestamp(), level(), message(), metadata(), simple())`. **This is the default format for `createLogger`.**
231
+ * `format.defaultJsonFormat`: Equivalent to `combine(errors({ stack: true }), timestamp(), level(), message(), metadata(), json())`.
209
232
 
210
233
  ---
211
234
 
@@ -217,7 +240,7 @@ Define log destinations. You can use multiple transports.
217
240
 
218
241
  Logs to `process.stdout` or `process.stderr`.
219
242
 
220
- * `level?: string`: Minimum level for this specific transport. Overrides the logger's level if more restrictive (e.g., logger 'debug', transport 'info' -> transport logs 'info' and above).
243
+ * `level?: string`: Minimum level for this specific transport. Filters logs *after* the main logger level filter.
221
244
  * `format?: LogFormat`: Specific format for this transport. Overrides the logger's format.
222
245
  * `useStdErrLevels?: string[]`: Array of levels to direct to `stderr` (default: `['error']`).
223
246
 
@@ -227,27 +250,27 @@ Logs to `process.stdout` or `process.stderr`.
227
250
  import { createLogger, format, transports } from 'scribelog';
228
251
 
229
252
  const logger = createLogger({
230
- level: 'info', // Logger handles info and above
253
+ level: 'info', // Logger allows info, warn, error
231
254
  transports: [
232
255
  // Log INFO and WARN to stdout using simple format
233
256
  new transports.Console({
234
- level: 'warn', // Catches info and warn from logger
257
+ level: 'warn', // Only logs warn and error passed from logger
235
258
  format: format.simple({ colors: true }),
236
- useStdErrLevels: [], // Ensure nothing goes to stderr from here
259
+ useStdErrLevels: [], // Nothing from here goes to stderr
237
260
  }),
238
261
  // Log only ERRORs to stderr using JSON format
239
262
  new transports.Console({
240
- level: 'error', // Catches only error from logger
241
- format: format.json(),
242
- useStdErrLevels: ['error'] // Explicitly send errors to stderr
263
+ level: 'error', // Only logs error passed from logger
264
+ format: format.json(), // Use JSON for errors
265
+ useStdErrLevels: ['error'] // Ensure errors go to stderr
243
266
  })
244
267
  ]
245
268
  });
246
269
 
247
- logger.info('User logged in'); // Goes to first console (stdout, simple)
270
+ logger.info('User logged in'); // Filtered out by the first transport's level ('warn')
248
271
  logger.warn('Disk space low'); // Goes to first console (stdout, simple)
249
- logger.error(new Error('DB Error')); // Goes to BOTH (stdout simple, stderr JSON)
250
- logger.debug('Should not appear'); // Ignored by logger level
272
+ logger.error('DB Error', { error: new Error('Connection failed')}); // Goes to BOTH (stdout simple, stderr JSON)
273
+ logger.debug('Should not appear'); // Filtered out by logger's level ('info')
251
274
  ```
252
275
 
253
276
  ---
@@ -262,19 +285,18 @@ import { createLogger } from 'scribelog';
262
285
  const baseLogger = createLogger({ level: 'debug', defaultMeta: { app: 'my-api' } });
263
286
 
264
287
  function processUserData(userId: string) {
265
- const userLogger = baseLogger.child({ userId }); // Inherits level, format, transports
266
- // Adds { userId: '...' }
288
+ // Create a logger specific to this user's context
289
+ const userLogger = baseLogger.child({ userId, module: 'userProcessing' });
267
290
 
268
- userLogger.debug('Starting data processing');
291
+ userLogger.debug('Starting data processing'); // Includes { app: 'my-api', userId: '...', module: '...' }
269
292
  // ...
270
293
  userLogger.info('Data processed');
271
- // Logs will include { app: 'my-api', userId: '...' }
272
294
  }
273
295
 
274
296
  function processAdminTask(adminId: string) {
297
+ // Create a logger for admin tasks
275
298
  const adminLogger = baseLogger.child({ adminId, scope: 'admin' });
276
299
  adminLogger.info('Performing admin task');
277
- // Logs will include { app: 'my-api', adminId: '...', scope: 'admin' }
278
300
  }
279
301
 
280
302
  processUserData('user-77');
@@ -288,26 +310,30 @@ processAdminTask('admin-01');
288
310
  Set `handleExceptions: true` and/or `handleRejections: true` in `createLogger` options to automatically log fatal errors.
289
311
 
290
312
  ```ts
291
- import { createLogger } from 'scribelog';
313
+ import { createLogger, format } from 'scribelog';
292
314
 
293
315
  const logger = createLogger({
294
316
  level: 'info',
295
- format: format.defaultJsonFormat, // Log errors as JSON
317
+ format: format.defaultJsonFormat, // Log errors as JSON for easier parsing
296
318
  handleExceptions: true,
297
319
  handleRejections: true,
298
- exitOnError: true // Default: Exit after logging fatal error
320
+ exitOnError: true // Default behavior: Exit after logging fatal error
299
321
  });
300
322
 
301
323
  logger.info('Application running with error handlers.');
302
324
 
303
- // This would cause the logger to log the error and exit:
304
- // throw new Error('Something broke badly!');
325
+ // Example of what would be caught:
326
+ // setTimeout(() => { throw new Error('Something broke badly!'); }, 50);
327
+ // Output (JSON): {"level":"error","message":"Something broke badly!","timestamp":"...","exception":true,"eventType":"uncaughtException","errorName":"Error","stack":"..."}
328
+ // ... and process exits
305
329
 
306
- // This would also cause logging and exit:
330
+ // Example of what would be caught:
307
331
  // Promise.reject('Unhandled promise rejection reason');
332
+ // Output (JSON): {"level":"error","message":"Unhandled promise rejection reason","timestamp":"...","exception":true,"eventType":"unhandledRejection","errorName":"Error","stack":"...","originalReason":"..."}
333
+ // ... and process exits
308
334
  ```
309
335
 
310
- The logger adds `{ exception: true, eventType: '...', errorName: '...', stack: '...' }` to the log metadata for these events.
336
+ The logger adds `{ exception: true, eventType: '...', ...errorDetails }` to the log metadata for these events, processed by the `format.errors()` formatter. Remember to have `format.errors()` in your format chain to see detailed error info.
311
337
 
312
338
  ---
313
339
 
@@ -322,14 +348,12 @@ The logger adds `{ exception: true, eventType: '...', errorName: '...', stack: '
322
348
 
323
349
  ## 🤝 Contributing
324
350
 
325
- Contributions are welcome! Please feel free to submit issues and pull requests.
326
-
327
- *(Consider adding contribution guidelines)*
351
+ Contributions are welcome! Please feel free to submit issues and pull requests. Check for any existing guidelines or open an issue to discuss larger changes.
328
352
 
329
353
  ---
330
354
 
331
355
  ## 📄 License
332
356
 
333
357
  MIT License
334
- Copyright (c) 2024 Tolan Games *(Zmień na swoje)*
358
+ Copyright (c) 2025 tolongames
335
359
  See [LICENSE](./LICENSE) for details.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scribelog",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "An advanced, configurable logger for Node.js applications.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",