hierarchical-area-logger 0.3.1 → 0.4.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 +182 -35
- package/dist/index.d.mts +145 -34
- package/dist/index.d.ts +145 -34
- package/dist/index.mjs +244 -92
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -4
package/README.md
CHANGED
|
@@ -4,11 +4,12 @@ A lightweight, structured logging utility for TypeScript applications. It allows
|
|
|
4
4
|
|
|
5
5
|
## 🚀 Features
|
|
6
6
|
|
|
7
|
-
- **Scoped Logging:** Group logs by logical "areas" (e.g., `db-layer`, `auth-
|
|
8
|
-
- **Traceability:**
|
|
7
|
+
- **Scoped Logging:** Group logs by logical "areas" (e.g., `db-layer`, `auth-instance`).
|
|
8
|
+
- **Traceability:** Event ID generation via a user-supplied factory and Parent Event ID mapping for distributed tracing.
|
|
9
9
|
- **Structured Payloads:** Log rich objects and Error instances without losing metadata.
|
|
10
|
-
- **Snapshot Dumping:** Retrieve the entire log state at any time for analysis or reporting.
|
|
11
|
-
- **
|
|
10
|
+
- **Snapshot Dumping:** Retrieve the entire log state at any time for analysis or reporting — nested or flattened.
|
|
11
|
+
- **Hydration:** Continue logging on top of existing log data (from another instance or a previous run).
|
|
12
|
+
- **Lightweight:** Zero runtime dependencies.
|
|
12
13
|
|
|
13
14
|
---
|
|
14
15
|
|
|
@@ -33,7 +34,8 @@ Instead of a flat stream of text, the logger categorizes logs into logical areas
|
|
|
33
34
|
import { createLogger } from 'hierarchical-area-logger';
|
|
34
35
|
|
|
35
36
|
const logger = createLogger({
|
|
36
|
-
details: {
|
|
37
|
+
details: { instance: 'payment-gateway' },
|
|
38
|
+
createEventId: () => crypto.randomUUID(),
|
|
37
39
|
});
|
|
38
40
|
|
|
39
41
|
const checkout = logger.getArea('checkout-process');
|
|
@@ -52,30 +54,43 @@ Track a request across your system by linking `eventId` and `parentEventId`.
|
|
|
52
54
|
|
|
53
55
|
```typescript
|
|
54
56
|
const logger = createLogger({
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
57
|
+
details: { instance: 'payment-gateway' },
|
|
58
|
+
createEventId: () => crypto.randomUUID(),
|
|
59
|
+
path: '/api/v1/user',
|
|
60
|
+
parentEventId: 'incoming-request-id-001',
|
|
58
61
|
});
|
|
59
62
|
|
|
60
|
-
console.log(logger.eventId); //
|
|
61
|
-
console.log(logger.parentEventId); // 'incoming-request-id-001'
|
|
62
|
-
|
|
63
|
+
console.log(logger.eventId); // ID created by createEventId
|
|
64
|
+
console.log(logger.retrieveRootPayload().parentEventId); // 'incoming-request-id-001'
|
|
63
65
|
```
|
|
64
66
|
|
|
65
|
-
### 3. Log
|
|
67
|
+
### 3. Log Hydration & State Management
|
|
66
68
|
|
|
67
|
-
You can
|
|
69
|
+
You can pre-populate a logger with existing log data — useful for consolidating logs from multiple micro-tasks or continuing a flow started elsewhere. Hydration accepts `LogData` or an array of `OrderedLogEvent`s; when the data carries a valid root payload, it is adopted and its `eventId` is reused.
|
|
68
70
|
|
|
69
71
|
```typescript
|
|
70
|
-
const mainLogger = createLogger({
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
72
|
+
const mainLogger = createLogger({
|
|
73
|
+
details: { instance: 'orchestrator' },
|
|
74
|
+
createEventId: () => crypto.randomUUID(),
|
|
75
|
+
populateLog: {
|
|
76
|
+
root: [
|
|
77
|
+
{
|
|
78
|
+
type: 'info',
|
|
79
|
+
message: 'Log started',
|
|
80
|
+
payload: {
|
|
81
|
+
eventId: 'upstream-event-001',
|
|
82
|
+
details: { instance: 'orchestrator' },
|
|
83
|
+
},
|
|
84
|
+
timestamp: Date.now(),
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
'worker-1': [
|
|
88
|
+
{ type: 'info', message: 'Task complete', timestamp: Date.now() },
|
|
89
|
+
],
|
|
90
|
+
},
|
|
91
|
+
});
|
|
77
92
|
|
|
78
|
-
mainLogger.
|
|
93
|
+
console.log(mainLogger.eventId); // 'upstream-event-001'
|
|
79
94
|
```
|
|
80
95
|
|
|
81
96
|
---
|
|
@@ -84,23 +99,155 @@ mainLogger.appendLogData(externalLogs);
|
|
|
84
99
|
|
|
85
100
|
### `createLogger(options)`
|
|
86
101
|
|
|
87
|
-
Factory function to initialize a new Logger instance.
|
|
102
|
+
Factory function to initialize a new `Logger` instance. `details` and `createEventId` are required; `details` can carry any additional fields, typed via the `Details`/`Logger` generic parameter.
|
|
103
|
+
|
|
104
|
+
| Option | Type | Required | Description |
|
|
105
|
+
| --------------------- | ------------------------------ | -------- | ------------------------------------------------------------------------------------------------------------ |
|
|
106
|
+
| `details` | `Details` | ✓ | Metadata about the instance or environment. `instance` is required. |
|
|
107
|
+
| `createEventId` | `(details: Details) => string` | ✓ | Factory that creates the event ID for this logging session. Called with `details`. |
|
|
108
|
+
| `path` | `string` | | The request path/route, stored in the root payload. |
|
|
109
|
+
| `method` | `Method` | | HTTP method (`get`, `post`, `put`, `delete`, `patch`, `head`, `options`, `trace`, `connect`). |
|
|
110
|
+
| `parentEventId` | `string` | | ID of the event that triggered this one, stored in the root payload. |
|
|
111
|
+
| `expectParentEventId` | `boolean` | | Logs an error entry when `parentEventId` is expected but missing. |
|
|
112
|
+
| `populateLog` | `LogData \| OrderedLogEvent[]` | | Pre-populate the logger with existing log data. A valid root payload is adopted and its `eventId` is reused. |
|
|
113
|
+
| `dumpOptions` | `DumpLoggerOptions` | | Default options applied by `dump()`/`dumpFlat()`; per-call options override them. |
|
|
114
|
+
|
|
115
|
+
### `Logger` instance
|
|
116
|
+
|
|
117
|
+
Properties:
|
|
118
|
+
|
|
119
|
+
- **`eventId: string`** — the unique ID of this logging session (created by `createEventId`, or adopted from populated log data).
|
|
120
|
+
|
|
121
|
+
#### `getArea(name)`
|
|
122
|
+
|
|
123
|
+
Returns a scoped logger for a specific area, creating it lazily on first use.
|
|
124
|
+
|
|
125
|
+
The returned area logger exposes:
|
|
126
|
+
|
|
127
|
+
- `.info(message, payload?)`
|
|
128
|
+
- `.warn(message, payload?)`
|
|
129
|
+
- `.error(message, payload? | Error)` — `Error` instances are converted to `{ message, name, stack }`
|
|
130
|
+
- `.log(message, payload?)`
|
|
131
|
+
- `.debug(message, payload?)`
|
|
132
|
+
|
|
133
|
+
#### `dump(options?)`
|
|
134
|
+
|
|
135
|
+
Returns the current log data as a `LogData` object (areas mapped to arrays of entries), derived from the internal flat list of ordered log events.
|
|
136
|
+
|
|
137
|
+
| Option | Type | Default | Description |
|
|
138
|
+
| ----------------- | ---------------- | ------- | -------------------------------------------------------------------------- |
|
|
139
|
+
| `omitRoot` | `boolean` | `false` | Excludes `root` holder events from the output. |
|
|
140
|
+
| `finalizeLog` | `boolean` | `true` | Appends a "Log completed" entry (with `totalDuration`) to the `root` area. |
|
|
141
|
+
| `excludeLogTypes` | `LogEntryType[]` | — | Entry types to remove from every area. No types are excluded by default. |
|
|
142
|
+
|
|
143
|
+
Areas without entries are omitted from the returned object. Dumps work on a copy of the internal log, so calling `dump()` repeatedly always returns the same result.
|
|
144
|
+
|
|
145
|
+
Options are merged in this order (later wins): built-in defaults → constructor `dumpOptions` → per-call options.
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
// Configure dump defaults once at construction:
|
|
149
|
+
const logger = createLogger({
|
|
150
|
+
details: { instance: 'payment-gateway' },
|
|
151
|
+
createEventId: () => crypto.randomUUID(),
|
|
152
|
+
dumpOptions: { excludeLogTypes: ['debug'], omitRoot: true },
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// Both calls honor the construction defaults; per-call options override them:
|
|
156
|
+
logger.dump(); // no root, no debug entries
|
|
157
|
+
logger.dump({ omitRoot: false }); // root included, still no debug entries
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
#### `dumpFlat(options?)`
|
|
161
|
+
|
|
162
|
+
Same options and processing as `dump`, but returns the internal flat `OrderedLogEvent[]` — the chronological list of events, each tagged with the name of its `holder` area — instead of grouping them into a `LogData` object.
|
|
163
|
+
|
|
164
|
+
#### `retrieveAreaEvents(area, excludeLogTypes?)`
|
|
165
|
+
|
|
166
|
+
Returns every `LogEntry` logged for the given area (an empty array when the area has never been used). When `excludeLogTypes` is provided, entries of the listed types are filtered out.
|
|
88
167
|
|
|
89
|
-
|
|
90
|
-
| --------------- | --------- | ------------------------------------------ |
|
|
91
|
-
| `details` | `Details` | Metadata about the service or environment. |
|
|
92
|
-
| `path` | `string` | (Optional) The execution path/route. |
|
|
93
|
-
| `parentEventId` | `string` | (Optional) ID of the triggering event. |
|
|
168
|
+
#### `retrieveRootPayload()`
|
|
94
169
|
|
|
95
|
-
|
|
170
|
+
Returns the root payload — the payload of the first entry in the `root` area (`path`, `method`, `eventId`, `parentEventId`, `details`).
|
|
171
|
+
|
|
172
|
+
### Exported Utilities
|
|
173
|
+
|
|
174
|
+
#### `prettyError(error)`
|
|
175
|
+
|
|
176
|
+
Converts an `Error` into a structured `{ message, name, stack }` object, with the stack trace cleaned up (no `Error: ` lines, no `file://` prefixes, truncated absolute paths).
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
import { prettyError } from 'hierarchical-area-logger';
|
|
180
|
+
|
|
181
|
+
const structured = prettyError(new Error('Boom'));
|
|
182
|
+
// { message: 'Boom', name: 'Error', stack: ['at ...', ...] }
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
#### `orderLogEvents(logData)`
|
|
186
|
+
|
|
187
|
+
Flattens a `LogData` object into a single array of events sorted by timestamp in ascending order. Each event is tagged with the name of its holder area.
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
import { orderLogEvents } from 'hierarchical-area-logger';
|
|
191
|
+
|
|
192
|
+
const logData = {
|
|
193
|
+
'db-layer': [{ type: 'info', message: 'Query complete', timestamp: 200 }],
|
|
194
|
+
root: [{ type: 'info', message: 'Log started', timestamp: 100 }],
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
const ordered = orderLogEvents(logData);
|
|
198
|
+
// [
|
|
199
|
+
// { holder: 'root', type: 'info', message: 'Log started', timestamp: 100 },
|
|
200
|
+
// { holder: 'db-layer', type: 'info', message: 'Query complete', timestamp: 200 },
|
|
201
|
+
// ]
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
#### `groupLogEvents(events)`
|
|
205
|
+
|
|
206
|
+
The inverse of `orderLogEvents`: groups an array of `OrderedLogEvent`s back into a `LogData` object keyed by the holder area of each event.
|
|
207
|
+
|
|
208
|
+
```typescript
|
|
209
|
+
import { groupLogEvents } from 'hierarchical-area-logger';
|
|
210
|
+
|
|
211
|
+
const logData = groupLogEvents([
|
|
212
|
+
{ holder: 'root', type: 'info', message: 'Log started', timestamp: 100 },
|
|
213
|
+
{
|
|
214
|
+
holder: 'db-layer',
|
|
215
|
+
type: 'info',
|
|
216
|
+
message: 'Query complete',
|
|
217
|
+
timestamp: 200,
|
|
218
|
+
},
|
|
219
|
+
]);
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Exported Guards
|
|
223
|
+
|
|
224
|
+
Type guards that narrow an `unknown` value to the library's log types by validating its structure.
|
|
225
|
+
|
|
226
|
+
- **`isLogData(data)`** — narrows to `LogData` (a non-array object whose values are arrays of valid log entries).
|
|
227
|
+
- **`isOrderedLogEvents(data)`** — narrows to `OrderedLogEvent[]` (log entries tagged with a string `holder`).
|
|
228
|
+
- **`hasRootPayload(log)`** — narrows to an `OrderedLogEvent[]` containing a valid root payload (a `root` holder event whose payload carries a string `eventId` and a `details` object with a string `instance`).
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
import {
|
|
232
|
+
isLogData,
|
|
233
|
+
isOrderedLogEvents,
|
|
234
|
+
hasRootPayload,
|
|
235
|
+
} from 'hierarchical-area-logger';
|
|
236
|
+
|
|
237
|
+
if (isLogData(value)) {
|
|
238
|
+
// value is LogData here
|
|
239
|
+
} else if (isOrderedLogEvents(value)) {
|
|
240
|
+
// value is OrderedLogEvent[] here
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (hasRootPayload(value)) {
|
|
244
|
+
// value is an OrderedLogEvent[] with a valid root payload here
|
|
245
|
+
}
|
|
246
|
+
```
|
|
96
247
|
|
|
97
|
-
|
|
98
|
-
- `.info(msg, payload?)`
|
|
99
|
-
- `.warn(msg, payload?)`
|
|
100
|
-
- `.error(msg, error?)`
|
|
248
|
+
### Exported Types
|
|
101
249
|
|
|
102
|
-
|
|
103
|
-
- **`appendLogData(data)`**: Manually injects log entries into the current instance.
|
|
250
|
+
`LogData`, `LogEntry`, `LogEntryType`, `Details`, `RootPayload`, `OrderedLogEvent`, `DumpLoggerOptions`.
|
|
104
251
|
|
|
105
252
|
---
|
|
106
253
|
|
|
@@ -117,4 +264,4 @@ npm run coverage
|
|
|
117
264
|
|
|
118
265
|
```
|
|
119
266
|
|
|
120
|
-
> **Note:**
|
|
267
|
+
> **Note:** Every logger seeds its `root` area with a "Log started" entry. With `finalizeLog` enabled (the default), `dump()` and `dumpFlat()` append a "Log completed" entry carrying the total request duration.
|
package/dist/index.d.mts
CHANGED
|
@@ -1,57 +1,168 @@
|
|
|
1
|
-
type Details = {
|
|
2
|
-
|
|
3
|
-
} &
|
|
1
|
+
type Details<AdditionalDetails extends Record<string, unknown> = Record<string, unknown>> = {
|
|
2
|
+
instance: string;
|
|
3
|
+
} & AdditionalDetails;
|
|
4
4
|
type Method = 'get' | 'post' | 'put' | 'delete' | 'patch' | 'head' | 'options' | 'trace' | 'connect';
|
|
5
5
|
type LogEntryType = 'info' | 'warn' | 'error' | 'log' | 'debug';
|
|
6
|
-
type
|
|
6
|
+
type LogData = Record<string, LogEntry[]>;
|
|
7
|
+
type OrderedLogEvent = LogEntry & {
|
|
8
|
+
holder: string;
|
|
9
|
+
};
|
|
10
|
+
interface LogEntry {
|
|
7
11
|
type: LogEntryType;
|
|
8
12
|
message: string;
|
|
9
13
|
payload?: object;
|
|
10
14
|
timestamp: number;
|
|
11
|
-
}
|
|
12
|
-
|
|
15
|
+
}
|
|
16
|
+
interface RootPayload<AdditionalDetails extends Record<string, unknown> = Record<string, unknown>> {
|
|
17
|
+
eventId: string;
|
|
18
|
+
details: Details<AdditionalDetails>;
|
|
13
19
|
path?: string;
|
|
14
20
|
method?: Method;
|
|
15
|
-
eventId: string;
|
|
16
21
|
parentEventId?: string;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
interface LoggerOptions {
|
|
21
|
-
details: Details;
|
|
22
|
-
path?: string;
|
|
22
|
+
}
|
|
23
|
+
interface LoggerOptions<AdditionalDetails extends Record<string, unknown> = Record<string, unknown>> {
|
|
24
|
+
populateLog?: LogData | OrderedLogEvent[];
|
|
23
25
|
parentEventId?: string;
|
|
24
|
-
|
|
26
|
+
expectParentEventId?: boolean;
|
|
27
|
+
details: Details<AdditionalDetails>;
|
|
28
|
+
path?: string;
|
|
25
29
|
method?: Method;
|
|
26
|
-
|
|
27
|
-
|
|
30
|
+
dumpOptions?: DumpLoggerOptions;
|
|
31
|
+
createEventId: (details: Details<AdditionalDetails>) => string;
|
|
32
|
+
}
|
|
33
|
+
interface DumpLoggerOptions {
|
|
34
|
+
omitRoot?: boolean;
|
|
35
|
+
finalizeLog?: boolean;
|
|
36
|
+
excludeLogTypes?: LogEntryType[];
|
|
37
|
+
}
|
|
38
|
+
interface GetAreaMethods {
|
|
39
|
+
info: (message: string, payload?: LogEntry['payload']) => void;
|
|
40
|
+
warn: (message: string, payload?: LogEntry['payload']) => void;
|
|
41
|
+
error: (message: string, payload?: LogEntry['payload'] | Error) => void;
|
|
42
|
+
log: (message: string, payload?: LogEntry['payload']) => void;
|
|
43
|
+
debug: (message: string, payload?: LogEntry['payload']) => void;
|
|
28
44
|
}
|
|
29
45
|
|
|
30
|
-
declare class Logger {
|
|
46
|
+
declare class Logger<AdditionalDetails extends Record<string, unknown> = Record<string, unknown>> {
|
|
47
|
+
/** Unique ID identifying this logging session (created via `createEventId` or adopted from populated log data). */
|
|
31
48
|
eventId: string;
|
|
32
49
|
private log;
|
|
33
|
-
|
|
34
|
-
private
|
|
35
|
-
|
|
36
|
-
|
|
50
|
+
private logPopulated;
|
|
51
|
+
private dumpOptions?;
|
|
52
|
+
/**
|
|
53
|
+
* Creates a new logger. Unless populated from `populateLog`, a `root`
|
|
54
|
+
* "Log started" event is seeded and `eventId` is created via
|
|
55
|
+
* `createEventId`. When `populateLog` carries a valid root payload, it is
|
|
56
|
+
* adopted instead and `eventId` is re-synced from it. `dumpOptions` act as
|
|
57
|
+
* defaults for `dump`/`dumpFlat` and can be overridden per call.
|
|
58
|
+
*/
|
|
59
|
+
constructor({ details, path, method, parentEventId, expectParentEventId, populateLog, dumpOptions, createEventId, }: LoggerOptions<AdditionalDetails>);
|
|
60
|
+
/**
|
|
61
|
+
* Adopts the populated log when it contains a valid root payload
|
|
62
|
+
* (re-syncing `eventId` from it). Populated data without a valid root
|
|
63
|
+
* payload is discarded in favor of the freshly created log.
|
|
64
|
+
*/
|
|
65
|
+
private finalizeHydratedLog;
|
|
66
|
+
/**
|
|
67
|
+
* Appends the closing "Log completed" event to the `root` holder,
|
|
68
|
+
* carrying the total duration since the "Log started" event.
|
|
69
|
+
*/
|
|
70
|
+
private finalizeLog;
|
|
71
|
+
/**
|
|
72
|
+
* Pushes a single ordered log event into the given area. `Error` payloads
|
|
73
|
+
* are converted into structured objects via `prettyError`.
|
|
74
|
+
*/
|
|
37
75
|
private addMessage;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
76
|
+
/**
|
|
77
|
+
* Extracts the root payload — the payload of the first event held by the
|
|
78
|
+
* `root` area.
|
|
79
|
+
*/
|
|
80
|
+
private getRootPayload;
|
|
81
|
+
/**
|
|
82
|
+
* Returns a scoped logging API for an area.
|
|
83
|
+
*
|
|
84
|
+
* The returned API exposes `info`, `warn`, `error`, `log` and `debug`;
|
|
85
|
+
* `error` also accepts `Error` instances as its payload.
|
|
86
|
+
*/
|
|
87
|
+
getArea(name: string): GetAreaMethods;
|
|
88
|
+
/**
|
|
89
|
+
* Applies the dump options to a copy of the internal ordered log events
|
|
90
|
+
* and returns the processed list. The internal log is never mutated.
|
|
91
|
+
*
|
|
92
|
+
* Options are merged in this order (later wins):
|
|
93
|
+
* `DEFAULT_PREPARE_DUMP_OPTIONS` → constructor `dumpOptions` → per-call
|
|
94
|
+
* `opts`.
|
|
95
|
+
*
|
|
96
|
+
* Defaults (see `DEFAULT_PREPARE_DUMP_OPTIONS`):
|
|
97
|
+
* - `omitRoot: false` — `root` holder events are kept in the output.
|
|
98
|
+
* - `finalizeLog: true` — a "Log completed" event is appended to the
|
|
99
|
+
* `root` holder.
|
|
100
|
+
* - `excludeLogTypes` — when provided, events of the listed types are
|
|
101
|
+
* removed; no types are excluded by default.
|
|
102
|
+
*/
|
|
103
|
+
private prepareLog;
|
|
104
|
+
/**
|
|
105
|
+
* Returns the current log data as a `LogData` object (areas mapped to
|
|
106
|
+
* arrays of entries) after applying the dump options. Areas without
|
|
107
|
+
* entries are omitted from the returned object.
|
|
108
|
+
*/
|
|
109
|
+
dump(opts?: DumpLoggerOptions): LogData;
|
|
110
|
+
/**
|
|
111
|
+
* Returns the current log data as an `OrderedLogEvent[]` — the flat,
|
|
112
|
+
* chronological list of events each tagged with the name of its holder
|
|
113
|
+
* area — after applying the same options as `dump`.
|
|
114
|
+
*/
|
|
115
|
+
dumpFlat(opts?: DumpLoggerOptions): OrderedLogEvent[];
|
|
116
|
+
/**
|
|
117
|
+
* Returns every entry logged for the given area (an empty array when the
|
|
118
|
+
* area has never been used). When `excludeLogTypes` is provided, entries
|
|
119
|
+
* of the listed types are filtered out.
|
|
120
|
+
*/
|
|
121
|
+
retrieveAreaEvents(area: string, excludeLogTypes?: LogEntryType[]): LogEntry[];
|
|
122
|
+
/**
|
|
123
|
+
* Returns the root payload — the payload of the first event held by the
|
|
124
|
+
* `root` area (`path`, `method`, `eventId`, `parentEventId`, `details`).
|
|
125
|
+
*/
|
|
126
|
+
retrieveRootPayload(): RootPayload;
|
|
48
127
|
}
|
|
49
|
-
declare const createLogger: (options: LoggerOptions) => Logger
|
|
128
|
+
declare const createLogger: <AdditionalDetails extends Record<string, unknown> = Record<string, unknown>>(options: LoggerOptions<AdditionalDetails>) => Logger<AdditionalDetails>;
|
|
50
129
|
|
|
130
|
+
/**
|
|
131
|
+
* Converts an Error into a `{ message, name, stack }` object with the stack cleaned
|
|
132
|
+
* up by `prettyStack`.
|
|
133
|
+
*/
|
|
51
134
|
declare const prettyError: (err: Error) => {
|
|
52
135
|
message: string;
|
|
136
|
+
name: string;
|
|
53
137
|
stack: string[];
|
|
54
138
|
};
|
|
139
|
+
/**
|
|
140
|
+
* Flattens log data into a single array of events sorted by timestamp in
|
|
141
|
+
* ascending order, tagging each event with the name of its holder area.
|
|
142
|
+
*/
|
|
143
|
+
declare const orderLogEvents: (logData: LogData) => OrderedLogEvent[];
|
|
144
|
+
/**
|
|
145
|
+
* Groups ordered log events back into a `LogData` object keyed by the holder
|
|
146
|
+
* area of each event, preserving the relative order within each area.
|
|
147
|
+
*/
|
|
148
|
+
declare const groupLogEvents: (events: OrderedLogEvent[]) => LogData;
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Type guard: checks whether the given value is an ordered log event array
|
|
152
|
+
* containing a valid root payload — a `root` holder event whose payload
|
|
153
|
+
* carries a string `eventId` and a `details` object with a string `instance`.
|
|
154
|
+
*/
|
|
155
|
+
declare const hasRootPayload: (log: unknown) => log is OrderedLogEvent[];
|
|
156
|
+
/**
|
|
157
|
+
* Type guard: checks whether the given value is a valid `LogData` object (a
|
|
158
|
+
* non-array object whose values are arrays of log entries).
|
|
159
|
+
*/
|
|
160
|
+
declare const isLogData: (data: unknown) => data is LogData;
|
|
161
|
+
/**
|
|
162
|
+
* Type guard: checks whether the given value is a valid array of
|
|
163
|
+
* `OrderedLogEvent`s (log entries tagged with a `holder` area name).
|
|
164
|
+
*/
|
|
165
|
+
declare const isOrderedLogEvents: (data: unknown) => data is OrderedLogEvent[];
|
|
55
166
|
|
|
56
|
-
export { Logger, createLogger, prettyError };
|
|
57
|
-
export type { Details, LogData, LogEntry, LogEntryType, RootPayload };
|
|
167
|
+
export { Logger, createLogger, groupLogEvents, hasRootPayload, isLogData, isOrderedLogEvents, orderLogEvents, prettyError };
|
|
168
|
+
export type { Details, DumpLoggerOptions, LogData, LogEntry, LogEntryType, OrderedLogEvent, RootPayload };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,57 +1,168 @@
|
|
|
1
|
-
type Details = {
|
|
2
|
-
|
|
3
|
-
} &
|
|
1
|
+
type Details<AdditionalDetails extends Record<string, unknown> = Record<string, unknown>> = {
|
|
2
|
+
instance: string;
|
|
3
|
+
} & AdditionalDetails;
|
|
4
4
|
type Method = 'get' | 'post' | 'put' | 'delete' | 'patch' | 'head' | 'options' | 'trace' | 'connect';
|
|
5
5
|
type LogEntryType = 'info' | 'warn' | 'error' | 'log' | 'debug';
|
|
6
|
-
type
|
|
6
|
+
type LogData = Record<string, LogEntry[]>;
|
|
7
|
+
type OrderedLogEvent = LogEntry & {
|
|
8
|
+
holder: string;
|
|
9
|
+
};
|
|
10
|
+
interface LogEntry {
|
|
7
11
|
type: LogEntryType;
|
|
8
12
|
message: string;
|
|
9
13
|
payload?: object;
|
|
10
14
|
timestamp: number;
|
|
11
|
-
}
|
|
12
|
-
|
|
15
|
+
}
|
|
16
|
+
interface RootPayload<AdditionalDetails extends Record<string, unknown> = Record<string, unknown>> {
|
|
17
|
+
eventId: string;
|
|
18
|
+
details: Details<AdditionalDetails>;
|
|
13
19
|
path?: string;
|
|
14
20
|
method?: Method;
|
|
15
|
-
eventId: string;
|
|
16
21
|
parentEventId?: string;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
interface LoggerOptions {
|
|
21
|
-
details: Details;
|
|
22
|
-
path?: string;
|
|
22
|
+
}
|
|
23
|
+
interface LoggerOptions<AdditionalDetails extends Record<string, unknown> = Record<string, unknown>> {
|
|
24
|
+
populateLog?: LogData | OrderedLogEvent[];
|
|
23
25
|
parentEventId?: string;
|
|
24
|
-
|
|
26
|
+
expectParentEventId?: boolean;
|
|
27
|
+
details: Details<AdditionalDetails>;
|
|
28
|
+
path?: string;
|
|
25
29
|
method?: Method;
|
|
26
|
-
|
|
27
|
-
|
|
30
|
+
dumpOptions?: DumpLoggerOptions;
|
|
31
|
+
createEventId: (details: Details<AdditionalDetails>) => string;
|
|
32
|
+
}
|
|
33
|
+
interface DumpLoggerOptions {
|
|
34
|
+
omitRoot?: boolean;
|
|
35
|
+
finalizeLog?: boolean;
|
|
36
|
+
excludeLogTypes?: LogEntryType[];
|
|
37
|
+
}
|
|
38
|
+
interface GetAreaMethods {
|
|
39
|
+
info: (message: string, payload?: LogEntry['payload']) => void;
|
|
40
|
+
warn: (message: string, payload?: LogEntry['payload']) => void;
|
|
41
|
+
error: (message: string, payload?: LogEntry['payload'] | Error) => void;
|
|
42
|
+
log: (message: string, payload?: LogEntry['payload']) => void;
|
|
43
|
+
debug: (message: string, payload?: LogEntry['payload']) => void;
|
|
28
44
|
}
|
|
29
45
|
|
|
30
|
-
declare class Logger {
|
|
46
|
+
declare class Logger<AdditionalDetails extends Record<string, unknown> = Record<string, unknown>> {
|
|
47
|
+
/** Unique ID identifying this logging session (created via `createEventId` or adopted from populated log data). */
|
|
31
48
|
eventId: string;
|
|
32
49
|
private log;
|
|
33
|
-
|
|
34
|
-
private
|
|
35
|
-
|
|
36
|
-
|
|
50
|
+
private logPopulated;
|
|
51
|
+
private dumpOptions?;
|
|
52
|
+
/**
|
|
53
|
+
* Creates a new logger. Unless populated from `populateLog`, a `root`
|
|
54
|
+
* "Log started" event is seeded and `eventId` is created via
|
|
55
|
+
* `createEventId`. When `populateLog` carries a valid root payload, it is
|
|
56
|
+
* adopted instead and `eventId` is re-synced from it. `dumpOptions` act as
|
|
57
|
+
* defaults for `dump`/`dumpFlat` and can be overridden per call.
|
|
58
|
+
*/
|
|
59
|
+
constructor({ details, path, method, parentEventId, expectParentEventId, populateLog, dumpOptions, createEventId, }: LoggerOptions<AdditionalDetails>);
|
|
60
|
+
/**
|
|
61
|
+
* Adopts the populated log when it contains a valid root payload
|
|
62
|
+
* (re-syncing `eventId` from it). Populated data without a valid root
|
|
63
|
+
* payload is discarded in favor of the freshly created log.
|
|
64
|
+
*/
|
|
65
|
+
private finalizeHydratedLog;
|
|
66
|
+
/**
|
|
67
|
+
* Appends the closing "Log completed" event to the `root` holder,
|
|
68
|
+
* carrying the total duration since the "Log started" event.
|
|
69
|
+
*/
|
|
70
|
+
private finalizeLog;
|
|
71
|
+
/**
|
|
72
|
+
* Pushes a single ordered log event into the given area. `Error` payloads
|
|
73
|
+
* are converted into structured objects via `prettyError`.
|
|
74
|
+
*/
|
|
37
75
|
private addMessage;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
76
|
+
/**
|
|
77
|
+
* Extracts the root payload — the payload of the first event held by the
|
|
78
|
+
* `root` area.
|
|
79
|
+
*/
|
|
80
|
+
private getRootPayload;
|
|
81
|
+
/**
|
|
82
|
+
* Returns a scoped logging API for an area.
|
|
83
|
+
*
|
|
84
|
+
* The returned API exposes `info`, `warn`, `error`, `log` and `debug`;
|
|
85
|
+
* `error` also accepts `Error` instances as its payload.
|
|
86
|
+
*/
|
|
87
|
+
getArea(name: string): GetAreaMethods;
|
|
88
|
+
/**
|
|
89
|
+
* Applies the dump options to a copy of the internal ordered log events
|
|
90
|
+
* and returns the processed list. The internal log is never mutated.
|
|
91
|
+
*
|
|
92
|
+
* Options are merged in this order (later wins):
|
|
93
|
+
* `DEFAULT_PREPARE_DUMP_OPTIONS` → constructor `dumpOptions` → per-call
|
|
94
|
+
* `opts`.
|
|
95
|
+
*
|
|
96
|
+
* Defaults (see `DEFAULT_PREPARE_DUMP_OPTIONS`):
|
|
97
|
+
* - `omitRoot: false` — `root` holder events are kept in the output.
|
|
98
|
+
* - `finalizeLog: true` — a "Log completed" event is appended to the
|
|
99
|
+
* `root` holder.
|
|
100
|
+
* - `excludeLogTypes` — when provided, events of the listed types are
|
|
101
|
+
* removed; no types are excluded by default.
|
|
102
|
+
*/
|
|
103
|
+
private prepareLog;
|
|
104
|
+
/**
|
|
105
|
+
* Returns the current log data as a `LogData` object (areas mapped to
|
|
106
|
+
* arrays of entries) after applying the dump options. Areas without
|
|
107
|
+
* entries are omitted from the returned object.
|
|
108
|
+
*/
|
|
109
|
+
dump(opts?: DumpLoggerOptions): LogData;
|
|
110
|
+
/**
|
|
111
|
+
* Returns the current log data as an `OrderedLogEvent[]` — the flat,
|
|
112
|
+
* chronological list of events each tagged with the name of its holder
|
|
113
|
+
* area — after applying the same options as `dump`.
|
|
114
|
+
*/
|
|
115
|
+
dumpFlat(opts?: DumpLoggerOptions): OrderedLogEvent[];
|
|
116
|
+
/**
|
|
117
|
+
* Returns every entry logged for the given area (an empty array when the
|
|
118
|
+
* area has never been used). When `excludeLogTypes` is provided, entries
|
|
119
|
+
* of the listed types are filtered out.
|
|
120
|
+
*/
|
|
121
|
+
retrieveAreaEvents(area: string, excludeLogTypes?: LogEntryType[]): LogEntry[];
|
|
122
|
+
/**
|
|
123
|
+
* Returns the root payload — the payload of the first event held by the
|
|
124
|
+
* `root` area (`path`, `method`, `eventId`, `parentEventId`, `details`).
|
|
125
|
+
*/
|
|
126
|
+
retrieveRootPayload(): RootPayload;
|
|
48
127
|
}
|
|
49
|
-
declare const createLogger: (options: LoggerOptions) => Logger
|
|
128
|
+
declare const createLogger: <AdditionalDetails extends Record<string, unknown> = Record<string, unknown>>(options: LoggerOptions<AdditionalDetails>) => Logger<AdditionalDetails>;
|
|
50
129
|
|
|
130
|
+
/**
|
|
131
|
+
* Converts an Error into a `{ message, name, stack }` object with the stack cleaned
|
|
132
|
+
* up by `prettyStack`.
|
|
133
|
+
*/
|
|
51
134
|
declare const prettyError: (err: Error) => {
|
|
52
135
|
message: string;
|
|
136
|
+
name: string;
|
|
53
137
|
stack: string[];
|
|
54
138
|
};
|
|
139
|
+
/**
|
|
140
|
+
* Flattens log data into a single array of events sorted by timestamp in
|
|
141
|
+
* ascending order, tagging each event with the name of its holder area.
|
|
142
|
+
*/
|
|
143
|
+
declare const orderLogEvents: (logData: LogData) => OrderedLogEvent[];
|
|
144
|
+
/**
|
|
145
|
+
* Groups ordered log events back into a `LogData` object keyed by the holder
|
|
146
|
+
* area of each event, preserving the relative order within each area.
|
|
147
|
+
*/
|
|
148
|
+
declare const groupLogEvents: (events: OrderedLogEvent[]) => LogData;
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Type guard: checks whether the given value is an ordered log event array
|
|
152
|
+
* containing a valid root payload — a `root` holder event whose payload
|
|
153
|
+
* carries a string `eventId` and a `details` object with a string `instance`.
|
|
154
|
+
*/
|
|
155
|
+
declare const hasRootPayload: (log: unknown) => log is OrderedLogEvent[];
|
|
156
|
+
/**
|
|
157
|
+
* Type guard: checks whether the given value is a valid `LogData` object (a
|
|
158
|
+
* non-array object whose values are arrays of log entries).
|
|
159
|
+
*/
|
|
160
|
+
declare const isLogData: (data: unknown) => data is LogData;
|
|
161
|
+
/**
|
|
162
|
+
* Type guard: checks whether the given value is a valid array of
|
|
163
|
+
* `OrderedLogEvent`s (log entries tagged with a `holder` area name).
|
|
164
|
+
*/
|
|
165
|
+
declare const isOrderedLogEvents: (data: unknown) => data is OrderedLogEvent[];
|
|
55
166
|
|
|
56
|
-
export { Logger, createLogger, prettyError };
|
|
57
|
-
export type { Details, LogData, LogEntry, LogEntryType, RootPayload };
|
|
167
|
+
export { Logger, createLogger, groupLogEvents, hasRootPayload, isLogData, isOrderedLogEvents, orderLogEvents, prettyError };
|
|
168
|
+
export type { Details, DumpLoggerOptions, LogData, LogEntry, LogEntryType, OrderedLogEvent, RootPayload };
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { init } from '@paralleldrive/cuid2';
|
|
2
|
-
|
|
3
1
|
const prettyStack = (stack) => {
|
|
4
2
|
if (!stack) return [];
|
|
5
3
|
let toReplace = "";
|
|
@@ -13,7 +11,8 @@ const prettyStack = (stack) => {
|
|
|
13
11
|
const prettyError = (err) => {
|
|
14
12
|
const stack = prettyStack(err.stack);
|
|
15
13
|
const message = err.message;
|
|
16
|
-
|
|
14
|
+
const name = err.name;
|
|
15
|
+
return { message, name, stack };
|
|
17
16
|
};
|
|
18
17
|
const createRootLogEntry = ({
|
|
19
18
|
path,
|
|
@@ -21,128 +20,281 @@ const createRootLogEntry = ({
|
|
|
21
20
|
details,
|
|
22
21
|
eventId,
|
|
23
22
|
parentEventId,
|
|
24
|
-
|
|
23
|
+
expectParentEventId
|
|
25
24
|
}) => {
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
rootLogEntry.root.push({
|
|
25
|
+
const rootLogEvents = [
|
|
26
|
+
{
|
|
27
|
+
holder: "root",
|
|
28
|
+
type: "info",
|
|
29
|
+
message: "Log started",
|
|
30
|
+
payload: {
|
|
31
|
+
eventId,
|
|
32
|
+
details,
|
|
33
|
+
...path && { path },
|
|
34
|
+
...method && { method },
|
|
35
|
+
...parentEventId && { parentEventId }
|
|
36
|
+
},
|
|
37
|
+
timestamp: Date.now()
|
|
38
|
+
}
|
|
39
|
+
];
|
|
40
|
+
if (expectParentEventId && !parentEventId) {
|
|
41
|
+
rootLogEvents.push({
|
|
42
|
+
holder: "root",
|
|
45
43
|
type: "error",
|
|
46
|
-
message: "Parent event ID expected but not
|
|
44
|
+
message: "Parent event ID expected but not provided",
|
|
47
45
|
timestamp: Date.now()
|
|
48
46
|
});
|
|
49
47
|
}
|
|
50
|
-
return
|
|
48
|
+
return rootLogEvents;
|
|
51
49
|
};
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
50
|
+
const excludeLogEntryTypes = (events, excludeLogTypes) => {
|
|
51
|
+
if (!excludeLogTypes || excludeLogTypes.length === 0) return events;
|
|
52
|
+
return events.filter((event) => !excludeLogTypes.includes(event.type));
|
|
53
|
+
};
|
|
54
|
+
const orderLogEvents = (logData) => {
|
|
55
|
+
return Object.entries(logData).flatMap(
|
|
56
|
+
([holder, events]) => events.map((event) => ({
|
|
57
|
+
holder,
|
|
58
|
+
...event
|
|
59
|
+
}))
|
|
60
|
+
).sort((a, b) => a.timestamp - b.timestamp);
|
|
61
|
+
};
|
|
62
|
+
const groupLogEvents = (events) => {
|
|
63
|
+
const logData = {};
|
|
64
|
+
for (const { holder, ...entry } of events) {
|
|
65
|
+
if (!logData[holder]) {
|
|
66
|
+
logData[holder] = [];
|
|
57
67
|
}
|
|
68
|
+
logData[holder].push(entry);
|
|
58
69
|
}
|
|
59
|
-
return
|
|
70
|
+
return logData;
|
|
60
71
|
};
|
|
61
|
-
|
|
62
|
-
|
|
72
|
+
|
|
73
|
+
const isLogEntryType = (value) => {
|
|
74
|
+
return value === "info" || value === "warn" || value === "error" || value === "log" || value === "debug";
|
|
63
75
|
};
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
76
|
+
const isLogEntry = (value) => {
|
|
77
|
+
if (typeof value !== "object" || value === null) return false;
|
|
78
|
+
const entry = value;
|
|
79
|
+
return isLogEntryType(entry.type) && typeof entry.message === "string" && typeof entry.timestamp === "number" && (entry.payload === void 0 || typeof entry.payload === "object" && entry.payload !== null);
|
|
80
|
+
};
|
|
81
|
+
const hasRootPayload = (log) => {
|
|
82
|
+
if (!isOrderedLogEvents(log)) return false;
|
|
83
|
+
const rootEvent = log.find((event) => event.holder === "root");
|
|
84
|
+
if (!rootEvent) return false;
|
|
85
|
+
const rootPayload = rootEvent.payload;
|
|
86
|
+
if (typeof rootPayload !== "object" || rootPayload === null) return false;
|
|
87
|
+
if (typeof rootPayload.eventId !== "string") return false;
|
|
88
|
+
const details = rootPayload.details;
|
|
89
|
+
if (typeof details !== "object" || details === null) return false;
|
|
90
|
+
return typeof details.instance === "string";
|
|
91
|
+
};
|
|
92
|
+
const isLogData = (data) => {
|
|
93
|
+
if (typeof data !== "object" || data === null || Array.isArray(data)) {
|
|
94
|
+
return false;
|
|
70
95
|
}
|
|
71
|
-
return
|
|
96
|
+
return Object.values(data).every(
|
|
97
|
+
(area) => Array.isArray(area) && area.every((entry) => isLogEntry(entry))
|
|
98
|
+
);
|
|
99
|
+
};
|
|
100
|
+
const isOrderedLogEvents = (data) => {
|
|
101
|
+
if (!Array.isArray(data)) return false;
|
|
102
|
+
return data.every((event) => {
|
|
103
|
+
if (typeof event !== "object" || event === null) return false;
|
|
104
|
+
const ordered = event;
|
|
105
|
+
return typeof ordered.holder === "string" && isLogEntry(event);
|
|
106
|
+
});
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const DEFAULT_PREPARE_DUMP_OPTIONS = {
|
|
110
|
+
omitRoot: false,
|
|
111
|
+
finalizeLog: true
|
|
72
112
|
};
|
|
73
113
|
|
|
74
114
|
class Logger {
|
|
115
|
+
/** Unique ID identifying this logging session (created via `createEventId` or adopted from populated log data). */
|
|
75
116
|
eventId;
|
|
76
117
|
log;
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
118
|
+
logPopulated;
|
|
119
|
+
dumpOptions;
|
|
120
|
+
/**
|
|
121
|
+
* Creates a new logger. Unless populated from `populateLog`, a `root`
|
|
122
|
+
* "Log started" event is seeded and `eventId` is created via
|
|
123
|
+
* `createEventId`. When `populateLog` carries a valid root payload, it is
|
|
124
|
+
* adopted instead and `eventId` is re-synced from it. `dumpOptions` act as
|
|
125
|
+
* defaults for `dump`/`dumpFlat` and can be overridden per call.
|
|
126
|
+
*/
|
|
127
|
+
constructor({
|
|
128
|
+
details,
|
|
129
|
+
path,
|
|
130
|
+
method,
|
|
131
|
+
parentEventId,
|
|
132
|
+
expectParentEventId,
|
|
133
|
+
populateLog,
|
|
134
|
+
dumpOptions,
|
|
135
|
+
createEventId
|
|
136
|
+
}) {
|
|
137
|
+
this.dumpOptions = dumpOptions;
|
|
138
|
+
this.logPopulated = false;
|
|
139
|
+
this.eventId = "unknown";
|
|
140
|
+
this.log = [];
|
|
141
|
+
if (populateLog) {
|
|
142
|
+
if (isOrderedLogEvents(populateLog)) {
|
|
143
|
+
this.log = this.finalizeHydratedLog(populateLog);
|
|
144
|
+
} else if (isLogData(populateLog)) {
|
|
145
|
+
this.log = this.finalizeHydratedLog(orderLogEvents(populateLog));
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
if (!this.logPopulated) {
|
|
149
|
+
this.eventId = createEventId(details);
|
|
150
|
+
this.log = createRootLogEntry({
|
|
151
|
+
eventId: this.eventId,
|
|
152
|
+
path,
|
|
153
|
+
method,
|
|
154
|
+
details,
|
|
155
|
+
parentEventId,
|
|
156
|
+
expectParentEventId
|
|
157
|
+
});
|
|
158
|
+
}
|
|
91
159
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
160
|
+
/**
|
|
161
|
+
* Adopts the populated log when it contains a valid root payload
|
|
162
|
+
* (re-syncing `eventId` from it). Populated data without a valid root
|
|
163
|
+
* payload is discarded in favor of the freshly created log.
|
|
164
|
+
*/
|
|
165
|
+
finalizeHydratedLog(log) {
|
|
166
|
+
if (hasRootPayload(log)) {
|
|
167
|
+
const { eventId } = this.getRootPayload(log);
|
|
168
|
+
this.eventId = eventId;
|
|
169
|
+
this.logPopulated = true;
|
|
170
|
+
return log;
|
|
171
|
+
}
|
|
172
|
+
return this.log;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Appends the closing "Log completed" event to the `root` holder,
|
|
176
|
+
* carrying the total duration since the "Log started" event.
|
|
177
|
+
*/
|
|
178
|
+
finalizeLog(log) {
|
|
179
|
+
const rootEvent = log.find((event) => event.holder === "root");
|
|
180
|
+
log.push({
|
|
181
|
+
holder: "root",
|
|
182
|
+
type: "info",
|
|
183
|
+
message: "Log completed",
|
|
184
|
+
payload: {
|
|
185
|
+
totalDuration: Date.now() - rootEvent.timestamp
|
|
186
|
+
},
|
|
187
|
+
timestamp: Date.now()
|
|
95
188
|
});
|
|
189
|
+
return log;
|
|
96
190
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
191
|
+
/**
|
|
192
|
+
* Pushes a single ordered log event into the given area. `Error` payloads
|
|
193
|
+
* are converted into structured objects via `prettyError`.
|
|
194
|
+
*/
|
|
195
|
+
addMessage(name, type, message, rawPayload) {
|
|
196
|
+
const payload = rawPayload instanceof Error ? prettyError(rawPayload) : rawPayload;
|
|
197
|
+
this.log.push({
|
|
198
|
+
holder: name,
|
|
100
199
|
type,
|
|
101
200
|
message,
|
|
102
|
-
payload
|
|
201
|
+
payload,
|
|
103
202
|
timestamp: Date.now()
|
|
104
203
|
});
|
|
105
204
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
205
|
+
/**
|
|
206
|
+
* Extracts the root payload — the payload of the first event held by the
|
|
207
|
+
* `root` area.
|
|
208
|
+
*/
|
|
209
|
+
getRootPayload(log) {
|
|
210
|
+
return log.find((event) => event.holder === "root").payload;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Returns a scoped logging API for an area.
|
|
214
|
+
*
|
|
215
|
+
* The returned API exposes `info`, `warn`, `error`, `log` and `debug`;
|
|
216
|
+
* `error` also accepts `Error` instances as its payload.
|
|
217
|
+
*/
|
|
218
|
+
getArea(name) {
|
|
111
219
|
return {
|
|
112
|
-
info: (message, payload) =>
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
},
|
|
118
|
-
error: (message, payload) => {
|
|
119
|
-
this.addMessage(name, "error", message, payload);
|
|
120
|
-
},
|
|
121
|
-
log: (message, payload) => {
|
|
122
|
-
this.addMessage(name, "log", message, payload);
|
|
123
|
-
},
|
|
124
|
-
debug: (message, payload) => {
|
|
125
|
-
this.addMessage(name, "debug", message, payload);
|
|
126
|
-
}
|
|
220
|
+
info: (message, payload) => this.addMessage(name, "info", message, payload),
|
|
221
|
+
warn: (message, payload) => this.addMessage(name, "warn", message, payload),
|
|
222
|
+
error: (message, payload) => this.addMessage(name, "error", message, payload),
|
|
223
|
+
log: (message, payload) => this.addMessage(name, "log", message, payload),
|
|
224
|
+
debug: (message, payload) => this.addMessage(name, "debug", message, payload)
|
|
127
225
|
};
|
|
128
226
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
227
|
+
/**
|
|
228
|
+
* Applies the dump options to a copy of the internal ordered log events
|
|
229
|
+
* and returns the processed list. The internal log is never mutated.
|
|
230
|
+
*
|
|
231
|
+
* Options are merged in this order (later wins):
|
|
232
|
+
* `DEFAULT_PREPARE_DUMP_OPTIONS` → constructor `dumpOptions` → per-call
|
|
233
|
+
* `opts`.
|
|
234
|
+
*
|
|
235
|
+
* Defaults (see `DEFAULT_PREPARE_DUMP_OPTIONS`):
|
|
236
|
+
* - `omitRoot: false` — `root` holder events are kept in the output.
|
|
237
|
+
* - `finalizeLog: true` — a "Log completed" event is appended to the
|
|
238
|
+
* `root` holder.
|
|
239
|
+
* - `excludeLogTypes` — when provided, events of the listed types are
|
|
240
|
+
* removed; no types are excluded by default.
|
|
241
|
+
*/
|
|
242
|
+
prepareLog(opts) {
|
|
243
|
+
const { omitRoot, finalizeLog, excludeLogTypes } = {
|
|
244
|
+
...DEFAULT_PREPARE_DUMP_OPTIONS,
|
|
245
|
+
...this.dumpOptions,
|
|
246
|
+
...opts
|
|
247
|
+
};
|
|
248
|
+
let localLog = [...this.log];
|
|
249
|
+
if (omitRoot) {
|
|
250
|
+
localLog = localLog.filter((event) => event.holder !== "root");
|
|
251
|
+
}
|
|
252
|
+
if (finalizeLog && !omitRoot) {
|
|
253
|
+
localLog = this.finalizeLog(localLog);
|
|
254
|
+
}
|
|
255
|
+
if (excludeLogTypes) {
|
|
256
|
+
localLog = excludeLogEntryTypes(localLog, excludeLogTypes);
|
|
257
|
+
}
|
|
258
|
+
return localLog;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Returns the current log data as a `LogData` object (areas mapped to
|
|
262
|
+
* arrays of entries) after applying the dump options. Areas without
|
|
263
|
+
* entries are omitted from the returned object.
|
|
264
|
+
*/
|
|
265
|
+
dump(opts) {
|
|
266
|
+
return groupLogEvents(this.prepareLog(opts));
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Returns the current log data as an `OrderedLogEvent[]` — the flat,
|
|
270
|
+
* chronological list of events each tagged with the name of its holder
|
|
271
|
+
* area — after applying the same options as `dump`.
|
|
272
|
+
*/
|
|
273
|
+
dumpFlat(opts) {
|
|
274
|
+
return this.prepareLog(opts);
|
|
133
275
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
276
|
+
/**
|
|
277
|
+
* Returns every entry logged for the given area (an empty array when the
|
|
278
|
+
* area has never been used). When `excludeLogTypes` is provided, entries
|
|
279
|
+
* of the listed types are filtered out.
|
|
280
|
+
*/
|
|
281
|
+
retrieveAreaEvents(area, excludeLogTypes) {
|
|
282
|
+
const areaEvents = this.log.filter((event) => event.holder === area);
|
|
283
|
+
return excludeLogEntryTypes(areaEvents, excludeLogTypes).map(
|
|
284
|
+
({ holder: _holder, ...entry }) => entry
|
|
285
|
+
);
|
|
137
286
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
287
|
+
/**
|
|
288
|
+
* Returns the root payload — the payload of the first event held by the
|
|
289
|
+
* `root` area (`path`, `method`, `eventId`, `parentEventId`, `details`).
|
|
290
|
+
*/
|
|
291
|
+
retrieveRootPayload() {
|
|
292
|
+
return this.getRootPayload(this.log);
|
|
141
293
|
}
|
|
142
294
|
}
|
|
143
295
|
const createLogger = (options) => {
|
|
144
296
|
return new Logger(options);
|
|
145
297
|
};
|
|
146
298
|
|
|
147
|
-
export { Logger, createLogger, prettyError };
|
|
299
|
+
export { Logger, createLogger, groupLogEvents, hasRootPayload, isLogData, isOrderedLogEvents, orderLogEvents, prettyError };
|
|
148
300
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":["../src/utils.ts","../src/Logger.ts"],"sourcesContent":["import {\n CreateRootLogEntryOptions,\n LogData,\n LogEntry,\n RootPayload,\n} from './types';\n\nexport const prettyStack = (stack?: string): string[] => {\n if (!stack) return [];\n let toReplace = '';\n\n const regex = /file:\\/\\/\\/(.*)(\\.wrangler|node_modules)\\/.*\\)/gm;\n const m = regex.exec(stack);\n\n if (m && m.length > 1) {\n toReplace = m[1];\n }\n\n return stack\n .split('\\n')\n .map((line) => line.trim())\n .filter((line) => !line.startsWith('Error: '))\n .map((line) => line.replace(toReplace, ''))\n .map((line) => line.replace('file://', ''));\n};\n\nexport const prettyError = (err: Error) => {\n const stack = prettyStack(err.stack);\n const message = err.message;\n return { message, stack };\n};\n\nexport const createRootLogEntry = ({\n path,\n method,\n details,\n eventId,\n parentEventId,\n withParentEventId,\n}: CreateRootLogEntryOptions): LogData => {\n const url = new URL(`http://example.com${path ?? '/'}`);\n\n const rootLogEntry: LogData = {\n root: [\n {\n type: 'info',\n message: 'Request received',\n payload: {\n path: `${url.pathname}${url.search}`,\n method,\n details,\n eventId,\n ...(parentEventId && { parentEventId }),\n } as RootPayload,\n timestamp: Date.now(),\n },\n ],\n };\n\n if (withParentEventId && !parentEventId) {\n rootLogEntry.root.push({\n type: 'error',\n message: 'Parent event ID expected but not found',\n timestamp: Date.now(),\n });\n }\n\n return rootLogEntry;\n};\n\nexport const removeEmptyAreas = (logData: LogData) => {\n const newLogData: LogData = {};\n for (const [key, value] of Object.entries(logData)) {\n if (value.length > 0) {\n newLogData[key] = value;\n }\n }\n return newLogData;\n};\n\nexport const excludeDebugLogs = (logEntries: LogEntry[]) => {\n return logEntries.filter((entry) => entry.type !== 'debug');\n};\n\nexport const processProductionLogData = (logData: LogData) => {\n const newLogData: LogData = {};\n for (const [key, value] of Object.entries(logData)) {\n if (key !== 'root') {\n newLogData[key] = excludeDebugLogs(value);\n }\n }\n return removeEmptyAreas(newLogData);\n};\n","import { init } from '@paralleldrive/cuid2';\nimport {\n createRootLogEntry,\n prettyError,\n processProductionLogData,\n} from './utils';\nimport type { LogData, LoggerOptions, LogEntry, LogEntryType } from './types';\n\nexport class Logger {\n public eventId: string;\n private log: LogData;\n public parentEventId?: string;\n private defaultArea: string;\n\n constructor(options: LoggerOptions) {\n this.parentEventId = options.parentEventId;\n this.eventId =\n options.overrideEventId ||\n init({ fingerprint: options.details.service })();\n this.defaultArea = options.defaultArea || 'defaultArea';\n\n this.log = createRootLogEntry({\n path: options.path || '/',\n method: options.method,\n details: options.details,\n eventId: this.eventId,\n parentEventId: options.parentEventId,\n withParentEventId: options.withParentEventId,\n });\n }\n\n private finalizeRootMessage() {\n this.addMessage('root', 'info', 'Request completed', {\n totalDuration: Date.now() - this.log.root[0].timestamp,\n });\n }\n\n private addMessage(\n name: string,\n type: LogEntryType,\n message: string,\n payload?: LogEntry['payload'] | Error\n ) {\n const finalPayload =\n payload instanceof Error ? prettyError(payload) : payload;\n\n this.log[name]!.push({\n type,\n message,\n payload: finalPayload,\n timestamp: Date.now(),\n });\n }\n\n // Area function that returns area-specific logger methods\n public getArea(name = this.defaultArea) {\n if (!this.log[name]) {\n this.log[name] = [];\n }\n\n return {\n info: (message: string, payload?: LogEntry['payload']) => {\n this.addMessage(name, 'info', message, payload);\n },\n warn: (message: string, payload?: LogEntry['payload']) => {\n this.addMessage(name, 'warn', message, payload);\n },\n error: (message: string, payload?: LogEntry['payload'] | Error) => {\n this.addMessage(name, 'error', message, payload);\n },\n log: (message: string, payload?: LogEntry['payload']) => {\n this.addMessage(name, 'log', message, payload);\n },\n debug: (message: string, payload?: LogEntry['payload']) => {\n this.addMessage(name, 'debug', message, payload);\n },\n };\n }\n\n // Public methods on main instance\n public dump(): LogData {\n this.finalizeRootMessage();\n return this.log;\n }\n\n public dumpProduction(): LogData {\n this.finalizeRootMessage();\n return processProductionLogData(this.log);\n }\n\n public appendLogData(logData: LogData): void {\n delete logData.root;\n this.log = { ...logData, ...this.log };\n }\n}\n\n// Factory function for convenience\nexport const createLogger = (options: LoggerOptions): Logger => {\n return new Logger(options);\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../src/utils.ts","../src/guards.ts","../src/constants.ts","../src/Logger.ts"],"sourcesContent":["import {\n CreateRootLogEntryOptions,\n LogData,\n LogEntryType,\n OrderedLogEvent,\n RootPayload,\n} from './types';\n\n/**\n * Cleans up an error stack trace: removes `Error: ` lines, trims whitespace,\n * strips `file://` prefixes, and truncates absolute paths up to `.wrangler/`\n * or `node_modules/`.\n */\nexport const prettyStack = (stack?: string): string[] => {\n if (!stack) return [];\n let toReplace = '';\n\n const regex = /file:\\/\\/\\/(.*)(\\.wrangler|node_modules)\\/.*\\)/gm;\n const m = regex.exec(stack);\n\n if (m && m.length > 1) {\n toReplace = m[1];\n }\n\n return stack\n .split('\\n')\n .map((line) => line.trim())\n .filter((line) => !line.startsWith('Error: '))\n .map((line) => line.replace(toReplace, ''))\n .map((line) => line.replace('file://', ''));\n};\n\n/**\n * Converts an Error into a `{ message, name, stack }` object with the stack cleaned\n * up by `prettyStack`.\n */\nexport const prettyError = (\n err: Error\n): {\n message: string;\n name: string;\n stack: string[];\n} => {\n const stack = prettyStack(err.stack);\n const message = err.message;\n const name = err.name;\n return { message, name, stack };\n};\n\n/**\n * Creates the initial ordered log events: a `root` \"Request received\" event.\n * When `expectParentEventId` is set but no `parentEventId` is provided, a\n * `root` error event is appended.\n */\nexport const createRootLogEntry = <\n AdditionalDetails extends Record<string, unknown> = Record<string, unknown>,\n>({\n path,\n method,\n details,\n eventId,\n parentEventId,\n expectParentEventId,\n}: CreateRootLogEntryOptions<AdditionalDetails>): OrderedLogEvent[] => {\n const rootLogEvents: OrderedLogEvent[] = [\n {\n holder: 'root',\n type: 'info',\n message: 'Log started',\n payload: {\n eventId,\n details,\n ...(path && { path }),\n ...(method && { method }),\n ...(parentEventId && { parentEventId }),\n } as RootPayload,\n timestamp: Date.now(),\n },\n ];\n\n if (expectParentEventId && !parentEventId) {\n rootLogEvents.push({\n holder: 'root',\n type: 'error',\n message: 'Parent event ID expected but not provided',\n timestamp: Date.now(),\n });\n }\n\n return rootLogEvents;\n};\n\n/**\n * Returns the given ordered log events without those whose type is listed in\n * `excludeLogTypes`. When no types are provided, the events are returned\n * unchanged.\n */\nexport const excludeLogEntryTypes = (\n events: OrderedLogEvent[],\n excludeLogTypes?: LogEntryType[]\n): OrderedLogEvent[] => {\n if (!excludeLogTypes || excludeLogTypes.length === 0) return events;\n return events.filter((event) => !excludeLogTypes.includes(event.type));\n};\n\n/**\n * Flattens log data into a single array of events sorted by timestamp in\n * ascending order, tagging each event with the name of its holder area.\n */\nexport const orderLogEvents = (logData: LogData): OrderedLogEvent[] => {\n return (\n Object.entries(logData)\n // 1. Flatten the object into a 1D array while mapping the holder name\n .flatMap(([holder, events]) =>\n events.map((event) => ({\n holder,\n ...event,\n }))\n )\n // 2. Sort the combined array by timestamp (ascending order)\n .sort((a, b) => a.timestamp - b.timestamp)\n );\n};\n\n/**\n * Groups ordered log events back into a `LogData` object keyed by the holder\n * area of each event, preserving the relative order within each area.\n */\nexport const groupLogEvents = (events: OrderedLogEvent[]): LogData => {\n const logData: LogData = {};\n for (const { holder, ...entry } of events) {\n if (!logData[holder]) {\n logData[holder] = [];\n }\n logData[holder].push(entry);\n }\n return logData;\n};\n","import type {\n Details,\n LogData,\n LogEntry,\n LogEntryType,\n OrderedLogEvent,\n RootPayload,\n} from './types';\n\nconst isLogEntryType = (value: unknown): value is LogEntryType => {\n return (\n value === 'info' ||\n value === 'warn' ||\n value === 'error' ||\n value === 'log' ||\n value === 'debug'\n );\n};\n\nconst isLogEntry = (value: unknown): value is LogEntry => {\n if (typeof value !== 'object' || value === null) return false;\n const entry = value as Record<string, unknown>;\n return (\n isLogEntryType(entry.type) &&\n typeof entry.message === 'string' &&\n typeof entry.timestamp === 'number' &&\n (entry.payload === undefined ||\n (typeof entry.payload === 'object' && entry.payload !== null))\n );\n};\n\n/**\n * Type guard: checks whether the given value is an ordered log event array\n * containing a valid root payload — a `root` holder event whose payload\n * carries a string `eventId` and a `details` object with a string `instance`.\n */\nexport const hasRootPayload = (log: unknown): log is OrderedLogEvent[] => {\n if (!isOrderedLogEvents(log)) return false;\n\n const rootEvent = log.find((event) => event.holder === 'root');\n if (!rootEvent) return false;\n\n const rootPayload = rootEvent.payload as RootPayload | undefined;\n if (typeof rootPayload !== 'object' || rootPayload === null) return false;\n\n if (typeof rootPayload.eventId !== 'string') return false;\n\n const details = rootPayload.details as Details | null;\n if (typeof details !== 'object' || details === null) return false;\n\n return typeof details.instance === 'string';\n};\n\n/**\n * Type guard: checks whether the given value is a valid `LogData` object (a\n * non-array object whose values are arrays of log entries).\n */\nexport const isLogData = (data: unknown): data is LogData => {\n if (typeof data !== 'object' || data === null || Array.isArray(data)) {\n return false;\n }\n return Object.values(data).every(\n (area) => Array.isArray(area) && area.every((entry) => isLogEntry(entry))\n );\n};\n\n/**\n * Type guard: checks whether the given value is a valid array of\n * `OrderedLogEvent`s (log entries tagged with a `holder` area name).\n */\nexport const isOrderedLogEvents = (\n data: unknown\n): data is OrderedLogEvent[] => {\n if (!Array.isArray(data)) return false;\n return data.every((event) => {\n if (typeof event !== 'object' || event === null) return false;\n const ordered = event as Record<string, unknown>;\n return typeof ordered.holder === 'string' && isLogEntry(event);\n });\n};\n","import type { DumpLoggerOptions } from './types';\n\n/**\n * Default options applied by `Logger#dump` / `Logger#dumpFlat`: keep the\n * `root` area and append the final \"Request completed\" entry. No log entry\n * types are excluded unless `excludeLogTypes` is passed explicitly.\n */\nexport const DEFAULT_PREPARE_DUMP_OPTIONS: DumpLoggerOptions = {\n omitRoot: false,\n finalizeLog: true,\n};\n","import {\n createRootLogEntry,\n excludeLogEntryTypes,\n groupLogEvents,\n orderLogEvents,\n prettyError,\n} from './utils';\nimport type {\n DumpLoggerOptions,\n GetAreaMethods,\n LogData,\n LogEntry,\n LogEntryType,\n LoggerOptions,\n OrderedLogEvent,\n RootPayload,\n} from './types';\nimport { hasRootPayload, isLogData, isOrderedLogEvents } from './guards';\nimport { DEFAULT_PREPARE_DUMP_OPTIONS } from './constants';\n\nexport class Logger<\n AdditionalDetails extends Record<string, unknown> = Record<string, unknown>,\n> {\n /** Unique ID identifying this logging session (created via `createEventId` or adopted from populated log data). */\n public eventId: string;\n private log: OrderedLogEvent[];\n private logPopulated: boolean;\n private dumpOptions?: DumpLoggerOptions;\n\n /**\n * Creates a new logger. Unless populated from `populateLog`, a `root`\n * \"Log started\" event is seeded and `eventId` is created via\n * `createEventId`. When `populateLog` carries a valid root payload, it is\n * adopted instead and `eventId` is re-synced from it. `dumpOptions` act as\n * defaults for `dump`/`dumpFlat` and can be overridden per call.\n */\n constructor({\n details,\n path,\n method,\n parentEventId,\n expectParentEventId,\n populateLog,\n dumpOptions,\n createEventId,\n }: LoggerOptions<AdditionalDetails>) {\n this.dumpOptions = dumpOptions;\n this.logPopulated = false;\n this.eventId = 'unknown';\n this.log = [];\n\n if (populateLog) {\n if (isOrderedLogEvents(populateLog)) {\n this.log = this.finalizeHydratedLog(populateLog);\n } else if (isLogData(populateLog)) {\n this.log = this.finalizeHydratedLog(orderLogEvents(populateLog));\n }\n }\n\n if (!this.logPopulated) {\n this.eventId = createEventId(details);\n\n this.log = createRootLogEntry<AdditionalDetails>({\n eventId: this.eventId,\n path,\n method,\n details,\n parentEventId,\n expectParentEventId,\n });\n }\n }\n\n /**\n * Adopts the populated log when it contains a valid root payload\n * (re-syncing `eventId` from it). Populated data without a valid root\n * payload is discarded in favor of the freshly created log.\n */\n private finalizeHydratedLog(log: OrderedLogEvent[]): OrderedLogEvent[] {\n if (hasRootPayload(log)) {\n const { eventId } = this.getRootPayload(log);\n this.eventId = eventId;\n this.logPopulated = true;\n return log;\n }\n return this.log;\n }\n\n /**\n * Appends the closing \"Log completed\" event to the `root` holder,\n * carrying the total duration since the \"Log started\" event.\n */\n private finalizeLog(log: OrderedLogEvent[]): OrderedLogEvent[] {\n // A logger always holds a `root` event after construction\n const rootEvent = log.find((event) => event.holder === 'root')!;\n\n log.push({\n holder: 'root',\n type: 'info',\n message: 'Log completed',\n payload: {\n totalDuration: Date.now() - rootEvent.timestamp,\n },\n timestamp: Date.now(),\n });\n return log;\n }\n\n /**\n * Pushes a single ordered log event into the given area. `Error` payloads\n * are converted into structured objects via `prettyError`.\n */\n private addMessage(\n name: string,\n type: LogEntryType,\n message: string,\n rawPayload?: LogEntry['payload'] | Error\n ): void {\n const payload =\n rawPayload instanceof Error ? prettyError(rawPayload) : rawPayload;\n\n this.log.push({\n holder: name,\n type,\n message,\n payload,\n timestamp: Date.now(),\n });\n }\n\n /**\n * Extracts the root payload — the payload of the first event held by the\n * `root` area.\n */\n private getRootPayload(log: OrderedLogEvent[]): RootPayload {\n return log.find((event) => event.holder === 'root')!.payload as RootPayload;\n }\n\n /**\n * Returns a scoped logging API for an area.\n *\n * The returned API exposes `info`, `warn`, `error`, `log` and `debug`;\n * `error` also accepts `Error` instances as its payload.\n */\n public getArea(name: string): GetAreaMethods {\n return {\n info: (message, payload) =>\n this.addMessage(name, 'info', message, payload),\n warn: (message, payload) =>\n this.addMessage(name, 'warn', message, payload),\n error: (message, payload) =>\n this.addMessage(name, 'error', message, payload),\n log: (message, payload) => this.addMessage(name, 'log', message, payload),\n debug: (message, payload) =>\n this.addMessage(name, 'debug', message, payload),\n };\n }\n\n /**\n * Applies the dump options to a copy of the internal ordered log events\n * and returns the processed list. The internal log is never mutated.\n *\n * Options are merged in this order (later wins):\n * `DEFAULT_PREPARE_DUMP_OPTIONS` → constructor `dumpOptions` → per-call\n * `opts`.\n *\n * Defaults (see `DEFAULT_PREPARE_DUMP_OPTIONS`):\n * - `omitRoot: false` — `root` holder events are kept in the output.\n * - `finalizeLog: true` — a \"Log completed\" event is appended to the\n * `root` holder.\n * - `excludeLogTypes` — when provided, events of the listed types are\n * removed; no types are excluded by default.\n */\n private prepareLog(opts?: DumpLoggerOptions): OrderedLogEvent[] {\n const { omitRoot, finalizeLog, excludeLogTypes } = {\n ...DEFAULT_PREPARE_DUMP_OPTIONS,\n ...this.dumpOptions,\n ...opts,\n };\n\n let localLog: OrderedLogEvent[] = [...this.log];\n\n if (omitRoot) {\n localLog = localLog.filter((event) => event.holder !== 'root');\n }\n\n if (finalizeLog && !omitRoot) {\n localLog = this.finalizeLog(localLog);\n }\n\n if (excludeLogTypes) {\n localLog = excludeLogEntryTypes(localLog, excludeLogTypes);\n }\n\n return localLog;\n }\n\n /**\n * Returns the current log data as a `LogData` object (areas mapped to\n * arrays of entries) after applying the dump options. Areas without\n * entries are omitted from the returned object.\n */\n public dump(opts?: DumpLoggerOptions): LogData {\n return groupLogEvents(this.prepareLog(opts));\n }\n\n /**\n * Returns the current log data as an `OrderedLogEvent[]` — the flat,\n * chronological list of events each tagged with the name of its holder\n * area — after applying the same options as `dump`.\n */\n public dumpFlat(opts?: DumpLoggerOptions): OrderedLogEvent[] {\n return this.prepareLog(opts);\n }\n\n /**\n * Returns every entry logged for the given area (an empty array when the\n * area has never been used). When `excludeLogTypes` is provided, entries\n * of the listed types are filtered out.\n */\n public retrieveAreaEvents(\n area: string,\n excludeLogTypes?: LogEntryType[]\n ): LogEntry[] {\n const areaEvents = this.log.filter((event) => event.holder === area);\n\n return excludeLogEntryTypes(areaEvents, excludeLogTypes).map(\n ({ holder: _holder, ...entry }) => entry\n );\n }\n\n /**\n * Returns the root payload — the payload of the first event held by the\n * `root` area (`path`, `method`, `eventId`, `parentEventId`, `details`).\n */\n public retrieveRootPayload(): RootPayload {\n return this.getRootPayload(this.log);\n }\n}\n\n// Factory function for convenience\nexport const createLogger = <\n AdditionalDetails extends Record<string, unknown> = Record<string, unknown>,\n>(\n options: LoggerOptions<AdditionalDetails>\n): Logger<AdditionalDetails> => {\n return new Logger(options);\n};\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hierarchical-area-logger",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.mjs",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -58,9 +58,6 @@
|
|
|
58
58
|
"unbuild": "^3.6.1",
|
|
59
59
|
"vitest": "^4.1.10"
|
|
60
60
|
},
|
|
61
|
-
"dependencies": {
|
|
62
|
-
"@paralleldrive/cuid2": "^3.0.6"
|
|
63
|
-
},
|
|
64
61
|
"keywords": [
|
|
65
62
|
"logger",
|
|
66
63
|
"logging",
|