Skip to content

Commit 3608f06

Browse files
authored
feat: sdk logger wrapper (#7276)
1 parent 2e62c29 commit 3608f06

File tree

8 files changed

+119
-16
lines changed

8 files changed

+119
-16
lines changed

.changeset/fuzzy-pugs-greet.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@vue-storefront/sdk": patch
3+
---
4+
5+
rc.1

packages/sdk/src/__tests__/integration/modules/loggerModule.spec.ts

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { LoggerFactory } from "@vue-storefront/logger";
22
import { buildModule } from "../../../modules/buildModule";
33
import { initSDK } from "../../../bootstrap";
44
import { loggerModule } from "../../../modules/loggerModule";
5+
import type { LoggerInterface } from "../../../modules/loggerModule/types";
56

67
describe("loggerModule", () => {
78
it("should be able to be used as standard SDK module", async () => {
@@ -24,7 +25,6 @@ describe("loggerModule", () => {
2425
"should have a function '%s' available within the logger",
2526
(functionName) => {
2627
const sdkConfig = { logger: buildModule(loggerModule) };
27-
2828
const sdk = initSDK(sdkConfig);
2929

3030
expect(
@@ -41,23 +41,12 @@ describe("loggerModule", () => {
4141

4242
it("should be able to pass custom handler", async () => {
4343
const mock = jest.fn();
44-
const customLogger = {
45-
log: mock,
46-
emergency: mock,
47-
alert: mock,
48-
critical: mock,
49-
error: mock,
50-
warning: mock,
51-
notice: mock,
52-
info: mock,
53-
debug: mock,
54-
};
44+
const handler = { info: mock } as unknown as LoggerInterface;
5545
const sdkConfig = {
5646
logger: buildModule(loggerModule, {
57-
handler: customLogger,
47+
handler,
5848
}),
5949
};
60-
6150
const sdk = initSDK(sdkConfig);
6251

6352
await sdk.logger.info("foo");
@@ -73,4 +62,16 @@ describe("loggerModule", () => {
7362

7463
expect(createSpy).toHaveBeenCalled();
7564
});
65+
66+
it("should warn about wrong configuration", async () => {
67+
const consoleSpy = jest.spyOn(console, "warn").mockImplementation(() => {});
68+
69+
loggerModule({
70+
handler: {} as unknown as LoggerInterface,
71+
foo: "bar",
72+
});
73+
74+
expect(consoleSpy).toHaveBeenCalled();
75+
consoleSpy.mockReset();
76+
});
7677
});
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { injectMetadata } from "../../../modules/loggerModule/injectMetadata";
2+
import type { LoggerInterface } from "../../../modules/loggerModule/types";
3+
4+
describe("loggerModule injectMetadata", () => {
5+
it("should return logger with injected metadata", () => {
6+
const mock = jest.fn();
7+
const logger = { info: mock } as unknown as LoggerInterface;
8+
const loggerWithMetadata = injectMetadata(logger, { foo: "bar" });
9+
10+
loggerWithMetadata.info("test message");
11+
12+
expect(mock).toHaveBeenCalledWith("test message", { foo: "bar" });
13+
});
14+
});
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import {
2+
isEmptyObject,
3+
isInvalidConfig,
4+
} from "../../../modules/loggerModule/utils";
5+
import type { LoggerInterface } from "../../../modules/loggerModule/types";
6+
7+
describe("loggerModule utils", () => {
8+
it("should verify if object is empty", () => {
9+
expect(isEmptyObject()).toBe(true);
10+
expect(isEmptyObject({})).toBe(true);
11+
expect(isEmptyObject({ foo: "bar" })).toBe(false);
12+
});
13+
14+
it("should verify if config is invalid", () => {
15+
expect(isInvalidConfig()).toBe(false);
16+
expect(isInvalidConfig({})).toBe(false);
17+
expect(isInvalidConfig({ foo: "bar" })).toBe(false);
18+
expect(isInvalidConfig({ handler: {} as LoggerInterface })).toBe(false);
19+
expect(
20+
isInvalidConfig({
21+
handler: {} as unknown as LoggerInterface,
22+
foo: "bar",
23+
})
24+
).toBe(true);
25+
});
26+
});
Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,32 @@
11
import { LoggerFactory, LoggerType } from "@vue-storefront/logger";
22
import type { Module } from "../../types";
33
import type { LoggerModuleConfig } from "./types";
4+
import { injectMetadata } from "./injectMetadata";
5+
import { isInvalidConfig } from "./utils";
46

57
export const loggerModule = (options?: LoggerModuleConfig) => {
68
const logger =
79
options?.handler ?? LoggerFactory.create(LoggerType.ConsolaGcp, options);
810

11+
if (isInvalidConfig(options)) {
12+
console.warn(
13+
`Both 'handler' and other config options are provided to logger's configuration.
14+
In such case 'handler' will be used and other options will be ignored as those are
15+
supported only by the built-in logger.
16+
If you want to use other options, please remove 'handler' from the configuration.
17+
If you want to use your handler, please remove other options from the configuration.`
18+
);
19+
}
20+
21+
const loggerWithMetadata = injectMetadata(logger, {
22+
alokai: {
23+
context: "storefront",
24+
},
25+
});
26+
927
return {
1028
connector: {
11-
...logger,
29+
...loggerWithMetadata,
1230
},
1331
} satisfies Module;
1432
};
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import type { LoggerInterface } from "./types";
2+
3+
export function injectMetadata(
4+
logger: LoggerInterface,
5+
externalData: Record<string, any>
6+
): LoggerInterface {
7+
return new Proxy(logger, {
8+
get(target, prop) {
9+
const targetProp = target[prop as keyof LoggerInterface];
10+
if (typeof targetProp === "function") {
11+
return (...args: Parameters<typeof targetProp>[]) => {
12+
const [logData, metadata] = args;
13+
targetProp(logData, {
14+
...metadata,
15+
...externalData,
16+
});
17+
};
18+
}
19+
return targetProp;
20+
},
21+
});
22+
}

packages/sdk/src/modules/loggerModule/types.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ type LogLevel =
1111
| "debug";
1212

1313
export interface LoggerInterface {
14-
log(level: LogLevel, logData: LogData, metadata?: Metadata): void;
1514
emergency(logData: LogData, metadata?: Metadata): void;
1615
alert(logData: LogData, metadata?: Metadata): void;
1716
critical(logData: LogData, metadata?: Metadata): void;
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import type { LoggerModuleConfig } from "./types";
2+
3+
export const isEmptyObject = (obj = {}) => {
4+
return Object.keys(obj).length === 0;
5+
};
6+
7+
/**
8+
* Check if the config is invalid. Invalid config is considered when both handler and other options are provided,
9+
* then handler will be used and other options will be ignored.
10+
* @param config
11+
*/
12+
export const isInvalidConfig = (config?: LoggerModuleConfig) => {
13+
if (config) {
14+
const { handler, ...rest } = config;
15+
return !!handler && !isEmptyObject(rest);
16+
}
17+
return false;
18+
};

0 commit comments

Comments
 (0)