Skip to content

Commit 6286f54

Browse files
committed
Better logger formatting
1 parent 5110419 commit 6286f54

10 files changed

Lines changed: 101 additions & 37 deletions

File tree

internal/helpers/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"dependencies": {
3+
"pino": "^9.7.0",
34
"zod": "^4.1.11"
45
},
56
"description": "Common helper utilities for NHS Notify Supplier API",
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { createLogger } from "../logger";
2+
3+
describe("createLogger", () => {
4+
it("should create a logger with default log level", () => {
5+
const logger = createLogger();
6+
7+
expect(logger.level).toBe("info");
8+
});
9+
10+
it("should create a logger with custom log level", () => {
11+
const logger = createLogger({ logLevel: "debug" });
12+
13+
expect(logger.level).toBe("debug");
14+
});
15+
16+
it("should have expected logging methods", () => {
17+
const logger = createLogger();
18+
19+
expect(typeof logger.info).toBe("function");
20+
expect(typeof logger.error).toBe("function");
21+
expect(typeof logger.warn).toBe("function");
22+
expect(typeof logger.debug).toBe("function");
23+
});
24+
});

internal/helpers/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@
77
export * from "./version";
88
export { default as $Environment } from "./environment";
99
export * from "./id-ref";
10+
export * from "./logger";

internal/helpers/src/logger.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import pino, { Logger } from "pino";
2+
3+
export type LoggerOptions = {
4+
logLevel?: string;
5+
};
6+
7+
/**
8+
* Creates a configured pino logger instance for use across lambdas.
9+
*
10+
* @param options - Optional configuration for the logger
11+
* @param options.logLevel - The log level (defaults to "info")
12+
* @returns A configured pino Logger instance
13+
*/
14+
export function createLogger(options: LoggerOptions = {}): Logger {
15+
const { logLevel = "info" } = options;
16+
17+
return pino({
18+
level: logLevel,
19+
formatters: {
20+
level: (label) => {
21+
return { level: label.toUpperCase() };
22+
},
23+
},
24+
timestamp: () => `,"timestamp":"${new Date(Date.now()).toISOString()}"`,
25+
});
26+
}

lambdas/api-handler/src/config/__tests__/deps.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ describe("createDependenciesContainer", () => {
1515
jest.clearAllMocks();
1616
jest.resetModules();
1717

18-
// pino
19-
jest.mock("pino", () => ({
20-
__esModule: true,
21-
default: jest.fn(() => ({
18+
// @internal/helpers - createLogger
19+
jest.mock("@internal/helpers", () => ({
20+
createLogger: jest.fn(() => ({
2221
info: jest.fn(),
2322
error: jest.fn(),
2423
warn: jest.fn(),
2524
debug: jest.fn(),
25+
level: "info",
2626
})),
2727
}));
2828

@@ -49,7 +49,7 @@ describe("createDependenciesContainer", () => {
4949
// get current mock instances
5050
const { S3Client } = jest.requireMock("@aws-sdk/client-s3");
5151
const { SQSClient } = jest.requireMock("@aws-sdk/client-sqs");
52-
const pinoMock = jest.requireMock("pino");
52+
const { createLogger } = jest.requireMock("@internal/helpers");
5353
const { LetterRepository, MIRepository } = jest.requireMock(
5454
"@internal/datastore",
5555
);
@@ -63,7 +63,7 @@ describe("createDependenciesContainer", () => {
6363

6464
expect(SQSClient).toHaveBeenCalledTimes(1);
6565

66-
expect(pinoMock.default).toHaveBeenCalledTimes(1);
66+
expect(createLogger).toHaveBeenCalledTimes(1);
6767

6868
expect(LetterRepository).toHaveBeenCalledTimes(1);
6969
const letterRepoCtorArgs = LetterRepository.mock.calls[0];

lambdas/api-handler/src/config/deps.ts

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@ import { S3Client } from "@aws-sdk/client-s3";
22
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
33
import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb";
44
import { SQSClient } from "@aws-sdk/client-sqs";
5-
import pino from "pino";
5+
import { Logger } from "pino";
66
import {
77
DBHealthcheck,
88
LetterRepository,
99
MIRepository,
1010
} from "@internal/datastore";
11+
import { createLogger } from "@internal/helpers";
1112
import { EnvVars, envVars } from "./env";
1213

1314
export type Deps = {
@@ -16,7 +17,7 @@ export type Deps = {
1617
letterRepo: LetterRepository;
1718
miRepo: MIRepository;
1819
dbHealthcheck: DBHealthcheck;
19-
logger: pino.Logger;
20+
logger: Logger;
2021
env: EnvVars;
2122
};
2223

@@ -26,7 +27,7 @@ function createDocumentClient(): DynamoDBDocumentClient {
2627
}
2728

2829
function createLetterRepository(
29-
log: pino.Logger,
30+
log: Logger,
3031
environment: EnvVars,
3132
): LetterRepository {
3233
const config = {
@@ -47,7 +48,7 @@ function createDBHealthcheck(environment: EnvVars): DBHealthcheck {
4748
}
4849

4950
function createMIRepository(
50-
log: pino.Logger,
51+
log: Logger,
5152
environment: EnvVars,
5253
): MIRepository {
5354
const config = {
@@ -59,15 +60,7 @@ function createMIRepository(
5960
}
6061

6162
export function createDependenciesContainer(): Deps {
62-
const log = pino({
63-
level: envVars.PINO_LOG_LEVEL || "info",
64-
formatters: {
65-
level: (label) => {
66-
return { level: label.toUpperCase() };
67-
},
68-
},
69-
timestamp: () => `,"timestamp":"${new Date(Date.now()).toISOString()}"`,
70-
});
63+
const log = createLogger({ logLevel: envVars.PINO_LOG_LEVEL });
7164

7265
return {
7366
s3Client: new S3Client(),

lambdas/upsert-letter/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"@aws-sdk/client-dynamodb": "^3.858.0",
44
"@aws-sdk/lib-dynamodb": "^3.858.0",
55
"@internal/datastore": "*",
6+
"@internal/helpers": "*",
67
"@nhsdigital/nhs-notify-event-schemas-letter-rendering": "^2.0.1",
78
"@nhsdigital/nhs-notify-event-schemas-letter-rendering-v1": "npm:@nhsdigital/nhs-notify-event-schemas-letter-rendering@^1.1.5",
89
"@nhsdigital/nhs-notify-event-schemas-supplier-api": "^1.0.8",

lambdas/upsert-letter/src/config/__tests__/deps.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ describe("createDependenciesContainer", () => {
1010
jest.clearAllMocks();
1111
jest.resetModules();
1212

13-
// pino
14-
jest.mock("pino", () => ({
15-
__esModule: true,
16-
default: jest.fn(() => ({
13+
// @internal/helpers - createLogger
14+
jest.mock("@internal/helpers", () => ({
15+
createLogger: jest.fn(() => ({
1716
info: jest.fn(),
1817
error: jest.fn(),
1918
warn: jest.fn(),
2019
debug: jest.fn(),
20+
level: "info",
2121
})),
2222
}));
2323

@@ -32,14 +32,14 @@ describe("createDependenciesContainer", () => {
3232

3333
test("constructs deps and wires repository config correctly", async () => {
3434
// get current mock instances
35-
const pinoMock = jest.requireMock("pino");
35+
const { createLogger } = jest.requireMock("@internal/helpers");
3636
const { LetterRepository } = jest.requireMock("@internal/datastore");
3737

3838
// eslint-disable-next-line @typescript-eslint/no-require-imports
3939
const { createDependenciesContainer } = require("../deps");
4040
const deps: Deps = createDependenciesContainer();
4141

42-
expect(pinoMock.default).toHaveBeenCalledTimes(1);
42+
expect(createLogger).toHaveBeenCalledTimes(1);
4343

4444
expect(LetterRepository).toHaveBeenCalledTimes(1);
4545
const letterRepoCtorArgs = LetterRepository.mock.calls[0];

lambdas/upsert-letter/src/config/deps.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
22
import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb";
3-
import pino from "pino";
3+
import { Logger } from "pino";
44
import { LetterRepository } from "@internal/datastore";
5+
import { createLogger } from "@internal/helpers";
56
import { EnvVars, envVars } from "./env";
67

78
export type Deps = {
89
letterRepo: LetterRepository;
9-
logger: pino.Logger;
10+
logger: Logger;
1011
env: EnvVars;
1112
};
1213

@@ -16,7 +17,7 @@ function createDocumentClient(): DynamoDBDocumentClient {
1617
}
1718

1819
function createLetterRepository(
19-
log: pino.Logger,
20+
log: Logger,
2021
// eslint-disable-next-line @typescript-eslint/no-shadow
2122
envVars: EnvVars,
2223
): LetterRepository {
@@ -29,7 +30,7 @@ function createLetterRepository(
2930
}
3031

3132
export function createDependenciesContainer(): Deps {
32-
const log = pino();
33+
const log = createLogger();
3334

3435
return {
3536
letterRepo: createLetterRepository(log, envVars),

package-lock.json

Lines changed: 25 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)