@ogcio/fastify-logging-wrapper 5.3.1 → 5.4.1

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.
Files changed (52) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +32 -0
  3. package/__tests__/fastify-logging-wrapper.errors.test.ts +2 -2
  4. package/__tests__/fastify-logging-wrapper.test.ts +85 -3
  5. package/__tests__/field-filter.test.ts +57 -0
  6. package/__tests__/helpers/build-fastify.ts +20 -2
  7. package/__tests__/helpers/fastify-test-helpers.ts +7 -5
  8. package/__tests__/logging-filtering.test.ts +99 -0
  9. package/__tests__/logging-wrapper.test.ts +8 -7
  10. package/coverage/cobertura-coverage.xml +347 -0
  11. package/coverage/lcov-report/base.css +224 -0
  12. package/coverage/lcov-report/block-navigation.js +87 -0
  13. package/coverage/lcov-report/fastify-logging-wrapper.ts.html +706 -0
  14. package/coverage/lcov-report/favicon.png +0 -0
  15. package/coverage/lcov-report/field-filter.ts.html +223 -0
  16. package/coverage/lcov-report/index.html +176 -0
  17. package/coverage/lcov-report/index.ts.html +130 -0
  18. package/coverage/lcov-report/logging-wrapper-entities.ts.html +484 -0
  19. package/coverage/lcov-report/logging-wrapper.ts.html +481 -0
  20. package/coverage/lcov-report/prettify.css +1 -0
  21. package/coverage/lcov-report/prettify.js +2 -0
  22. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  23. package/coverage/lcov-report/sorter.js +210 -0
  24. package/coverage/lcov.info +372 -0
  25. package/dist/fastify-logging-wrapper.d.ts +2 -1
  26. package/dist/fastify-logging-wrapper.d.ts.map +1 -1
  27. package/dist/fastify-logging-wrapper.js +58 -5
  28. package/dist/fastify-logging-wrapper.js.map +1 -1
  29. package/dist/field-filter.d.ts +17 -0
  30. package/dist/field-filter.d.ts.map +1 -0
  31. package/dist/field-filter.js +22 -0
  32. package/dist/field-filter.js.map +1 -0
  33. package/dist/index.d.ts +3 -2
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +2 -2
  36. package/dist/index.js.map +1 -1
  37. package/dist/logging-wrapper-entities.d.ts +9 -4
  38. package/dist/logging-wrapper-entities.d.ts.map +1 -1
  39. package/dist/logging-wrapper-entities.js.map +1 -1
  40. package/dist/logging-wrapper.d.ts +4 -1
  41. package/dist/logging-wrapper.d.ts.map +1 -1
  42. package/dist/logging-wrapper.js +25 -8
  43. package/dist/logging-wrapper.js.map +1 -1
  44. package/package.json +38 -34
  45. package/src/fastify-logging-wrapper.ts +91 -8
  46. package/src/field-filter.ts +46 -0
  47. package/src/index.ts +7 -6
  48. package/src/logging-wrapper-entities.ts +11 -5
  49. package/src/logging-wrapper.ts +34 -9
  50. package/tsconfig.json +9 -11
  51. package/tsconfig.prod.tsbuildinfo +1 -0
  52. package/vitest.config.mts +8 -3
package/CHANGELOG.md CHANGED
@@ -3,6 +3,35 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [5.4.0](https://github.com/ogcio/shared-node-utils/compare/@ogcio/fastify-logging-wrapper@v5.3.0...@ogcio/fastify-logging-wrapper@v5.4.0) (2026-07-14)
7
+
8
+
9
+ ### Features
10
+
11
+ * AB[#36812](https://github.com/ogcio/shared-node-utils/issues/36812) pii-hash fastify logging wrapper ([#188](https://github.com/ogcio/shared-node-utils/issues/188)) ([e58f050](https://github.com/ogcio/shared-node-utils/commit/e58f050cda8931859eef9a2f738727f56534dc8f))
12
+ * AB[#36812](https://github.com/ogcio/shared-node-utils/issues/36812) pii-utils - fastify error handler ([#199](https://github.com/ogcio/shared-node-utils/issues/199)) ([ab0a2ad](https://github.com/ogcio/shared-node-utils/commit/ab0a2ad6e7c3470f4d7fd4e7e98928e56b71e4fb))
13
+ * **fastify-logging-wrapper:** add customConfig for initialize new pino instance ([#8](https://github.com/ogcio/shared-node-utils/issues/8)) ([847f075](https://github.com/ogcio/shared-node-utils/commit/847f075c3c3b873a844e413085ca97c0f6e1f1a7))
14
+ * **fastify-logging-wrapper:** log properties filter AB[#40055](https://github.com/ogcio/shared-node-utils/issues/40055) ([#286](https://github.com/ogcio/shared-node-utils/issues/286)) ([fe2c1dd](https://github.com/ogcio/shared-node-utils/commit/fe2c1dd992ee7fff47497cde7d59b8aba3111ee0))
15
+ * **root:** startup repo ([7422a6c](https://github.com/ogcio/shared-node-utils/commit/7422a6c8a7d51722299e6cd61eebacefe2b80d6d))
16
+ * updated deps across packages ([#129](https://github.com/ogcio/shared-node-utils/issues/129)) ([86d83ca](https://github.com/ogcio/shared-node-utils/commit/86d83ca57c614fd1a2612862b7e946a0a0d23576))
17
+ * **v5:** add api auth package ([#19](https://github.com/ogcio/shared-node-utils/issues/19)) ([cbc4b83](https://github.com/ogcio/shared-node-utils/commit/cbc4b831ceb29e926f0a7dd869039f0a7575fc69))
18
+
19
+
20
+ ### Bug Fixes
21
+
22
+ * log request in pre parsing ([#118](https://github.com/ogcio/shared-node-utils/issues/118)) ([c7f6d42](https://github.com/ogcio/shared-node-utils/commit/c7f6d42fe141b7f9bad4de6ae96d171dbd34284c))
23
+ * prepublish with pnpm ([#255](https://github.com/ogcio/shared-node-utils/issues/255)) ([d0746d4](https://github.com/ogcio/shared-node-utils/commit/d0746d43d7c359e06dee6d33a3898e27d75e896e))
24
+ * publish shared errors for version 5 ([#4](https://github.com/ogcio/shared-node-utils/issues/4)) ([7159dcd](https://github.com/ogcio/shared-node-utils/commit/7159dcdd2564a730bacbf3ff300aa129debbfe3a))
25
+ * skip internal objects serialize if empty AB[#26429](https://github.com/ogcio/shared-node-utils/issues/26429) ([#75](https://github.com/ogcio/shared-node-utils/issues/75)) ([b667b9d](https://github.com/ogcio/shared-node-utils/commit/b667b9ddd5c4f4b0f937ad8e11e171f81af8bba4))
26
+
27
+
28
+ ### Miscellaneous Chores
29
+
30
+ * bump patch release for fastify loggin wrapper ([#78](https://github.com/ogcio/shared-node-utils/issues/78)) ([8fae0da](https://github.com/ogcio/shared-node-utils/commit/8fae0dab725a9e05581b84945249668580a667e9))
31
+ * dependabot v5 ([#17](https://github.com/ogcio/shared-node-utils/issues/17)) ([89f9630](https://github.com/ogcio/shared-node-utils/commit/89f96309bed5637de99de5f8beeed275e74f2ef7))
32
+ * setup pnpm workspace ([#242](https://github.com/ogcio/shared-node-utils/issues/242)) ([a75f672](https://github.com/ogcio/shared-node-utils/commit/a75f6728bbf2f44a00f033b0ada12058756f06dd))
33
+ * update deps to 5.1.0 ([#14](https://github.com/ogcio/shared-node-utils/issues/14)) ([6b7821b](https://github.com/ogcio/shared-node-utils/commit/6b7821ba037ae00db96c2303b5911563deef029c))
34
+
6
35
  ## 5.0.2 (2024-10-03)
7
36
 
8
37
 
package/README.md CHANGED
@@ -60,6 +60,38 @@ If an error is thrown, a log entry is automatically written.
60
60
  {"level":50,"level_name":"ERROR","hostname":"hostname","request_id":"1kPptKhMSeyZ9OwcSwBxhg-0000000008","timestamp":1713869258238,"request":{"scheme":"http","method":"GET","path":"/this-path-must-not-exist","hostname":"localhost:80","query_params":{"status_code":"404","error_message":"Not Found"}},"error":{"class":"REQUEST_ERROR","message":"Not Found","trace":"FastifyError: Not Found..... The whole trace here","code":"FST_ERR_NOT_FOUND"},"message":"ERROR"}
61
61
  ```
62
62
 
63
+ ## Filtering logged fields
64
+
65
+ By default the wrapper logs the full request and response, so headers, query
66
+ params, cookies and similar fields end up in the logs. A built-in list always
67
+ masks the most sensitive headers (`authorization`, `cookie`, `set-cookie`,
68
+ `x-api-key`, `x-amz-security-token`, `proxy-authorization`).
69
+
70
+ To avoid logging additional sensitive or PII fields, pass an optional
71
+ configuration to `initializeLoggingHooks`. Rules are **additive**: they run on
72
+ top of the built-in redaction, they never disable it. Omitting the config keeps
73
+ the current behaviour unchanged.
74
+
75
+ ```typescript
76
+ initializeLoggingHooks(server, {
77
+ request: {
78
+ headers: { omit: ["x-internal-trace"], mask: ["x-custom-token"] },
79
+ queryParams: { omit: ["email"], mask: ["ppsn"] },
80
+ clientIp: "omit",
81
+ userAgent: "omit",
82
+ },
83
+ response: {
84
+ headers: { omit: ["x-debug-info"] },
85
+ },
86
+ });
87
+ ```
88
+
89
+ - `omit` removes the field entirely from the log entry.
90
+ - `mask` keeps the field but replaces its value with `[redacted]`.
91
+ - Header names are matched **case-insensitively**; query-param names are matched
92
+ **exactly**.
93
+ - `clientIp` and `userAgent` are single values, so they only accept `"omit"`.
94
+
63
95
  ## Additional entries
64
96
 
65
97
  Additional log entries can be added as needed, but they will include, thanks to this package, common info about the request context that will be useful for future troubleshooting.
@@ -1,12 +1,12 @@
1
1
  import { httpErrors } from "@fastify/sensible";
2
- import { assert, afterEach, describe, it } from "vitest";
2
+ import { afterEach, assert, describe, it } from "vitest";
3
3
  import { LogErrorClasses } from "../src/logging-wrapper-entities.js";
4
4
  import {
5
- DEFAULT_METHOD,
6
5
  checkExpectedApiTrackEntry,
7
6
  checkExpectedErrorEntry,
8
7
  checkExpectedRequestEntry,
9
8
  checkExpectedResponseEntry,
9
+ DEFAULT_METHOD,
10
10
  initializeServer,
11
11
  parseLogEntry,
12
12
  runErrorTest,
@@ -1,12 +1,12 @@
1
1
  import { REQUEST_ID_HEADER } from "@ogcio/shared-errors";
2
- import { assert, afterEach, describe, it } from "vitest";
2
+ import { afterEach, assert, describe, it } from "vitest";
3
3
  import { LogMessages } from "../src/logging-wrapper-entities.js";
4
4
  import {
5
- DEFAULT_METHOD,
6
- DEFAULT_PATH,
7
5
  checkExpectedRequestEntry,
8
6
  checkExpectedResponseEntry,
9
7
  checkGenericEntryFields,
8
+ DEFAULT_METHOD,
9
+ DEFAULT_PATH,
10
10
  initializeServer,
11
11
  parseLogEntry,
12
12
  } from "./helpers/fastify-test-helpers.js";
@@ -121,3 +121,85 @@ describe("Additional logs are correctly written", () => {
121
121
  assert.ok(typeof parsedAdditional.request !== "undefined");
122
122
  });
123
123
  });
124
+
125
+ describe("PseudoUser is included in logging context", () => {
126
+ it("should include pseudoUser in response and apiTrack entries", async () => {
127
+ const { server, loggingDestination } = initializeServer();
128
+ afterEach(() => server.close());
129
+
130
+ const response = await server.inject({
131
+ method: DEFAULT_METHOD,
132
+ url: "/with-pseudo-user",
133
+ });
134
+
135
+ assert.ok(typeof response !== "undefined");
136
+ assert.equal(response?.statusCode, 200);
137
+ const loggedRecords = loggingDestination.getLoggedRecords();
138
+ assert.equal(loggedRecords.length, 3);
139
+
140
+ // Request entry should NOT have pseudoUser (not yet set)
141
+ const requestEntry = parseLogEntry(loggedRecords[0]);
142
+ assert.ok(typeof requestEntry.pseudoUser === "undefined");
143
+
144
+ // Response entry should have pseudoUser
145
+ const responseEntry = parseLogEntry(loggedRecords[1]);
146
+ assert.ok(typeof responseEntry.pseudoUser !== "undefined");
147
+ assert.equal(responseEntry.pseudoUser.id, "pseudo-user-id");
148
+ assert.equal(responseEntry.pseudoUser.version, "v1");
149
+
150
+ // ApiTrack entry should have pseudoUser
151
+ const apiTrackEntry = parseLogEntry(loggedRecords[2]);
152
+ assert.ok(typeof apiTrackEntry.pseudoUser !== "undefined");
153
+ assert.equal(apiTrackEntry.pseudoUser.id, "pseudo-user-id");
154
+ assert.equal(apiTrackEntry.pseudoUser.version, "v1");
155
+ });
156
+
157
+ it("should not include pseudoUser when userData has invalid shape", async () => {
158
+ const { server, loggingDestination } = initializeServer();
159
+ afterEach(() => server.close());
160
+
161
+ const response = await server.inject({
162
+ method: DEFAULT_METHOD,
163
+ url: "/with-invalid-pseudo-user",
164
+ });
165
+
166
+ assert.ok(typeof response !== "undefined");
167
+ assert.equal(response?.statusCode, 200);
168
+ const loggedRecords = loggingDestination.getLoggedRecords();
169
+ assert.equal(loggedRecords.length, 3);
170
+
171
+ // pseudoUser should not be set when shape is invalid
172
+ const responseEntry = parseLogEntry(loggedRecords[1]);
173
+ assert.ok(typeof responseEntry.pseudoUser === "undefined");
174
+
175
+ const apiTrackEntry = parseLogEntry(loggedRecords[2]);
176
+ assert.ok(typeof apiTrackEntry.pseudoUser === "undefined");
177
+ });
178
+
179
+ it("should reset pseudoUser between requests", async () => {
180
+ const { server, loggingDestination } = initializeServer();
181
+ afterEach(() => server.close());
182
+
183
+ // First request with pseudoUser
184
+ await server.inject({
185
+ method: DEFAULT_METHOD,
186
+ url: "/with-pseudo-user",
187
+ });
188
+
189
+ // Second request without pseudoUser
190
+ await server.inject({
191
+ method: DEFAULT_METHOD,
192
+ url: DEFAULT_PATH,
193
+ });
194
+
195
+ const loggedRecords = loggingDestination.getLoggedRecords();
196
+ assert.equal(loggedRecords.length, 6);
197
+
198
+ // Second request's response should NOT have pseudoUser
199
+ const secondResponseEntry = parseLogEntry(loggedRecords[4]);
200
+ assert.ok(typeof secondResponseEntry.pseudoUser === "undefined");
201
+
202
+ const secondApiTrackEntry = parseLogEntry(loggedRecords[5]);
203
+ assert.ok(typeof secondApiTrackEntry.pseudoUser === "undefined");
204
+ });
205
+ });
@@ -0,0 +1,57 @@
1
+ import { assert, describe, it } from "vitest";
2
+ import { applyFieldRules } from "../src/field-filter.js";
3
+ import { REDACTED_VALUE } from "../src/logging-wrapper-entities.js";
4
+
5
+ describe("applyFieldRules", () => {
6
+ it("returns the value untouched when no rules are given", () => {
7
+ const value = { a: 1, b: 2 };
8
+ assert.strictEqual(applyFieldRules(value, undefined), value);
9
+ assert.strictEqual(applyFieldRules(value, {}), value);
10
+ assert.strictEqual(applyFieldRules(value, { omit: [], mask: [] }), value);
11
+ });
12
+
13
+ it("omits the requested keys", () => {
14
+ const result = applyFieldRules({ a: 1, b: 2, c: 3 }, { omit: ["b"] });
15
+ assert.deepStrictEqual(result, { a: 1, c: 3 });
16
+ });
17
+
18
+ it("masks the requested keys", () => {
19
+ const result = applyFieldRules({ a: 1, b: 2 }, { mask: ["b"] });
20
+ assert.deepStrictEqual(result, { a: 1, b: REDACTED_VALUE });
21
+ });
22
+
23
+ it("omit takes precedence over mask for the same key", () => {
24
+ const result = applyFieldRules(
25
+ { a: 1, b: 2 },
26
+ {
27
+ omit: ["b"],
28
+ mask: ["b"],
29
+ },
30
+ );
31
+ assert.deepStrictEqual(result, { a: 1 });
32
+ });
33
+
34
+ it("matches keys case-insensitively when requested", () => {
35
+ const result = applyFieldRules(
36
+ { "x-custom-token": "secret", "content-type": "json" },
37
+ { mask: ["X-Custom-Token"] },
38
+ true,
39
+ );
40
+ assert.deepStrictEqual(result, {
41
+ "x-custom-token": REDACTED_VALUE,
42
+ "content-type": "json",
43
+ });
44
+ });
45
+
46
+ it("matches keys case-sensitively by default", () => {
47
+ const result = applyFieldRules({ Email: "a@b.com" }, { omit: ["email"] });
48
+ assert.deepStrictEqual(result, { Email: "a@b.com" });
49
+ });
50
+
51
+ it("passes through non-object values", () => {
52
+ assert.strictEqual(applyFieldRules("plain", { omit: ["a"] }), "plain");
53
+ assert.strictEqual(applyFieldRules(null, { omit: ["a"] }), null);
54
+ const arr = [1, 2];
55
+ assert.strictEqual(applyFieldRules(arr, { omit: ["a"] }), arr);
56
+ });
57
+ });
@@ -6,15 +6,19 @@ import {
6
6
  getLoggingConfiguration,
7
7
  initializeLoggingHooks,
8
8
  } from "../../src/fastify-logging-wrapper.js";
9
+ import type { LoggingOptions } from "../../src/field-filter.js";
9
10
 
10
- export const buildFastify = (loggerDestination?: DestinationStream) => {
11
+ export const buildFastify = (
12
+ loggerDestination?: DestinationStream,
13
+ options?: LoggingOptions,
14
+ ) => {
11
15
  const server = Fastify({
12
16
  ...getLoggingConfiguration({
13
17
  loggerDestination: loggerDestination,
14
18
  }),
15
19
  });
16
20
 
17
- initializeLoggingHooks(server);
21
+ initializeLoggingHooks(server, options);
18
22
 
19
23
  server.get("/ping", async (_request, _reply) => {
20
24
  return { data: "pong\n" };
@@ -52,5 +56,19 @@ export const buildFastify = (loggerDestination?: DestinationStream) => {
52
56
  return { data: { message: logMessage } };
53
57
  });
54
58
 
59
+ server.get("/with-pseudo-user", async (request, _reply) => {
60
+ (request as unknown as { userData: unknown }).userData = {
61
+ pseudoUser: { id: "pseudo-user-id", version: "v1" },
62
+ };
63
+ return { data: "ok" };
64
+ });
65
+
66
+ server.get("/with-invalid-pseudo-user", async (request, _reply) => {
67
+ (request as unknown as { userData: unknown }).userData = {
68
+ pseudoUser: { id: 123 },
69
+ };
70
+ return { data: "ok" };
71
+ });
72
+
55
73
  return server;
56
74
  };
@@ -1,13 +1,14 @@
1
1
  import type { FastifyInstance } from "fastify";
2
2
  import { assert } from "vitest";
3
+ import type { LoggingOptions } from "../../src/field-filter.js";
3
4
  import {
4
5
  type LogErrorClasses,
5
6
  LogMessages,
6
7
  } from "../../src/logging-wrapper-entities.js";
7
8
  import { buildFastify } from "./build-fastify.js";
8
9
  import {
9
- type TestingLoggerDestination,
10
10
  getTestingDestinationLogger,
11
+ type TestingLoggerDestination,
11
12
  } from "./build-logger.js";
12
13
 
13
14
  export const DEFAULT_HOSTNAME = "localhost";
@@ -23,18 +24,19 @@ export const DEFAULT_METHOD = "GET";
23
24
  export const DEFAULT_SCHEME = "http";
24
25
  export const DEFAULT_PATH = "/ping";
25
26
 
26
- export const initializeServer = (): {
27
+ export const initializeServer = (
28
+ options?: LoggingOptions,
29
+ ): {
27
30
  server: FastifyInstance;
28
31
  loggingDestination: TestingLoggerDestination;
29
32
  } => {
30
33
  const loggingDestination = getTestingDestinationLogger();
31
- const server = buildFastify(loggingDestination.loggerDestination);
34
+ const server = buildFastify(loggingDestination.loggerDestination, options);
32
35
 
33
36
  return { server, loggingDestination };
34
37
  };
35
38
 
36
- // biome-ignore lint/suspicious/noExplicitAny: <explanation>
37
- // biome-ignore lint/suspicious/noExplicitAny: <explanation>
39
+ // biome-ignore lint/suspicious/noExplicitAny: Needed for testing purposes
38
40
  export const parseLogEntry = (logEntry: string): { [x: string]: any } =>
39
41
  JSON.parse(logEntry);
40
42
 
@@ -0,0 +1,99 @@
1
+ import { afterEach, assert, describe, it } from "vitest";
2
+ import { REDACTED_VALUE } from "../src/logging-wrapper-entities.js";
3
+ import {
4
+ DEFAULT_METHOD,
5
+ initializeServer,
6
+ parseLogEntry,
7
+ } from "./helpers/fastify-test-helpers.js";
8
+
9
+ describe("Logging options filter request and response fields", () => {
10
+ it("omits and masks request headers (case-insensitive)", async () => {
11
+ const { server, loggingDestination } = initializeServer({
12
+ request: {
13
+ headers: { omit: ["x-drop-me"], mask: ["X-Secret"] },
14
+ },
15
+ });
16
+ afterEach(() => server.close());
17
+
18
+ await server.inject({
19
+ method: DEFAULT_METHOD,
20
+ url: "/ping",
21
+ headers: { "x-drop-me": "gone", "x-secret": "sensitive", "x-keep": "ok" },
22
+ });
23
+
24
+ const request = parseLogEntry(
25
+ loggingDestination.getLoggedRecords()[0],
26
+ ).request;
27
+ assert.notProperty(request.headers, "x-drop-me");
28
+ assert.equal(request.headers["x-secret"], REDACTED_VALUE);
29
+ assert.equal(request.headers["x-keep"], "ok");
30
+ });
31
+
32
+ it("omits and masks query params (case-sensitive)", async () => {
33
+ const { server, loggingDestination } = initializeServer({
34
+ request: {
35
+ queryParams: { omit: ["email"], mask: ["ppsn"] },
36
+ },
37
+ });
38
+ afterEach(() => server.close());
39
+
40
+ await server.inject({
41
+ method: DEFAULT_METHOD,
42
+ url: "/ping?email=a@b.com&ppsn=123&keep=1",
43
+ });
44
+
45
+ const request = parseLogEntry(
46
+ loggingDestination.getLoggedRecords()[0],
47
+ ).request;
48
+ assert.notProperty(request.query_params, "email");
49
+ assert.equal(request.query_params.ppsn, REDACTED_VALUE);
50
+ assert.equal(request.query_params.keep, "1");
51
+ });
52
+
53
+ it("omits derived client_ip and user_agent fields", async () => {
54
+ const { server, loggingDestination } = initializeServer({
55
+ request: { clientIp: "omit", userAgent: "omit" },
56
+ });
57
+ afterEach(() => server.close());
58
+
59
+ await server.inject({ method: DEFAULT_METHOD, url: "/ping" });
60
+
61
+ const request = parseLogEntry(
62
+ loggingDestination.getLoggedRecords()[0],
63
+ ).request;
64
+ assert.notProperty(request, "client_ip");
65
+ assert.notProperty(request, "user_agent");
66
+ });
67
+
68
+ it("masks response headers", async () => {
69
+ const { server, loggingDestination } = initializeServer({
70
+ response: { headers: { mask: ["content-type"] } },
71
+ });
72
+ afterEach(() => server.close());
73
+
74
+ await server.inject({ method: DEFAULT_METHOD, url: "/ping" });
75
+
76
+ const response = parseLogEntry(
77
+ loggingDestination.getLoggedRecords()[1],
78
+ ).response;
79
+ assert.equal(response.headers["content-type"], REDACTED_VALUE);
80
+ });
81
+
82
+ it("keeps the default behaviour when no options are given", async () => {
83
+ const { server, loggingDestination } = initializeServer();
84
+ afterEach(() => server.close());
85
+
86
+ await server.inject({
87
+ method: DEFAULT_METHOD,
88
+ url: "/ping",
89
+ headers: { "x-anything": "kept" },
90
+ });
91
+
92
+ const request = parseLogEntry(
93
+ loggingDestination.getLoggedRecords()[0],
94
+ ).request;
95
+ assert.equal(request.headers["x-anything"], "kept");
96
+ assert.property(request, "client_ip");
97
+ assert.property(request, "user_agent");
98
+ });
99
+ });
@@ -1,7 +1,8 @@
1
+ import type { LogLevel } from "fastify";
1
2
  import { hostname } from "os";
2
3
  import { assert, describe, it } from "vitest";
3
- import { REDACTED_VALUE } from "../src/logging-wrapper-entities.js";
4
4
  import { getLoggerConfiguration } from "../src/logging-wrapper.js";
5
+ import { REDACTED_VALUE } from "../src/logging-wrapper-entities.js";
5
6
  import { buildLogger } from "./helpers/build-logger.js";
6
7
 
7
8
  const getRandomFieldValue = () => Math.random().toString(36).slice(2);
@@ -59,7 +60,10 @@ const toRedactFields = {
59
60
  },
60
61
  };
61
62
 
62
- const methodsDataProvider = [
63
+ const methodsDataProvider: {
64
+ method: LogLevel;
65
+ expected: { level: number; level_name: string };
66
+ }[] = [
63
67
  {
64
68
  method: "trace",
65
69
  expected: {
@@ -121,7 +125,7 @@ describe("Basic format is the expected one", () => {
121
125
  parsed.timestamp > Date.now() - 2000,
122
126
  "the timestamp must be newer than 2 seconds ago",
123
127
  );
124
- // biome-ignore lint/performance/noDelete: Would change behaviour of the test
128
+
125
129
  delete parsed.timestamp;
126
130
  assert.deepStrictEqual(parsed, {
127
131
  level: 20,
@@ -141,13 +145,10 @@ describe("Fields are redacted as expected", () => {
141
145
 
142
146
  const loggedRecords = loggedRecordsMethod();
143
147
  const parsed = JSON.parse(loggedRecords[0]);
144
- // biome-ignore lint/performance/noDelete: Would change behaviour of the test
148
+
145
149
  delete parsed.hostname;
146
- // biome-ignore lint/performance/noDelete: Would change behaviour of the test
147
150
  delete parsed.level;
148
- // biome-ignore lint/performance/noDelete: Would change behaviour of the test
149
151
  delete parsed.level_name;
150
- // biome-ignore lint/performance/noDelete: Would change behaviour of the test
151
152
  delete parsed.timestamp;
152
153
 
153
154
  assert.deepStrictEqual(parsed, toRedactFields.expected_output);