widelogger 0.4.0 → 0.6.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/dist/index.d.ts +11 -3
- package/dist/index.js +132 -15
- package/dist/types.d.ts +7 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DottedKey, FieldValue } from "./types";
|
|
1
|
+
import type { DottedKey, ErrorParser, FieldValue } from "./types";
|
|
2
2
|
export interface WideloggerOptions {
|
|
3
3
|
service: string;
|
|
4
4
|
defaultEventName: string;
|
|
@@ -11,12 +11,18 @@ export interface WideloggerOptions {
|
|
|
11
11
|
export interface ErrorFieldsOptions {
|
|
12
12
|
prefix?: string;
|
|
13
13
|
includeStack?: boolean;
|
|
14
|
+
slug?: string;
|
|
15
|
+
retriable?: boolean;
|
|
16
|
+
requiresReauth?: boolean;
|
|
17
|
+
}
|
|
18
|
+
interface StickyHandle {
|
|
19
|
+
sticky: () => void;
|
|
14
20
|
}
|
|
15
21
|
declare function measure<K extends string, T>(key: DottedKey<K>, callback: () => Promise<T>): Promise<T>;
|
|
16
22
|
declare function measure<K extends string, T>(key: DottedKey<K>, callback: () => T): T;
|
|
17
23
|
export declare const widelog: {
|
|
18
|
-
set: <K extends string>(key: DottedKey<K>, value: FieldValue) =>
|
|
19
|
-
setFields: (fields: Record<string, unknown>) =>
|
|
24
|
+
set: <K extends string>(key: DottedKey<K>, value: FieldValue) => StickyHandle;
|
|
25
|
+
setFields: (fields: Record<string, unknown>) => StickyHandle;
|
|
20
26
|
count: <K extends string>(key: DottedKey<K>, amount?: number) => void;
|
|
21
27
|
append: <K extends string>(key: DottedKey<K>, value: FieldValue) => void;
|
|
22
28
|
max: <K extends string>(key: DottedKey<K>, value: number) => void;
|
|
@@ -26,6 +32,8 @@ export declare const widelog: {
|
|
|
26
32
|
stop: <K extends string>(key: DottedKey<K>) => void;
|
|
27
33
|
measure: typeof measure;
|
|
28
34
|
};
|
|
35
|
+
errors: (parser: ErrorParser) => void;
|
|
36
|
+
error: <K extends string>(key: DottedKey<K>, error: unknown) => void;
|
|
29
37
|
errorFields: (error: unknown, options?: ErrorFieldsOptions) => void;
|
|
30
38
|
flush: () => void;
|
|
31
39
|
};
|
package/dist/index.js
CHANGED
|
@@ -32,9 +32,29 @@ var createAggregators = () => ({
|
|
|
32
32
|
arrays: Object.create(null),
|
|
33
33
|
maxValues: Object.create(null),
|
|
34
34
|
minValues: Object.create(null),
|
|
35
|
-
timers: Object.create(null)
|
|
35
|
+
timers: Object.create(null),
|
|
36
|
+
errors: Object.create(null)
|
|
36
37
|
});
|
|
37
|
-
var
|
|
38
|
+
var aggregateError = (agg, key, slug) => {
|
|
39
|
+
const existing = agg.errors[key];
|
|
40
|
+
if (existing) {
|
|
41
|
+
existing.total += 1;
|
|
42
|
+
const previousCount = existing.counts[slug];
|
|
43
|
+
if (typeof previousCount === "number") {
|
|
44
|
+
existing.counts[slug] = previousCount + 1;
|
|
45
|
+
} else {
|
|
46
|
+
existing.counts[slug] = 1;
|
|
47
|
+
existing.slugs.push(slug);
|
|
48
|
+
}
|
|
49
|
+
} else {
|
|
50
|
+
agg.errors[key] = {
|
|
51
|
+
slugs: [slug],
|
|
52
|
+
counts: { [slug]: 1 },
|
|
53
|
+
total: 1
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
var processOperation = (agg, entry, errorParser) => {
|
|
38
58
|
switch (entry.operation) {
|
|
39
59
|
case "set":
|
|
40
60
|
setNested(agg.event, entry.key, entry.value);
|
|
@@ -66,9 +86,9 @@ var processOperation = (agg, entry) => {
|
|
|
66
86
|
break;
|
|
67
87
|
}
|
|
68
88
|
case "time.start": {
|
|
69
|
-
const
|
|
70
|
-
if (
|
|
71
|
-
|
|
89
|
+
const existingTimer = agg.timers[entry.key];
|
|
90
|
+
if (existingTimer) {
|
|
91
|
+
existingTimer.start = entry.time;
|
|
72
92
|
} else {
|
|
73
93
|
agg.timers[entry.key] = { start: entry.time, accumulated: 0 };
|
|
74
94
|
}
|
|
@@ -82,6 +102,13 @@ var processOperation = (agg, entry) => {
|
|
|
82
102
|
}
|
|
83
103
|
break;
|
|
84
104
|
}
|
|
105
|
+
case "error": {
|
|
106
|
+
if (errorParser) {
|
|
107
|
+
const slug = errorParser(entry.error);
|
|
108
|
+
aggregateError(agg, entry.key, slug);
|
|
109
|
+
}
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
85
112
|
default:
|
|
86
113
|
}
|
|
87
114
|
};
|
|
@@ -90,7 +117,8 @@ var mergeAggregators = (agg) => {
|
|
|
90
117
|
agg.counters,
|
|
91
118
|
agg.arrays,
|
|
92
119
|
agg.maxValues,
|
|
93
|
-
agg.minValues
|
|
120
|
+
agg.minValues,
|
|
121
|
+
agg.errors
|
|
94
122
|
];
|
|
95
123
|
for (const source of sources) {
|
|
96
124
|
for (const key of Object.keys(source)) {
|
|
@@ -105,9 +133,17 @@ var flush = (context) => {
|
|
|
105
133
|
if (!context) {
|
|
106
134
|
return {};
|
|
107
135
|
}
|
|
136
|
+
const hasStickyOperations = context.stickyOperations.length > 0;
|
|
137
|
+
const hasOperations = context.operations.length > 0;
|
|
138
|
+
if (!(hasStickyOperations || hasOperations)) {
|
|
139
|
+
return {};
|
|
140
|
+
}
|
|
108
141
|
const agg = createAggregators();
|
|
142
|
+
for (const entry of context.stickyOperations) {
|
|
143
|
+
processOperation(agg, entry, context.errorParser);
|
|
144
|
+
}
|
|
109
145
|
for (const entry of context.operations) {
|
|
110
|
-
processOperation(agg, entry);
|
|
146
|
+
processOperation(agg, entry, context.errorParser);
|
|
111
147
|
}
|
|
112
148
|
mergeAggregators(agg);
|
|
113
149
|
context.operations = [];
|
|
@@ -117,6 +153,7 @@ var flush = (context) => {
|
|
|
117
153
|
// src/index.ts
|
|
118
154
|
var isFieldValue = (value) => typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
119
155
|
var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
156
|
+
var isFieldValueArray = (value) => Array.isArray(value) && value.every(isFieldValue);
|
|
120
157
|
function getErrorFields(error, includeStack = true) {
|
|
121
158
|
if (error instanceof Error) {
|
|
122
159
|
return {
|
|
@@ -136,9 +173,32 @@ function getErrorFields(error, includeStack = true) {
|
|
|
136
173
|
error_message: "Unknown error"
|
|
137
174
|
};
|
|
138
175
|
}
|
|
176
|
+
var extractErrorProperty = (error, property) => {
|
|
177
|
+
if (isRecord2(error) && property in error) {
|
|
178
|
+
return error[property];
|
|
179
|
+
}
|
|
180
|
+
return;
|
|
181
|
+
};
|
|
182
|
+
var noop = () => {
|
|
183
|
+
return;
|
|
184
|
+
};
|
|
185
|
+
var noopSticky = { sticky: noop };
|
|
139
186
|
var storage = new AsyncLocalStorage;
|
|
140
187
|
function pushOp(operation) {
|
|
141
|
-
storage.getStore()
|
|
188
|
+
const store = storage.getStore();
|
|
189
|
+
if (!store) {
|
|
190
|
+
return noopSticky;
|
|
191
|
+
}
|
|
192
|
+
store.operations.push(operation);
|
|
193
|
+
return {
|
|
194
|
+
sticky: () => {
|
|
195
|
+
const index = store.operations.indexOf(operation);
|
|
196
|
+
if (index !== -1) {
|
|
197
|
+
store.operations.splice(index, 1);
|
|
198
|
+
}
|
|
199
|
+
store.stickyOperations.push(operation);
|
|
200
|
+
}
|
|
201
|
+
};
|
|
142
202
|
}
|
|
143
203
|
function applyFields(operations, fields, parentKey) {
|
|
144
204
|
for (const key of Object.keys(fields)) {
|
|
@@ -148,6 +208,12 @@ function applyFields(operations, fields, parentKey) {
|
|
|
148
208
|
operations.push({ operation: "set", key: fullKey, value });
|
|
149
209
|
continue;
|
|
150
210
|
}
|
|
211
|
+
if (isFieldValueArray(value)) {
|
|
212
|
+
for (const element of value) {
|
|
213
|
+
operations.push({ operation: "append", key: fullKey, value: element });
|
|
214
|
+
}
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
151
217
|
if (isRecord2(value)) {
|
|
152
218
|
applyFields(operations, value, fullKey);
|
|
153
219
|
}
|
|
@@ -177,13 +243,21 @@ function measure(key, callback) {
|
|
|
177
243
|
}
|
|
178
244
|
var widelog = {
|
|
179
245
|
set: (key, value) => {
|
|
180
|
-
pushOp({ operation: "set", key, value });
|
|
246
|
+
return pushOp({ operation: "set", key, value });
|
|
181
247
|
},
|
|
182
248
|
setFields: (fields) => {
|
|
183
|
-
const
|
|
184
|
-
if (
|
|
185
|
-
|
|
249
|
+
const store = storage.getStore();
|
|
250
|
+
if (!store) {
|
|
251
|
+
return noopSticky;
|
|
186
252
|
}
|
|
253
|
+
const startIndex = store.operations.length;
|
|
254
|
+
applyFields(store.operations, fields);
|
|
255
|
+
return {
|
|
256
|
+
sticky: () => {
|
|
257
|
+
const added = store.operations.splice(startIndex);
|
|
258
|
+
store.stickyOperations.push(...added);
|
|
259
|
+
}
|
|
260
|
+
};
|
|
187
261
|
},
|
|
188
262
|
count: (key, amount = 1) => {
|
|
189
263
|
pushOp({ operation: "count", key, amount });
|
|
@@ -206,6 +280,16 @@ var widelog = {
|
|
|
206
280
|
},
|
|
207
281
|
measure
|
|
208
282
|
},
|
|
283
|
+
errors: (parser) => {
|
|
284
|
+
const store = storage.getStore();
|
|
285
|
+
if (!store) {
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
store.errorParser = parser;
|
|
289
|
+
},
|
|
290
|
+
error: (key, error) => {
|
|
291
|
+
pushOp({ operation: "error", key, error });
|
|
292
|
+
},
|
|
209
293
|
errorFields: (error, options = {}) => {
|
|
210
294
|
const context = storage.getStore();
|
|
211
295
|
if (!context) {
|
|
@@ -229,10 +313,37 @@ var widelog = {
|
|
|
229
313
|
value: fields.error_stack
|
|
230
314
|
});
|
|
231
315
|
}
|
|
316
|
+
const slug = options.slug ?? extractErrorProperty(error, "slug");
|
|
317
|
+
if (typeof slug === "string") {
|
|
318
|
+
context.operations.push({
|
|
319
|
+
operation: "set",
|
|
320
|
+
key: `${prefix}.slug`,
|
|
321
|
+
value: slug
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
const retriable = options.retriable ?? extractErrorProperty(error, "retriable");
|
|
325
|
+
if (typeof retriable === "boolean") {
|
|
326
|
+
context.operations.push({
|
|
327
|
+
operation: "set",
|
|
328
|
+
key: `${prefix}.retriable`,
|
|
329
|
+
value: retriable
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
const requiresReauth = options.requiresReauth ?? extractErrorProperty(error, "requiresReauth");
|
|
333
|
+
if (typeof requiresReauth === "boolean") {
|
|
334
|
+
context.operations.push({
|
|
335
|
+
operation: "set",
|
|
336
|
+
key: `${prefix}.requires_reauth`,
|
|
337
|
+
value: requiresReauth
|
|
338
|
+
});
|
|
339
|
+
}
|
|
232
340
|
},
|
|
233
341
|
flush: () => {
|
|
234
342
|
const store = storage.getStore();
|
|
235
|
-
if (!store
|
|
343
|
+
if (!store) {
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
if (store.operations.length === 0 && store.stickyOperations.length === 0) {
|
|
236
347
|
return;
|
|
237
348
|
}
|
|
238
349
|
const event = flush(store);
|
|
@@ -276,12 +387,18 @@ var widelogger = (options) => {
|
|
|
276
387
|
};
|
|
277
388
|
const clearContext = () => {
|
|
278
389
|
const context2 = storage.getStore();
|
|
279
|
-
if (context2
|
|
390
|
+
if (context2) {
|
|
280
391
|
context2.operations = [];
|
|
392
|
+
context2.stickyOperations = [];
|
|
281
393
|
}
|
|
282
394
|
};
|
|
283
395
|
function context(callback) {
|
|
284
|
-
return storage.run({
|
|
396
|
+
return storage.run({
|
|
397
|
+
operations: [],
|
|
398
|
+
stickyOperations: [],
|
|
399
|
+
errorParser: null,
|
|
400
|
+
transport
|
|
401
|
+
}, () => {
|
|
285
402
|
let result;
|
|
286
403
|
try {
|
|
287
404
|
result = callback();
|
package/dist/types.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ interface KeyErrorBrand {
|
|
|
5
5
|
}
|
|
6
6
|
type ValidateKey<T extends string> = T extends "" ? "widelog keys cannot be empty" & KeyErrorBrand : T extends `.${string}` ? "widelog keys cannot start with a dot" & KeyErrorBrand : T extends `${string}.` ? "widelog keys cannot end with a dot" & KeyErrorBrand : T extends `${string}..${string}` ? "widelog keys cannot contain empty segments" & KeyErrorBrand : T;
|
|
7
7
|
export type DottedKey<T extends string> = ValidateKey<T>;
|
|
8
|
+
export type ErrorParser = (error: unknown) => string;
|
|
8
9
|
export type Operation = {
|
|
9
10
|
operation: "set";
|
|
10
11
|
key: string;
|
|
@@ -33,9 +34,15 @@ export type Operation = {
|
|
|
33
34
|
operation: "time.stop";
|
|
34
35
|
key: string;
|
|
35
36
|
time: number;
|
|
37
|
+
} | {
|
|
38
|
+
operation: "error";
|
|
39
|
+
key: string;
|
|
40
|
+
error: unknown;
|
|
36
41
|
};
|
|
37
42
|
export interface Context {
|
|
38
43
|
operations: Operation[];
|
|
44
|
+
stickyOperations: Operation[];
|
|
45
|
+
errorParser: ErrorParser | null;
|
|
39
46
|
transport: (event: Record<string, unknown>) => void;
|
|
40
47
|
}
|
|
41
48
|
export {};
|