mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-17 08:34:54 -04:00
fix(repository): Move backend code into subdirectory
Signed-off-by: Tilman Vatteroth <git@tilmanvatteroth.de>
This commit is contained in:
parent
86584e705f
commit
bf30cbcf48
272 changed files with 87 additions and 67 deletions
38
backend/src/logger/console-logger.service.spec.ts
Normal file
38
backend/src/logger/console-logger.service.spec.ts
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { ConsoleLoggerService } from './console-logger.service';
|
||||
|
||||
describe('sanitize', () => {
|
||||
it('removes non-printable ASCII character', () => {
|
||||
for (let i = 0; i++; i < 32) {
|
||||
const hexString = i.toString(16);
|
||||
expect(ConsoleLoggerService.sanitize(`a${hexString}b`)).toEqual('ab');
|
||||
}
|
||||
});
|
||||
it('replaces non-zero-width space with space', () => {
|
||||
const nonZeroWidthSpaces = [
|
||||
'\u0020', // space
|
||||
'\u00A0', // non-breaking space
|
||||
'\u2000', // en quad
|
||||
'\u2001', // en quad
|
||||
'\u2002', // en space
|
||||
'\u2003', // en space
|
||||
'\u2004', // three-per-em space
|
||||
'\u2005', // four-per-em space
|
||||
'\u2006', // six-per-em space
|
||||
'\u2007', // figure space
|
||||
'\u2008', // punctuation space
|
||||
'\u2009', // thin space
|
||||
'\u200a', // hair space
|
||||
'\u202F', // narrow no-break space
|
||||
'\u205F', // medium mathematical space
|
||||
'\u3000', // ideographic space
|
||||
];
|
||||
nonZeroWidthSpaces.forEach((space) => {
|
||||
expect(ConsoleLoggerService.sanitize(`c${space}d`)).toEqual('c d');
|
||||
});
|
||||
});
|
||||
});
|
181
backend/src/logger/console-logger.service.ts
Normal file
181
backend/src/logger/console-logger.service.ts
Normal file
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import {
|
||||
Inject,
|
||||
Injectable,
|
||||
LoggerService,
|
||||
Optional,
|
||||
Scope,
|
||||
} from '@nestjs/common';
|
||||
import { isObject } from '@nestjs/common/utils/shared.utils';
|
||||
|
||||
import appConfiguration, { AppConfig } from '../config/app.config';
|
||||
import { Loglevel } from '../config/loglevel.enum';
|
||||
import { needToLog } from '../config/utils';
|
||||
|
||||
import clc = require('cli-color');
|
||||
import DateTimeFormatOptions = Intl.DateTimeFormatOptions;
|
||||
|
||||
@Injectable({ scope: Scope.TRANSIENT })
|
||||
export class ConsoleLoggerService implements LoggerService {
|
||||
private classContext: string | undefined;
|
||||
private lastTimestamp: number;
|
||||
private skipColor = false;
|
||||
|
||||
constructor(
|
||||
@Inject(appConfiguration.KEY)
|
||||
private appConfig: AppConfig,
|
||||
@Optional() context?: string,
|
||||
) {
|
||||
this.classContext = context;
|
||||
}
|
||||
|
||||
setContext(context: string): void {
|
||||
this.classContext = context;
|
||||
}
|
||||
|
||||
setSkipColor(skipColor: boolean): void {
|
||||
this.skipColor = skipColor;
|
||||
}
|
||||
|
||||
error(message: unknown, trace = '', functionContext?: string): void {
|
||||
this.printMessage(
|
||||
message,
|
||||
clc.red,
|
||||
this.makeContextString(functionContext),
|
||||
false,
|
||||
);
|
||||
ConsoleLoggerService.printStackTrace(trace);
|
||||
}
|
||||
|
||||
log(message: unknown, functionContext?: string): void {
|
||||
if (needToLog(this.appConfig.loglevel, Loglevel.INFO)) {
|
||||
this.printMessage(
|
||||
message,
|
||||
clc.green,
|
||||
this.makeContextString(functionContext),
|
||||
false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
warn(message: unknown, functionContext?: string): void {
|
||||
if (needToLog(this.appConfig.loglevel, Loglevel.WARN)) {
|
||||
this.printMessage(
|
||||
message,
|
||||
clc.yellow,
|
||||
this.makeContextString(functionContext),
|
||||
false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
debug(message: unknown, functionContext?: string): void {
|
||||
if (needToLog(this.appConfig.loglevel, Loglevel.DEBUG)) {
|
||||
this.printMessage(
|
||||
message,
|
||||
clc.magentaBright,
|
||||
this.makeContextString(functionContext),
|
||||
false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
verbose(message: unknown, functionContext?: string): void {
|
||||
if (needToLog(this.appConfig.loglevel, Loglevel.TRACE)) {
|
||||
this.printMessage(
|
||||
message,
|
||||
clc.cyanBright,
|
||||
this.makeContextString(functionContext),
|
||||
false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private makeContextString(functionContext?: string): string {
|
||||
let context = this.classContext;
|
||||
if (!context) {
|
||||
context = 'HedgeDoc';
|
||||
}
|
||||
if (functionContext) {
|
||||
context += '.' + functionContext + '()';
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
static sanitize(input: string): string {
|
||||
return (
|
||||
input
|
||||
// remove ASCII control characters
|
||||
.replace(/\p{C}/gu, '')
|
||||
// replace all non-zeros width spaces with one space
|
||||
.replace(/\p{Zs}/gu, ' ')
|
||||
);
|
||||
}
|
||||
|
||||
private printMessage(
|
||||
message: unknown,
|
||||
color: (message: string) => string,
|
||||
context = '',
|
||||
isTimeDiffEnabled?: boolean,
|
||||
): void {
|
||||
let output;
|
||||
|
||||
// if skipColor is set, we do not use colors and skip sanitizing
|
||||
if (this.skipColor) {
|
||||
if (isObject(message)) {
|
||||
output = `${color('Object:')}\n${JSON.stringify(message, null, 2)}\n`;
|
||||
} else {
|
||||
output = message as string;
|
||||
}
|
||||
} else {
|
||||
if (isObject(message)) {
|
||||
output = `${color('Object:')}\n${ConsoleLoggerService.sanitize(
|
||||
JSON.stringify(message, null, 2),
|
||||
)}\n`;
|
||||
} else {
|
||||
output = color(ConsoleLoggerService.sanitize(message as string));
|
||||
}
|
||||
}
|
||||
|
||||
const localeStringOptions: DateTimeFormatOptions = {
|
||||
year: 'numeric',
|
||||
hour: 'numeric',
|
||||
minute: 'numeric',
|
||||
second: 'numeric',
|
||||
day: '2-digit',
|
||||
month: '2-digit',
|
||||
};
|
||||
//TODO make timestamp optional
|
||||
const timestamp = new Date(Date.now()).toLocaleString(
|
||||
undefined,
|
||||
localeStringOptions,
|
||||
);
|
||||
|
||||
const contextMessage = context ? clc.blue(`[${context}] `) : '';
|
||||
const timestampDiff = this.updateAndGetTimestampDiff(isTimeDiffEnabled);
|
||||
|
||||
process.stdout.write(
|
||||
`${timestamp} ${contextMessage}${output}${timestampDiff}\n`,
|
||||
);
|
||||
}
|
||||
|
||||
private updateAndGetTimestampDiff(isTimeDiffEnabled?: boolean): string {
|
||||
const includeTimestamp = this.lastTimestamp && isTimeDiffEnabled;
|
||||
const result = includeTimestamp
|
||||
? clc.yellow(` +${Date.now() - this.lastTimestamp}ms`)
|
||||
: '';
|
||||
this.lastTimestamp = Date.now();
|
||||
return result;
|
||||
}
|
||||
|
||||
private static printStackTrace(trace: string): void {
|
||||
if (!trace) {
|
||||
return;
|
||||
}
|
||||
process.stdout.write(`${trace}\n`);
|
||||
}
|
||||
}
|
15
backend/src/logger/logger.module.ts
Normal file
15
backend/src/logger/logger.module.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
import { ConsoleLoggerService } from './console-logger.service';
|
||||
import { TypeormLoggerService } from './typeorm-logger.service';
|
||||
|
||||
@Module({
|
||||
providers: [ConsoleLoggerService, TypeormLoggerService],
|
||||
exports: [ConsoleLoggerService, TypeormLoggerService],
|
||||
})
|
||||
export class LoggerModule {}
|
98
backend/src/logger/typeorm-logger.service.ts
Normal file
98
backend/src/logger/typeorm-logger.service.ts
Normal file
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*
|
||||
* The code in this class is based on:
|
||||
* https://github.com/typeorm/typeorm/blob/master/src/logger/AdvancedConsoleLogger.ts
|
||||
*/
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Logger, QueryRunner } from 'typeorm';
|
||||
import { PlatformTools } from 'typeorm/platform/PlatformTools';
|
||||
|
||||
import { ConsoleLoggerService } from './console-logger.service';
|
||||
|
||||
@Injectable()
|
||||
export class TypeormLoggerService implements Logger {
|
||||
constructor(private readonly logger: ConsoleLoggerService) {
|
||||
this.logger.setContext('TypeORM');
|
||||
this.logger.setSkipColor(true);
|
||||
}
|
||||
|
||||
log(level: 'log' | 'info' | 'warn', message: unknown, _?: QueryRunner): void {
|
||||
switch (level) {
|
||||
case 'log':
|
||||
case 'info':
|
||||
this.logger.log(message);
|
||||
break;
|
||||
case 'warn':
|
||||
this.logger.warn(message);
|
||||
}
|
||||
}
|
||||
|
||||
logMigration(message: string, _?: QueryRunner): void {
|
||||
// eslint-disable-next-line local-rules/correct-logger-context
|
||||
this.logger.log(message, 'migration');
|
||||
}
|
||||
|
||||
logQuery(query: string, parameters?: unknown[], _?: QueryRunner): void {
|
||||
const sql =
|
||||
query +
|
||||
(parameters && parameters.length
|
||||
? ' -- PARAMETERS: ' + this.stringifyParams(parameters)
|
||||
: '');
|
||||
// eslint-disable-next-line local-rules/correct-logger-context
|
||||
this.logger.debug(PlatformTools.highlightSql(sql), 'query');
|
||||
}
|
||||
|
||||
logQueryError(
|
||||
error: string | Error,
|
||||
query: string,
|
||||
parameters?: unknown[],
|
||||
_?: QueryRunner,
|
||||
): void {
|
||||
const sql =
|
||||
query +
|
||||
(parameters && parameters.length
|
||||
? ` -- PARAMETERS: ${this.stringifyParams(parameters)}`
|
||||
: '');
|
||||
this.logger.debug(PlatformTools.highlightSql(sql));
|
||||
// eslint-disable-next-line local-rules/correct-logger-context
|
||||
this.logger.debug(error.toString(), 'queryError');
|
||||
}
|
||||
|
||||
logQuerySlow(
|
||||
time: number,
|
||||
query: string,
|
||||
parameters?: unknown[],
|
||||
_?: QueryRunner,
|
||||
): void {
|
||||
const sql =
|
||||
query +
|
||||
(parameters && parameters.length
|
||||
? ` -- PARAMETERS: ${this.stringifyParams(parameters)}`
|
||||
: '');
|
||||
/* eslint-disable local-rules/correct-logger-context */
|
||||
this.logger.warn(PlatformTools.highlightSql(sql), 'querySlow');
|
||||
this.logger.warn(`execution time: ${time}`, 'querySlow');
|
||||
/* eslint-enable local-rules/correct-logger-context */
|
||||
}
|
||||
|
||||
logSchemaBuild(message: string, _?: QueryRunner): void {
|
||||
// eslint-disable-next-line local-rules/correct-logger-context
|
||||
this.logger.debug(message, 'schemaBuild');
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts parameters to a string.
|
||||
* Sometimes parameters can have circular objects and therefore we are handle this case too.
|
||||
*/
|
||||
protected stringifyParams(parameters: unknown[]): string {
|
||||
try {
|
||||
return JSON.stringify(parameters);
|
||||
} catch (error) {
|
||||
// most probably circular objects in parameters
|
||||
return parameters.toString();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue