widelogger 0.2.0 → 0.3.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 +83 -65
- package/dist/index.d.ts +17 -17
- package/dist/index.js +71 -67
- package/dist/types.d.ts +1 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -41,7 +41,7 @@ npm install widelogger
|
|
|
41
41
|
```ts
|
|
42
42
|
import { widelogger } from "widelogger";
|
|
43
43
|
|
|
44
|
-
const {
|
|
44
|
+
const { context, destroy } = widelogger({
|
|
45
45
|
service: "checkout-api",
|
|
46
46
|
defaultEventName: "http_request",
|
|
47
47
|
version: "1.0.0",
|
|
@@ -49,116 +49,129 @@ const { widelog, destroy } = widelogger({
|
|
|
49
49
|
});
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
+
`widelogger()` returns a `context` function to wrap request lifecycles and a `destroy` function for graceful shutdown. To log fields, import `widelog` directly from the package — it works anywhere inside a `context()` call thanks to `AsyncLocalStorage`.
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
import { widelog } from "widelogger";
|
|
56
|
+
|
|
57
|
+
widelog.set("user.id", userId);
|
|
58
|
+
```
|
|
59
|
+
|
|
52
60
|
### Express
|
|
53
61
|
|
|
54
|
-
Create a
|
|
62
|
+
Create a logger instance once, use middleware to wrap requests in a context, and accumulate fields from anywhere in your codebase by importing `widelog` directly.
|
|
55
63
|
|
|
56
64
|
```ts
|
|
57
|
-
//
|
|
65
|
+
// src/logger.ts
|
|
58
66
|
import { widelogger } from "widelogger";
|
|
59
67
|
|
|
60
|
-
const {
|
|
68
|
+
export const { context, destroy } = widelogger({
|
|
61
69
|
service: "checkout-api",
|
|
62
70
|
defaultEventName: "http_request",
|
|
63
71
|
});
|
|
64
|
-
|
|
65
|
-
export { widelog, destroy };
|
|
66
72
|
```
|
|
67
73
|
|
|
68
74
|
```ts
|
|
69
|
-
// middleware/logging.ts
|
|
70
|
-
import { widelog } from "
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
75
|
+
// src/middleware/logging.ts
|
|
76
|
+
import { widelog } from "widelogger";
|
|
77
|
+
import { context } from "../logger";
|
|
78
|
+
|
|
79
|
+
export const logging = (request, response, next) => {
|
|
80
|
+
context(
|
|
81
|
+
() =>
|
|
82
|
+
new Promise((resolve) => {
|
|
83
|
+
widelog.set("method", request.method);
|
|
84
|
+
widelog.set("path", request.path);
|
|
85
|
+
widelog.time.start("duration_ms");
|
|
86
|
+
|
|
87
|
+
response.on("finish", () => {
|
|
88
|
+
widelog.set("status_code", response.statusCode);
|
|
89
|
+
widelog.time.stop("duration_ms");
|
|
90
|
+
widelog.flush();
|
|
91
|
+
resolve();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
next();
|
|
95
|
+
}),
|
|
96
|
+
);
|
|
86
97
|
};
|
|
87
98
|
```
|
|
88
99
|
|
|
89
100
|
```ts
|
|
90
|
-
// routes/checkout.ts
|
|
91
|
-
import { widelog } from "
|
|
92
|
-
|
|
93
|
-
export const checkout = async (
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
widelog.set("user.
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
res.status(500).json({ error: "checkout failed" });
|
|
108
|
-
}
|
|
101
|
+
// src/routes/checkout.ts
|
|
102
|
+
import { widelog } from "widelogger";
|
|
103
|
+
|
|
104
|
+
export const checkout = async (request, response) => {
|
|
105
|
+
const { userId } = request.body;
|
|
106
|
+
|
|
107
|
+
widelog.set("user.id", userId);
|
|
108
|
+
widelog.set("user.plan", "premium");
|
|
109
|
+
|
|
110
|
+
widelog.time.start("db_ms");
|
|
111
|
+
const order = await processOrder(userId);
|
|
112
|
+
widelog.time.stop("db_ms");
|
|
113
|
+
|
|
114
|
+
widelog.set("order.total_cents", order.totalCents);
|
|
115
|
+
widelog.count("order.items", order.itemCount);
|
|
116
|
+
|
|
117
|
+
response.json({ orderId: order.id });
|
|
109
118
|
};
|
|
110
119
|
```
|
|
111
120
|
|
|
112
|
-
The handler doesn't need to know about context setup or flushing — it just imports `widelog` and adds fields. `AsyncLocalStorage` ensures concurrent requests never leak into each other.
|
|
121
|
+
The handler doesn't need to know about context setup or flushing — it just imports `widelog` from the package and adds fields. `AsyncLocalStorage` ensures concurrent requests never leak into each other.
|
|
113
122
|
|
|
114
123
|
### Bun
|
|
115
124
|
|
|
116
125
|
The same pattern works with Bun's built-in server.
|
|
117
126
|
|
|
118
127
|
```ts
|
|
119
|
-
//
|
|
128
|
+
// src/logger.ts
|
|
120
129
|
import { widelogger } from "widelogger";
|
|
121
130
|
|
|
122
|
-
const {
|
|
131
|
+
export const { context, destroy } = widelogger({
|
|
123
132
|
service: "checkout-api",
|
|
124
133
|
defaultEventName: "http_request",
|
|
125
134
|
});
|
|
126
|
-
|
|
127
|
-
export { widelog, destroy };
|
|
128
135
|
```
|
|
129
136
|
|
|
130
137
|
```ts
|
|
131
|
-
// routes/checkout.ts
|
|
132
|
-
import { widelog } from "
|
|
138
|
+
// src/routes/checkout.ts
|
|
139
|
+
import { widelog } from "widelogger";
|
|
140
|
+
|
|
141
|
+
export const checkout = async (request: Request) => {
|
|
142
|
+
const { userId } = await request.json();
|
|
133
143
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
widelog.
|
|
144
|
+
widelog.set("user.id", userId);
|
|
145
|
+
widelog.set("user.plan", "premium");
|
|
146
|
+
|
|
147
|
+
widelog.time.start("db_ms");
|
|
148
|
+
const order = await processOrder(userId);
|
|
149
|
+
widelog.time.stop("db_ms");
|
|
138
150
|
|
|
139
|
-
const order = await processOrder(user);
|
|
140
151
|
widelog.set("order.total_cents", order.totalCents);
|
|
141
|
-
widelog.count("order.items", order.
|
|
152
|
+
widelog.count("order.items", order.itemCount);
|
|
142
153
|
|
|
143
154
|
return Response.json({ orderId: order.id });
|
|
144
155
|
};
|
|
145
156
|
```
|
|
146
157
|
|
|
147
158
|
```ts
|
|
148
|
-
// server.ts
|
|
149
|
-
import {
|
|
159
|
+
// src/server.ts
|
|
160
|
+
import { serve } from "bun";
|
|
161
|
+
import { widelog } from "widelogger";
|
|
162
|
+
import { context } from "./logger";
|
|
150
163
|
import { checkout } from "./routes/checkout";
|
|
151
164
|
|
|
152
|
-
|
|
153
|
-
fetch: (
|
|
154
|
-
|
|
155
|
-
const url = new URL(
|
|
156
|
-
widelog.set("method",
|
|
165
|
+
serve({
|
|
166
|
+
fetch: (request) =>
|
|
167
|
+
context(async () => {
|
|
168
|
+
const url = new URL(request.url);
|
|
169
|
+
widelog.set("method", request.method);
|
|
157
170
|
widelog.set("path", url.pathname);
|
|
158
171
|
widelog.time.start("duration_ms");
|
|
159
172
|
|
|
160
173
|
try {
|
|
161
|
-
const response = await checkout(
|
|
174
|
+
const response = await checkout(request);
|
|
162
175
|
widelog.set("status_code", response.status);
|
|
163
176
|
widelog.set("outcome", "success");
|
|
164
177
|
return response;
|
|
@@ -197,7 +210,7 @@ Events with `status_code >= 500` or `outcome === "error"` are emitted at `error`
|
|
|
197
210
|
|
|
198
211
|
### `widelogger(options)`
|
|
199
212
|
|
|
200
|
-
Creates a logger instance. Returns `{
|
|
213
|
+
Creates a logger instance. Returns `{ context, destroy }`.
|
|
201
214
|
|
|
202
215
|
| Option | Type | Description |
|
|
203
216
|
|--------|------|-------------|
|
|
@@ -209,11 +222,16 @@ Creates a logger instance. Returns `{ widelog, destroy }`.
|
|
|
209
222
|
| `environment` | `string` | Environment name (defaults to `NODE_ENV`) |
|
|
210
223
|
| `level` | `string` | Log level (defaults to `LOG_LEVEL` env or `"info"`) |
|
|
211
224
|
|
|
225
|
+
### `context(fn)`
|
|
226
|
+
|
|
227
|
+
Run a function inside an isolated async context. All `widelog` calls within this function (and any functions it calls) are scoped to this context. Supports both sync and async callbacks.
|
|
228
|
+
|
|
212
229
|
### `widelog`
|
|
213
230
|
|
|
231
|
+
Imported directly from `"widelogger"`. All methods operate on the current async context established by `context()`.
|
|
232
|
+
|
|
214
233
|
| Method | Description |
|
|
215
234
|
|--------|-------------|
|
|
216
|
-
| `context(fn)` | Run a function in an isolated async context |
|
|
217
235
|
| `set(key, value)` | Set a field value (last write wins) |
|
|
218
236
|
| `count(key, amount?)` | Increment a counter (default +1) |
|
|
219
237
|
| `append(key, value)` | Append a value to an array |
|
package/dist/index.d.ts
CHANGED
|
@@ -12,24 +12,24 @@ export interface ErrorFieldsOptions {
|
|
|
12
12
|
prefix?: string;
|
|
13
13
|
includeStack?: boolean;
|
|
14
14
|
}
|
|
15
|
+
export declare const widelog: {
|
|
16
|
+
set: <K extends string>(key: DottedKey<K>, value: FieldValue) => void;
|
|
17
|
+
count: <K extends string>(key: DottedKey<K>, amount?: number) => void;
|
|
18
|
+
append: <K extends string>(key: DottedKey<K>, value: FieldValue) => void;
|
|
19
|
+
max: <K extends string>(key: DottedKey<K>, value: number) => void;
|
|
20
|
+
min: <K extends string>(key: DottedKey<K>, value: number) => void;
|
|
21
|
+
time: {
|
|
22
|
+
start: <K extends string>(key: DottedKey<K>) => void;
|
|
23
|
+
stop: <K extends string>(key: DottedKey<K>) => void;
|
|
24
|
+
};
|
|
25
|
+
errorFields: (error: unknown, options?: ErrorFieldsOptions) => void;
|
|
26
|
+
flush: () => void;
|
|
27
|
+
};
|
|
15
28
|
export declare const widelogger: (options: WideloggerOptions) => {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
append: <K extends string>(key: DottedKey<K>, value: FieldValue) => void;
|
|
20
|
-
max: <K extends string>(key: DottedKey<K>, value: number) => void;
|
|
21
|
-
min: <K extends string>(key: DottedKey<K>, value: number) => void;
|
|
22
|
-
time: {
|
|
23
|
-
start: <K extends string>(key: DottedKey<K>) => void;
|
|
24
|
-
stop: <K extends string>(key: DottedKey<K>) => void;
|
|
25
|
-
};
|
|
26
|
-
errorFields: (error: unknown, options?: ErrorFieldsOptions) => void;
|
|
27
|
-
flush: () => void;
|
|
28
|
-
context: {
|
|
29
|
-
<T>(callback: () => Promise<T>): Promise<T>;
|
|
30
|
-
<T>(callback: () => T): T;
|
|
31
|
-
};
|
|
29
|
+
context: {
|
|
30
|
+
<T>(callback: () => Promise<T>): Promise<T>;
|
|
31
|
+
<T>(callback: () => T): T;
|
|
32
32
|
};
|
|
33
33
|
destroy: () => Promise<void>;
|
|
34
34
|
};
|
|
35
|
-
export type Widelog =
|
|
35
|
+
export type Widelog = typeof widelog;
|
package/dist/index.js
CHANGED
|
@@ -134,6 +134,69 @@ function getErrorFields(error, includeStack = true) {
|
|
|
134
134
|
error_message: "Unknown error"
|
|
135
135
|
};
|
|
136
136
|
}
|
|
137
|
+
var storage = new AsyncLocalStorage;
|
|
138
|
+
var widelog = {
|
|
139
|
+
set: (key, value) => {
|
|
140
|
+
storage.getStore()?.operations.push({ operation: "set", key, value });
|
|
141
|
+
},
|
|
142
|
+
count: (key, amount = 1) => {
|
|
143
|
+
storage.getStore()?.operations.push({ operation: "count", key, amount });
|
|
144
|
+
},
|
|
145
|
+
append: (key, value) => {
|
|
146
|
+
storage.getStore()?.operations.push({ operation: "append", key, value });
|
|
147
|
+
},
|
|
148
|
+
max: (key, value) => {
|
|
149
|
+
storage.getStore()?.operations.push({ operation: "max", key, value });
|
|
150
|
+
},
|
|
151
|
+
min: (key, value) => {
|
|
152
|
+
storage.getStore()?.operations.push({ operation: "min", key, value });
|
|
153
|
+
},
|
|
154
|
+
time: {
|
|
155
|
+
start: (key) => {
|
|
156
|
+
storage.getStore()?.operations.push({
|
|
157
|
+
operation: "time.start",
|
|
158
|
+
key,
|
|
159
|
+
time: performance.now()
|
|
160
|
+
});
|
|
161
|
+
},
|
|
162
|
+
stop: (key) => {
|
|
163
|
+
storage.getStore()?.operations.push({
|
|
164
|
+
operation: "time.stop",
|
|
165
|
+
key,
|
|
166
|
+
time: performance.now()
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
errorFields: (error, options = {}) => {
|
|
171
|
+
const context = storage.getStore();
|
|
172
|
+
if (!context) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const prefix = options.prefix ?? "error";
|
|
176
|
+
const fields = getErrorFields(error, options.includeStack ?? true);
|
|
177
|
+
const nameKey = `${prefix}.error_name`;
|
|
178
|
+
const messageKey = `${prefix}.error_message`;
|
|
179
|
+
context.operations.push({ operation: "set", key: nameKey, value: fields.error_name }, { operation: "set", key: messageKey, value: fields.error_message });
|
|
180
|
+
if (fields.error_stack !== undefined) {
|
|
181
|
+
context.operations.push({
|
|
182
|
+
operation: "set",
|
|
183
|
+
key: `${prefix}.error_stack`,
|
|
184
|
+
value: fields.error_stack
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
flush: () => {
|
|
189
|
+
const store = storage.getStore();
|
|
190
|
+
if (!store) {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
const event = flush(store);
|
|
194
|
+
if (Object.keys(event).length === 0) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
store.transport(event);
|
|
198
|
+
}
|
|
199
|
+
};
|
|
137
200
|
var widelogger = (options) => {
|
|
138
201
|
const environment = options.environment ?? "development" ?? "development";
|
|
139
202
|
const isDevelopment = environment !== "production";
|
|
@@ -157,11 +220,7 @@ var widelogger = (options) => {
|
|
|
157
220
|
environment
|
|
158
221
|
}
|
|
159
222
|
}, pinoTransport);
|
|
160
|
-
const storage = new AsyncLocalStorage;
|
|
161
223
|
const transport = (event) => {
|
|
162
|
-
if (Object.keys(event).length === 0) {
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
224
|
const statusCode = typeof event.status_code === "number" ? event.status_code : undefined;
|
|
166
225
|
const isError = statusCode !== undefined ? statusCode >= 500 : event.outcome === "error";
|
|
167
226
|
const payload = { event_name: options.defaultEventName, ...event };
|
|
@@ -172,13 +231,13 @@ var widelogger = (options) => {
|
|
|
172
231
|
logger.info(payload);
|
|
173
232
|
};
|
|
174
233
|
const clearContext = () => {
|
|
175
|
-
const
|
|
176
|
-
if (
|
|
177
|
-
|
|
234
|
+
const context2 = storage.getStore();
|
|
235
|
+
if (context2 && context2.operations.length > 0) {
|
|
236
|
+
context2.operations = [];
|
|
178
237
|
}
|
|
179
238
|
};
|
|
180
|
-
function
|
|
181
|
-
return storage.run({ operations: [] }, () => {
|
|
239
|
+
function context(callback) {
|
|
240
|
+
return storage.run({ operations: [], transport }, () => {
|
|
182
241
|
let result;
|
|
183
242
|
try {
|
|
184
243
|
result = callback();
|
|
@@ -193,62 +252,6 @@ var widelogger = (options) => {
|
|
|
193
252
|
return result;
|
|
194
253
|
});
|
|
195
254
|
}
|
|
196
|
-
const widelog = {
|
|
197
|
-
set: (key, value) => {
|
|
198
|
-
storage.getStore()?.operations.push({ operation: "set", key, value });
|
|
199
|
-
},
|
|
200
|
-
count: (key, amount = 1) => {
|
|
201
|
-
storage.getStore()?.operations.push({ operation: "count", key, amount });
|
|
202
|
-
},
|
|
203
|
-
append: (key, value) => {
|
|
204
|
-
storage.getStore()?.operations.push({ operation: "append", key, value });
|
|
205
|
-
},
|
|
206
|
-
max: (key, value) => {
|
|
207
|
-
storage.getStore()?.operations.push({ operation: "max", key, value });
|
|
208
|
-
},
|
|
209
|
-
min: (key, value) => {
|
|
210
|
-
storage.getStore()?.operations.push({ operation: "min", key, value });
|
|
211
|
-
},
|
|
212
|
-
time: {
|
|
213
|
-
start: (key) => {
|
|
214
|
-
storage.getStore()?.operations.push({
|
|
215
|
-
operation: "time.start",
|
|
216
|
-
key,
|
|
217
|
-
time: performance.now()
|
|
218
|
-
});
|
|
219
|
-
},
|
|
220
|
-
stop: (key) => {
|
|
221
|
-
storage.getStore()?.operations.push({
|
|
222
|
-
operation: "time.stop",
|
|
223
|
-
key,
|
|
224
|
-
time: performance.now()
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
},
|
|
228
|
-
errorFields: (error, options2 = {}) => {
|
|
229
|
-
const context = storage.getStore();
|
|
230
|
-
if (!context) {
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
const prefix = options2.prefix ?? "error";
|
|
234
|
-
const fields = getErrorFields(error, options2.includeStack ?? true);
|
|
235
|
-
const nameKey = `${prefix}.error_name`;
|
|
236
|
-
const messageKey = `${prefix}.error_message`;
|
|
237
|
-
context.operations.push({ operation: "set", key: nameKey, value: fields.error_name }, { operation: "set", key: messageKey, value: fields.error_message });
|
|
238
|
-
if (fields.error_stack !== undefined) {
|
|
239
|
-
context.operations.push({
|
|
240
|
-
operation: "set",
|
|
241
|
-
key: `${prefix}.error_stack`,
|
|
242
|
-
value: fields.error_stack
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
},
|
|
246
|
-
flush: () => {
|
|
247
|
-
const event = flush(storage.getStore());
|
|
248
|
-
transport(event);
|
|
249
|
-
},
|
|
250
|
-
context: runContext
|
|
251
|
-
};
|
|
252
255
|
const destroy = async () => {
|
|
253
256
|
await new Promise((resolve) => {
|
|
254
257
|
logger.flush(() => resolve());
|
|
@@ -257,8 +260,9 @@ var widelogger = (options) => {
|
|
|
257
260
|
pinoTransport.end();
|
|
258
261
|
}
|
|
259
262
|
};
|
|
260
|
-
return {
|
|
263
|
+
return { context, destroy };
|
|
261
264
|
};
|
|
262
265
|
export {
|
|
263
|
-
widelogger
|
|
266
|
+
widelogger,
|
|
267
|
+
widelog
|
|
264
268
|
};
|
package/dist/types.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "widelogger",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
11
|
"types": "./dist/index.d.ts",
|
|
12
|
-
"import": "./dist/index.js"
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"default": "./dist/index.js"
|
|
13
14
|
}
|
|
14
15
|
},
|
|
15
16
|
"repository": {
|