@remit/logger-lambda 0.0.12 → 0.0.13
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/package.json +1 -1
- package/src/log-output.test.ts +76 -1
- package/src/logger.ts +30 -24
package/package.json
CHANGED
package/src/log-output.test.ts
CHANGED
|
@@ -28,7 +28,9 @@ process.stdout.write = ((
|
|
|
28
28
|
return (originalWrite as (...args: unknown[]) => boolean)(chunk, ...rest);
|
|
29
29
|
}) as typeof process.stdout.write;
|
|
30
30
|
|
|
31
|
-
const { createLogger, logger, withLogContext } = await import(
|
|
31
|
+
const { createLogger, logger, withLogContext, withTelemetry } = await import(
|
|
32
|
+
"./logger.js"
|
|
33
|
+
);
|
|
32
34
|
|
|
33
35
|
const parse = (): Line[] =>
|
|
34
36
|
written
|
|
@@ -353,3 +355,76 @@ describe("withLogContext", () => {
|
|
|
353
355
|
assert.equal(repeats.length, 1);
|
|
354
356
|
});
|
|
355
357
|
});
|
|
358
|
+
|
|
359
|
+
describe("withTelemetry", () => {
|
|
360
|
+
const context = {
|
|
361
|
+
awsRequestId: "req-1",
|
|
362
|
+
functionName: "test-function",
|
|
363
|
+
} as unknown as Parameters<Parameters<typeof withTelemetry>[0]>[1];
|
|
364
|
+
|
|
365
|
+
it("puts its own start line inside the scope", async () => {
|
|
366
|
+
const lines = await captureAsync(async () => {
|
|
367
|
+
await withTelemetry(async () => "ok")({}, context);
|
|
368
|
+
});
|
|
369
|
+
const started = lines.find(
|
|
370
|
+
(line) => line.msg === "Lambda invocation started",
|
|
371
|
+
);
|
|
372
|
+
assert.ok(started, "expected the start line");
|
|
373
|
+
assert.equal(started.requestId, "req-1");
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
// The line an operator correlates from is written after the handler has
|
|
377
|
+
// unwound, which is exactly what a scope opened inside the handler misses.
|
|
378
|
+
it("puts its own failure line inside the scope", async () => {
|
|
379
|
+
const lines = await captureAsync(async () => {
|
|
380
|
+
await assert.rejects(
|
|
381
|
+
withTelemetry(async () => {
|
|
382
|
+
throw new Error("boom");
|
|
383
|
+
})({}, context),
|
|
384
|
+
);
|
|
385
|
+
});
|
|
386
|
+
const failed = lines.find(
|
|
387
|
+
(line) => line.msg === "Lambda invocation failed",
|
|
388
|
+
);
|
|
389
|
+
assert.ok(failed, "expected the failure line");
|
|
390
|
+
assert.equal(failed.requestId, "req-1");
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
it("carries the same requestId onto the handler's own lines", async () => {
|
|
394
|
+
const lines = await captureAsync(async () => {
|
|
395
|
+
await withTelemetry(async () => {
|
|
396
|
+
logger.warn("from the handler");
|
|
397
|
+
return "ok";
|
|
398
|
+
})({}, context);
|
|
399
|
+
});
|
|
400
|
+
assert.deepEqual(
|
|
401
|
+
[...new Set(lines.map((line) => line.requestId))],
|
|
402
|
+
["req-1"],
|
|
403
|
+
);
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
it("keeps concurrent invocations apart", async () => {
|
|
407
|
+
const invoke = (id: string, delayMs: number) =>
|
|
408
|
+
withTelemetry(async () => {
|
|
409
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
410
|
+
logger.warn(`handled ${id}`);
|
|
411
|
+
})({}, {
|
|
412
|
+
awsRequestId: id,
|
|
413
|
+
functionName: "test-function",
|
|
414
|
+
} as unknown as typeof context);
|
|
415
|
+
|
|
416
|
+
const lines = await captureAsync(async () => {
|
|
417
|
+
await Promise.all([invoke("slow", 10), invoke("fast", 1)]);
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
assert.deepEqual(
|
|
421
|
+
lines
|
|
422
|
+
.filter((line) => String(line.msg).startsWith("handled "))
|
|
423
|
+
.map((line) => [line.msg, line.requestId]),
|
|
424
|
+
[
|
|
425
|
+
["handled fast", "fast"],
|
|
426
|
+
["handled slow", "slow"],
|
|
427
|
+
],
|
|
428
|
+
);
|
|
429
|
+
});
|
|
430
|
+
});
|
package/src/logger.ts
CHANGED
|
@@ -159,32 +159,38 @@ export const logger: Logger = createAdapter(root, {});
|
|
|
159
159
|
|
|
160
160
|
export const createLogger = (): Logger => createAdapter(root, {});
|
|
161
161
|
|
|
162
|
+
// The scope opens around the wrapper's own two lines, not just the handler:
|
|
163
|
+
// "Lambda invocation failed" is the line an operator correlates from, and it is
|
|
164
|
+
// written after the handler has already unwound, so a scope opened inside the
|
|
165
|
+
// handler no longer covers it. Everything the invocation writes — the wrapper's
|
|
166
|
+
// lines and the handler's — carries the same `requestId`.
|
|
162
167
|
export const withTelemetry = <TEvent, TResult>(
|
|
163
168
|
handler: (event: TEvent, context: Context) => Promise<TResult>,
|
|
164
169
|
): ((event: TEvent, context: Context) => Promise<TResult>) => {
|
|
165
|
-
return async (event: TEvent, context: Context): Promise<TResult> =>
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const start = Date.now();
|
|
171
|
-
|
|
172
|
-
try {
|
|
173
|
-
const result = await handler(event, context);
|
|
174
|
-
recordHandlerOutcome({
|
|
175
|
-
handler: context.functionName,
|
|
176
|
-
outcome: "success",
|
|
177
|
-
durationMs: Date.now() - start,
|
|
178
|
-
});
|
|
179
|
-
return result;
|
|
180
|
-
} catch (err) {
|
|
181
|
-
recordHandlerOutcome({
|
|
182
|
-
handler: context.functionName,
|
|
183
|
-
outcome: "failure",
|
|
184
|
-
durationMs: Date.now() - start,
|
|
170
|
+
return async (event: TEvent, context: Context): Promise<TResult> =>
|
|
171
|
+
withLogContext({ requestId: context.awsRequestId }, async () => {
|
|
172
|
+
logger.debug("Lambda invocation started", {
|
|
173
|
+
functionName: context.functionName,
|
|
185
174
|
});
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
175
|
+
|
|
176
|
+
const start = Date.now();
|
|
177
|
+
|
|
178
|
+
try {
|
|
179
|
+
const result = await handler(event, context);
|
|
180
|
+
recordHandlerOutcome({
|
|
181
|
+
handler: context.functionName,
|
|
182
|
+
outcome: "success",
|
|
183
|
+
durationMs: Date.now() - start,
|
|
184
|
+
});
|
|
185
|
+
return result;
|
|
186
|
+
} catch (err) {
|
|
187
|
+
recordHandlerOutcome({
|
|
188
|
+
handler: context.functionName,
|
|
189
|
+
outcome: "failure",
|
|
190
|
+
durationMs: Date.now() - start,
|
|
191
|
+
});
|
|
192
|
+
logger.error("Lambda invocation failed", { error: err });
|
|
193
|
+
throw err;
|
|
194
|
+
}
|
|
195
|
+
});
|
|
190
196
|
};
|