From d2426957857945f9974a12c02db7f51f9a38c56c Mon Sep 17 00:00:00 2001 From: Yaroslav Grishajev Date: Thu, 28 Nov 2024 11:00:28 +0100 Subject: [PATCH] fix(observability): ensure pino-pretty works in built app closes #474 --- apps/api/mvm.lock | 2 +- apps/deploy-web/mvm.lock | 1 + apps/deploy-web/package.json | 1 + package-lock.json | 19 +++++++-- packages/logging/package.json | 14 +++---- .../servicies/logger/logger.service.spec.ts | 26 +++++++----- .../src/servicies/logger/logger.service.ts | 42 ++++++++++++------- 7 files changed, 69 insertions(+), 36 deletions(-) diff --git a/apps/api/mvm.lock b/apps/api/mvm.lock index e3c3f96a8..eeba268dd 100644 --- a/apps/api/mvm.lock +++ b/apps/api/mvm.lock @@ -3,6 +3,6 @@ "@akashnetwork/database": "1.0.0", "@akashnetwork/env-loader": "1.0.1", "@akashnetwork/http-sdk": "1.0.8", - "@akashnetwork/logging": "2.0.1" + "@akashnetwork/logging": "2.0.2" } } diff --git a/apps/deploy-web/mvm.lock b/apps/deploy-web/mvm.lock index 6ed210e74..8b020adc1 100644 --- a/apps/deploy-web/mvm.lock +++ b/apps/deploy-web/mvm.lock @@ -2,6 +2,7 @@ "dependencies": { "@akashnetwork/env-loader": "1.0.1", "@akashnetwork/http-sdk": "1.0.8", + "@akashnetwork/logging": "2.0.2", "@akashnetwork/network-store": "1.0.1", "@akashnetwork/ui": "1.0.0" }, diff --git a/apps/deploy-web/package.json b/apps/deploy-web/package.json index d8cbc1098..80fbf1537 100644 --- a/apps/deploy-web/package.json +++ b/apps/deploy-web/package.json @@ -21,6 +21,7 @@ "@akashnetwork/akashjs": "^0.10.0", "@akashnetwork/env-loader": "*", "@akashnetwork/http-sdk": "*", + "@akashnetwork/logging": "*", "@akashnetwork/network-store": "*", "@akashnetwork/ui": "*", "@auth0/nextjs-auth0": "^3.5.0", diff --git a/package-lock.json b/package-lock.json index 9c70de49d..1ebe2eab0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,7 +31,7 @@ }, "apps/api": { "name": "@akashnetwork/console-api", - "version": "2.34.0", + "version": "2.35.1", "license": "Apache-2.0", "dependencies": { "@akashnetwork/akash-api": "^1.3.0", @@ -236,6 +236,7 @@ "@akashnetwork/akashjs": "^0.10.0", "@akashnetwork/env-loader": "*", "@akashnetwork/http-sdk": "*", + "@akashnetwork/logging": "*", "@akashnetwork/network-store": "*", "@akashnetwork/ui": "*", "@auth0/nextjs-auth0": "^3.5.0", @@ -18484,6 +18485,7 @@ }, "node_modules/colorette": { "version": "2.0.20", + "dev": true, "license": "MIT" }, "node_modules/colors": { @@ -19860,6 +19862,7 @@ }, "node_modules/dateformat": { "version": "4.6.3", + "dev": true, "license": "MIT", "engines": { "node": "*" @@ -21963,6 +21966,7 @@ }, "node_modules/fast-copy": { "version": "3.0.2", + "dev": true, "license": "MIT" }, "node_modules/fast-deep-equal": { @@ -23541,6 +23545,7 @@ }, "node_modules/help-me": { "version": "5.0.0", + "dev": true, "license": "MIT" }, "node_modules/hexoid": { @@ -25689,6 +25694,7 @@ }, "node_modules/joycon": { "version": "3.1.1", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -31046,6 +31052,7 @@ "version": "11.3.0", "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-11.3.0.tgz", "integrity": "sha512-oXwn7ICywaZPHmu3epHGU2oJX4nPmKvHvB/bwrJHlGcbEWaVcotkpyVHMKLKmiVryWYByNp0jpgAcXpFJDXJzA==", + "dev": true, "dependencies": { "colorette": "^2.0.7", "dateformat": "^4.6.3", @@ -31068,6 +31075,7 @@ }, "node_modules/pino-pretty/node_modules/on-exit-leak-free": { "version": "2.1.2", + "dev": true, "license": "MIT", "engines": { "node": ">=14.0.0" @@ -31077,6 +31085,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz", "integrity": "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==", + "dev": true, "dependencies": { "split2": "^4.0.0" } @@ -31085,6 +31094,7 @@ "version": "4.5.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz", "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==", + "dev": true, "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", @@ -31098,6 +31108,7 @@ }, "node_modules/pino-pretty/node_modules/sonic-boom": { "version": "4.0.1", + "dev": true, "license": "MIT", "dependencies": { "atomic-sleep": "^1.0.0" @@ -31107,6 +31118,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, "dependencies": { "safe-buffer": "~5.2.0" } @@ -34492,6 +34504,7 @@ }, "node_modules/secure-json-parse": { "version": "2.7.0", + "dev": true, "license": "BSD-3-Clause" }, "node_modules/semver": { @@ -39528,7 +39541,6 @@ "pino": "^9.5.0", "pino-cloud-logging": "^1.0.6", "pino-fluentd": "^0.2.4", - "pino-pretty": "^11.3.0", "stream": "^0.0.3", "ts-jest": "^29.1.4", "zod": "^3.23.8" @@ -39536,7 +39548,8 @@ "devDependencies": { "@b12k/mvm": "^0.0.10", "@types/http-errors": "^2.0.4", - "@types/node": "^22.8.6" + "@types/node": "^22.8.6", + "pino-pretty": "^11.3.0" } }, "packages/logging/node_modules/@types/node": { diff --git a/packages/logging/package.json b/packages/logging/package.json index f5a39880b..1c771bc76 100644 --- a/packages/logging/package.json +++ b/packages/logging/package.json @@ -1,16 +1,16 @@ { "name": "@akashnetwork/logging", - "version": "2.0.1", + "version": "2.0.2", "description": "Package containing logging tools", + "license": "ISC", + "author": "", "main": "src/index.ts", "scripts": { "format": "prettier --write ./*.{ts,json} **/*.{ts,json}", "lint": "eslint .", - "update-apps-local-deps": "mvm-update", - "test": "jest" + "test": "jest", + "update-apps-local-deps": "mvm-update" }, - "author": "", - "license": "ISC", "dependencies": { "@types/jest": "^29.5.14", "dotenv": "^16.4.5", @@ -19,7 +19,6 @@ "pino": "^9.5.0", "pino-cloud-logging": "^1.0.6", "pino-fluentd": "^0.2.4", - "pino-pretty": "^11.3.0", "stream": "^0.0.3", "ts-jest": "^29.1.4", "zod": "^3.23.8" @@ -27,6 +26,7 @@ "devDependencies": { "@b12k/mvm": "^0.0.10", "@types/http-errors": "^2.0.4", - "@types/node": "^22.8.6" + "@types/node": "^22.8.6", + "pino-pretty": "^11.3.0" } } diff --git a/packages/logging/src/servicies/logger/logger.service.spec.ts b/packages/logging/src/servicies/logger/logger.service.spec.ts index c06b973d6..6eb90b5c9 100644 --- a/packages/logging/src/servicies/logger/logger.service.spec.ts +++ b/packages/logging/src/servicies/logger/logger.service.spec.ts @@ -1,5 +1,6 @@ import createHttpError from "http-errors"; -import pino from "pino"; +import { Transform } from "node:stream"; +import pino, { LoggerOptions } from "pino"; import { gcpLogOptions } from "pino-cloud-logging"; import { config } from "../../config"; @@ -12,6 +13,11 @@ jest.mock("pino-cloud-logging"); describe("LoggerService", () => { const defaultLogFormat = config.STD_OUT_LOG_FORMAT; + const COMMON_EXPECTED_OPTIONS: LoggerOptions = { + level: "info", + mixin: undefined, + timestamp: expect.any(Function) + }; afterEach(() => { config.STD_OUT_LOG_FORMAT = defaultLogFormat; @@ -23,11 +29,7 @@ describe("LoggerService", () => { config.STD_OUT_LOG_FORMAT = "pretty"; new LoggerService(); - expect(pino).toHaveBeenCalledWith({ - level: "info", - mixin: undefined, - transport: { target: "pino-pretty", options: { colorize: true, sync: true } } - }); + expect(pino).toHaveBeenCalledWith(COMMON_EXPECTED_OPTIONS, expect.any(Transform)); expect(gcpLogOptions).not.toHaveBeenCalled(); }); @@ -35,7 +37,11 @@ describe("LoggerService", () => { config.STD_OUT_LOG_FORMAT = "json"; new LoggerService(); - expect(pino).toHaveBeenCalledWith({ level: "info", mixin: undefined }); + expect(pino).toHaveBeenCalledWith({ + level: "info", + mixin: undefined, + timestamp: expect.any(Function) + }); expect(gcpLogOptions).toHaveBeenCalled(); }); @@ -46,7 +52,7 @@ describe("LoggerService", () => { LoggerService.mixin = globalMixin; new LoggerService(); - expect(pino).toHaveBeenCalledWith({ level: "info", mixin: globalMixin }); + expect(pino).toHaveBeenCalledWith({ ...COMMON_EXPECTED_OPTIONS, mixin: globalMixin }); LoggerService.mixin = undefined; }); @@ -61,7 +67,7 @@ describe("LoggerService", () => { LoggerService.mixin = globalMixin; new LoggerService({ mixin: localMixin }); - expect(pino).toHaveBeenCalledWith({ level: "info", mixin: localMixin }); + expect(pino).toHaveBeenCalledWith({ ...COMMON_EXPECTED_OPTIONS, mixin: localMixin }); LoggerService.mixin = undefined; }); @@ -69,7 +75,7 @@ describe("LoggerService", () => { it("should initialize pino with provided log level overriding global log level", () => { new LoggerService({ level: "debug" }); - expect(pino).toHaveBeenCalledWith({ level: "debug" }); + expect(pino).toHaveBeenCalledWith({ ...COMMON_EXPECTED_OPTIONS, level: "debug" }); LoggerService.mixin = undefined; }); diff --git a/packages/logging/src/servicies/logger/logger.service.ts b/packages/logging/src/servicies/logger/logger.service.ts index b1ccca278..3efd157fe 100644 --- a/packages/logging/src/servicies/logger/logger.service.ts +++ b/packages/logging/src/servicies/logger/logger.service.ts @@ -1,6 +1,7 @@ import { isHttpError } from "http-errors"; import pino from "pino"; import { gcpLogOptions } from "pino-cloud-logging"; +import type { PinoPretty } from "pino-pretty"; import { config } from "../../config"; @@ -23,38 +24,49 @@ export class LoggerService implements Logger { protected pino: pino.Logger; - constructor(options?: LoggerOptions) { - this.pino = this.initPino(options); + constructor(private readonly options?: LoggerOptions) { + this.pino = this.initPino(); } - private initPino(inputOptions: LoggerOptions = {}): pino.Logger { - let options: LoggerOptions = { + private initPino(): pino.Logger { + const options: LoggerOptions = { level: config.LOG_LEVEL, mixin: LoggerService.mixin, timestamp: () => `,"time":"${new Date().toISOString()}"`, - ...inputOptions + ...this.options }; - if (typeof window === "undefined" && config.STD_OUT_LOG_FORMAT === "pretty") { - options.transport = { - target: "pino-pretty", - options: { colorize: true, sync: true } - }; - } else { - options = gcpLogOptions(options as any) as LoggerOptions; + const pretty = this.getPrettyIfPresent(); + + if (pretty) { + return pino(options, pretty); + } + + return pino(gcpLogOptions(options as any)); + } + + private getPrettyIfPresent(): PinoPretty.PrettyStream | undefined { + if (typeof window !== "undefined" || config.STD_OUT_LOG_FORMAT !== "pretty") { + return; } - return pino(options); + try { + // eslint-disable-next-line @typescript-eslint/no-var-requires + return require("pino-pretty")({ colorize: true, sync: true }); + } catch (e) { + this.debug({ context: LoggerService.name, message: "Failed to load pino-pretty", error: e }); + /* empty */ + } } setContext(context: string) { - this.pino.setBindings({ context }); + this.bind({ context }); return this; } bind(bindings: pino.Bindings) { - this.pino.setBindings(bindings); + this.pino = this.pino.child(bindings); return this; }