scribelog 1.0.4 → 1.1.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.
- package/README.md +340 -134
- package/dist/format.d.ts +6 -0
- package/dist/format.js +78 -21
- package/dist/format.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +14 -16
- package/dist/logger.js +107 -75
- package/dist/logger.js.map +1 -1
- package/dist/transports/file.d.ts +14 -0
- package/dist/transports/file.js +165 -0
- package/dist/transports/file.js.map +1 -0
- package/dist/types.d.ts +31 -17
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
|
|
1
2
|
# Scribelog 🪵📝
|
|
2
3
|
|
|
3
4
|
[](https://www.npmjs.com/package/scribelog)
|
|
@@ -5,20 +6,23 @@
|
|
|
5
6
|
[](https://github.com/tolongames/scribelog/actions/workflows/node.js.yml)
|
|
6
7
|
<!-- Add other badges if you have them (e.g., coverage) -->
|
|
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,
|
|
9
|
+
**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, automatic error catching, and printf-style interpolation, aiming for a great developer experience.
|
|
9
10
|
|
|
10
11
|
---
|
|
11
12
|
|
|
12
13
|
## ✨ Key Features
|
|
13
14
|
|
|
14
15
|
* **Standard Logging Levels:** Uses familiar levels (`error`, `warn`, `info`, `http`, `verbose`, `debug`, `silly`).
|
|
15
|
-
* **Highly Flexible Formatting:** Combine powerful formatters (`simple`, `json`, `timestamp`, `metadata`, `errors`, etc.) using a composable API (`format.combine`). Customize timestamps, include/exclude metadata, and more.
|
|
16
|
+
* **Highly Flexible Formatting:** Combine powerful formatters (`simple`, `json`, `timestamp`, `metadata`, `errors`, `splat`, etc.) using a composable API (`format.combine`). Customize timestamps, include/exclude metadata, and more.
|
|
17
|
+
* **Printf-Style Logging:** Use `printf`-like placeholders (`%s`, `%d`, `%j`) for easy message interpolation.
|
|
16
18
|
* **Console Color Support:** Automatic, readable colorization for the `simple` format in TTY environments.
|
|
17
|
-
* **Multiple Transports:** Log to different destinations.
|
|
19
|
+
* **Multiple Transports:** Log to different destinations. Built-in `ConsoleTransport` and `FileTransport` with rotation options.
|
|
18
20
|
* **Child Loggers:** Easily create contextual loggers (`logger.child({...})`) that inherit settings but add specific metadata (like `requestId`).
|
|
19
21
|
* **Automatic Error Handling:** Optionally catch and log `uncaughtException` and `unhandledRejection` events, including stack traces.
|
|
20
22
|
* **TypeScript First:** Written entirely in TypeScript for type safety and excellent editor autocompletion.
|
|
21
23
|
|
|
24
|
+
**Explore all features in the [Full Documentation](./DOCUMENTATION.md)!** ⬅
|
|
25
|
+
|
|
22
26
|
---
|
|
23
27
|
|
|
24
28
|
## 📦 Installation
|
|
@@ -45,47 +49,51 @@ import { createLogger, format, transports } from 'scribelog';
|
|
|
45
49
|
// - Transport: Console
|
|
46
50
|
const logger = createLogger();
|
|
47
51
|
|
|
48
|
-
//
|
|
52
|
+
// Standard logging
|
|
49
53
|
logger.info('Application started successfully.');
|
|
50
|
-
logger.warn('Warning: Cache memory usage high.', { usage: '85%' }); //
|
|
51
|
-
|
|
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.
|
|
56
|
-
const dbError = new Error('Database connection timeout');
|
|
57
|
-
(dbError as any).code = 'DB_TIMEOUT'; // You can add custom properties to errors
|
|
58
|
-
logger.error('Database Error Occurred', { error: dbError });
|
|
54
|
+
logger.warn('Warning: Cache memory usage high.', { usage: '85%' }); // With metadata
|
|
59
55
|
|
|
60
|
-
|
|
56
|
+
// Printf-style formatting (using the default format's built-in splat())
|
|
57
|
+
const username = 'Alice';
|
|
58
|
+
const userId = 123;
|
|
59
|
+
logger.info('User %s (ID: %d) logged in.', username, userId);
|
|
61
60
|
|
|
62
|
-
//
|
|
63
|
-
|
|
61
|
+
// Correct way to log Errors (pass error object in metadata)
|
|
62
|
+
const dbError = new Error('Database connection timeout');
|
|
63
|
+
(dbError as any).code = 'DB_TIMEOUT'; // Add custom properties
|
|
64
|
+
logger.error('Database Error Occurred', { error: dbError }); // format.errors() will process this
|
|
64
65
|
|
|
65
|
-
//
|
|
66
|
-
const
|
|
67
|
-
level: 'debug', // Log
|
|
68
|
-
|
|
66
|
+
// Log to a file in JSON format
|
|
67
|
+
const fileLogger = createLogger({
|
|
68
|
+
level: 'debug', // Log more details to the file
|
|
69
|
+
transports: [
|
|
70
|
+
new transports.File({
|
|
71
|
+
filename: 'app-%DATE%.log', // Filename pattern (date-fns)
|
|
72
|
+
interval: '1d', // Rotate daily
|
|
73
|
+
path: './logs', // Store logs in a 'logs' subfolder
|
|
74
|
+
compress: 'gzip', // Compress rotated files
|
|
75
|
+
maxFiles: 7, // Keep 7 days of logs
|
|
76
|
+
format: format.defaultJsonFormat // Log as JSON to the file
|
|
77
|
+
})
|
|
78
|
+
]
|
|
69
79
|
});
|
|
70
80
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
// {"level":"debug","message":"Debugging operation X","timestamp":"...ISO_STRING...","operationId":"op-xyz"}
|
|
81
|
+
fileLogger.debug('Writing detailed debug log to file.', { data: { complex: true }});
|
|
82
|
+
fileLogger.info('User action logged to file.', { userId: 456 });
|
|
74
83
|
```
|
|
75
84
|
|
|
76
|
-
**Example Output (Default Simple Format with Colors):**
|
|
85
|
+
**Example Console Output (Default Simple Format with Colors):**
|
|
77
86
|
|
|
78
87
|
```bash
|
|
79
|
-
# (
|
|
88
|
+
# (Timestamps gray, Levels colored, Metadata inspected)
|
|
80
89
|
2024-05-01T10:00:00.123Z [INFO]: Application started successfully.
|
|
81
90
|
2024-05-01T10:00:01.456Z [WARN]: Warning: Cache memory usage high. { usage: '85%' }
|
|
91
|
+
2024-05-01T10:00:01.890Z [INFO]: User Alice (ID: 123) logged in.
|
|
82
92
|
2024-05-01T10:00:02.789Z [ERROR]: Database connection timeout { exception: true, eventType: undefined, errorName: 'Error', code: 'DB_TIMEOUT' }
|
|
83
93
|
Error: Database connection timeout
|
|
84
94
|
at <anonymous>:10:17
|
|
85
95
|
... (stack trace) ...
|
|
86
|
-
2024-05-01T10:00:03.111Z [INFO]: Operation completed { user: 'admin', durationMs: 120 }
|
|
87
96
|
```
|
|
88
|
-
*(Note: `eventType` is undefined here because the error wasn't logged via `handleExceptions`/`handleRejections`)*
|
|
89
97
|
|
|
90
98
|
---
|
|
91
99
|
|
|
@@ -105,180 +113,182 @@ Create and configure your logger using `createLogger(options?: LoggerOptions)`.
|
|
|
105
113
|
| `handleRejections` | `boolean` | `false` | Catch and log `unhandledRejection` events. |
|
|
106
114
|
| `exitOnError` | `boolean` | `true` | If handling exceptions/rejections, exit process (`process.exit(1)`) after logging. |
|
|
107
115
|
|
|
108
|
-
**Example:
|
|
116
|
+
**Example: Advanced Configuration**
|
|
109
117
|
|
|
110
118
|
```ts
|
|
111
|
-
import { createLogger, format, transports } from 'scribelog';
|
|
119
|
+
import { createLogger, format, transports, LogLevel } from 'scribelog';
|
|
112
120
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
121
|
+
// Helper function to safely get log level from environment
|
|
122
|
+
function getLogLevel(): LogLevel { /* ... (implementation from previous example) ... */ }
|
|
123
|
+
|
|
124
|
+
const advancedLogger = createLogger({
|
|
125
|
+
level: getLogLevel(),
|
|
126
|
+
format: format.combine( // Custom format pipeline
|
|
127
|
+
format.errors({ stack: true }),
|
|
128
|
+
format.splat(), // Apply splat formatting early
|
|
129
|
+
format.timestamp({ format: 'isoDateTime' }), // Use date-fns named format
|
|
130
|
+
format.level(),
|
|
131
|
+
format.message(),
|
|
132
|
+
format.metadata({ alias: 'context' }), // Nest metadata
|
|
133
|
+
format.json() // Output as JSON
|
|
134
|
+
),
|
|
116
135
|
transports: [
|
|
136
|
+
// Log info and above to console with simple format
|
|
117
137
|
new transports.Console({
|
|
118
|
-
|
|
138
|
+
level: 'info',
|
|
139
|
+
format: format.defaultSimpleFormat // Override main format
|
|
119
140
|
}),
|
|
120
|
-
//
|
|
141
|
+
// Log everything to a rotating file
|
|
142
|
+
new transports.File({
|
|
143
|
+
filename: '/var/log/my-app/app.log',
|
|
144
|
+
level: 'debug', // Log everything to file
|
|
145
|
+
// format: // Inherits the JSON format from the logger
|
|
146
|
+
size: '10M', // Rotate after 10 MB
|
|
147
|
+
maxFiles: 5, // Keep 5 rotated files
|
|
148
|
+
compress: 'gzip'
|
|
149
|
+
})
|
|
121
150
|
],
|
|
122
151
|
defaultMeta: {
|
|
123
|
-
service: '
|
|
152
|
+
service: 'advanced-service',
|
|
124
153
|
pid: process.pid,
|
|
125
|
-
// You can add more static metadata here
|
|
126
154
|
},
|
|
127
|
-
handleExceptions: true,
|
|
128
|
-
handleRejections: true,
|
|
129
|
-
|
|
155
|
+
handleExceptions: true,
|
|
156
|
+
handleRejections: true,
|
|
157
|
+
exitOnError: false // Don't exit automatically
|
|
130
158
|
});
|
|
131
159
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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');
|
|
160
|
+
advancedLogger.info('Advanced logger ready.');
|
|
161
|
+
advancedLogger.debug('This goes only to the file transport as JSON.');
|
|
162
|
+
advancedLogger.error('An error occurred!', { error: new Error("Config read failed"), critical: true });
|
|
143
163
|
```
|
|
144
164
|
|
|
145
165
|
---
|
|
146
166
|
|
|
147
167
|
## 📊 Logging Levels
|
|
148
168
|
|
|
149
|
-
|
|
169
|
+
(Content is the same as before - list of levels and explanation)
|
|
150
170
|
|
|
151
171
|
```text
|
|
152
172
|
error: 0, warn: 1, info: 2, http: 3, verbose: 4, debug: 5, silly: 6
|
|
153
173
|
```
|
|
154
|
-
|
|
155
|
-
Setting the `level` option filters messages *at or above* the specified severity. `level: 'info'` logs `info`, `warn`, and `error`. `level: 'debug'` logs everything.
|
|
156
|
-
|
|
157
174
|
---
|
|
158
175
|
|
|
159
176
|
## 🎨 Formatting
|
|
160
177
|
|
|
161
|
-
Formatters transform the log `info` object
|
|
178
|
+
Formatters transform the log `info` object. Chain them using `format.combine(...)`. The order matters!
|
|
162
179
|
|
|
163
180
|
**How it Works:**
|
|
164
|
-
`
|
|
181
|
+
`log(msg, ...args)` -> Creates `LogInfo { message, splat?, ... }` -> Passes to `format` -> `combine` applies chain -> Result passed to `transport.log()`.
|
|
165
182
|
|
|
166
183
|
### Available Formatters
|
|
167
184
|
|
|
168
|
-
* **`format.timestamp(options?)`**: Adds/formats a timestamp.
|
|
169
|
-
* `alias?: string
|
|
170
|
-
* `format?: string | ((date: Date) => string)
|
|
171
|
-
```ts
|
|
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...' }
|
|
174
|
-
```
|
|
185
|
+
* **`format.timestamp(options?)`**: Adds/formats a timestamp (default: ISO).
|
|
186
|
+
* `alias?: string` (default: `'timestamp'`)
|
|
187
|
+
* `format?: string | ((date: Date) => string)` (`date-fns` format or function).
|
|
175
188
|
* **`format.level(options?)`**: Adds the log level string.
|
|
176
|
-
* `alias?: string
|
|
177
|
-
* **`format.message(options?)`**: Adds the log message string.
|
|
178
|
-
* `alias?: string
|
|
179
|
-
* **`format.
|
|
180
|
-
|
|
181
|
-
*
|
|
182
|
-
|
|
183
|
-
* `
|
|
184
|
-
*
|
|
185
|
-
|
|
186
|
-
*
|
|
187
|
-
|
|
189
|
+
* `alias?: string` (default: `'level'`).
|
|
190
|
+
* **`format.message(options?)`**: Adds the log message string (after potential `splat` formatting).
|
|
191
|
+
* `alias?: string` (default: `'message'`).
|
|
192
|
+
* **`format.splat()`**: Interpolates the `message` string using `util.format` and arguments found in `info.splat`. Place **after** `errors()` but **before** `message()` and `metadata()`.
|
|
193
|
+
* **`format.errors(options?)`**: Extracts info from an `Error` object (expected at `info.error`). Adds `errorName`, `stack?`, etc. Place **early** in the chain.
|
|
194
|
+
* `stack?: boolean` (default: `true`).
|
|
195
|
+
* **`format.metadata(options?)`**: Gathers remaining properties. Excludes standard fields (`level`, `message`, `timestamp`, etc.) and error fields.
|
|
196
|
+
* `alias?: string`: Nest metadata under this key.
|
|
197
|
+
* `exclude?: string[]`: Additional keys to exclude.
|
|
198
|
+
* **`format.json(options?)`**: **Terminal.** Serializes `info` to JSON.
|
|
199
|
+
* `space?: string | number`: Pretty-print spaces.
|
|
200
|
+
* **`format.simple(options?)`**: **Terminal.** Creates a human-readable string (colored if TTY). Includes `timestamp`, `level`, `message`, `{ metadata }`, and `stack` (new line).
|
|
201
|
+
* `colors?: boolean`: Force colors (default: auto-detect).
|
|
188
202
|
|
|
189
203
|
### Combining Formatters (`format.combine`)
|
|
190
204
|
|
|
191
|
-
The order matters! Formatters run sequentially. Terminal formatters (`json`, `simple`) should be last.
|
|
192
|
-
|
|
193
205
|
```ts
|
|
194
206
|
import { createLogger, format } from 'scribelog';
|
|
195
207
|
|
|
196
|
-
// Example:
|
|
197
|
-
const
|
|
198
|
-
|
|
199
|
-
format.
|
|
208
|
+
// Example: Simple format with printf-style interpolation first
|
|
209
|
+
const printfSimpleFormat = format.combine(
|
|
210
|
+
format.splat(), // Apply interpolation first
|
|
211
|
+
format.errors({ stack: false }),
|
|
212
|
+
format.timestamp({ format: 'HH:mm:ss' }),
|
|
200
213
|
format.level(),
|
|
201
|
-
format.message(),
|
|
202
|
-
|
|
203
|
-
format.simple()
|
|
204
|
-
);
|
|
205
|
-
const minimalLogger = createLogger({ format: minimalFormat });
|
|
206
|
-
minimalLogger.info('Minimal log', { extra: 'this is ignored'});
|
|
207
|
-
// Output: 10:45:00.123 [INFO]: Minimal log
|
|
208
|
-
|
|
209
|
-
// Example: JSON output with specific fields and nested metadata
|
|
210
|
-
const customJsonFormat = format.combine(
|
|
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
|
|
214
|
+
format.message(), // Will use the result from splat()
|
|
215
|
+
format.metadata(),
|
|
216
|
+
format.simple()
|
|
217
217
|
);
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
// Output:
|
|
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}}}
|
|
218
|
+
const printfLogger = createLogger({ format: printfSimpleFormat });
|
|
219
|
+
printfLogger.info('User %s logged in (ID: %d)', 'Bob', 42, { ip: '127.0.0.1' });
|
|
220
|
+
// Output: 11:22:33 [INFO]: User Bob logged in (ID: 42) { ip: '127.0.0.1' }
|
|
226
221
|
```
|
|
227
222
|
|
|
228
223
|
### Predefined Formats
|
|
229
224
|
|
|
230
|
-
* `format.defaultSimpleFormat`:
|
|
231
|
-
* `format.defaultJsonFormat`:
|
|
225
|
+
* `format.defaultSimpleFormat`: `combine(errors(stack), splat(), timestamp(), level(), message(), metadata(), simple())`. **Default for `createLogger`.**
|
|
226
|
+
* `format.defaultJsonFormat`: `combine(errors(stack), splat(), timestamp(), level(), message(), metadata(), json())`.
|
|
232
227
|
|
|
233
228
|
---
|
|
234
229
|
|
|
235
230
|
## 📤 Transports
|
|
236
231
|
|
|
237
|
-
Define log destinations.
|
|
232
|
+
Define log destinations.
|
|
238
233
|
|
|
239
234
|
### `transports.Console(options?: ConsoleTransportOptions)`
|
|
240
235
|
|
|
241
|
-
Logs to `process.stdout`
|
|
236
|
+
Logs to `process.stdout` / `process.stderr`.
|
|
242
237
|
|
|
243
|
-
* `level?: string`:
|
|
244
|
-
* `format?: LogFormat`:
|
|
245
|
-
* `useStdErrLevels?: string[]`:
|
|
238
|
+
* `level?: string`: Transport-specific minimum level.
|
|
239
|
+
* `format?: LogFormat`: Transport-specific format.
|
|
240
|
+
* `useStdErrLevels?: string[]`: Levels to log to `stderr` (default: `['error']`).
|
|
246
241
|
|
|
247
|
-
|
|
242
|
+
### `transports.File(options: FileTransportOptions)`
|
|
243
|
+
|
|
244
|
+
Logs to a rotating file using [`rotating-file-stream`](https://github.com/iccicci/rotating-file-stream).
|
|
245
|
+
|
|
246
|
+
* `filename: string`: Path/name of the log file (required). Can include date patterns like `%DATE%`.
|
|
247
|
+
* `level?: string`: Transport-specific minimum level.
|
|
248
|
+
* `format?: LogFormat`: Transport-specific format (defaults to `format.defaultJsonFormat`).
|
|
249
|
+
* `size?: string`: Max file size before rotation (e.g., `'10M'`).
|
|
250
|
+
* `interval?: string`: Rotation interval (e.g., `'1d'`, `'2h'`).
|
|
251
|
+
* `path?: string`: Directory for rotated/archived files.
|
|
252
|
+
* `compress?: string | boolean`: Compress rotated files (`'gzip'` or `true`).
|
|
253
|
+
* `maxFiles?: number`: Max number of rotated files to keep.
|
|
254
|
+
* `maxSize?: string`: Max total size of all log files.
|
|
255
|
+
* `createPath?: boolean`: Create log directory if it doesn't exist (default: `true`).
|
|
256
|
+
* `fsWriteStreamOptions?: object`: Options passed to `fs.createWriteStream`.
|
|
257
|
+
* *(See `rotating-file-stream` docs for more options like `utc`, generators)*
|
|
258
|
+
|
|
259
|
+
**Example: Logging to Console and File**
|
|
248
260
|
|
|
249
261
|
```ts
|
|
250
262
|
import { createLogger, format, transports } from 'scribelog';
|
|
251
263
|
|
|
252
|
-
const
|
|
253
|
-
level: '
|
|
264
|
+
const fileAndConsoleLogger = createLogger({
|
|
265
|
+
level: 'debug',
|
|
254
266
|
transports: [
|
|
255
|
-
//
|
|
267
|
+
// Console for immediate feedback (info and above)
|
|
256
268
|
new transports.Console({
|
|
257
|
-
level: '
|
|
258
|
-
format: format.simple({ colors: true })
|
|
259
|
-
useStdErrLevels: [], // Nothing from here goes to stderr
|
|
269
|
+
level: 'info',
|
|
270
|
+
format: format.simple({ colors: true })
|
|
260
271
|
}),
|
|
261
|
-
//
|
|
262
|
-
new transports.
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
272
|
+
// File for detailed logs (debug and above, JSON)
|
|
273
|
+
new transports.File({
|
|
274
|
+
filename: 'app-debug.log',
|
|
275
|
+
level: 'debug',
|
|
276
|
+
format: format.defaultJsonFormat,
|
|
277
|
+
size: '5M', // Rotate every 5MB
|
|
278
|
+
maxFiles: 3
|
|
266
279
|
})
|
|
267
280
|
]
|
|
268
281
|
});
|
|
269
282
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
logger.debug('Should not appear'); // Filtered out by logger's level ('info')
|
|
283
|
+
fileAndConsoleLogger.debug('Detailed info only in file');
|
|
284
|
+
fileAndConsoleLogger.info('General info in console and file');
|
|
285
|
+
fileAndConsoleLogger.error('Error in console and file', { error: new Error('Failure') });
|
|
274
286
|
```
|
|
275
287
|
|
|
276
288
|
---
|
|
277
289
|
|
|
278
290
|
## 🌱 Child Loggers
|
|
279
291
|
|
|
280
|
-
Create contextual loggers using `logger.child(defaultMeta)`. They inherit settings but automatically add the specified metadata.
|
|
281
|
-
|
|
282
292
|
```ts
|
|
283
293
|
import { createLogger } from 'scribelog';
|
|
284
294
|
|
|
@@ -337,12 +347,208 @@ The logger adds `{ exception: true, eventType: '...', ...errorDetails }` to the
|
|
|
337
347
|
|
|
338
348
|
---
|
|
339
349
|
|
|
350
|
+
## 💻 Showcase
|
|
351
|
+
|
|
352
|
+
You can run this script to see a demonstration of various Scribelog features in action.
|
|
353
|
+
|
|
354
|
+
<details>
|
|
355
|
+
<summary>Click to show/hide showcase.ts code</summary>
|
|
356
|
+
|
|
357
|
+
```ts
|
|
358
|
+
// showcase.ts
|
|
359
|
+
// Import everything needed from scribelog
|
|
360
|
+
import {
|
|
361
|
+
createLogger,
|
|
362
|
+
format, // Object containing formatters
|
|
363
|
+
transports, // Object containing transports
|
|
364
|
+
Logger, // Logger interface type
|
|
365
|
+
LogLevel, // Log level type ('info', 'debug', etc.)
|
|
366
|
+
LogFormat, // Formatter function type
|
|
367
|
+
Transport, // Transport interface type
|
|
368
|
+
LoggerOptions // Configuration options type
|
|
369
|
+
} from 'scribelog'; // Import from your published package
|
|
370
|
+
// Import 'process' for PID access
|
|
371
|
+
import process from 'process';
|
|
372
|
+
// Import 'crypto' for generating unique IDs
|
|
373
|
+
import crypto from 'crypto';
|
|
374
|
+
// Import 'date-fns' for custom date formatting (used in one example)
|
|
375
|
+
import { format as formatDate } from 'date-fns';
|
|
376
|
+
// Import chalk to demonstrate color control (optional for user)
|
|
377
|
+
import chalk from 'chalk';
|
|
378
|
+
|
|
379
|
+
// --- MAIN DEMO FUNCTION ---
|
|
380
|
+
async function runShowcase() {
|
|
381
|
+
console.log('\n===========================================');
|
|
382
|
+
console.log('🚀 Scribelog Showcase - All Features Demo 🚀');
|
|
383
|
+
console.log('===========================================\n');
|
|
384
|
+
|
|
385
|
+
// === 1. Basic Configuration & Levels ===
|
|
386
|
+
console.log('--- 1. Basic Configuration & Levels ---');
|
|
387
|
+
const logger1 = createLogger({ level: 'debug' });
|
|
388
|
+
logger1.info('Logger 1 (level: debug, format: simple)');
|
|
389
|
+
logger1.warn('Warning from Logger 1');
|
|
390
|
+
logger1.debug('Debug message from Logger 1 (should appear)');
|
|
391
|
+
logger1.error('Error from Logger 1');
|
|
392
|
+
|
|
393
|
+
// === 2. Different Formats ===
|
|
394
|
+
console.log('\n--- 2. Different Formats ---');
|
|
395
|
+
|
|
396
|
+
// 2a. JSON Format
|
|
397
|
+
console.log('\n--- 2a. JSON Format ---');
|
|
398
|
+
const logger2a = createLogger({ format: format.defaultJsonFormat, level: 'info' });
|
|
399
|
+
logger2a.info('Log in JSON format.', { data: true, value: 123 });
|
|
400
|
+
const jsonError = new Error("JSON Formatted Error");
|
|
401
|
+
(jsonError as any).code = "E_JSON";
|
|
402
|
+
logger2a.error('An error occurred (JSON)', { error: jsonError, user: 'admin' });
|
|
403
|
+
|
|
404
|
+
// 2b. Custom Simple Format (Colored)
|
|
405
|
+
console.log('\n--- 2b. Custom Simple Format (Colored) ---');
|
|
406
|
+
const customSimpleFormat = format.combine(
|
|
407
|
+
format.timestamp({ format: 'HH:mm:ss' }),
|
|
408
|
+
format.level(),
|
|
409
|
+
format.splat(), // Apply splat formatting
|
|
410
|
+
format.message(),
|
|
411
|
+
format.metadata({ exclude: ['pid'] }),
|
|
412
|
+
format.errors({ stack: false }),
|
|
413
|
+
format.simple({ colors: true })
|
|
414
|
+
);
|
|
415
|
+
const logger2b = createLogger({ format: customSimpleFormat, level: 'info' });
|
|
416
|
+
const originalChalkLevel2b = chalk.level;
|
|
417
|
+
chalk.level = 1; // Force colors
|
|
418
|
+
logger2b.info('Custom simple format for %s', 'user', { pid: 12345, user: 'demo' }); // Use splat
|
|
419
|
+
logger2b.error('Another error (custom simple)', { error: new Error("Simple format error")});
|
|
420
|
+
chalk.level = originalChalkLevel2b; // Restore
|
|
421
|
+
|
|
422
|
+
// 2c. Custom JSON Format with Aliases and Nesting
|
|
423
|
+
console.log('\n--- 2c. Custom JSON Format (Aliases & Nesting) ---');
|
|
424
|
+
const customJson = format.combine(
|
|
425
|
+
format.errors({ stack: true }), // Handle errors first
|
|
426
|
+
format.splat(), // Then splat
|
|
427
|
+
format.timestamp({ alias: '@timestamp' }),
|
|
428
|
+
format.level({ alias: 'severity' }),
|
|
429
|
+
format.message(),
|
|
430
|
+
format.metadata({ alias: 'details' }),
|
|
431
|
+
format.json()
|
|
432
|
+
);
|
|
433
|
+
const logger2c = createLogger({ format: customJson, level: 'info' });
|
|
434
|
+
logger2c.warn('Warn %s nested meta', 'with', { transactionId: 'xyz', status: 'WARN' }); // Use splat
|
|
435
|
+
const nestedError = new Error("Nested Error");
|
|
436
|
+
nestedError.stack = "Fake stack\n at place";
|
|
437
|
+
logger2c.error("Error with nested meta", { error: nestedError, code: 503 });
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
// === 3. Multiple Transports ===
|
|
441
|
+
console.log('\n--- 3. Multiple Transports ---');
|
|
442
|
+
const originalChalkLevel3 = chalk.level;
|
|
443
|
+
chalk.level = 0; // Disable colors for comparison
|
|
444
|
+
const logger3 = createLogger({
|
|
445
|
+
level: 'debug',
|
|
446
|
+
transports: [
|
|
447
|
+
new transports.Console({
|
|
448
|
+
level: 'info',
|
|
449
|
+
format: format.defaultSimpleFormat, // Contains splat()
|
|
450
|
+
useStdErrLevels: ['error']
|
|
451
|
+
}),
|
|
452
|
+
new transports.Console({
|
|
453
|
+
level: 'debug',
|
|
454
|
+
format: format.defaultJsonFormat, // Contains splat()
|
|
455
|
+
useStdErrLevels: ['warn', 'error']
|
|
456
|
+
})
|
|
457
|
+
]
|
|
458
|
+
});
|
|
459
|
+
logger3.debug('Debug log: %s', 'JSON only');
|
|
460
|
+
logger3.info('Info log: %s', 'Simple & JSON');
|
|
461
|
+
logger3.warn('Warn log: %s', 'Simple(stdout) & JSON(stderr)');
|
|
462
|
+
logger3.error('Error log: %s', 'Simple(stderr) & JSON(stderr)');
|
|
463
|
+
chalk.level = originalChalkLevel3; // Restore
|
|
464
|
+
|
|
465
|
+
// === 4. Loggery Potomne (child) ===
|
|
466
|
+
console.log('\n--- 4. Child Loggers ---');
|
|
467
|
+
const parentLogger = createLogger({
|
|
468
|
+
level: 'debug',
|
|
469
|
+
format: format.simple({ colors: false }), // Use simple, no colors
|
|
470
|
+
defaultMeta: { service: 'MainService' }
|
|
471
|
+
});
|
|
472
|
+
parentLogger.info('Parent log.');
|
|
473
|
+
const childLogger1 = parentLogger.child({ module: 'ModuleA' });
|
|
474
|
+
childLogger1.info('Child 1 log for action: %s', 'read'); // Use splat
|
|
475
|
+
const childLogger2 = childLogger1.child({ function: 'doWork', module: 'OverrideModule' });
|
|
476
|
+
childLogger2.debug('Child 2 log (debug).', { value: 42 });
|
|
477
|
+
|
|
478
|
+
// === 5. logEntry ===
|
|
479
|
+
console.log('\n--- 5. logEntry Method ---');
|
|
480
|
+
const entryLogger = createLogger({ level: 'http' });
|
|
481
|
+
entryLogger.logEntry({
|
|
482
|
+
level: 'http',
|
|
483
|
+
message: 'Manual %s entry with custom data %j', // Add splat placeholders
|
|
484
|
+
splat: ['log', { status: 201 }], // Provide splat data
|
|
485
|
+
method: 'POST', url: '/api/users', statusCode: 201,
|
|
486
|
+
});
|
|
487
|
+
entryLogger.logEntry({ level: 'info', message: 'This info entry will also show' });
|
|
488
|
+
|
|
489
|
+
// === 6. Obsługa wyjątków i odrzuceń (Symulacja) ===
|
|
490
|
+
// (Keep this section as in the previous example, it doesn't need _internalExit mock)
|
|
491
|
+
console.log('\n--- 6. Exception/Rejection Handling (Simulating real events) ---');
|
|
492
|
+
const handleErrorsAndExit = false;
|
|
493
|
+
let errorHandlingLogger: Logger | undefined = undefined;
|
|
494
|
+
|
|
495
|
+
console.log(`Creating logger with handleExceptions/Rejections, exitOnError: ${handleErrorsAndExit}`);
|
|
496
|
+
errorHandlingLogger = createLogger({
|
|
497
|
+
level: 'debug',
|
|
498
|
+
transports: [new transports.Console({ format: format.defaultSimpleFormat })],
|
|
499
|
+
handleExceptions: true,
|
|
500
|
+
handleRejections: true,
|
|
501
|
+
exitOnError: handleErrorsAndExit
|
|
502
|
+
});
|
|
503
|
+
errorHandlingLogger.info(`Error handlers active (exitOnError: ${handleErrorsAndExit}).`);
|
|
504
|
+
|
|
505
|
+
console.log("Simulating unhandled rejection (will be logged)...");
|
|
506
|
+
Promise.reject("Simulated rejection reason (handled by logger)");
|
|
507
|
+
|
|
508
|
+
console.log("Simulating uncaught exception in 100ms (will be logged)...");
|
|
509
|
+
const exceptionTimer = setTimeout(() => {
|
|
510
|
+
try { throw new Error("Simulated uncaught exception (handled by logger)"); }
|
|
511
|
+
catch (e) { process.emit('uncaughtException', e as Error); }
|
|
512
|
+
if (!handleErrorsAndExit && errorHandlingLogger && typeof (errorHandlingLogger as any).removeExceptionHandlers === 'function') {
|
|
513
|
+
(errorHandlingLogger as any).removeExceptionHandlers();
|
|
514
|
+
console.log("Error handlers removed for no-exit logger.");
|
|
515
|
+
}
|
|
516
|
+
console.log('\n--- Showcase Finished (Error Handlers Tested) ---');
|
|
517
|
+
}, 100);
|
|
518
|
+
|
|
519
|
+
if (!handleErrorsAndExit) {
|
|
520
|
+
await new Promise(resolve => setTimeout(resolve, 300));
|
|
521
|
+
} else {
|
|
522
|
+
// If we expect exit, keep the process running briefly
|
|
523
|
+
// This usually isn't needed as process.exit stops everything
|
|
524
|
+
// await new Promise(resolve => setTimeout(resolve, 1500));
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
} // End runShowcase
|
|
528
|
+
|
|
529
|
+
runShowcase().catch(e => {
|
|
530
|
+
console.error("!!! Unexpected error running showcase:", e);
|
|
531
|
+
});
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
</details>
|
|
535
|
+
|
|
536
|
+
If you have any questions about scribelog or would like to know more about how to use any of the features. You can write to me on discord:
|
|
537
|
+
theonlytolon
|
|
538
|
+
|
|
539
|
+
---
|
|
540
|
+
|
|
541
|
+
## 📘 Documentation
|
|
542
|
+
|
|
543
|
+
For detailed documentation covering all features, configuration options, and advanced examples, please see the [**Full Documentation**](./DOCUMENTATION.md).
|
|
544
|
+
|
|
545
|
+
---
|
|
546
|
+
|
|
340
547
|
## 📚 Future Work
|
|
341
548
|
|
|
342
|
-
*
|
|
343
|
-
*
|
|
344
|
-
*
|
|
345
|
-
* **Async Handling:** Better guarantees for transports finishing writes before `exitOnError`.
|
|
549
|
+
* More built-in formatters (e.g., customizable color themes).
|
|
550
|
+
* Ability to define custom logging levels.
|
|
551
|
+
* Improved handling of asynchronous operations in transports (especially for `exitOnError`).
|
|
346
552
|
|
|
347
553
|
---
|
|
348
554
|
|
package/dist/format.d.ts
CHANGED
|
@@ -14,6 +14,12 @@ interface ErrorsOptions {
|
|
|
14
14
|
stack?: boolean;
|
|
15
15
|
}
|
|
16
16
|
export declare const errors: (options?: ErrorsOptions) => LogFormat;
|
|
17
|
+
/**
|
|
18
|
+
* Formater: Interpoluje wiadomość w stylu printf używając argumentów z `info.splat`.
|
|
19
|
+
* Zastępuje oryginalne pole `info.message`, jeśli interpolacja jest możliwa.
|
|
20
|
+
* Powinien być umieszczony w `combine` PRZED `format.message()` i PRZED `format.metadata()`.
|
|
21
|
+
*/
|
|
22
|
+
export declare const splat: () => LogFormat;
|
|
17
23
|
export declare const metadata: (options?: {
|
|
18
24
|
alias?: string;
|
|
19
25
|
exclude?: string[];
|