diff --git a/__tests__/unit/core-logger-pino/driver.test.ts b/__tests__/unit/core-logger-pino/driver.test.ts index 47911992e8..af2f0f0adc 100644 --- a/__tests__/unit/core-logger-pino/driver.test.ts +++ b/__tests__/unit/core-logger-pino/driver.test.ts @@ -7,6 +7,7 @@ import { Container, Identifiers } from "@packages/core-kernel/src/ioc"; import { PinoLogger } from "@packages/core-logger-pino/src/driver"; import capcon from "capture-console"; import { readdirSync } from "fs-extra"; +import { Writable } from "stream"; import { dirSync, setGracefulCleanup } from "tmp"; let logger: Logger; @@ -16,6 +17,7 @@ let app: Application; beforeEach(async () => { app = new Application(new Container()); + app.bind(Identifiers.ConfigFlags).toConstantValue("core"); app.bind(Identifiers.ApplicationNamespace).toConstantValue("ark-unitnet"); app.bind("path.log").toConstantValue(dirSync().name); @@ -127,10 +129,39 @@ describe("Logger", () => { expect(message).toMatch(/non_silent_message/); }); - // TODO: Re-enable tests - // this passes locally but fails on pipelines - it.skip("should rotate the log 3 times", async () => { + it("should log error if there is an error on file stream", async () => { + const logger = app.resolve(PinoLogger); + + const writableMock = new Writable({ + write(chunk, enc, cb) { + throw new Error("Stream error"); + }, + }); + // @ts-ignore + logger.getFileStream = () => { + return writableMock; + }; + + await logger.make({ + levels: { + console: "invalid", + file: process.env.CORE_LOG_LEVEL_FILE || "debug", + }, + fileRotator: { + interval: "1d", + }, + }); + + writableMock.destroy(new Error("Test error")); + + await sleep(100); + + expect(message).toMatch("File stream closed due to an error: Error: Test error"); + }); + + it("should rotate the log 3 times", async () => { const app = new Application(new Container()); + app.bind(Identifiers.ConfigFlags).toConstantValue("core"); app.bind(Identifiers.ApplicationNamespace).toConstantValue("ark-unitnet"); app.useLogPath(dirSync().name); @@ -147,7 +178,7 @@ describe("Logger", () => { for (let i = 0; i < 3; i++) { logger.info(`Test ${i + 1}`); - await sleep(1000); + await sleep(900); } const files = readdirSync(app.logPath()); diff --git a/__tests__/unit/core-logger-pino/service-provider.test.ts b/__tests__/unit/core-logger-pino/service-provider.test.ts index 4925a87b2d..ea1fc029f8 100644 --- a/__tests__/unit/core-logger-pino/service-provider.test.ts +++ b/__tests__/unit/core-logger-pino/service-provider.test.ts @@ -1,7 +1,6 @@ import "jest-extended"; -import { Providers } from "@arkecosystem/core-kernel"; -import { Application, Container, Services } from "@packages/core-kernel/src"; +import { Application, Container, Providers, Services } from "@packages/core-kernel"; import { ServiceProvider } from "@packages/core-logger-pino/src"; import { defaults } from "@packages/core-logger-pino/src/defaults"; import { AnySchema } from "joi"; @@ -11,6 +10,8 @@ let app: Application; beforeEach(() => { app = new Application(new Container.Container()); + + app.bind(Container.Identifiers.ConfigFlags).toConstantValue("core"); }); describe("ServiceProvider", () => { diff --git a/packages/core-logger-pino/src/driver.ts b/packages/core-logger-pino/src/driver.ts index 7056279b57..f547583e7e 100644 --- a/packages/core-logger-pino/src/driver.ts +++ b/packages/core-logger-pino/src/driver.ts @@ -1,5 +1,6 @@ import { Container, Contracts, Utils } from "@arkecosystem/core-kernel"; import chalk, { Chalk } from "chalk"; +import * as console from "console"; import pino, { PrettyOptions } from "pino"; import PinoPretty from "pino-pretty"; import pump from "pump"; @@ -24,6 +25,9 @@ export class PinoLogger implements Contracts.Kernel.Logger { @Container.inject(Container.Identifiers.Application) private readonly app!: Contracts.Kernel.Application; + @Container.inject(Container.Identifiers.ConfigFlags) + private readonly configFlags!: { processType: string }; + /** * @private * @type {Record} @@ -103,6 +107,10 @@ export class PinoLogger implements Contracts.Kernel.Logger { // @ts-ignore - Object literal may only specify known properties, and 'colorize' does not exist in type 'PrettyOptions'. this.createPrettyTransport(options.levels.console, { colorize: true }), process.stdout, + /* istanbul ignore next */ + (err) => { + console.error("Stdout stream closed due to an error:", err); + }, ); } @@ -113,6 +121,9 @@ export class PinoLogger implements Contracts.Kernel.Logger { // @ts-ignore - Object literal may only specify known properties, and 'colorize' does not exist in type 'PrettyOptions'. this.createPrettyTransport(options.levels.file, { colorize: false }), this.fileStream, + (err) => { + console.error("File stream closed due to an error:", err); + }, ); } @@ -262,7 +273,7 @@ export class PinoLogger implements Contracts.Kernel.Logger { return createStream( (time: number | Date, index?: number): string => { if (!time) { - return `${this.app.namespace()}-current.log`; + return `${this.app.namespace()}-${this.configFlags.processType}-current.log`; } if (typeof time === "number") { @@ -276,7 +287,7 @@ export class PinoLogger implements Contracts.Kernel.Logger { filename += `.${index}`; } - return `${this.app.namespace()}-${filename}.log.gz`; + return `${this.app.namespace()}-${this.configFlags.processType}-${filename}.log.gz`; }, { path: this.app.logPath(),