Skip to content

Commit 02e11cb

Browse files
committed
feat(middleware-logger): log request errors
1 parent 8cf39f6 commit 02e11cb

File tree

2 files changed

+96
-14
lines changed

2 files changed

+96
-14
lines changed

packages/middleware-logger/src/loggerMiddleware.spec.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,14 @@ describe("loggerMiddleware", () => {
7272
expect(response).toStrictEqual(mockResponse);
7373
});
7474

75+
it("rejects without logging if context.logger doesn't have error function", async () => {
76+
const nextError = new Error("next error");
77+
mockNext.mockRejectedValueOnce(nextError);
78+
const logger = {} as Logger;
79+
const response = await expect(loggerMiddleware()(mockNext, { logger })(mockArgs)).rejects.toThrow(nextError);
80+
expect(mockNext).toHaveBeenCalledTimes(1);
81+
});
82+
7583
describe("logs if context.logger has info function", () => {
7684
it("success case with clientName, commandName, input, metadata", async () => {
7785
mockNext.mockResolvedValueOnce(mockResponse);
@@ -149,4 +157,76 @@ describe("loggerMiddleware", () => {
149157
});
150158
});
151159
});
160+
161+
describe("logs if context.logger has error function", () => {
162+
it("next throws synchronously", async () => {
163+
const { $metadata } = mockOutput;
164+
const nextError = new Error("example error");
165+
Object.assign(nextError, { $metadata });
166+
mockNext.mockImplementationOnce(() => {
167+
throw nextError;
168+
});
169+
170+
const clientName = "mockClientName";
171+
const commandName = "mockCommandName";
172+
173+
const logger = { error: jest.fn() } as unknown as Logger;
174+
const inputFilterSensitiveLog = jest.fn().mockImplementationOnce((input) => input);
175+
const outputFilterSensitiveLog = jest.fn().mockImplementationOnce((output) => output);
176+
177+
const context = {
178+
clientName,
179+
commandName,
180+
logger,
181+
inputFilterSensitiveLog,
182+
outputFilterSensitiveLog,
183+
};
184+
185+
await expect(loggerMiddleware()(mockNext, context)(mockArgs)).rejects.toThrow(nextError);
186+
expect(mockNext).toHaveBeenCalledTimes(1);
187+
188+
expect(logger.error).toHaveBeenCalledTimes(1);
189+
expect(logger.error).toHaveBeenCalledWith({
190+
clientName,
191+
commandName,
192+
input: mockArgs.input,
193+
error: nextError,
194+
metadata: $metadata,
195+
});
196+
});
197+
198+
it("next rejects", async () => {
199+
const { $metadata } = mockOutput;
200+
const nextError = new Error("example error");
201+
Object.assign(nextError, { $metadata });
202+
mockNext.mockRejectedValueOnce(nextError);
203+
204+
const clientName = "mockClientName";
205+
const commandName = "mockCommandName";
206+
207+
const logger = { error: jest.fn() } as unknown as Logger;
208+
const inputFilterSensitiveLog = jest.fn().mockImplementationOnce((input) => input);
209+
const outputFilterSensitiveLog = jest.fn().mockImplementationOnce((output) => output);
210+
211+
const context = {
212+
clientName,
213+
commandName,
214+
logger,
215+
inputFilterSensitiveLog,
216+
outputFilterSensitiveLog,
217+
};
218+
219+
await expect(loggerMiddleware()(mockNext, context)(mockArgs)).rejects.toThrow(nextError);
220+
expect(mockNext).toHaveBeenCalledTimes(1);
221+
222+
expect(logger.error).toHaveBeenCalledTimes(1);
223+
expect(logger.error).toHaveBeenCalledWith({
224+
clientName,
225+
commandName,
226+
input: mockArgs.input,
227+
error: nextError,
228+
metadata: $metadata,
229+
});
230+
});
231+
});
152232
});

packages/middleware-logger/src/loggerMiddleware.ts

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,26 +16,28 @@ export const loggerMiddleware =
1616
context: HandlerExecutionContext
1717
): InitializeHandler<any, Output> =>
1818
async (args: InitializeHandlerArguments<any>): Promise<InitializeHandlerOutput<Output>> => {
19-
const { clientName, commandName, inputFilterSensitiveLog, logger, outputFilterSensitiveLog } = context;
20-
21-
const response = await next(args);
22-
23-
if (!logger) {
24-
return response;
25-
}
26-
27-
if (typeof logger.info === "function") {
28-
const { $metadata, ...outputWithoutMetadata } = response.output;
29-
logger.info({
19+
const { clientName, commandName, inputFilterSensitiveLog, outputFilterSensitiveLog, logger } = context;
20+
try {
21+
const response = await next(args);
22+
const { $metadata, ...output } = response.output;
23+
logger?.info?.({
3024
clientName,
3125
commandName,
3226
input: inputFilterSensitiveLog(args.input),
33-
output: outputFilterSensitiveLog(outputWithoutMetadata),
27+
output: outputFilterSensitiveLog(output),
3428
metadata: $metadata,
3529
});
30+
return response;
31+
} catch (error) {
32+
logger?.error?.({
33+
clientName,
34+
commandName,
35+
input: inputFilterSensitiveLog(args.input),
36+
error,
37+
metadata: (error as any).$metadata,
38+
});
39+
throw error;
3640
}
37-
38-
return response;
3941
};
4042

4143
export const loggerMiddlewareOptions: InitializeHandlerOptions & AbsoluteLocation = {

0 commit comments

Comments
 (0)