Skip to content

Commit 3a2f617

Browse files
authored
fix: log requestId, extendedRequestId, cfId in metadata (#1640)
1 parent 441480b commit 3a2f617

File tree

3 files changed

+71
-27
lines changed

3 files changed

+71
-27
lines changed

packages/middleware-logger/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"tslib": "^1.8.0"
2424
},
2525
"devDependencies": {
26+
"@aws-sdk/protocol-http": "1.0.0-rc.3",
2627
"@types/jest": "^26.0.4",
2728
"@types/node": "^10.0.0",
2829
"jest": "^26.1.0",

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

+52-13
Original file line numberDiff line numberDiff line change
@@ -32,37 +32,40 @@ describe("loggerMiddleware", () => {
3232
};
3333

3434
const mockResponse = {
35-
output: {
36-
$metadata: {
37-
statusCode: 200,
38-
requestId: "requestId",
35+
response: {
36+
statusCode: 200,
37+
headers: {
38+
"x-amzn-requestid": "requestId",
39+
"x-amz-id-2": "extendedRequestId",
40+
"x-amz-cf-id": "cfId",
3941
},
42+
},
43+
output: {
4044
outputKey: "outputValue",
4145
},
4246
};
4347

44-
beforeEach(() => {
45-
mockNext.mockResolvedValueOnce(mockResponse);
46-
});
47-
4848
afterEach(() => {
4949
jest.clearAllMocks();
5050
});
5151

5252
it("returns without logging if context.logger is not defined", async () => {
53+
mockNext.mockResolvedValueOnce(mockResponse);
5354
const response = await loggerMiddleware()(mockNext, {})(mockArgs);
5455
expect(mockNext).toHaveBeenCalledTimes(1);
5556
expect(response).toStrictEqual(mockResponse);
5657
});
5758

5859
it("returns without logging if context.logger doesn't have info function", async () => {
60+
mockNext.mockResolvedValueOnce(mockResponse);
5961
const logger = {} as Logger;
6062
const response = await loggerMiddleware()(mockNext, { logger })(mockArgs);
6163
expect(mockNext).toHaveBeenCalledTimes(1);
6264
expect(response).toStrictEqual(mockResponse);
6365
});
6466

65-
it("logs $metadata if context.logger has info function", async () => {
67+
it("logs metadata if context.logger has info function", async () => {
68+
mockNext.mockResolvedValueOnce(mockResponse);
6669
const logger = ({ info: jest.fn() } as unknown) as Logger;
6770

6871
const context = {
@@ -75,11 +78,47 @@ describe("loggerMiddleware", () => {
7578

7679
expect(logger.info).toHaveBeenCalledTimes(1);
7780

78-
const {
79-
output: { $metadata },
80-
} = mockResponse;
8181
expect(logger.info).toHaveBeenCalledWith({
82-
$metadata,
82+
metadata: {
83+
statusCode: mockResponse.response.statusCode,
84+
requestId: mockResponse.response.headers["x-amzn-requestid"],
85+
extendedRequestId: mockResponse.response.headers["x-amz-id-2"],
86+
cfId: mockResponse.response.headers["x-amz-cf-id"],
87+
},
88+
});
89+
});
90+
91+
it("logs header x-amzn-request-id as requestId if x-amzn-requestid is not present", async () => {
92+
const requestIdBackup = "requestIdBackup";
93+
const customResponse = {
94+
...mockResponse,
95+
response: {
96+
...mockResponse.response,
97+
headers: {
98+
"x-amzn-request-id": requestIdBackup,
99+
},
100+
},
101+
};
102+
mockNext.mockResolvedValueOnce(customResponse);
103+
const logger = ({ info: jest.fn() } as unknown) as Logger;
104+
105+
const context = {
106+
logger,
107+
};
108+
109+
const response = await loggerMiddleware()(mockNext, context)(mockArgs);
110+
expect(mockNext).toHaveBeenCalledTimes(1);
111+
expect(response).toStrictEqual(customResponse);
112+
113+
expect(logger.info).toHaveBeenCalledTimes(1);
114+
115+
expect(logger.info).toHaveBeenCalledWith({
116+
metadata: {
117+
statusCode: customResponse.response.statusCode,
118+
requestId: requestIdBackup,
119+
extendedRequestId: undefined,
120+
cfId: undefined,
121+
},
83122
});
84123
});
85124
});

packages/middleware-logger/src/loggerMiddleware.ts

+18-14
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
1+
import { HttpResponse } from "@aws-sdk/protocol-http";
12
import {
23
AbsoluteLocation,
3-
BuildHandler,
4-
BuildHandlerArguments,
5-
BuildHandlerOptions,
6-
BuildHandlerOutput,
74
HandlerExecutionContext,
5+
InitializeHandler,
6+
InitializeHandlerArguments,
7+
InitializeHandlerOptions,
8+
InitializeHandlerOutput,
89
MetadataBearer,
910
Pluggable,
1011
} from "@aws-sdk/types";
1112

1213
export const loggerMiddleware = () => <Output extends MetadataBearer = MetadataBearer>(
13-
next: BuildHandler<any, Output>,
14+
next: InitializeHandler<any, Output>,
1415
context: HandlerExecutionContext
15-
): BuildHandler<any, Output> => async (args: BuildHandlerArguments<any>): Promise<BuildHandlerOutput<Output>> => {
16+
): InitializeHandler<any, Output> => async (
17+
args: InitializeHandlerArguments<any>
18+
): Promise<InitializeHandlerOutput<Output>> => {
1619
const { logger } = context;
1720

1821
const response = await next(args);
@@ -21,25 +24,26 @@ export const loggerMiddleware = () => <Output extends MetadataBearer = MetadataB
2124
return response;
2225
}
2326

24-
const {
25-
output: { $metadata },
26-
} = response;
27+
const httpResponse = response.response as HttpResponse;
2728

28-
// TODO: Populate custom metadata in https://github.com/aws/aws-sdk-js-v3/issues/1491#issuecomment-692174256
29-
// $metadata will be removed in https://github.com/aws/aws-sdk-js-v3/issues/1490
3029
if (typeof logger.info === "function") {
3130
logger.info({
32-
$metadata,
31+
metadata: {
32+
statusCode: httpResponse.statusCode,
33+
requestId: httpResponse.headers["x-amzn-requestid"] ?? httpResponse.headers["x-amzn-request-id"],
34+
extendedRequestId: httpResponse.headers["x-amz-id-2"],
35+
cfId: httpResponse.headers["x-amz-cf-id"],
36+
},
3337
});
3438
}
3539

3640
return response;
3741
};
3842

39-
export const loggerMiddlewareOptions: BuildHandlerOptions & AbsoluteLocation = {
43+
export const loggerMiddlewareOptions: InitializeHandlerOptions & AbsoluteLocation = {
4044
name: "loggerMiddleware",
4145
tags: ["LOGGER"],
42-
step: "build",
46+
step: "initialize",
4347
};
4448

4549
// eslint-disable-next-line @typescript-eslint/no-unused-vars

0 commit comments

Comments
 (0)