Skip to content

Commit 9eab472

Browse files
committed
CR-277: App logger
1 parent 5269e78 commit 9eab472

File tree

2 files changed

+129
-3
lines changed

2 files changed

+129
-3
lines changed
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import { LoggerService, Injectable } from '@nestjs/common';
2+
import { WinstonModule, WinstonModuleOptions } from 'nest-winston';
3+
4+
type LogMeta = object;
5+
6+
type LogObject = {
7+
[key: string]: unknown;
8+
};
9+
10+
type ErrorOrMeta = Error | LogMeta | string;
11+
12+
@Injectable()
13+
export class AppLogger implements LoggerService {
14+
private readonly logger: ReturnType<typeof WinstonModule.createLogger>;
15+
16+
static startupContexts = [
17+
'InstanceLoader',
18+
'RoutesResolver',
19+
'RouterExplorer',
20+
'WebSocketsController',
21+
'NestFactory',
22+
];
23+
24+
constructor(loggerConfig: WinstonModuleOptions) {
25+
this.logger = WinstonModule.createLogger(loggerConfig);
26+
}
27+
28+
private isException(error?: unknown) {
29+
return !!(
30+
error instanceof Error
31+
|| ((error as Error)?.stack && (error as Error)?.message)
32+
);
33+
}
34+
35+
private parseLoggerArgs(
36+
message: string | LogObject,
37+
optionalParams: ErrorOrMeta[],
38+
isErrorLevel = false,
39+
) {
40+
const messageObj: LogObject = (
41+
typeof message === 'object' ? message : { message }
42+
) as LogObject;
43+
const meta = [];
44+
let errorMessage: string;
45+
let errorStack: string;
46+
47+
// nest passes the logger context as the last argument
48+
const contextArg = optionalParams?.[optionalParams.length - 1];
49+
50+
// the global exception filter converts the error object to strings
51+
if (
52+
isErrorLevel
53+
&& typeof optionalParams[0] === 'string'
54+
&& optionalParams.length > 1
55+
) {
56+
errorStack = optionalParams.shift() as string;
57+
}
58+
59+
for (const k in optionalParams) {
60+
if (this.isException(optionalParams[k])) {
61+
errorMessage = (optionalParams[k] as Error).message;
62+
errorStack = (optionalParams[k] as Error).stack;
63+
} else if (optionalParams[k] !== contextArg) {
64+
meta.push(optionalParams[k]);
65+
}
66+
}
67+
const metaObj = meta.length > 1 ? meta : meta[0];
68+
69+
return {
70+
context: contextArg && typeof contextArg === 'string' ? contextArg : null,
71+
...metaObj,
72+
...(messageObj || {}),
73+
...(errorMessage || errorStack
74+
? {
75+
error: errorMessage,
76+
stack: [errorStack],
77+
}
78+
: {}),
79+
};
80+
}
81+
82+
/**
83+
* Write a 'log' level log.
84+
*/
85+
log(message: string | LogObject, ...optionalParams: ErrorOrMeta[]) {
86+
const parsedArgs = this.parseLoggerArgs(message, optionalParams);
87+
if (!AppLogger.startupContexts.includes(parsedArgs.context)) {
88+
this.logger.log(parsedArgs);
89+
}
90+
}
91+
92+
/**
93+
* Write a 'fatal' level log.
94+
*/
95+
fatal(message: string | LogObject, ...optionalParams: ErrorOrMeta[]) {
96+
this.logger.fatal(this.parseLoggerArgs(message, optionalParams, true));
97+
}
98+
99+
/**
100+
* Write an 'error' level log.
101+
*/
102+
error(message: string | LogObject, ...optionalParams: ErrorOrMeta[]) {
103+
this.logger.error(this.parseLoggerArgs(message, optionalParams, true));
104+
}
105+
106+
/**
107+
* Write a 'warn' level log.
108+
*/
109+
warn(message: string | LogObject, ...optionalParams: ErrorOrMeta[]) {
110+
this.logger.warn(this.parseLoggerArgs(message, optionalParams, true));
111+
}
112+
113+
/**
114+
* Write a 'debug' level log.
115+
*/
116+
debug?(message: string | LogObject, ...optionalParams: ErrorOrMeta[]) {
117+
this.logger.debug(this.parseLoggerArgs(message, optionalParams));
118+
}
119+
120+
/**
121+
* Write a 'verbose' level log.
122+
*/
123+
verbose?(message: string | LogObject, ...optionalParams: ErrorOrMeta[]) {
124+
this.logger.verbose(this.parseLoggerArgs(message, optionalParams));
125+
}
126+
}

redisinsight/api/src/main.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ import { SwaggerModule } from '@nestjs/swagger';
55
import { NestExpressApplication } from '@nestjs/platform-express';
66
import { INestApplication, NestApplicationOptions } from '@nestjs/common';
77
import * as bodyParser from 'body-parser';
8-
import { WinstonModule } from 'nest-winston';
98
import { GlobalExceptionFilter } from 'src/exceptions/global-exception.filter';
109
import { get, Config } from 'src/utils';
1110
import { migrateHomeFolder, removeOldFolders } from 'src/init-helper';
1211
import { LogFileProvider } from 'src/modules/profiler/providers/log-file.provider';
1312
import { WindowsAuthAdapter } from 'src/modules/auth/window-auth/adapters/window-auth.adapter';
13+
import { AppLogger } from 'src/common/logger/app-logger';
1414
import { AppModule } from './app.module';
1515
import SWAGGER_CONFIG from '../config/swagger';
1616
import LOGGER_CONFIG from '../config/logger';
@@ -26,11 +26,11 @@ interface IApp {
2626

2727
export default async function bootstrap(apiPort?: number): Promise<IApp> {
2828
if (serverConfig.migrateOldFolders) {
29-
await migrateHomeFolder() && await removeOldFolders();
29+
(await migrateHomeFolder()) && (await removeOldFolders());
3030
}
3131

3232
const { port, host } = serverConfig;
33-
const logger = WinstonModule.createLogger(LOGGER_CONFIG);
33+
const logger = new AppLogger(LOGGER_CONFIG);
3434

3535
const options: NestApplicationOptions = {
3636
logger,

0 commit comments

Comments
 (0)