widelogger 0.3.0 → 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 +35 -10
- package/dist/index.d.ts +5 -0
- package/dist/index.js +71 -27
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -104,12 +104,11 @@ import { widelog } from "widelogger";
|
|
|
104
104
|
export const checkout = async (request, response) => {
|
|
105
105
|
const { userId } = request.body;
|
|
106
106
|
|
|
107
|
-
widelog.
|
|
108
|
-
widelog.set("user.plan", "premium");
|
|
107
|
+
widelog.setFields({ user: { id: userId, plan: "premium" } });
|
|
109
108
|
|
|
110
|
-
widelog.time.
|
|
111
|
-
|
|
112
|
-
|
|
109
|
+
const order = await widelog.time.measure("db_ms", () =>
|
|
110
|
+
processOrder(userId),
|
|
111
|
+
);
|
|
113
112
|
|
|
114
113
|
widelog.set("order.total_cents", order.totalCents);
|
|
115
114
|
widelog.count("order.items", order.itemCount);
|
|
@@ -141,12 +140,11 @@ import { widelog } from "widelogger";
|
|
|
141
140
|
export const checkout = async (request: Request) => {
|
|
142
141
|
const { userId } = await request.json();
|
|
143
142
|
|
|
144
|
-
widelog.
|
|
145
|
-
widelog.set("user.plan", "premium");
|
|
143
|
+
widelog.setFields({ user: { id: userId, plan: "premium" } });
|
|
146
144
|
|
|
147
|
-
widelog.time.
|
|
148
|
-
|
|
149
|
-
|
|
145
|
+
const order = await widelog.time.measure("db_ms", () =>
|
|
146
|
+
processOrder(userId),
|
|
147
|
+
);
|
|
150
148
|
|
|
151
149
|
widelog.set("order.total_cents", order.totalCents);
|
|
152
150
|
widelog.count("order.items", order.itemCount);
|
|
@@ -202,6 +200,31 @@ widelog.set("user.plan", "premium");
|
|
|
202
200
|
// Output: { user: { id: "usr_123", plan: "premium" } }
|
|
203
201
|
```
|
|
204
202
|
|
|
203
|
+
### Bulk Fields
|
|
204
|
+
|
|
205
|
+
`setFields` accepts a nested object and recursively flattens it into individual `set` calls. Non-primitive values (other than plain objects) are silently ignored.
|
|
206
|
+
|
|
207
|
+
```ts
|
|
208
|
+
widelog.setFields({
|
|
209
|
+
user: { id: "usr_123", plan: "premium" },
|
|
210
|
+
status_code: 200,
|
|
211
|
+
});
|
|
212
|
+
// Equivalent to:
|
|
213
|
+
// widelog.set("user.id", "usr_123");
|
|
214
|
+
// widelog.set("user.plan", "premium");
|
|
215
|
+
// widelog.set("status_code", 200);
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Measured Timing
|
|
219
|
+
|
|
220
|
+
`time.measure` wraps a sync or async callback, automatically recording start and stop times. It returns the callback's result and still records timing even if the callback throws.
|
|
221
|
+
|
|
222
|
+
```ts
|
|
223
|
+
const order = await widelog.time.measure("db_ms", () =>
|
|
224
|
+
processOrder(userId),
|
|
225
|
+
);
|
|
226
|
+
```
|
|
227
|
+
|
|
205
228
|
### Log Routing
|
|
206
229
|
|
|
207
230
|
Events with `status_code >= 500` or `outcome === "error"` are emitted at `error` level. Everything else is `info`. In development, logs are pretty-printed; in production, they're structured JSON.
|
|
@@ -233,12 +256,14 @@ Imported directly from `"widelogger"`. All methods operate on the current async
|
|
|
233
256
|
| Method | Description |
|
|
234
257
|
|--------|-------------|
|
|
235
258
|
| `set(key, value)` | Set a field value (last write wins) |
|
|
259
|
+
| `setFields(fields)` | Recursively flatten a nested object into dotted-key `set` calls |
|
|
236
260
|
| `count(key, amount?)` | Increment a counter (default +1) |
|
|
237
261
|
| `append(key, value)` | Append a value to an array |
|
|
238
262
|
| `max(key, value)` | Track the maximum value for a key |
|
|
239
263
|
| `min(key, value)` | Track the minimum value for a key |
|
|
240
264
|
| `time.start(key)` | Start a timer |
|
|
241
265
|
| `time.stop(key)` | Stop a timer and record elapsed ms |
|
|
266
|
+
| `time.measure(key, fn)` | Time a sync or async callback, returns the callback's result |
|
|
242
267
|
| `errorFields(error, opts?)` | Extract error name, message, and stack |
|
|
243
268
|
| `flush()` | Aggregate all operations and emit the event |
|
|
244
269
|
|
package/dist/index.d.ts
CHANGED
|
@@ -12,8 +12,11 @@ export interface ErrorFieldsOptions {
|
|
|
12
12
|
prefix?: string;
|
|
13
13
|
includeStack?: boolean;
|
|
14
14
|
}
|
|
15
|
+
declare function measure<K extends string, T>(key: DottedKey<K>, callback: () => Promise<T>): Promise<T>;
|
|
16
|
+
declare function measure<K extends string, T>(key: DottedKey<K>, callback: () => T): T;
|
|
15
17
|
export declare const widelog: {
|
|
16
18
|
set: <K extends string>(key: DottedKey<K>, value: FieldValue) => void;
|
|
19
|
+
setFields: (fields: Record<string, unknown>) => void;
|
|
17
20
|
count: <K extends string>(key: DottedKey<K>, amount?: number) => void;
|
|
18
21
|
append: <K extends string>(key: DottedKey<K>, value: FieldValue) => void;
|
|
19
22
|
max: <K extends string>(key: DottedKey<K>, value: number) => void;
|
|
@@ -21,6 +24,7 @@ export declare const widelog: {
|
|
|
21
24
|
time: {
|
|
22
25
|
start: <K extends string>(key: DottedKey<K>) => void;
|
|
23
26
|
stop: <K extends string>(key: DottedKey<K>) => void;
|
|
27
|
+
measure: typeof measure;
|
|
24
28
|
};
|
|
25
29
|
errorFields: (error: unknown, options?: ErrorFieldsOptions) => void;
|
|
26
30
|
flush: () => void;
|
|
@@ -33,3 +37,4 @@ export declare const widelogger: (options: WideloggerOptions) => {
|
|
|
33
37
|
destroy: () => Promise<void>;
|
|
34
38
|
};
|
|
35
39
|
export type Widelog = typeof widelog;
|
|
40
|
+
export {};
|
package/dist/index.js
CHANGED
|
@@ -115,6 +115,8 @@ var flush = (context) => {
|
|
|
115
115
|
};
|
|
116
116
|
|
|
117
117
|
// src/index.ts
|
|
118
|
+
var isFieldValue = (value) => typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
119
|
+
var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
118
120
|
function getErrorFields(error, includeStack = true) {
|
|
119
121
|
if (error instanceof Error) {
|
|
120
122
|
return {
|
|
@@ -135,37 +137,74 @@ function getErrorFields(error, includeStack = true) {
|
|
|
135
137
|
};
|
|
136
138
|
}
|
|
137
139
|
var storage = new AsyncLocalStorage;
|
|
140
|
+
function pushOp(operation) {
|
|
141
|
+
storage.getStore()?.operations.push(operation);
|
|
142
|
+
}
|
|
143
|
+
function applyFields(operations, fields, parentKey) {
|
|
144
|
+
for (const key of Object.keys(fields)) {
|
|
145
|
+
const value = fields[key];
|
|
146
|
+
const fullKey = parentKey ? `${parentKey}.${key}` : key;
|
|
147
|
+
if (isFieldValue(value)) {
|
|
148
|
+
operations.push({ operation: "set", key: fullKey, value });
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
if (isRecord2(value)) {
|
|
152
|
+
applyFields(operations, value, fullKey);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
function measure(key, callback) {
|
|
157
|
+
const operations = storage.getStore()?.operations;
|
|
158
|
+
operations?.push({ operation: "time.start", key, time: performance.now() });
|
|
159
|
+
let result;
|
|
160
|
+
try {
|
|
161
|
+
result = callback();
|
|
162
|
+
} catch (error) {
|
|
163
|
+
operations?.push({ operation: "time.stop", key, time: performance.now() });
|
|
164
|
+
throw error;
|
|
165
|
+
}
|
|
166
|
+
if (result instanceof Promise) {
|
|
167
|
+
return result.finally(() => {
|
|
168
|
+
operations?.push({
|
|
169
|
+
operation: "time.stop",
|
|
170
|
+
key,
|
|
171
|
+
time: performance.now()
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
operations?.push({ operation: "time.stop", key, time: performance.now() });
|
|
176
|
+
return result;
|
|
177
|
+
}
|
|
138
178
|
var widelog = {
|
|
139
179
|
set: (key, value) => {
|
|
140
|
-
|
|
180
|
+
pushOp({ operation: "set", key, value });
|
|
181
|
+
},
|
|
182
|
+
setFields: (fields) => {
|
|
183
|
+
const operations = storage.getStore()?.operations;
|
|
184
|
+
if (operations) {
|
|
185
|
+
applyFields(operations, fields);
|
|
186
|
+
}
|
|
141
187
|
},
|
|
142
188
|
count: (key, amount = 1) => {
|
|
143
|
-
|
|
189
|
+
pushOp({ operation: "count", key, amount });
|
|
144
190
|
},
|
|
145
191
|
append: (key, value) => {
|
|
146
|
-
|
|
192
|
+
pushOp({ operation: "append", key, value });
|
|
147
193
|
},
|
|
148
194
|
max: (key, value) => {
|
|
149
|
-
|
|
195
|
+
pushOp({ operation: "max", key, value });
|
|
150
196
|
},
|
|
151
197
|
min: (key, value) => {
|
|
152
|
-
|
|
198
|
+
pushOp({ operation: "min", key, value });
|
|
153
199
|
},
|
|
154
200
|
time: {
|
|
155
201
|
start: (key) => {
|
|
156
|
-
|
|
157
|
-
operation: "time.start",
|
|
158
|
-
key,
|
|
159
|
-
time: performance.now()
|
|
160
|
-
});
|
|
202
|
+
pushOp({ operation: "time.start", key, time: performance.now() });
|
|
161
203
|
},
|
|
162
204
|
stop: (key) => {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
time: performance.now()
|
|
167
|
-
});
|
|
168
|
-
}
|
|
205
|
+
pushOp({ operation: "time.stop", key, time: performance.now() });
|
|
206
|
+
},
|
|
207
|
+
measure
|
|
169
208
|
},
|
|
170
209
|
errorFields: (error, options = {}) => {
|
|
171
210
|
const context = storage.getStore();
|
|
@@ -174,9 +213,15 @@ var widelog = {
|
|
|
174
213
|
}
|
|
175
214
|
const prefix = options.prefix ?? "error";
|
|
176
215
|
const fields = getErrorFields(error, options.includeStack ?? true);
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
216
|
+
context.operations.push({
|
|
217
|
+
operation: "set",
|
|
218
|
+
key: `${prefix}.error_name`,
|
|
219
|
+
value: fields.error_name
|
|
220
|
+
}, {
|
|
221
|
+
operation: "set",
|
|
222
|
+
key: `${prefix}.error_message`,
|
|
223
|
+
value: fields.error_message
|
|
224
|
+
});
|
|
180
225
|
if (fields.error_stack !== undefined) {
|
|
181
226
|
context.operations.push({
|
|
182
227
|
operation: "set",
|
|
@@ -187,18 +232,16 @@ var widelog = {
|
|
|
187
232
|
},
|
|
188
233
|
flush: () => {
|
|
189
234
|
const store = storage.getStore();
|
|
190
|
-
if (!store) {
|
|
235
|
+
if (!store || store.operations.length === 0) {
|
|
191
236
|
return;
|
|
192
237
|
}
|
|
193
238
|
const event = flush(store);
|
|
194
|
-
if (Object.keys(event).length === 0) {
|
|
195
|
-
return;
|
|
196
|
-
}
|
|
197
239
|
store.transport(event);
|
|
198
240
|
}
|
|
199
241
|
};
|
|
200
242
|
var widelogger = (options) => {
|
|
201
|
-
const
|
|
243
|
+
const nodeEnvironment = typeof process.env === "object" ? "development" : undefined;
|
|
244
|
+
const environment = options.environment ?? nodeEnvironment ?? "development";
|
|
202
245
|
const isDevelopment = environment !== "production";
|
|
203
246
|
const pinoTransport = isDevelopment ? pino.transport({
|
|
204
247
|
target: "pino-pretty",
|
|
@@ -220,15 +263,16 @@ var widelogger = (options) => {
|
|
|
220
263
|
environment
|
|
221
264
|
}
|
|
222
265
|
}, pinoTransport);
|
|
266
|
+
const defaultEventName = options.defaultEventName;
|
|
223
267
|
const transport = (event) => {
|
|
224
268
|
const statusCode = typeof event.status_code === "number" ? event.status_code : undefined;
|
|
225
269
|
const isError = statusCode !== undefined ? statusCode >= 500 : event.outcome === "error";
|
|
226
|
-
|
|
270
|
+
event.event_name = defaultEventName;
|
|
227
271
|
if (isError) {
|
|
228
|
-
logger.error(
|
|
272
|
+
logger.error(event);
|
|
229
273
|
return;
|
|
230
274
|
}
|
|
231
|
-
logger.info(
|
|
275
|
+
logger.info(event);
|
|
232
276
|
};
|
|
233
277
|
const clearContext = () => {
|
|
234
278
|
const context2 = storage.getStore();
|