@remit/logger-lambda 0.0.4 → 0.0.6
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 +2 -5
- package/src/logger.test.ts +121 -115
- package/vitest.config.ts +0 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remit/logger-lambda",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "src/index.ts",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
},
|
|
13
13
|
"scripts": {
|
|
14
14
|
"test:typecheck": "tsgo --noEmit",
|
|
15
|
-
"test:run": "
|
|
15
|
+
"test:run": "node --experimental-test-module-mocks --import tsx --experimental-test-coverage --test-coverage-include='src/**' --test-coverage-exclude='src/**/*.test.ts' --test-coverage-exclude='src/**/*.test.tsx' --test-coverage-lines=50 --test 'src/**/*.test.ts'",
|
|
16
16
|
"test": "npm run test:typecheck && npm run test:run",
|
|
17
17
|
"build": "npm run test:typecheck"
|
|
18
18
|
},
|
|
@@ -21,9 +21,6 @@
|
|
|
21
21
|
"@aws-lambda-powertools/metrics": "^2",
|
|
22
22
|
"@types/aws-lambda": "*"
|
|
23
23
|
},
|
|
24
|
-
"devDependencies": {
|
|
25
|
-
"vitest": "*"
|
|
26
|
-
},
|
|
27
24
|
"license": "MIT",
|
|
28
25
|
"publishConfig": {
|
|
29
26
|
"access": "public"
|
package/src/logger.test.ts
CHANGED
|
@@ -1,51 +1,79 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { beforeEach, describe, it, mock } from "node:test";
|
|
1
3
|
import type { Context } from "aws-lambda";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
4
|
+
|
|
5
|
+
const addMetric = mock.fn();
|
|
6
|
+
const publishStoredMetrics = mock.fn();
|
|
7
|
+
const captureColdStartMetric = mock.fn();
|
|
8
|
+
const addContext = mock.fn();
|
|
9
|
+
const logTrace = mock.fn();
|
|
10
|
+
const logDebug = mock.fn();
|
|
11
|
+
const logInfo = mock.fn();
|
|
12
|
+
const logWarn = mock.fn();
|
|
13
|
+
const logError = mock.fn();
|
|
14
|
+
const logCritical = mock.fn();
|
|
15
|
+
const appendPersistentKeys = mock.fn();
|
|
16
|
+
|
|
17
|
+
class MockLogger {
|
|
18
|
+
addContext = addContext;
|
|
19
|
+
trace = logTrace;
|
|
20
|
+
debug = logDebug;
|
|
21
|
+
info = logInfo;
|
|
22
|
+
warn = logWarn;
|
|
23
|
+
error = logError;
|
|
24
|
+
critical = logCritical;
|
|
25
|
+
appendPersistentKeys = appendPersistentKeys;
|
|
26
|
+
createChild = () => createChild();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const createChild = mock.fn(() => new MockLogger());
|
|
30
|
+
|
|
31
|
+
class MockMetrics {
|
|
32
|
+
addMetric = addMetric;
|
|
33
|
+
publishStoredMetrics = publishStoredMetrics;
|
|
34
|
+
captureColdStartMetric = captureColdStartMetric;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
mock.module("@aws-lambda-powertools/logger", {
|
|
38
|
+
namedExports: { Logger: MockLogger },
|
|
31
39
|
});
|
|
32
40
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
info = mockLogInfo;
|
|
39
|
-
warn = mockLogWarn;
|
|
40
|
-
error = mockLogError;
|
|
41
|
-
critical = mockLogCritical;
|
|
42
|
-
appendPersistentKeys = mockAppendPersistentKeys;
|
|
43
|
-
createChild = mockCreateChild;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return { Logger: MockLogger };
|
|
41
|
+
mock.module("@aws-lambda-powertools/metrics", {
|
|
42
|
+
namedExports: {
|
|
43
|
+
Metrics: MockMetrics,
|
|
44
|
+
MetricUnit: { Count: "Count", Milliseconds: "Milliseconds" },
|
|
45
|
+
},
|
|
47
46
|
});
|
|
48
47
|
|
|
48
|
+
const { createLogger, metrics, withTelemetry } = await import("./logger.js");
|
|
49
|
+
const { Metrics } = await import("@aws-lambda-powertools/metrics");
|
|
50
|
+
|
|
51
|
+
type Recorded = { mock: { calls: { arguments: unknown[] }[] } };
|
|
52
|
+
|
|
53
|
+
const calls = (fn: Recorded): unknown[][] =>
|
|
54
|
+
fn.mock.calls.map((call) => call.arguments);
|
|
55
|
+
|
|
56
|
+
const lastCall = (fn: Recorded): unknown[] => {
|
|
57
|
+
const recorded = calls(fn);
|
|
58
|
+
assert.ok(recorded.length > 0, "expected the mock to have been called");
|
|
59
|
+
return recorded[recorded.length - 1];
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const recorded = [
|
|
63
|
+
addMetric,
|
|
64
|
+
publishStoredMetrics,
|
|
65
|
+
captureColdStartMetric,
|
|
66
|
+
addContext,
|
|
67
|
+
logTrace,
|
|
68
|
+
logDebug,
|
|
69
|
+
logInfo,
|
|
70
|
+
logWarn,
|
|
71
|
+
logError,
|
|
72
|
+
logCritical,
|
|
73
|
+
appendPersistentKeys,
|
|
74
|
+
createChild,
|
|
75
|
+
];
|
|
76
|
+
|
|
49
77
|
const makeContext = (): Context =>
|
|
50
78
|
({
|
|
51
79
|
awsRequestId: "test-request-id",
|
|
@@ -57,140 +85,118 @@ const makeContext = (): Context =>
|
|
|
57
85
|
getRemainingTimeInMillis: () => 30000,
|
|
58
86
|
callbackWaitsForEmptyEventLoop: false,
|
|
59
87
|
functionVersion: "$LATEST",
|
|
60
|
-
done:
|
|
61
|
-
fail:
|
|
62
|
-
succeed:
|
|
88
|
+
done: () => {},
|
|
89
|
+
fail: () => {},
|
|
90
|
+
succeed: () => {},
|
|
63
91
|
}) as unknown as Context;
|
|
64
92
|
|
|
65
93
|
describe("remit-logger-lambda", () => {
|
|
66
94
|
beforeEach(() => {
|
|
67
|
-
|
|
68
|
-
mockCreateChild.mockImplementation(() => {
|
|
69
|
-
const child = {
|
|
70
|
-
trace: mockLogTrace,
|
|
71
|
-
debug: mockLogDebug,
|
|
72
|
-
info: mockLogInfo,
|
|
73
|
-
warn: mockLogWarn,
|
|
74
|
-
error: mockLogError,
|
|
75
|
-
critical: mockLogCritical,
|
|
76
|
-
appendPersistentKeys: mockAppendPersistentKeys,
|
|
77
|
-
createChild: mockCreateChild,
|
|
78
|
-
};
|
|
79
|
-
return child;
|
|
80
|
-
});
|
|
95
|
+
for (const fn of recorded) fn.mock.resetCalls();
|
|
81
96
|
});
|
|
82
97
|
|
|
83
|
-
it("exports metrics as a Metrics instance",
|
|
84
|
-
|
|
85
|
-
const { Metrics } = await import("@aws-lambda-powertools/metrics");
|
|
86
|
-
expect(metrics).toBeInstanceOf(Metrics);
|
|
98
|
+
it("exports metrics as a Metrics instance", () => {
|
|
99
|
+
assert.ok(metrics instanceof Metrics);
|
|
87
100
|
});
|
|
88
101
|
|
|
89
|
-
it("object-first call maps to Powertools message + attributes",
|
|
90
|
-
const { createLogger } = await import("./logger.js");
|
|
102
|
+
it("object-first call maps to Powertools message + attributes", () => {
|
|
91
103
|
const log = createLogger(makeContext());
|
|
92
104
|
log.error({ error: "boom", messageId: "m1" }, "Failed to parse message");
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
messageId: "m1",
|
|
96
|
-
|
|
105
|
+
assert.deepEqual(lastCall(logError), [
|
|
106
|
+
"Failed to parse message",
|
|
107
|
+
{ error: "boom", messageId: "m1" },
|
|
108
|
+
]);
|
|
97
109
|
});
|
|
98
110
|
|
|
99
|
-
it("object-first call without message uses empty string",
|
|
100
|
-
const { createLogger } = await import("./logger.js");
|
|
111
|
+
it("object-first call without message uses empty string", () => {
|
|
101
112
|
const log = createLogger();
|
|
102
113
|
log.info({ count: 3 });
|
|
103
|
-
|
|
114
|
+
assert.deepEqual(lastCall(logInfo), ["", { count: 3 }]);
|
|
104
115
|
});
|
|
105
116
|
|
|
106
|
-
it("string-first call passes message then attributes",
|
|
107
|
-
const { createLogger } = await import("./logger.js");
|
|
117
|
+
it("string-first call passes message then attributes", () => {
|
|
108
118
|
const log = createLogger();
|
|
109
119
|
log.warn("watch out", { reason: "slow" });
|
|
110
|
-
|
|
120
|
+
assert.deepEqual(lastCall(logWarn), ["watch out", { reason: "slow" }]);
|
|
111
121
|
});
|
|
112
122
|
|
|
113
|
-
it("string-first call without attributes passes only the message",
|
|
114
|
-
const { createLogger } = await import("./logger.js");
|
|
123
|
+
it("string-first call without attributes passes only the message", () => {
|
|
115
124
|
const log = createLogger();
|
|
116
125
|
log.debug("hello");
|
|
117
|
-
|
|
126
|
+
assert.deepEqual(lastCall(logDebug), ["hello"]);
|
|
118
127
|
});
|
|
119
128
|
|
|
120
|
-
it("fatal maps to Powertools critical",
|
|
121
|
-
const { createLogger } = await import("./logger.js");
|
|
129
|
+
it("fatal maps to Powertools critical", () => {
|
|
122
130
|
const log = createLogger();
|
|
123
131
|
log.fatal({ fatal: true }, "the end");
|
|
124
|
-
|
|
132
|
+
assert.deepEqual(lastCall(logCritical), ["the end", { fatal: true }]);
|
|
125
133
|
});
|
|
126
134
|
|
|
127
|
-
it("trace maps to Powertools trace",
|
|
128
|
-
const { createLogger } = await import("./logger.js");
|
|
135
|
+
it("trace maps to Powertools trace", () => {
|
|
129
136
|
const log = createLogger();
|
|
130
137
|
log.trace("trace me");
|
|
131
|
-
|
|
138
|
+
assert.deepEqual(lastCall(logTrace), ["trace me"]);
|
|
132
139
|
});
|
|
133
140
|
|
|
134
|
-
it("child creates a Powertools child and appends bindings",
|
|
135
|
-
const { createLogger } = await import("./logger.js");
|
|
141
|
+
it("child creates a Powertools child and appends bindings", () => {
|
|
136
142
|
const log = createLogger();
|
|
137
143
|
const child = log.child({ queue: "imap" });
|
|
138
|
-
|
|
139
|
-
|
|
144
|
+
assert.equal(calls(createChild).length, 1);
|
|
145
|
+
assert.deepEqual(lastCall(appendPersistentKeys), [{ queue: "imap" }]);
|
|
140
146
|
child.info({ done: true }, "child log");
|
|
141
|
-
|
|
147
|
+
assert.deepEqual(lastCall(logInfo), ["child log", { done: true }]);
|
|
142
148
|
});
|
|
143
149
|
|
|
144
|
-
it("setBindings appends persistent keys",
|
|
145
|
-
const { createLogger } = await import("./logger.js");
|
|
150
|
+
it("setBindings appends persistent keys", () => {
|
|
146
151
|
const log = createLogger();
|
|
147
152
|
log.setBindings({ requestId: "r1" });
|
|
148
|
-
|
|
153
|
+
assert.deepEqual(lastCall(appendPersistentKeys), [{ requestId: "r1" }]);
|
|
149
154
|
});
|
|
150
155
|
|
|
151
156
|
it("withTelemetry calls the handler and returns its result", async () => {
|
|
152
|
-
const
|
|
153
|
-
const handler = vi.fn().mockResolvedValue("hello");
|
|
157
|
+
const handler = mock.fn(async () => "hello");
|
|
154
158
|
const wrapped = withTelemetry(handler);
|
|
155
159
|
const result = await wrapped({ key: "value" }, makeContext());
|
|
156
|
-
|
|
157
|
-
|
|
160
|
+
assert.equal(result, "hello");
|
|
161
|
+
assert.equal(calls(handler).length, 1);
|
|
158
162
|
});
|
|
159
163
|
|
|
160
164
|
it("withTelemetry re-throws handler errors", async () => {
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
|
|
165
|
+
const handler = mock.fn(async () => {
|
|
166
|
+
throw new Error("boom");
|
|
167
|
+
});
|
|
164
168
|
const wrapped = withTelemetry(handler);
|
|
165
|
-
await
|
|
169
|
+
await assert.rejects(wrapped({}, makeContext()), /boom/);
|
|
166
170
|
});
|
|
167
171
|
|
|
168
172
|
it("withTelemetry publishes metrics in finally even on error", async () => {
|
|
169
|
-
const
|
|
170
|
-
|
|
173
|
+
const handler = mock.fn(async () => {
|
|
174
|
+
throw new Error("fail");
|
|
175
|
+
});
|
|
171
176
|
const wrapped = withTelemetry(handler);
|
|
172
|
-
await
|
|
173
|
-
|
|
177
|
+
await assert.rejects(wrapped({}, makeContext()));
|
|
178
|
+
assert.ok(calls(publishStoredMetrics).length > 0);
|
|
174
179
|
});
|
|
175
180
|
|
|
176
181
|
it("withTelemetry emits errorCount on handler failure", async () => {
|
|
177
|
-
const
|
|
178
|
-
|
|
182
|
+
const handler = mock.fn(async () => {
|
|
183
|
+
throw new Error("fail");
|
|
184
|
+
});
|
|
179
185
|
const wrapped = withTelemetry(handler);
|
|
180
|
-
await
|
|
181
|
-
|
|
186
|
+
await assert.rejects(wrapped({}, makeContext()));
|
|
187
|
+
assert.deepEqual(calls(addMetric), [["errorCount", "Count", 1]]);
|
|
182
188
|
});
|
|
183
189
|
|
|
184
190
|
it("withTelemetry emits invocationCount and invocationLatency on success", async () => {
|
|
185
|
-
const
|
|
186
|
-
const handler = vi.fn().mockResolvedValue(42);
|
|
191
|
+
const handler = mock.fn(async () => 42);
|
|
187
192
|
const wrapped = withTelemetry(handler);
|
|
188
193
|
await wrapped({}, makeContext());
|
|
189
|
-
|
|
190
|
-
|
|
194
|
+
const [countCall, latencyCall] = calls(addMetric);
|
|
195
|
+
assert.deepEqual(countCall, ["invocationCount", "Count", 1]);
|
|
196
|
+
assert.deepEqual(latencyCall.slice(0, 2), [
|
|
191
197
|
"invocationLatency",
|
|
192
198
|
"Milliseconds",
|
|
193
|
-
|
|
194
|
-
);
|
|
199
|
+
]);
|
|
200
|
+
assert.equal(typeof latencyCall[2], "number");
|
|
195
201
|
});
|
|
196
202
|
});
|
package/vitest.config.ts
DELETED