Use AsyncLocalStorage to provide requestId context

This commit is contained in:
Alice Gaudon 2021-01-22 15:54:26 +01:00
parent 6f9ecaa9c4
commit 8fab93e709
23 changed files with 108 additions and 99 deletions

View File

@ -35,6 +35,7 @@
"@types/jest": "^26.0.4",
"@types/mjml": "^4.0.4",
"@types/mysql": "^2.15.10",
"@types/nanoid": "^2.1.0",
"@types/node-fetch": "^2.5.7",
"@types/nodemailer": "^6.4.0",
"@types/nunjucks": "^3.1.3",
@ -69,6 +70,7 @@
"geoip-lite": "^1.4.2",
"mjml": "^4.6.2",
"mysql": "^2.18.1",
"nanoid": "^3.1.20",
"nodemailer": "^6.4.6",
"nunjucks": "^3.2.1",
"on-finished": "^2.3.0",

View File

@ -16,7 +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 {logger, loggingContextMiddleware} from "./Logger";
import TemplateError = lib.TemplateError;
export default abstract class Application implements Extendable<ApplicationComponent | WebSocketListener<Application>> {
@ -46,7 +46,7 @@ export default abstract class Application implements Extendable<ApplicationCompo
const path = thing.path();
this.webSocketListeners[path] = thing;
thing.init(this);
log.info(`Added websocket listener on ${path}`);
logger.info(`Added websocket listener on ${path}`);
} else {
thing.setApp(this);
this.components.push(thing);
@ -58,7 +58,7 @@ export default abstract class Application implements Extendable<ApplicationCompo
}
public async start(): Promise<void> {
log.info(`${config.get('app.name')} v${this.version} - hi`);
logger.info(`${config.get('app.name')} v${this.version} - hi`);
process.once('SIGINT', () => {
this.stop().catch(console.error);
});
@ -82,6 +82,11 @@ export default abstract class Application implements Extendable<ApplicationCompo
// Init express
const app = express();
// Logging context
app.use(loggingContextMiddleware);
// Routers
const initRouter = express.Router();
const handleRouter = express.Router();
app.use(initRouter);
@ -191,7 +196,7 @@ export default abstract class Application implements Extendable<ApplicationCompo
for (let i = 2; i < args.length; i++) {
switch (args[i]) {
case '--verbose':
log.setSettings({minLevel: "trace"});
logger.setSettings({minLevel: "trace"});
break;
case '--full-http-requests':
LogRequestsComponent.logFullHttpRequests();
@ -200,7 +205,7 @@ export default abstract class Application implements Extendable<ApplicationCompo
await MysqlConnectionManager.migrationCommand(args.slice(i + 1));
return true;
default:
log.warn('Unrecognized argument', args[i]);
logger.warn('Unrecognized argument', args[i]);
return true;
}
}
@ -228,13 +233,13 @@ export default abstract class Application implements Extendable<ApplicationCompo
}
public async stop(): Promise<void> {
log.info('Stopping application...');
logger.info('Stopping application...');
for (const component of this.components) {
await component.stop?.();
}
log.info(`${this.constructor.name} v${this.version} - bye`);
logger.info(`${this.constructor.name} v${this.version} - bye`);
}
private routes(initRouter: Router, handleRouter: Router) {
@ -242,7 +247,7 @@ export default abstract class Application implements Extendable<ApplicationCompo
if (controller.hasGlobalMiddlewares()) {
controller.setupGlobalHandlers(handleRouter);
log.info(`Registered global middlewares for controller ${controller.constructor.name}`);
logger.info(`Registered global middlewares for controller ${controller.constructor.name}`);
}
}
@ -251,7 +256,7 @@ export default abstract class Application implements Extendable<ApplicationCompo
initRouter.use(controller.getRoutesPrefix(), fileUploadFormRouter);
handleRouter.use(controller.getRoutesPrefix(), mainRouter);
log.info(`> Registered routes for controller ${controller.constructor.name} at ${controller.getRoutesPrefix()}`);
logger.info(`> Registered routes for controller ${controller.constructor.name} at ${controller.getRoutesPrefix()}`);
}
handleRouter.use((req: Request) => {

View File

@ -1,5 +1,5 @@
import {Express, Router} from "express";
import {log} from "./Logger";
import {logger} 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;
log.error(err, `${name} failed to prepare; retrying in 5s...`);
logger.error(err, `${name} failed to prepare; retrying in 5s...`);
await sleep(5000);
}
} while (err);
log.info(`${name} ready!`);
logger.info(`${name} ready!`);
}
protected async close(thingName: string, fn: (callback: (err?: Error | null) => void) => void): Promise<void> {
@ -42,9 +42,9 @@ export default abstract class ApplicationComponent {
else resolve();
}));
log.info(`${thingName} closed.`);
logger.info(`${thingName} closed.`);
} catch (e) {
log.error(e, `An error occurred while closing the ${thingName}.`);
logger.error(e, `An error occurred while closing the ${thingName}.`);
}
}

View File

@ -1,7 +1,7 @@
import express, {IRouter, RequestHandler, Router} from "express";
import {PathParams} from "express-serve-static-core";
import config from "config";
import {log} from "./Logger";
import {logger} from "./Logger";
import FileUploadMiddleware from "./FileUploadMiddleware";
import * as querystring from "querystring";
import {ParsedUrlQueryInput} from "querystring";
@ -75,7 +75,7 @@ export default abstract class Controller {
protected use(handler: RequestHandler): void {
this.router.use(this.wrap(handler));
log.info('Installed anonymous middleware on ' + this.getRoutesPrefix());
logger.info('Installed anonymous middleware on ' + this.getRoutesPrefix());
}
protected useMiddleware(...middlewares: MiddlewareType<Middleware>[]): void {
@ -87,7 +87,7 @@ export default abstract class Controller {
this.router.use(this.wrap(instance.getRequestHandler()));
}
log.info('Installed ' + middleware.name + ' on ' + this.getRoutesPrefix());
logger.info('Installed ' + middleware.name + ' on ' + this.getRoutesPrefix());
}
}
@ -176,10 +176,10 @@ export default abstract class Controller {
if (!Controller.routes[routeName]) {
if (typeof routePath === 'string') {
log.info(`Route ${routeName} has path ${routePath}`);
logger.info(`Route ${routeName} has path ${routePath}`);
Controller.routes[routeName] = routePath;
} else {
log.warn(`Cannot assign path to route ${routeName}.`);
logger.warn(`Cannot assign path to route ${routeName}.`);
}
}
}

View File

@ -1,11 +1,18 @@
import {v4 as uuid} from "uuid";
import {Logger as TsLogger} from "tslog";
import {AsyncLocalStorage} from "async_hooks";
import {RequestHandler} from "express";
import {nanoid} from "nanoid";
export const log = new TsLogger();
const requestIdStorage: AsyncLocalStorage<string> = new AsyncLocalStorage();
export function makeUniqueLogger(): TsLogger {
const id = uuid();
return log.getChildLogger({
requestId: id,
export const logger = new TsLogger({
requestId: (): string => {
return requestIdStorage.getStore() as string;
},
});
export const loggingContextMiddleware: RequestHandler = (req, res, next) => {
requestIdStorage.run(nanoid(8), () => {
next();
});
}
};

View File

@ -27,10 +27,10 @@ import CsrfProtectionComponent from "./components/CsrfProtectionComponent";
import MailController from "./mail/MailController";
import WebSocketServerComponent from "./components/WebSocketServerComponent";
import Controller from "./Controller";
import packageJson = require('../package.json');
import AccountController from "./auth/AccountController";
import MakeMagicLinksSessionNotUniqueMigration from "./auth/magic_link/MakeMagicLinksSessionNotUniqueMigration";
import AddUsedToMagicLinksMigration from "./auth/magic_link/AddUsedToMagicLinksMigration";
import packageJson = require('../package.json');
export const MIGRATIONS = [
CreateMigrationsTable,

View File

@ -1,5 +1,5 @@
import {TooManyRequestsHttpError} from "./HttpError";
import {log} from "./Logger";
import {logger} from "./Logger";
export default class Throttler {
private static readonly throttles: Record<string, Throttle | undefined> = {};
@ -81,7 +81,7 @@ class Throttle {
trigger.jailed = currentDate;
const unjailedIn = trigger.jailed + this.jailPeriod - currentDate;
log.info(`Jail ${this.jailName} triggered by ${id} and will be unjailed in ${unjailedIn}ms.`);
logger.info(`Jail ${this.jailName} triggered by ${id} and will be unjailed in ${unjailedIn}ms.`);
return this.throw(unjailedIn);
}

View File

@ -1,5 +1,3 @@
import * as crypto from "crypto";
export async function sleep(ms: number): Promise<void> {
return await new Promise(resolve => {
setTimeout(() => resolve(), ms);
@ -23,17 +21,6 @@ export abstract class WrappingError extends Error {
}
}
export function cryptoRandomDictionary(size: number, dictionary: string): string {
const randomBytes = crypto.randomBytes(size);
const output = new Array(size);
for (let i = 0; i < size; i++) {
output[i] = dictionary[Math.floor(randomBytes[i] / 255 * dictionary.length)];
}
return output.join('');
}
export type Type<T> = { new(...args: never[]): T };
export function bufferToUuid(buffer: Buffer): string {

View File

@ -11,7 +11,7 @@ import UserEmail from "./models/UserEmail";
import MagicLinkController from "./magic_link/MagicLinkController";
import {MailTemplate} from "../mail/Mail";
import {ADD_EMAIL_MAIL_TEMPLATE} from "../Mails";
import {log} from "../Logger";
import {logger} from "../Logger";
import AuthMagicLinkActionType from "./magic_link/AuthMagicLinkActionType";
export default class AccountController extends Controller {
@ -65,7 +65,7 @@ export default class AccountController extends Controller {
await passwordComponent.setPassword(req.body.new_password, 'new_password');
await user.save();
log.debug('user ' + user.id + ' changed their password and was saved.');
logger.debug('user ' + user.id + ' changed their password and was saved.');
req.flash('success', 'Password changed successfully.');
res.redirectBack(Controller.route('account'));

View File

@ -17,7 +17,7 @@ import AuthMagicLinkActionType from "./AuthMagicLinkActionType";
import {QueryVariable} from "../../db/MysqlConnectionManager";
import UserNameComponent from "../models/UserNameComponent";
import MagicLinkUserNameComponent from "../models/MagicLinkUserNameComponent";
import {log} from "../../Logger";
import {logger} from "../../Logger";
export default class MagicLinkController<A extends Application> extends Controller {
public static async sendMagicLink(
@ -233,7 +233,7 @@ export default class MagicLinkController<A extends Application> extends Controll
break;
}
default:
log.warn('Unknown magic link action type ' + magicLink.action_type);
logger.warn('Unknown magic link action type ' + magicLink.action_type);
break;
}
}

View File

@ -3,12 +3,12 @@ import config from "config";
import * as child_process from "child_process";
import ApplicationComponent from "../ApplicationComponent";
import {ForbiddenHttpError} from "../HttpError";
import {log} from "../Logger";
import {logger} from "../Logger";
export default class AutoUpdateComponent extends ApplicationComponent {
private static async runCommand(command: string): Promise<void> {
log.info(`> ${command}`);
log.info(child_process.execSync(command).toString());
logger.info(`> ${command}`);
logger.info(child_process.execSync(command).toString());
}
public async checkSecuritySettings(): Promise<void> {
@ -21,7 +21,7 @@ export default class AutoUpdateComponent extends ApplicationComponent {
if (!token || token !== config.get<string>('gitlab_webhook_token'))
throw new ForbiddenHttpError('Invalid token', req.url);
this.update(req.body).catch(req.log.error);
this.update(req.body).catch(logger.error);
res.json({
'status': 'ok',
@ -30,10 +30,10 @@ export default class AutoUpdateComponent extends ApplicationComponent {
}
private async update(params: { [p: string]: unknown }) {
log.info('Update params:', params);
logger.info('Update params:', params);
try {
log.info('Starting auto update...');
logger.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();
log.info('Success!');
logger.info('Success!');
} catch (e) {
log.error(e, 'An error occurred while running the auto update.');
logger.error(e, 'An error occurred while running the auto update.');
}
}
}

View File

@ -1,6 +1,6 @@
import ApplicationComponent from "../ApplicationComponent";
import express, {Express, Router} from "express";
import {log, makeUniqueLogger} from "../Logger";
import {logger} 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<void> {
this.server = app.listen(this.port, this.addr, () => {
log.info(`Web server running on ${this.addr}:${this.port}.`);
logger.info(`Web server running on ${this.addr}:${this.port}.`);
});
// Proxy
@ -41,7 +41,6 @@ export default class ExpressAppComponent extends ApplicationComponent {
router.use(compression());
router.use((req, res, next) => {
req.log = makeUniqueLogger();
req.middlewares = [];
req.as = <M extends Middleware>(type: Type<M>): M => {
const middleware = req.middlewares.find(m => m.constructor === type);

View File

@ -1,6 +1,6 @@
import ApplicationComponent from "../ApplicationComponent";
import onFinished from "on-finished";
import {log} from "../Logger";
import {logger} 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;
log.info('Http requests will be logged with more details.');
logger.info('Http requests will be logged with more details.');
}
public static logRequest(
@ -38,12 +38,12 @@ export default class LogRequestsComponent extends ApplicationComponent {
}, null, 4);
if (err) {
if (err instanceof Error) {
return req.log.error(err, requestObj, err).requestId;
return logger.error(err, requestObj, err).requestId;
} else {
return req.log.error(new Error(String(err)), requestObj).requestId;
return logger.error(new Error(String(err)), requestObj).requestId;
}
} else {
req.log.info(requestObj);
logger.info(requestObj);
}
} else {
let codeDescription = '';
@ -59,15 +59,15 @@ export default class LogRequestsComponent extends ApplicationComponent {
if (silent) {
if (err instanceof HttpError) logStr += ` ${err.errorCode}`;
logStr += ` ${err.name}`;
return req.log.info(err.name, logStr).requestId;
return logger.info(err.name, logStr).requestId;
} else {
return req.log.error(err, logStr, additionalStr, err).requestId;
return logger.error(err, logStr, additionalStr, err).requestId;
}
} else {
return req.log.error(new Error(String(err)), logStr).requestId;
return logger.error(new Error(String(err)), logStr).requestId;
}
} else {
req.log.info(logStr);
logger.info(logStr);
}
}

View File

@ -8,7 +8,7 @@ import {ParsedUrlQueryInput} from "querystring";
import * as util from "util";
import * as path from "path";
import * as fs from "fs";
import {log} from "../Logger";
import {logger} 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) {
log.warn('Couldn\'t determine coreVersion.', e);
logger.warn('Couldn\'t determine coreVersion.', e);
}
const opts = {

View File

@ -2,6 +2,7 @@ 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 {
@ -28,10 +29,10 @@ export default class RedirectBackComponent extends ApplicationComponent {
contentType && typeof contentType !== 'number' && contentType.indexOf('text/html') >= 0
)) {
session.previousUrl = req.originalUrl;
req.log.debug('Prev url set to', session.previousUrl);
logger.debug('Prev url set to', session.previousUrl);
session.save((err) => {
if (err) {
req.log.error(err, 'Error while saving session');
logger.error(err, 'Error while saving session');
}
});
}

View File

@ -2,7 +2,7 @@ import ApplicationComponent from "../ApplicationComponent";
import {Express} from "express";
import redis, {RedisClient} from "redis";
import config from "config";
import {log} from "../Logger";
import {logger} 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<string>('redis.password') : undefined,
});
this.redisClient.on('error', (err: Error) => {
log.error(err, 'An error occurred with redis.');
logger.error(err, 'An error occurred with redis.');
});
this.store = new RedisStore({
client: this.redisClient,

View File

@ -1,7 +1,7 @@
import ApplicationComponent from "../ApplicationComponent";
import {Express, Request} from "express";
import WebSocket, {Server as WebSocketServer} from "ws";
import {log} from "../Logger";
import {logger} 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(),
}, () => {
log.info(`Websocket server started over webserver.`);
logger.info(`Websocket server started over webserver.`);
}).on('error', (err) => {
log.error(err, 'An error occurred in the websocket server.');
logger.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 => {
log.error(err, 'Error in websocket listener.');
logger.error(err, 'Error in websocket listener.');
});
return;
}
log.debug(`Websocket on ${request.url}`);
logger.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) {
log.error(err, 'Error while initializing session in websocket.');
logger.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>request, session);
listener.handle(socket, request, (<Request>request).session).catch(err => {
log.error(err, 'Error in websocket listener.');
logger.error(err, 'Error in websocket listener.');
});
});
});

View File

@ -1,7 +1,7 @@
import mysql, {Connection, FieldInfo, MysqlError, Pool, PoolConnection} from 'mysql';
import config from 'config';
import Migration, {MigrationType} from "./Migration";
import {log} from "../Logger";
import {logger} 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<void> {
if (config.get('mysql.create_database_automatically') === true) {
const dbName = config.get('mysql.database');
log.info(`Creating database ${dbName}...`);
logger.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();
log.info(`Database ${dbName} created!`);
logger.info(`Database ${dbName} created!`);
}
this.databaseReady = true;
@ -97,7 +97,7 @@ export default class MysqlConnectionManager {
}
this.currentPool.end(() => {
log.info('Mysql connection pool ended.');
logger.info('Mysql connection pool ended.');
resolve();
});
this.currentPool = undefined;
@ -110,7 +110,7 @@ export default class MysqlConnectionManager {
connection?: Connection,
): Promise<QueryResult> {
return await new Promise<QueryResult>((resolve, reject) => {
log.debug('SQL:', log.settings.minLevel === 'trace' || log.settings.minLevel === 'silly' ?
logger.debug('SQL:', logger.settings.minLevel === 'trace' || logger.settings.minLevel === 'silly' ?
mysql.format(queryString, values) :
queryString);
@ -195,7 +195,7 @@ export default class MysqlConnectionManager {
const currentVersion = await this.getCurrentMigrationVersion();
for (const migration of this.migrations) {
if (await migration.shouldRun(currentVersion)) {
log.info('Running migration ', migration.version, migration.constructor.name);
logger.info('Running migration ', migration.version, migration.constructor.name);
await MysqlConnectionManager.wrapTransaction<void>(async c => {
migration.setCurrentConnection(c);
await migration.install();
@ -219,7 +219,7 @@ export default class MysqlConnectionManager {
public static async rollbackMigration(migrationId: number = 0): Promise<void> {
migrationId--;
const migration = this.migrations[migrationId];
log.info('Rolling back migration ', migration.version, migration.constructor.name);
logger.info('Rolling back migration ', migration.version, migration.constructor.name);
await MysqlConnectionManager.wrapTransaction<void>(async c => {
migration.setCurrentConnection(c);
await migration.rollback();
@ -230,7 +230,7 @@ export default class MysqlConnectionManager {
public static async migrationCommand(args: string[]): Promise<void> {
try {
log.info('Current migration:', await this.getCurrentMigrationVersion());
logger.info('Current migration:', await this.getCurrentMigrationVersion());
for (let i = 0; i < args.length; i++) {
if (args[i] === 'rollback') {

View File

@ -5,7 +5,7 @@ import {Environment} from 'nunjucks';
import * as util from "util";
import {WrappingError} from "../Utils";
import mjml2html from "mjml";
import {log} from "../Logger";
import {logger} 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);
}
log.info(`Mail ready to be distributed via ${config.get('mail.host')}:${config.get('mail.port')}`);
logger.info(`Mail ready to be distributed via ${config.get('mail.host')}:${config.get('mail.port')}`);
}
public static end(): void {
@ -110,7 +110,7 @@ export default class Mail {
this.data.app = config.get('app');
// Log
log.debug('Send mail', this.options);
logger.debug('Send mail', this.options);
// Render email
this.options.html = Mail.parse(this.environment, 'mails/' + this.template.template + '.mjml.njk',

View File

@ -6,15 +6,15 @@ process.env['NODE_CONFIG_DIR'] =
+ delimiter
+ (process.env['NODE_CONFIG_DIR'] || __dirname + '/../../config/');
import {log} from "./Logger";
import {logger} from "./Logger";
import TestApp from "./TestApp";
import config from "config";
(async () => {
log.debug('Config path:', process.env['NODE_CONFIG_DIR']);
logger.debug('Config path:', process.env['NODE_CONFIG_DIR']);
const app = new TestApp(config.get<string>('listen_addr'), config.get<number>('port'));
await app.start();
})().catch(err => {
log.error(err);
logger.error(err);
});

View File

@ -2,16 +2,12 @@ import {Files} from "formidable";
import {Type} from "../Utils";
import Middleware from "../Middleware";
import {FlashMessages} from "../components/SessionComponent";
import {Logger} from "tslog";
import {Session, SessionData} from "express-session";
import {PasswordAuthProofSessionData} from "../auth/password/PasswordAuthProof";
declare global {
namespace Express {
export interface Request {
log: Logger;
getSession(): Session & Partial<SessionData>;
getSessionOptional(): Session & Partial<SessionData> | undefined;

View File

@ -2,7 +2,7 @@ import MysqlConnectionManager from "../src/db/MysqlConnectionManager";
import Model from "../src/db/Model";
import ModelFactory from "../src/db/ModelFactory";
import {ValidationBag} from "../src/db/Validator";
import {log} from "../src/Logger";
import {logger} from "../src/Logger";
import {ManyThroughModelRelation, OneModelRelation} from "../src/db/ModelRelation";
import {MIGRATIONS} from "../src/TestApp";
import config from "config";
@ -104,7 +104,7 @@ beforeAll(async () => {
await MysqlConnectionManager.query('DROP DATABASE IF EXISTS ' + config.get<string>('mysql.database'));
await MysqlConnectionManager.endPool();
log.setSettings({minLevel: "trace"});
logger.setSettings({minLevel: "trace"});
MysqlConnectionManager.registerMigrations(MIGRATIONS);
ModelFactory.register(FakeDummyModel);
ModelFactory.register(Post);

View File

@ -742,6 +742,13 @@
dependencies:
"@types/node" "*"
"@types/nanoid@^2.1.0":
version "2.1.0"
resolved "https://registry.yarnpkg.com/@types/nanoid/-/nanoid-2.1.0.tgz#41edfda78986e9127d0dc14de982de766f994020"
integrity sha512-xdkn/oRTA0GSNPLIKZgHWqDTWZsVrieKomxJBOQUK9YDD+zfSgmwD5t4WJYra5S7XyhTw7tfvwznW+pFexaepQ==
dependencies:
"@types/node" "*"
"@types/node-fetch@^2.5.7":
version "2.5.8"
resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.8.tgz#e199c835d234c7eb0846f6618012e558544ee2fb"
@ -4815,6 +4822,11 @@ mysql@^2.18.1:
safe-buffer "5.1.2"
sqlstring "2.3.1"
nanoid@^3.1.20:
version "3.1.20"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.20.tgz#badc263c6b1dcf14b71efaa85f6ab4c1d6cfc788"
integrity sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==
nanomatch@^1.2.9:
version "1.2.13"
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"