From 88e5e19730ba079f2f3cd743e08fd79ecd627d01 Mon Sep 17 00:00:00 2001 From: Alice Gaudon Date: Mon, 2 Nov 2020 17:48:52 +0100 Subject: [PATCH] Replace custom logging system with tslog --- package.json | 1 + src/Application.ts | 20 +-- src/ApplicationComponent.ts | 10 +- src/Controller.ts | 6 +- src/Logger.ts | 145 ++------------------- src/Mail.ts | 6 +- src/components/AutoUpdateComponent.ts | 16 +-- src/components/ExpressAppComponent.ts | 5 +- src/components/LogRequestsComponent.ts | 20 +-- src/components/NunjucksComponent.ts | 4 +- src/components/RedirectBackComponent.ts | 5 +- src/components/RedisComponent.ts | 4 +- src/components/WebSocketServerComponent.ts | 14 +- src/db/MysqlConnectionManager.ts | 18 +-- src/migrations/CreateLogsTable.ts | 32 ----- src/migrations/DropLegacyLogsTable.ts | 12 ++ src/migrations/DummyMigration.ts | 11 ++ src/models/Log.ts | 60 --------- src/types/Express.d.ts | 3 + test/Model.test.ts | 4 +- test/_migrations.ts | 2 - yarn.lock | 9 +- 22 files changed, 110 insertions(+), 297 deletions(-) delete mode 100644 src/migrations/CreateLogsTable.ts create mode 100644 src/migrations/DropLegacyLogsTable.ts create mode 100644 src/migrations/DummyMigration.ts delete mode 100644 src/models/Log.ts diff --git a/package.json b/package.json index 8a95f5b..fdd0980 100644 --- a/package.json +++ b/package.json @@ -69,6 +69,7 @@ "on-finished": "^2.3.0", "redis": "^3.0.2", "ts-node": "^9.0.0", + "tslog": "^2.10.0", "uuid": "^8.0.0", "ws": "^7.2.3" } diff --git a/src/Application.ts b/src/Application.ts index 6385db1..a96b8ea 100644 --- a/src/Application.ts +++ b/src/Application.ts @@ -1,7 +1,6 @@ import express, {NextFunction, Request, Response, Router} from 'express'; import {BadRequestError, HttpError, NotFoundHttpError, ServerError, ServiceUnavailableHttpError} from "./HttpError"; import {lib} from "nunjucks"; -import Logger from "./Logger"; import WebSocketListener from "./WebSocketListener"; import ApplicationComponent from "./ApplicationComponent"; import Controller from "./Controller"; @@ -17,6 +16,7 @@ import * as path from "path"; import CacheProvider from "./CacheProvider"; import RedisComponent from "./components/RedisComponent"; import Extendable from "./Extendable"; +import {log} from "./Logger"; import TemplateError = lib.TemplateError; export default abstract class Application implements Extendable> { @@ -46,7 +46,7 @@ export default abstract class Application implements Extendable { - Logger.info(`${config.get('app.name')} v${this.version} - hi`); + log.info(`${config.get('app.name')} v${this.version} - hi`); process.once('SIGINT', () => { this.stop().catch(console.error); }); @@ -114,7 +114,7 @@ export default abstract class Application implements Extendable { - Logger.info('Stopping application...'); + log.info('Stopping application...'); for (const component of this.components) { await component.stop?.(); } - Logger.info(`${this.constructor.name} v${this.version} - bye`); + log.info(`${this.constructor.name} v${this.version} - bye`); } private routes(initRouter: Router, handleRouter: Router) { @@ -234,7 +234,7 @@ export default abstract class Application implements Extendable Registered routes for controller ${controller.constructor.name}`); + log.info(`> Registered routes for controller ${controller.constructor.name}`); } handleRouter.use((req: Request) => { diff --git a/src/ApplicationComponent.ts b/src/ApplicationComponent.ts index 61f036f..4cc5a56 100644 --- a/src/ApplicationComponent.ts +++ b/src/ApplicationComponent.ts @@ -1,5 +1,5 @@ import {Express, Router} from "express"; -import Logger from "./Logger"; +import {log} from "./Logger"; import {sleep} from "./Utils"; import Application from "./Application"; import config from "config"; @@ -28,11 +28,11 @@ export default abstract class ApplicationComponent { err = null; } catch (e) { err = e; - Logger.error(err, `${name} failed to prepare; retrying in 5s...`); + log.error(err, `${name} failed to prepare; retrying in 5s...`); await sleep(5000); } } while (err); - Logger.info(`${name} ready!`); + log.info(`${name} ready!`); } protected async close(thingName: string, fn: (callback: (err?: Error | null) => void) => void): Promise { @@ -42,9 +42,9 @@ export default abstract class ApplicationComponent { else resolve(); })); - Logger.info(`${thingName} closed.`); + log.info(`${thingName} closed.`); } catch (e) { - Logger.error(e, `An error occurred while closing the ${thingName}.`); + log.error(e, `An error occurred while closing the ${thingName}.`); } } diff --git a/src/Controller.ts b/src/Controller.ts index 686fcfb..93934c3 100644 --- a/src/Controller.ts +++ b/src/Controller.ts @@ -1,7 +1,7 @@ import express, {IRouter, RequestHandler, Router} from "express"; import {PathParams} from "express-serve-static-core"; import config from "config"; -import Logger from "./Logger"; +import {log} from "./Logger"; import Validator, {ValidationBag} from "./db/Validator"; import FileUploadMiddleware from "./FileUploadMiddleware"; import * as querystring from "querystring"; @@ -163,10 +163,10 @@ export default abstract class Controller { if (!Controller.routes[routeName]) { if (typeof routePath === 'string') { - Logger.info(`Route ${routeName} has path ${routePath}`); + log.info(`Route ${routeName} has path ${routePath}`); Controller.routes[routeName] = routePath; } else { - Logger.warn(`Cannot assign path to route ${routeName}.`); + log.warn(`Cannot assign path to route ${routeName}.`); } } } diff --git a/src/Logger.ts b/src/Logger.ts index fd3f249..ef341d8 100644 --- a/src/Logger.ts +++ b/src/Logger.ts @@ -1,140 +1,11 @@ -import config from "config"; import {v4 as uuid} from "uuid"; -import Log from "./models/Log"; -import {bufferToUuid} from "./Utils"; -import ModelFactory from "./db/ModelFactory"; +import {Logger as TsLogger} from "tslog"; -export enum LogLevel { - ERROR, - WARN, - INFO, - DEBUG, - DEV, -} - -export type LogLevelKeys = keyof typeof LogLevel; - -/** - * TODO: make logger not static - */ -export default class Logger { - private static logLevel: LogLevel = LogLevel[config.get('log.level')]; - private static dbLogLevel: LogLevel = LogLevel[config.get('log.db_level')]; - private static verboseMode: boolean = config.get('log.verbose'); - - public static verbose(): void { - this.verboseMode = true; - if (LogLevel[this.logLevel + 1]) this.logLevel++; - if (LogLevel[this.dbLogLevel + 1]) this.dbLogLevel++; - Logger.info('Verbose mode'); - } - - public static isVerboseMode(): boolean { - return this.verboseMode; - } - - public static silentError(error: Error, ...message: unknown[]): string { - return this.log(LogLevel.ERROR, message, error, true) || ''; - } - - public static error(error: Error, ...message: unknown[]): string { - return this.log(LogLevel.ERROR, message, error) || ''; - } - - public static warn(...message: unknown[]): void { - this.log(LogLevel.WARN, message); - } - - public static info(...message: unknown[]): void { - this.log(LogLevel.INFO, message); - } - - public static debug(...message: unknown[]): void { - this.log(LogLevel.DEBUG, message); - } - - public static dev(...message: unknown[]): void { - this.log(LogLevel.DEV, message); - } - - private static log(level: LogLevel, message: unknown[], error?: Error, silent: boolean = false): string | null { - if (level <= this.logLevel) { - if (error) { - if (level > LogLevel.ERROR) this.warn(`Wrong log level ${level} with attached error.`); - } else { - if (level <= LogLevel.ERROR) this.warn(`No error attached with log level ${level}.`); - } - - const computedMsg = message.map(v => { - if (typeof v === 'string') { - return v; - } else { - return JSON.stringify(v, (key: string, value: string | unknown[] | Record) => { - if (!Array.isArray(value) && value instanceof Object) { - if (value.type === 'Buffer' && typeof value.data === 'string') { - return `Buffer<${Buffer.from(value.data).toString('hex')}>`; - } else if (value !== v) { - return `[object Object]`; - } - } - if (typeof value === 'string' && value.length > 96) { - return value.substr(0, 96) + '...'; - } - return value; - }, 4); - } - }).join(' '); - - const shouldSaveToDB = level <= this.dbLogLevel; - - let output = `[${LogLevel[level]}] `; - const pad = output.length; - - const logId = Buffer.alloc(16); - uuid({}, logId); - const strLogId = bufferToUuid(logId); - if (shouldSaveToDB) output += `${strLogId} - `; - - output += computedMsg.replace(/\n/g, '\n' + ' '.repeat(pad)); - - switch (level) { - case LogLevel.ERROR: - if (silent || !error) { - console.error(output); - } else { - console.error(output, error); - } - break; - case LogLevel.WARN: - console.warn(output); - break; - case LogLevel.INFO: - console.info(output); - break; - case LogLevel.DEBUG: - case LogLevel.DEV: - console.debug(output); - break; - } - - if (shouldSaveToDB && ModelFactory.has(Log)) { - const log = Log.create({}); - log.setLevel(level); - log.message = computedMsg; - log.setError(error); - log.setLogId(logId); - log.save().catch(err => { - if (!silent && err.message.indexOf('ECONNREFUSED') < 0) { - console.error({save_err: err, error}); - } - }); - } - return strLogId; - } - return null; - } - - private constructor() { - // disable constructor - } +export const log = new TsLogger(); + +export function makeUniqueLogger(): TsLogger { + const id = uuid(); + return log.getChildLogger({ + requestId: id, + }); } diff --git a/src/Mail.ts b/src/Mail.ts index b9f8aee..b7b8024 100644 --- a/src/Mail.ts +++ b/src/Mail.ts @@ -5,7 +5,7 @@ import nunjucks from 'nunjucks'; import * as util from "util"; import {WrappingError} from "./Utils"; import mjml2html from "mjml"; -import Logger from "./Logger"; +import {log} from "./Logger"; import Controller from "./Controller"; import {ParsedUrlQueryInput} from "querystring"; @@ -38,7 +38,7 @@ export default class Mail { throw new MailError('Connection to mail service unsuccessful.', e); } - Logger.info(`Mail ready to be distributed via ${config.get('mail.host')}:${config.get('mail.port')}`); + log.info(`Mail ready to be distributed via ${config.get('mail.host')}:${config.get('mail.port')}`); } public static end(): void { @@ -103,7 +103,7 @@ export default class Mail { this.data.app = config.get('app'); // Log - Logger.dev('Send mail', this.options); + log.debug('Send mail', this.options); // Render email this.options.html = Mail.parse('mails/' + this.template.template + '.mjml.njk', this.data, false); diff --git a/src/components/AutoUpdateComponent.ts b/src/components/AutoUpdateComponent.ts index 6b28e41..ad79d25 100644 --- a/src/components/AutoUpdateComponent.ts +++ b/src/components/AutoUpdateComponent.ts @@ -3,12 +3,12 @@ import config from "config"; import * as child_process from "child_process"; import ApplicationComponent from "../ApplicationComponent"; import {ForbiddenHttpError} from "../HttpError"; -import Logger from "../Logger"; +import {log} from "../Logger"; export default class AutoUpdateComponent extends ApplicationComponent { private static async runCommand(command: string): Promise { - Logger.info(`> ${command}`); - Logger.info(child_process.execSync(command).toString()); + log.info(`> ${command}`); + log.info(child_process.execSync(command).toString()); } public async checkSecuritySettings(): Promise { @@ -21,7 +21,7 @@ export default class AutoUpdateComponent extends ApplicationComponent { if (!token || token !== config.get('gitlab_webhook_token')) throw new ForbiddenHttpError('Invalid token', req.url); - this.update(req.body).catch(Logger.error); + this.update(req.body).catch(req.log.error); res.json({ 'status': 'ok', @@ -30,10 +30,10 @@ export default class AutoUpdateComponent extends ApplicationComponent { } private async update(params: { [p: string]: unknown }) { - Logger.info('Update params:', params); + log.info('Update params:', params); try { - Logger.info('Starting auto update...'); + log.info('Starting auto update...'); // Fetch await AutoUpdateComponent.runCommand(`git pull`); @@ -47,9 +47,9 @@ export default class AutoUpdateComponent extends ApplicationComponent { // Stop app await this.getApp().stop(); - Logger.info('Success!'); + log.info('Success!'); } catch (e) { - Logger.error(e, 'An error occurred while running the auto update.'); + log.error(e, 'An error occurred while running the auto update.'); } } } diff --git a/src/components/ExpressAppComponent.ts b/src/components/ExpressAppComponent.ts index 90489fb..cdf4748 100644 --- a/src/components/ExpressAppComponent.ts +++ b/src/components/ExpressAppComponent.ts @@ -1,6 +1,6 @@ import ApplicationComponent from "../ApplicationComponent"; import express, {Express, Router} from "express"; -import Logger from "../Logger"; +import {log, makeUniqueLogger} from "../Logger"; import {Server} from "http"; import compression from "compression"; import Middleware from "../Middleware"; @@ -20,7 +20,7 @@ export default class ExpressAppComponent extends ApplicationComponent { public async start(app: Express): Promise { this.server = app.listen(this.port, this.addr, () => { - Logger.info(`Web server running on ${this.addr}:${this.port}.`); + log.info(`Web server running on ${this.addr}:${this.port}.`); }); // Proxy @@ -41,6 +41,7 @@ export default class ExpressAppComponent extends ApplicationComponent { router.use(compression()); router.use((req, res, next) => { + req.log = makeUniqueLogger(); req.middlewares = []; req.as = (type: Type): M => { const middleware = req.middlewares.find(m => m.constructor === type); diff --git a/src/components/LogRequestsComponent.ts b/src/components/LogRequestsComponent.ts index c6e6ccf..57266a9 100644 --- a/src/components/LogRequestsComponent.ts +++ b/src/components/LogRequestsComponent.ts @@ -1,6 +1,6 @@ import ApplicationComponent from "../ApplicationComponent"; import onFinished from "on-finished"; -import Logger from "../Logger"; +import {log} from "../Logger"; import {Request, Response, Router} from "express"; import {HttpError} from "../HttpError"; @@ -9,7 +9,7 @@ export default class LogRequestsComponent extends ApplicationComponent { public static logFullHttpRequests(): void { this.fullRequests = true; - Logger.info('Http requests will be logged with more details.'); + log.info('Http requests will be logged with more details.'); } public static logRequest( @@ -18,7 +18,7 @@ export default class LogRequestsComponent extends ApplicationComponent { err?: unknown, additionalStr: string = '', silent: boolean = false, - ): string { + ): string | undefined { if (LogRequestsComponent.fullRequests) { const requestObj = JSON.stringify({ ip: req.ip, @@ -38,12 +38,12 @@ export default class LogRequestsComponent extends ApplicationComponent { }, null, 4); if (err) { if (err instanceof Error) { - return Logger.error(err, requestObj, err); + return req.log.error(err, requestObj, err).requestId; } else { - return Logger.error(new Error(String(err)), requestObj); + return req.log.error(new Error(String(err)), requestObj).requestId; } } else { - Logger.info(requestObj); + req.log.info(requestObj); } } else { let logStr = `${req.method} ${req.originalUrl} - ${res.statusCode}`; @@ -52,15 +52,15 @@ export default class LogRequestsComponent extends ApplicationComponent { if (silent) { if (err instanceof HttpError) logStr += ` ${err.errorCode}`; logStr += ` ${err.name}`; - return Logger.silentError(err, logStr); + return req.log.error(err, logStr, additionalStr).requestId; } else { - return Logger.error(err, logStr, additionalStr, err); + return req.log.error(err, logStr, additionalStr, err).requestId; } } else { - return Logger.error(new Error(String(err)), logStr); + return req.log.error(new Error(String(err)), logStr).requestId; } } else { - Logger.info(logStr); + req.log.info(logStr); } } diff --git a/src/components/NunjucksComponent.ts b/src/components/NunjucksComponent.ts index 79dc4a6..8f681bb 100644 --- a/src/components/NunjucksComponent.ts +++ b/src/components/NunjucksComponent.ts @@ -8,7 +8,7 @@ import {ParsedUrlQueryInput} from "querystring"; import * as util from "util"; import * as path from "path"; import * as fs from "fs"; -import Logger from "../Logger"; +import {log} from "../Logger"; import Middleware from "../Middleware"; export default class NunjucksComponent extends ApplicationComponent { @@ -29,7 +29,7 @@ export default class NunjucksComponent extends ApplicationComponent { try { coreVersion = JSON.parse(fs.readFileSync(file).toString()).version; } catch (e) { - Logger.warn('Couldn\'t determine coreVersion.', e); + log.warn('Couldn\'t determine coreVersion.', e); } this.env = new nunjucks.Environment([ diff --git a/src/components/RedirectBackComponent.ts b/src/components/RedirectBackComponent.ts index 9b08553..90d2642 100644 --- a/src/components/RedirectBackComponent.ts +++ b/src/components/RedirectBackComponent.ts @@ -2,7 +2,6 @@ import ApplicationComponent from "../ApplicationComponent"; import {Request, Router} from "express"; import {ServerError} from "../HttpError"; import onFinished from "on-finished"; -import Logger from "../Logger"; export default class RedirectBackComponent extends ApplicationComponent { public static getPreviousURL(req: Request, defaultUrl?: string): string | undefined { @@ -29,10 +28,10 @@ export default class RedirectBackComponent extends ApplicationComponent { contentType && typeof contentType !== 'number' && contentType.indexOf('text/html') >= 0 )) { session.previousUrl = req.originalUrl; - Logger.debug('Prev url set to', session.previousUrl); + req.log.debug('Prev url set to', session.previousUrl); session.save((err) => { if (err) { - Logger.error(err, 'Error while saving session'); + req.log.error(err, 'Error while saving session'); } }); } diff --git a/src/components/RedisComponent.ts b/src/components/RedisComponent.ts index aad7e7d..af2952f 100644 --- a/src/components/RedisComponent.ts +++ b/src/components/RedisComponent.ts @@ -2,7 +2,7 @@ import ApplicationComponent from "../ApplicationComponent"; import {Express} from "express"; import redis, {RedisClient} from "redis"; import config from "config"; -import Logger from "../Logger"; +import {log} from "../Logger"; import session, {Store} from "express-session"; import connect_redis from "connect-redis"; import CacheProvider from "../CacheProvider"; @@ -18,7 +18,7 @@ export default class RedisComponent extends ApplicationComponent implements Cach password: config.has('redis.password') ? config.get('redis.password') : undefined, }); this.redisClient.on('error', (err: Error) => { - Logger.error(err, 'An error occurred with redis.'); + log.error(err, 'An error occurred with redis.'); }); this.store = new RedisStore({ client: this.redisClient, diff --git a/src/components/WebSocketServerComponent.ts b/src/components/WebSocketServerComponent.ts index ff3dff1..58f4888 100644 --- a/src/components/WebSocketServerComponent.ts +++ b/src/components/WebSocketServerComponent.ts @@ -1,7 +1,7 @@ import ApplicationComponent from "../ApplicationComponent"; import {Express, Request} from "express"; import WebSocket, {Server as WebSocketServer} from "ws"; -import Logger from "../Logger"; +import {log} from "../Logger"; import cookie from "cookie"; import cookieParser from "cookie-parser"; import config from "config"; @@ -28,9 +28,9 @@ export default class WebSocketServerComponent extends ApplicationComponent { this.wss = new WebSocketServer({ server: this.expressAppComponent.getServer(), }, () => { - Logger.info(`Websocket server started over webserver.`); + log.info(`Websocket server started over webserver.`); }).on('error', (err) => { - Logger.error(err, 'An error occurred in the websocket server.'); + log.error(err, 'An error occurred in the websocket server.'); }).on('connection', (socket, request) => { const listener = request.url ? listeners[request.url] : null; @@ -39,12 +39,12 @@ export default class WebSocketServerComponent extends ApplicationComponent { return; } else if (!request.headers.cookie) { listener.handle(socket, request, null).catch(err => { - Logger.error(err, 'Error in websocket listener.'); + log.error(err, 'Error in websocket listener.'); }); return; } - Logger.debug(`Websocket on ${request.url}`); + log.debug(`Websocket on ${request.url}`); const cookies = cookie.parse(request.headers.cookie); const sid = cookieParser.signedCookie(cookies['connect.sid'], config.get('session.secret')); @@ -57,7 +57,7 @@ export default class WebSocketServerComponent extends ApplicationComponent { const store = this.storeComponent.getStore(); store.get(sid, (err, session) => { if (err || !session) { - Logger.error(err, 'Error while initializing session in websocket.'); + log.error(err, 'Error while initializing session in websocket.'); socket.close(1011); return; } @@ -66,7 +66,7 @@ export default class WebSocketServerComponent extends ApplicationComponent { store.createSession(request, session); listener.handle(socket, request, session).catch(err => { - Logger.error(err, 'Error in websocket listener.'); + log.error(err, 'Error in websocket listener.'); }); }); }); diff --git a/src/db/MysqlConnectionManager.ts b/src/db/MysqlConnectionManager.ts index 87093d1..8cd1049 100644 --- a/src/db/MysqlConnectionManager.ts +++ b/src/db/MysqlConnectionManager.ts @@ -1,7 +1,7 @@ import mysql, {Connection, FieldInfo, MysqlError, Pool, PoolConnection} from 'mysql'; import config from 'config'; import Migration, {MigrationType} from "./Migration"; -import Logger from "../Logger"; +import {log} from "../Logger"; import {Type} from "../Utils"; export interface QueryResult { @@ -50,7 +50,7 @@ export default class MysqlConnectionManager { public static async prepare(runMigrations: boolean = true): Promise { if (config.get('mysql.create_database_automatically') === true) { const dbName = config.get('mysql.database'); - Logger.info(`Creating database ${dbName}...`); + log.info(`Creating database ${dbName}...`); const connection = mysql.createConnection({ host: config.get('mysql.host'), user: config.get('mysql.user'), @@ -65,7 +65,7 @@ export default class MysqlConnectionManager { }); }); connection.end(); - Logger.info(`Database ${dbName} created!`); + log.info(`Database ${dbName} created!`); } this.databaseReady = true; @@ -97,7 +97,7 @@ export default class MysqlConnectionManager { } this.currentPool.end(() => { - Logger.info('Mysql connection pool ended.'); + log.info('Mysql connection pool ended.'); resolve(); }); this.currentPool = undefined; @@ -110,7 +110,9 @@ export default class MysqlConnectionManager { connection?: Connection, ): Promise { return await new Promise((resolve, reject) => { - Logger.dev('SQL:', Logger.isVerboseMode() ? mysql.format(queryString, values) : queryString); + log.debug('SQL:', log.settings.minLevel === 'trace' || log.settings.minLevel === 'silly' ? + mysql.format(queryString, values) : + queryString); (connection ? connection : this.pool).query(queryString, values, (error, results, fields) => { if (error !== null) { @@ -193,7 +195,7 @@ export default class MysqlConnectionManager { const currentVersion = await this.getCurrentMigrationVersion(); for (const migration of this.migrations) { if (await migration.shouldRun(currentVersion)) { - Logger.info('Running migration ', migration.version, migration.constructor.name); + log.info('Running migration ', migration.version, migration.constructor.name); await MysqlConnectionManager.wrapTransaction(async c => { await migration.install(c); await query('INSERT INTO migrations VALUES(?, ?, NOW())', [ @@ -215,7 +217,7 @@ export default class MysqlConnectionManager { public static async rollbackMigration(migrationId: number = 0): Promise { migrationId--; const migration = this.migrations[migrationId]; - Logger.info('Rolling back migration ', migration.version, migration.constructor.name); + log.info('Rolling back migration ', migration.version, migration.constructor.name); await MysqlConnectionManager.wrapTransaction(async c => { await migration.rollback(c); await query('DELETE FROM migrations WHERE id=?', [migration.version]); @@ -224,7 +226,7 @@ export default class MysqlConnectionManager { public static async migrationCommand(args: string[]): Promise { try { - Logger.info('Current migration:', await this.getCurrentMigrationVersion()); + log.info('Current migration:', await this.getCurrentMigrationVersion()); for (let i = 0; i < args.length; i++) { if (args[i] === 'rollback') { diff --git a/src/migrations/CreateLogsTable.ts b/src/migrations/CreateLogsTable.ts deleted file mode 100644 index 830e8ac..0000000 --- a/src/migrations/CreateLogsTable.ts +++ /dev/null @@ -1,32 +0,0 @@ -import Migration from "../db/Migration"; -import {Connection} from "mysql"; -import ModelFactory from "../db/ModelFactory"; -import Log from "../models/Log"; - -/** - * Must be the first migration - */ -export default class CreateLogsTable extends Migration { - public async install(connection: Connection): Promise { - await this.query(`CREATE TABLE logs - ( - id INT NOT NULL AUTO_INCREMENT, - level TINYINT UNSIGNED NOT NULL, - message TEXT NOT NULL, - log_id BINARY(16), - error_name VARCHAR(128), - error_message VARCHAR(512), - error_stack TEXT, - created_at DATETIME NOT NULL DEFAULT NOW(), - PRIMARY KEY (id) - )`, connection); - } - - public async rollback(connection: Connection): Promise { - await this.query('DROP TABLE logs', connection); - } - - public registerModels(): void { - ModelFactory.register(Log); - } -} diff --git a/src/migrations/DropLegacyLogsTable.ts b/src/migrations/DropLegacyLogsTable.ts new file mode 100644 index 0000000..c18a713 --- /dev/null +++ b/src/migrations/DropLegacyLogsTable.ts @@ -0,0 +1,12 @@ +import Migration from "../db/Migration"; +import {Connection} from "mysql"; + +export default class DropLegacyLogsTable extends Migration { + public async install(connection: Connection): Promise { + await this.query('DROP TABLE IF EXIST logs', connection); + } + + public async rollback(): Promise { + // Do nothing + } +} diff --git a/src/migrations/DummyMigration.ts b/src/migrations/DummyMigration.ts new file mode 100644 index 0000000..bfa47bc --- /dev/null +++ b/src/migrations/DummyMigration.ts @@ -0,0 +1,11 @@ +import Migration from "../db/Migration"; + +export default class DummyMigration extends Migration { + public async install(): Promise { + // Do nothing + } + + public async rollback(): Promise { + // Do nothing + } +} diff --git a/src/models/Log.ts b/src/models/Log.ts deleted file mode 100644 index 1dc0430..0000000 --- a/src/models/Log.ts +++ /dev/null @@ -1,60 +0,0 @@ -import Model from "../db/Model"; -import {LogLevel, LogLevelKeys} from "../Logger"; -import {bufferToUuid} from "../Utils"; - -export default class Log extends Model { - public readonly id?: number = undefined; - private level?: number = undefined; - public message?: string = undefined; - private log_id?: Buffer = undefined; - private error_name?: string = undefined; - private error_message?: string = undefined; - private error_stack?: string = undefined; - private created_at?: Date = undefined; - - protected init(): void { - this.setValidation('level').defined(); - this.setValidation('message').defined().between(0, 65535); - this.setValidation('log_id').acceptUndefined().length(16); - this.setValidation('error_name').acceptUndefined().between(0, 128); - this.setValidation('error_message').acceptUndefined().between(0, 512); - this.setValidation('error_stack').acceptUndefined().between(0, 65535); - } - - public getLevel(): LogLevelKeys { - if (typeof this.level !== 'number') return 'ERROR'; - return LogLevel[this.level]; - } - - public setLevel(level: LogLevel): void { - this.level = level; - } - - public getLogId(): string | null { - return this.log_id ? bufferToUuid(this.log_id) : null; - } - - public setLogId(buffer: Buffer): void { - this.log_id = buffer; - } - - public getErrorName(): string { - return this.error_name || ''; - } - - public getErrorMessage(): string { - return this.error_message || ''; - } - - public getErrorStack(): string { - return this.error_stack || ''; - } - - public setError(error?: Error): void { - if (!error) return; - - this.error_name = error.name; - this.error_message = error.message; - this.error_stack = error.stack; - } -} diff --git a/src/types/Express.d.ts b/src/types/Express.d.ts index e73d653..a0be0f8 100644 --- a/src/types/Express.d.ts +++ b/src/types/Express.d.ts @@ -2,10 +2,13 @@ import {Files} from "formidable"; import {Type} from "../Utils"; import Middleware from "../Middleware"; import {FlashMessages} from "../components/SessionComponent"; +import {Logger} from "tslog"; declare global { namespace Express { export interface Request { + log: Logger; + getSession(): Session; diff --git a/test/Model.test.ts b/test/Model.test.ts index 574ba10..913e3f7 100644 --- a/test/Model.test.ts +++ b/test/Model.test.ts @@ -3,7 +3,7 @@ import Model from "../src/db/Model"; import {MIGRATIONS} from "./_migrations"; import ModelFactory from "../src/db/ModelFactory"; import {ValidationBag} from "../src/db/Validator"; -import Logger from "../src/Logger"; +import {log} from "../src/Logger"; import {ManyThroughModelRelation, OneModelRelation} from "../src/db/ModelRelation"; class FakeDummyModel extends Model { @@ -99,7 +99,7 @@ let roleFactory: ModelFactory; let permissionFactory: ModelFactory; beforeAll(async () => { - Logger.verbose(); + log.setSettings({minLevel: "trace"}); MysqlConnectionManager.registerMigrations(MIGRATIONS); ModelFactory.register(FakeDummyModel); ModelFactory.register(Post); diff --git a/test/_migrations.ts b/test/_migrations.ts index eb8fffe..cc2618e 100644 --- a/test/_migrations.ts +++ b/test/_migrations.ts @@ -1,5 +1,4 @@ import CreateMigrationsTable from "../src/migrations/CreateMigrationsTable"; -import CreateLogsTable from "../src/migrations/CreateLogsTable"; import CreateUsersAndUserEmailsTable from "../src/auth/migrations/CreateUsersAndUserEmailsTable"; import FixUserMainEmailRelation from "../src/auth/migrations/FixUserMainEmailRelation"; import DropNameFromUsers from "../src/auth/migrations/DropNameFromUsers"; @@ -7,7 +6,6 @@ import CreateMagicLinksTable from "../src/auth/migrations/CreateMagicLinksTable" export const MIGRATIONS = [ CreateMigrationsTable, - CreateLogsTable, CreateUsersAndUserEmailsTable, FixUserMainEmailRelation, DropNameFromUsers, diff --git a/yarn.lock b/yarn.lock index 66c5260..73a0c17 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5621,7 +5621,7 @@ source-map-resolve@^0.5.0: source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@^0.5.17, source-map-support@^0.5.6: +source-map-support@^0.5.17, source-map-support@^0.5.19, source-map-support@^0.5.6: version "0.5.19" resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== @@ -6058,6 +6058,13 @@ tslib@^1.8.1: resolved "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043" integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q== +tslog@^2.10.0: + version "2.10.0" + resolved "https://registry.npmjs.org/tslog/-/tslog-2.10.0.tgz#725fe08e097b31dfabbb1b67929a81b7351dda8f" + integrity sha512-quVCes9HYxR3gHkT1JgDPj56OzbFeMxdKKbJwCMEW2lRSM80Awcr/WbBMTqzu9PI++mD9IDwIT4MJOa5CKh99Q== + dependencies: + source-map-support "^0.5.19" + tsutils@^3.17.1: version "3.17.1" resolved "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759"