From c99ba4052d71637c0b0a1982541acdd4b5e74a7f Mon Sep 17 00:00:00 2001 From: Arty <26905074+artysidorenko@users.noreply.github.com> Date: Wed, 2 Sep 2020 15:41:55 +0100 Subject: [PATCH] feat: FileLogger accepts custom file path (#6642) This allows users to override default log filepath and save typeorm logs in a custom location Closes: #4410 --- src/logger/FileLogger.ts | 15 ++-- src/logger/LoggerOptions.ts | 10 +++ test/github-issues/4410/entity/Username.ts | 12 ++++ test/github-issues/4410/issue-4410.ts | 81 ++++++++++++++++++++++ 4 files changed, 114 insertions(+), 4 deletions(-) create mode 100644 test/github-issues/4410/entity/Username.ts create mode 100644 test/github-issues/4410/issue-4410.ts diff --git a/src/logger/FileLogger.ts b/src/logger/FileLogger.ts index 3bdccda7bd..f50d65283d 100644 --- a/src/logger/FileLogger.ts +++ b/src/logger/FileLogger.ts @@ -1,4 +1,4 @@ -import {LoggerOptions} from "./LoggerOptions"; +import {LoggerOptions, FileLoggerOptions} from "./LoggerOptions"; import {QueryRunner} from "../query-runner/QueryRunner"; import {Logger} from "./Logger"; import {PlatformTools} from "../platform/PlatformTools"; @@ -13,7 +13,10 @@ export class FileLogger implements Logger { // Constructor // ------------------------------------------------------------------------- - constructor(private options?: LoggerOptions) { + constructor( + private options?: LoggerOptions, + private fileLoggerOptions?: FileLoggerOptions, + ) { } // ------------------------------------------------------------------------- @@ -97,9 +100,13 @@ export class FileLogger implements Logger { */ protected write(strings: string|string[]) { strings = Array.isArray(strings) ? strings : [strings]; - const basePath = PlatformTools.load("app-root-path").path; + const basePath = PlatformTools.load("app-root-path").path + "/"; + let logPath = "ormlogs.log"; + if (this.fileLoggerOptions && this.fileLoggerOptions.logPath) { + logPath = PlatformTools.pathNormalize(this.fileLoggerOptions.logPath); + } strings = (strings as string[]).map(str => "[" + new Date().toISOString() + "]" + str); - PlatformTools.appendFileSync(basePath + "/ormlogs.log", strings.join("\r\n") + "\r\n"); // todo: use async or implement promises? + PlatformTools.appendFileSync(basePath + logPath, strings.join("\r\n") + "\r\n"); // todo: use async or implement promises? } /** diff --git a/src/logger/LoggerOptions.ts b/src/logger/LoggerOptions.ts index 67049d5a4f..adfff93488 100644 --- a/src/logger/LoggerOptions.ts +++ b/src/logger/LoggerOptions.ts @@ -2,3 +2,13 @@ * Logging options. */ export type LoggerOptions = boolean|"all"|("query"|"schema"|"error"|"warn"|"info"|"log"|"migration")[]; + +/** + * File logging option. + */ +export type FileLoggerOptions = { + /** + * Specify custom path for log file, relative to application root + */ + logPath: string; +}; diff --git a/test/github-issues/4410/entity/Username.ts b/test/github-issues/4410/entity/Username.ts new file mode 100644 index 0000000000..ad0ee27175 --- /dev/null +++ b/test/github-issues/4410/entity/Username.ts @@ -0,0 +1,12 @@ +import { Column } from "../../../../src/decorator/columns/Column"; +import { PrimaryColumn } from "../../../../src/decorator/columns/PrimaryColumn"; +import { Entity } from "../../../../src/decorator/entity/Entity"; + +@Entity() +export class Username { + @PrimaryColumn() + username: string; + + @Column() + email: string; +} diff --git a/test/github-issues/4410/issue-4410.ts b/test/github-issues/4410/issue-4410.ts new file mode 100644 index 0000000000..52dfceab53 --- /dev/null +++ b/test/github-issues/4410/issue-4410.ts @@ -0,0 +1,81 @@ +import sinon from "sinon"; +import { Connection, FileLogger } from "../../../src"; +import { createTestingConnections, reloadTestingDatabases, closeTestingConnections, TestingOptions } from "../../utils/test-utils"; +import { Username } from "./entity/Username"; +import { PlatformTools } from "../../../src/platform/PlatformTools"; + +describe("github issues > #4410 allow custom filepath for FileLogger", () => { + let connections: Connection[]; + let stub: sinon.SinonStub; + + const testingOptions: TestingOptions = { + entities: [Username], + schemaCreate: true, + dropSchema: true, + }; + const testQuery = "SELECT COUNT(*) from username;"; + + before(() => stub = sinon.stub(PlatformTools, "appendFileSync")); + beforeEach(() => reloadTestingDatabases(connections)); + afterEach(async () => { + stub.resetHistory(); await closeTestingConnections(connections); + }); + + describe("when no option is passed", () => { + before(async () => { + connections = await createTestingConnections({ + ...testingOptions, + createLogger: () => new FileLogger("all"), + }); + }); + it("writes to the base path", async () => + Promise.all(connections.map(async (connection) => { + await connection.query(testQuery); + sinon.assert.calledWith( + stub, + PlatformTools.load("app-root-path").path + "/ormlogs.log", + sinon.match(testQuery) + ); + }))); + }); + + describe("when logPath option is passed as a file", () => { + before(async () => { + connections = await createTestingConnections({ + ...testingOptions, + createLogger: () => new FileLogger("all", { + logPath: "test.log" + }), + }); + }); + it("writes to the given filename", async () => + Promise.all(connections.map(async (connection) => { + await connection.query(testQuery); + sinon.assert.calledWith( + stub, + PlatformTools.load("app-root-path").path + "/test.log", + sinon.match(testQuery) + ); + }))); + }); + + describe("when logPath option is passed as a nested path", () => { + before(async () => { + connections = await createTestingConnections({ + ...testingOptions, + createLogger: () => new FileLogger("all", { + logPath: "./test/test.log" + }), + }); + }); + it("writes to the given path", () => + Promise.all(connections.map(async (connection) => { + await connection.query(testQuery); + sinon.assert.calledWith( + stub, + PlatformTools.load("app-root-path").path + "/test/test.log", + sinon.match(testQuery) + ); + }))); + }); +});