Skip to content

Commit 619bbfc

Browse files
VIA-357 Log nextUrl and traceId on ClientSideError. Refactor requestContext to reduce duplication
nextURL is now available on requestContext and included in all nodeJs logs
1 parent 586e7e9 commit 619bbfc

File tree

12 files changed

+50
-31
lines changed

12 files changed

+50
-31
lines changed

auth.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ import { getUpdatedSession } from "@src/utils/auth/callbacks/get-updated-session
88
import { isValidSignIn } from "@src/utils/auth/callbacks/is-valid-signin";
99
import { MaxAgeInSeconds } from "@src/utils/auth/types";
1010
import { AppConfig, configProvider } from "@src/utils/config";
11-
import { extractRootTraceIdFromAmznTraceId, logger } from "@src/utils/logger";
11+
import { logger } from "@src/utils/logger";
1212
import { profilePerformanceEnd, profilePerformanceStart } from "@src/utils/performance";
1313
import { RequestContext, asyncLocalStorage } from "@src/utils/requestContext";
14+
import { extractRequestContextFromHeaders } from "@src/utils/requestScopedStorageWrapper";
1415
import NextAuth from "next-auth";
1516
import "next-auth/jwt";
1617
import { headers } from "next/headers";
@@ -25,9 +26,8 @@ export const { handlers, signIn, signOut, auth } = NextAuth(async () => {
2526
const config: AppConfig = await configProvider();
2627
const MAX_SESSION_AGE_SECONDS: number = config.MAX_SESSION_AGE_MINUTES * 60;
2728
const headerValues = await headers();
28-
const traceId =
29-
extractRootTraceIdFromAmznTraceId(headerValues.get("X-Amzn-Trace-Id") ?? "") ?? "undefined-request-id";
30-
const requestContext: RequestContext = { traceId: traceId };
29+
30+
const requestContext: RequestContext = extractRequestContextFromHeaders(headerValues);
3131

3232
return await asyncLocalStorage.run(requestContext, async () => {
3333
return {
@@ -58,7 +58,11 @@ export const { handlers, signIn, signOut, auth } = NextAuth(async () => {
5858
}
5959

6060
if (response) {
61-
const auditEvent: AuditEvent = createLoginAuditEvent(profile!.nhs_number, traceId, "Success");
61+
const auditEvent: AuditEvent = createLoginAuditEvent(
62+
profile!.nhs_number,
63+
requestContext.traceId,
64+
"Success",
65+
);
6266
await sendAuditEvent(auditEvent);
6367
}
6468

contract/fetch-eligibility-content.contract.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ pactWith({ consumer: "VitA", provider: "EliD", port: 1234, logLevel: "warn" }, (
8181
});
8282

8383
it("fetches eligibility content successfully", async () => {
84-
const response = await asyncLocalStorage.run({ traceId: vitaTraceId }, async () => {
84+
const response = await asyncLocalStorage.run({ traceId: vitaTraceId, nextUrl: "" }, async () => {
8585
return await fetchEligibilityContent(mockNhsNumber);
8686
});
8787

src/_lambda/content-cache-hydrator/handler.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ describe("Lambda Handler", () => {
258258

259259
await handler({}, contextWithRequestId);
260260

261-
expect(asyncLocalStorage.run).toHaveBeenCalledWith({ traceId: requestId }, expect.anything());
261+
expect(asyncLocalStorage.run).toHaveBeenCalledWith({ traceId: requestId, nextUrl: "" }, expect.anything());
262262
});
263263

264264
it("should only update one vaccine if vaccine name is set in inbound event", async () => {

src/_lambda/content-cache-hydrator/handler.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ const runContentCacheHydrator = async (event: ContentCacheHydratorEvent) => {
188188
export const handler = async (event: object, context: Context): Promise<void> => {
189189
const requestContext: RequestContext = {
190190
traceId: context.awsRequestId,
191+
nextUrl: "",
191192
};
192193

193194
await asyncLocalStorage.run(requestContext, () => runContentCacheHydrator(event));

src/app/api/sso-to-nbs/route.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { SSO_FAILURE_ROUTE } from "@src/app/sso-failure/constants";
22
import { VaccineTypes } from "@src/models/vaccine";
33
import { getNbsQueryParams, getSSOUrlToNBSForVaccine } from "@src/services/nbs/nbs-service";
4-
import { extractRootTraceIdFromAmznTraceId, logger } from "@src/utils/logger";
4+
import { logger } from "@src/utils/logger";
55
import { getVaccineTypeFromLowercaseString } from "@src/utils/path";
66
import { profilePerformanceEnd, profilePerformanceStart } from "@src/utils/performance";
77
import { RequestContext, asyncLocalStorage } from "@src/utils/requestContext";
8+
import { extractRequestContextFromHeaders } from "@src/utils/requestScopedStorageWrapper";
89
import { notFound, redirect } from "next/navigation";
910
import { NextRequest } from "next/server";
1011

@@ -14,9 +15,7 @@ const REDIRECT_TARGET_PARAM = "redirectTarget";
1415
const ApiSSONBSPerformanceMarker = "api-sso-nbs";
1516

1617
export const GET = async (request: NextRequest) => {
17-
const traceId =
18-
extractRootTraceIdFromAmznTraceId(request?.headers?.get("X-Amzn-Trace-Id") ?? "") ?? "undefined-request-id";
19-
const requestContext: RequestContext = { traceId: traceId };
18+
const requestContext: RequestContext = extractRequestContextFromHeaders(request?.headers);
2019
await asyncLocalStorage.run(requestContext, async () => {
2120
let shouldReturnNotFound: boolean;
2221
let finalRedirectUrl: string;

src/app/api/sso/route.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { signIn } from "@project/auth";
22
import { NHS_LOGIN_PROVIDER_ID } from "@src/app/api/auth/[...nextauth]/provider";
33
import { SSO_FAILURE_ROUTE } from "@src/app/sso-failure/constants";
4-
import { extractRootTraceIdFromAmznTraceId, logger } from "@src/utils/logger";
4+
import { logger } from "@src/utils/logger";
55
import { profilePerformanceEnd, profilePerformanceStart } from "@src/utils/performance";
66
import { RequestContext, asyncLocalStorage } from "@src/utils/requestContext";
7+
import { extractRequestContextFromHeaders } from "@src/utils/requestScopedStorageWrapper";
78
import { redirect } from "next/navigation";
89
import { NextRequest } from "next/server";
910

@@ -12,9 +13,8 @@ const ASSERTED_LOGIN_IDENTITY_PARAM = "assertedLoginIdentity";
1213
const ApiSSOPerformanceMarker = "api-sso";
1314

1415
export const GET = async (request: NextRequest) => {
15-
const traceId =
16-
extractRootTraceIdFromAmznTraceId(request?.headers?.get("X-Amzn-Trace-Id") ?? "") ?? "undefined-request-id";
17-
const requestContext: RequestContext = { traceId: traceId };
16+
const requestContext: RequestContext = extractRequestContextFromHeaders(request?.headers);
17+
1818
await asyncLocalStorage.run(requestContext, async () => {
1919
const assertedLoginIdentity: string | null = request.nextUrl.searchParams.get(ASSERTED_LOGIN_IDENTITY_PARAM);
2020

src/middleware.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { auth } from "@project/auth";
22
import { AppConfig, configProvider } from "@src/utils/config";
3-
import { extractRootTraceIdFromAmznTraceId, logger } from "@src/utils/logger";
3+
import { logger } from "@src/utils/logger";
44
import { profilePerformanceEnd, profilePerformanceStart } from "@src/utils/performance";
55
import { RequestContext, asyncLocalStorage } from "@src/utils/requestContext";
6+
import { extractRequestContextFromHeaders } from "@src/utils/requestScopedStorageWrapper";
67
import { Session } from "next-auth";
78
import { NextRequest, NextResponse } from "next/server";
89
import { Logger } from "pino";
@@ -11,17 +12,19 @@ const log: Logger = logger.child({ module: "middleware" });
1112
const MiddlewarePerformanceMarker = "middleware";
1213

1314
export async function middleware(request: NextRequest) {
14-
const requestContext: RequestContext = {
15-
traceId:
16-
extractRootTraceIdFromAmznTraceId(request?.headers?.get("X-Amzn-Trace-Id") ?? "") ?? "undefined-request-id",
17-
};
15+
const requestContext: RequestContext = extractRequestContextFromHeaders(request?.headers);
1816

1917
return await asyncLocalStorage.run(requestContext, () => middlewareWrapper(request));
2018
}
2119

2220
const middlewareWrapper = async (request: NextRequest) => {
2321
profilePerformanceStart(MiddlewarePerformanceMarker);
2422
log.info({ context: { nextUrl: request.nextUrl.href } }, "Inspecting request");
23+
24+
// Add URL to request headers to make available for logging in the nodejs layer
25+
const headers = new Headers(request.headers);
26+
headers.set("nextUrl", request.nextUrl.href);
27+
2528
const config: AppConfig = await configProvider();
2629

2730
let response: NextResponse;
@@ -30,7 +33,7 @@ const middlewareWrapper = async (request: NextRequest) => {
3033
log.info({ context: { nextUrl: request.nextUrl.href } }, "Missing user session, redirecting to login");
3134
response = NextResponse.redirect(new URL(config.NHS_APP_REDIRECT_LOGIN_URL));
3235
} else {
33-
response = NextResponse.next();
36+
response = NextResponse.next({ headers });
3437
}
3538

3639
profilePerformanceEnd(MiddlewarePerformanceMarker);

src/utils/auth/callbacks/get-token.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ import { retrieveApimCredentials } from "@src/utils/auth/apim/get-apim-access-to
33
import { ApimAccessCredentials } from "@src/utils/auth/apim/types";
44
import { ExpiresSoonAt, IdToken, MaxAgeInSeconds, NowInSeconds } from "@src/utils/auth/types";
55
import { AppConfig } from "@src/utils/config";
6-
import { extractRootTraceIdFromAmznTraceId, logger } from "@src/utils/logger";
6+
import { logger } from "@src/utils/logger";
77
import { RequestContext, asyncLocalStorage } from "@src/utils/requestContext";
8+
import { extractRequestContextFromHeaders } from "@src/utils/requestScopedStorageWrapper";
89
import { Account, Profile } from "next-auth";
910
import { JWT } from "next-auth/jwt";
1011
import { headers } from "next/headers";
@@ -27,9 +28,9 @@ const getToken = async (
2728
maxAgeInSeconds: MaxAgeInSeconds,
2829
) => {
2930
const headerValues = await headers();
30-
const traceId =
31-
extractRootTraceIdFromAmznTraceId(headerValues?.get("X-Amzn-Trace-Id") ?? "") ?? "undefined-request-id";
32-
const requestContext: RequestContext = { traceId: traceId };
31+
32+
const requestContext: RequestContext = extractRequestContextFromHeaders(headerValues);
33+
3334
return await asyncLocalStorage.run(requestContext, async () => {
3435
if (!token) {
3536
log.error("getToken: No token available in jwt callback. Returning null");

src/utils/client-side-error-logger/client-side-error-logger.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,16 @@
22

33
import { ClientSideErrorTypes } from "@src/utils/constants";
44
import { logger } from "@src/utils/logger";
5+
import { requestScopedStorageWrapper } from "@src/utils/requestScopedStorageWrapper";
56
import { Logger } from "pino";
67

78
const log: Logger = logger.child({ module: "client-side-error-logger" });
89

910
const logClientSideError = async (clientSideErrorType: ClientSideErrorTypes): Promise<void> => {
11+
return requestScopedStorageWrapper(logClientSideErrorAction, clientSideErrorType);
12+
};
13+
14+
const logClientSideErrorAction = async (clientSideErrorType: ClientSideErrorTypes): Promise<void> => {
1015
log.error({ context: { clientSideErrorType: clientSideErrorType } }, "Client side error occurred");
1116
};
1217

src/utils/logger.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ const pinoLoggerForNode = () => {
7575
mixin() {
7676
return {
7777
traceId: asyncLocalStorage?.getStore()?.traceId,
78+
nextUrl: asyncLocalStorage?.getStore()?.nextUrl,
7879
...applicationContextFields,
7980
};
8081
},

0 commit comments

Comments
 (0)