Merge pull request #631 from Hexastack/fix/logger-2nd-attempt

Fix/logger 2nd attempt
This commit is contained in:
Med Marrouchi 2025-01-28 19:21:47 +01:00 committed by GitHub
commit ad07884fb0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 110 additions and 131 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Hexastack. All rights reserved. * Copyright © 2025 Hexastack. All rights reserved.
* *
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
@ -127,10 +127,10 @@ export class BotStatsService extends BaseService<BotStats> {
try { try {
await this.updateOne(insight.id, { value: insight.value + 1 }); await this.updateOne(insight.id, { value: insight.value + 1 });
} catch (err) { } catch (err) {
this.logger.error('Stats hook : Unable to update insight', err); this.logger.error('Unable to update insight', err);
} }
} catch (err) { } catch (err) {
this.logger.error('Stats hook : Unable to find or create insight', err); this.logger.error('Unable to find or create insight', err);
} }
} }
} }

View File

@ -108,7 +108,7 @@ describe('AttachmentController', () => {
helperService = module.get<HelperService>(HelperService); helperService = module.get<HelperService>(HelperService);
settingService = module.get<SettingService>(SettingService); settingService = module.get<SettingService>(SettingService);
loggerService = module.get<LoggerService>(LoggerService); loggerService = await module.resolve<LoggerService>(LoggerService);
helperService.register( helperService.register(
new LocalStorageHelper(settingService, helperService, loggerService), new LocalStorageHelper(settingService, helperService, loggerService),

View File

@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Hexastack. All rights reserved. * Copyright © 2025 Hexastack. All rights reserved.
* *
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
@ -173,7 +173,7 @@ export class MessageController extends BaseController<
success: true, success: true,
}; };
} catch (err) { } catch (err) {
this.logger.debug('MessageController send : Unable to send message', err); this.logger.debug('Unable to send message', err);
throw new BadRequestException( throw new BadRequestException(
'MessageController send : unable to send message', 'MessageController send : unable to send message',
); );

View File

@ -286,7 +286,7 @@ export class BlockService extends BaseService<
return e.entity === ev.entity; return e.entity === ev.entity;
}); });
} else { } else {
this.logger.warn('Block Service : Unknown NLP match type', ev); this.logger.warn('Unknown NLP match type', ev);
return false; return false;
} }
}); });

View File

@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Hexastack. All rights reserved. * Copyright © 2025 Hexastack. All rights reserved.
* *
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
@ -62,10 +62,7 @@ export class BotService {
context = context || getDefaultConversationContext(); context = context || getDefaultConversationContext();
fallback = typeof fallback !== 'undefined' ? fallback : false; fallback = typeof fallback !== 'undefined' ? fallback : false;
const options = block.options; const options = block.options;
this.logger.debug( this.logger.debug('Sending message ... ', event.getSenderForeignId());
'Bot service : Sending message ... ',
event.getSenderForeignId(),
);
// Process message : Replace tokens with context data and then send the message // Process message : Replace tokens with context data and then send the message
const recipient = event.getSender(); const recipient = event.getSender();
const envelope = await this.blockService.processMessage( const envelope = await this.blockService.processMessage(
@ -116,7 +113,7 @@ export class BotService {
assignTo, assignTo,
); );
this.logger.debug('Bot service : Assigned labels ', blockLabels); this.logger.debug('Assigned labels ', blockLabels);
return response; return response;
} }
@ -375,7 +372,7 @@ export class BotService {
); );
this.logger.debug( this.logger.debug(
'Bot service : Started a new conversation with ', 'Started a new conversation with ',
subscriber.id, subscriber.id,
block.name, block.name,
); );
@ -386,14 +383,11 @@ export class BotService {
false, false,
); );
} catch (err) { } catch (err) {
this.logger.error('Bot service : Unable to store context data!', err); this.logger.error('Unable to store context data!', err);
this.eventEmitter.emit('hook:conversation:end', convo, true); this.eventEmitter.emit('hook:conversation:end', convo, true);
} }
} catch (err) { } catch (err) {
this.logger.error( this.logger.error('Unable to start a new conversation with ', err);
'Botservice : Unable to start a new conversation with ',
err,
);
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright © 2024 Hexastack. All rights reserved. * Copyright © 2025 Hexastack. All rights reserved.
* *
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
@ -65,10 +65,7 @@ export class MessageService extends BaseService<
success: true, success: true,
}); });
} catch (e) { } catch (e) {
this.logger.error( this.logger.error('Websocket subscription', e);
'MessageController subscribe : Websocket subscription',
e,
);
throw new InternalServerErrorException(e); throw new InternalServerErrorException(e);
} }
} }

View File

@ -72,9 +72,7 @@ export class SubscriberService extends BaseService<
subscribe: Room.SUBSCRIBER, subscribe: Room.SUBSCRIBER,
}); });
} catch (e) { } catch (e) {
this.logger.error( this.logger.error('Websocket subscription');
'SubscriberController subscribe : Websocket subscription',
);
throw new InternalServerErrorException(e); throw new InternalServerErrorException(e);
} }
} }

View File

@ -89,7 +89,7 @@ export default abstract class BaseWebChannelHandler<
* @returns - * @returns -
*/ */
init(): void { init(): void {
this.logger.debug('Web Channel Handler : initialization ...'); this.logger.debug('initialization ...');
} }
/** /**
@ -108,22 +108,17 @@ export default abstract class BaseWebChannelHandler<
return; return;
} }
this.logger.debug( this.logger.debug('WS connected .. sending settings');
'Web Channel Handler : WS connected .. sending settings',
);
try { try {
const menu = await this.menuService.getTree(); const menu = await this.menuService.getTree();
return client.emit('settings', { menu, ...settings }); return client.emit('settings', { menu, ...settings });
} catch (err) { } catch (err) {
this.logger.warn('Web Channel Handler : Unable to retrieve menu ', err); this.logger.warn('Unable to retrieve menu ', err);
return client.emit('settings', settings); return client.emit('settings', settings);
} }
} catch (err) { } catch (err) {
this.logger.error( this.logger.error('Unable to initiate websocket connection', err);
'Web Channel Handler : Unable to initiate websocket connection',
err,
);
client.disconnect(); client.disconnect();
} }
} }
@ -315,7 +310,7 @@ export default abstract class BaseWebChannelHandler<
// Check if we have an origin header... // Check if we have an origin header...
if (!req.headers?.origin) { if (!req.headers?.origin) {
this.logger.debug('Web Channel Handler : No origin ', req.headers); this.logger.debug('No origin ', req.headers);
throw new Error('CORS - No origin provided!'); throw new Error('CORS - No origin provided!');
} }
@ -332,10 +327,7 @@ export default abstract class BaseWebChannelHandler<
try { try {
return new URL(origin.trim()).origin; return new URL(origin.trim()).origin;
} catch (error) { } catch (error) {
this.logger.error( this.logger.error(`Invalid URL in allowed domains: ${origin}`, error);
`Web Channel Handler : Invalid URL in allowed domains: ${origin}`,
error,
);
return null; return null;
} }
}) })
@ -353,10 +345,7 @@ export default abstract class BaseWebChannelHandler<
// For HTTP requests, set the Access-Control-Allow-Origin header to '', which the browser will // For HTTP requests, set the Access-Control-Allow-Origin header to '', which the browser will
// interpret as, 'no way Jose.' // interpret as, 'no way Jose.'
res.set('Access-Control-Allow-Origin', ''); res.set('Access-Control-Allow-Origin', '');
this.logger.debug( this.logger.debug('No origin found ', req.headers.origin);
'Web Channel Handler : No origin found ',
req.headers.origin,
);
throw new Error('CORS - Domain not allowed!'); throw new Error('CORS - Domain not allowed!');
} else { } else {
res.set('Access-Control-Allow-Origin', originUrl.origin); res.set('Access-Control-Allow-Origin', originUrl.origin);
@ -384,10 +373,7 @@ export default abstract class BaseWebChannelHandler<
next: (profile: Subscriber) => void, next: (profile: Subscriber) => void,
) { ) {
if (!req.session?.web?.profile?.id) { if (!req.session?.web?.profile?.id) {
this.logger.warn( this.logger.warn('No session ID to be found!', req.session);
'Web Channel Handler : No session ID to be found!',
req.session,
);
return res return res
.status(403) .status(403)
.json({ err: 'Web Channel Handler : Unauthorized!' }); .json({ err: 'Web Channel Handler : Unauthorized!' });
@ -397,7 +383,7 @@ export default abstract class BaseWebChannelHandler<
!Array.isArray(req.session.web.messageQueue) !Array.isArray(req.session.web.messageQueue)
) { ) {
this.logger.warn( this.logger.warn(
'Web Channel Handler : Mixed channel request or invalid session data!', 'Mixed channel request or invalid session data!',
req.session, req.session,
); );
return res return res
@ -420,10 +406,7 @@ export default abstract class BaseWebChannelHandler<
try { try {
await this.validateCors(req, res); await this.validateCors(req, res);
} catch (err) { } catch (err) {
this.logger.warn( this.logger.warn('Attempt to access from an unauthorized origin', err);
'Web Channel Handler : Attempt to access from an unauthorized origin',
err,
);
throw new Error('Unauthorized, invalid origin !'); throw new Error('Unauthorized, invalid origin !');
} }
} }
@ -498,18 +481,14 @@ export default abstract class BaseWebChannelHandler<
private getMessageQueue(req: Request, res: Response) { private getMessageQueue(req: Request, res: Response) {
// Polling not authorized when using websockets // Polling not authorized when using websockets
if (this.isSocketRequest(req)) { if (this.isSocketRequest(req)) {
this.logger.warn( this.logger.warn('Polling not authorized when using websockets');
'Web Channel Handler : Polling not authorized when using websockets',
);
return res return res
.status(403) .status(403)
.json({ err: 'Polling not authorized when using websockets' }); .json({ err: 'Polling not authorized when using websockets' });
} }
// Session must be active // Session must be active
if (!(req.session && req.session.web && req.session.web.profile.id)) { if (!(req.session && req.session.web && req.session.web.profile.id)) {
this.logger.warn( this.logger.warn('Must be connected to poll messages');
'Web Channel Handler : Must be connected to poll messages',
);
return res return res
.status(403) .status(403)
.json({ err: 'Polling not authorized : Must be connected' }); .json({ err: 'Polling not authorized : Must be connected' });
@ -517,9 +496,7 @@ export default abstract class BaseWebChannelHandler<
// Can only request polling once at a time // Can only request polling once at a time
if (req.session && req.session.web && req.session.web.polling) { if (req.session && req.session.web && req.session.web.polling) {
this.logger.warn( this.logger.warn('Poll rejected ... already requested');
'Web Channel Handler : Poll rejected ... already requested',
);
return res return res
.status(403) .status(403)
.json({ err: 'Poll rejected ... already requested' }); .json({ err: 'Poll rejected ... already requested' });
@ -543,16 +520,14 @@ export default abstract class BaseWebChannelHandler<
req.session.web.polling = false; req.session.web.polling = false;
return res.status(200).json(messages.map((msg) => ['message', msg])); return res.status(200).json(messages.map((msg) => ['message', msg]));
} else { } else {
this.logger.error( this.logger.error('Polling failed .. no session data');
'Web Channel Handler : Polling failed .. no session data',
);
return res.status(500).json({ err: 'No session data' }); return res.status(500).json({ err: 'No session data' });
} }
} catch (err) { } catch (err) {
if (req.session.web) { if (req.session.web) {
req.session.web.polling = false; req.session.web.polling = false;
} }
this.logger.error('Web Channel Handler : Polling failed', err); this.logger.error('Polling failed', err);
return res.status(500).json({ err: 'Polling failed' }); return res.status(500).json({ err: 'Polling failed' });
} }
}; };
@ -569,11 +544,7 @@ export default abstract class BaseWebChannelHandler<
req: Request | SocketRequest, req: Request | SocketRequest,
res: Response | SocketResponse, res: Response | SocketResponse,
) { ) {
this.logger.debug( this.logger.debug('subscribe (isSocket=' + this.isSocketRequest(req) + ')');
'Web Channel Handler : subscribe (isSocket=' +
this.isSocketRequest(req) +
')',
);
try { try {
const profile = await this.getOrCreateSession(req); const profile = await this.getOrCreateSession(req);
// Join socket room when using websocket // Join socket room when using websocket
@ -581,10 +552,7 @@ export default abstract class BaseWebChannelHandler<
try { try {
await req.socket.join(profile.foreign_id); await req.socket.join(profile.foreign_id);
} catch (err) { } catch (err) {
this.logger.error( this.logger.error('Unable to subscribe via websocket', err);
'Web Channel Handler : Unable to subscribe via websocket',
err,
);
} }
} }
// Fetch message history // Fetch message history
@ -595,7 +563,7 @@ export default abstract class BaseWebChannelHandler<
const messages = await this.fetchHistory(req, criteria); const messages = await this.fetchHistory(req, criteria);
return res.status(200).json({ profile, messages }); return res.status(200).json({ profile, messages });
} catch (err) { } catch (err) {
this.logger.warn('Web Channel Handler : Unable to subscribe ', err); this.logger.warn('Unable to subscribe ', err);
return res.status(500).json({ err: 'Unable to subscribe' }); return res.status(500).json({ err: 'Unable to subscribe' });
} }
} }
@ -610,13 +578,13 @@ export default abstract class BaseWebChannelHandler<
const { type, data } = req.body as Web.IncomingMessage; const { type, data } = req.body as Web.IncomingMessage;
if (!req.session?.web?.profile?.id) { if (!req.session?.web?.profile?.id) {
this.logger.debug('Web Channel Handler : No session'); this.logger.debug('No session');
return null; return null;
} }
// Check if any file is provided // Check if any file is provided
if (type !== 'file' || !('file' in data) || !data.file) { if (type !== 'file' || !('file' in data) || !data.file) {
this.logger.debug('Web Channel Handler : No files provided'); this.logger.debug('No files provided');
return null; return null;
} }
@ -636,10 +604,7 @@ export default abstract class BaseWebChannelHandler<
createdBy: req.session?.web?.profile?.id, createdBy: req.session?.web?.profile?.id,
}); });
} catch (err) { } catch (err) {
this.logger.error( this.logger.error('Unable to store uploaded file', err);
'Web Channel Handler : Unable to store uploaded file',
err,
);
throw new Error('Unable to upload file!'); throw new Error('Unable to upload file!');
} }
} }
@ -671,10 +636,7 @@ export default abstract class BaseWebChannelHandler<
(resolve, reject) => { (resolve, reject) => {
upload(req as Request, res as Response, async (err?: any) => { upload(req as Request, res as Response, async (err?: any) => {
if (err) { if (err) {
this.logger.error( this.logger.error('Unable to store uploaded file', err);
'Web Channel Handler : Unable to store uploaded file',
err,
);
reject(new Error('Unable to upload file!')); reject(new Error('Unable to upload file!'));
} }
@ -689,7 +651,7 @@ export default abstract class BaseWebChannelHandler<
// Check if any file is provided // Check if any file is provided
if (!file) { if (!file) {
this.logger.debug('Web Channel Handler : No files provided'); this.logger.debug('No files provided');
return null; return null;
} }
@ -703,10 +665,7 @@ export default abstract class BaseWebChannelHandler<
createdBy: req.session.web.profile?.id, createdBy: req.session.web.profile?.id,
}); });
} catch (err) { } catch (err) {
this.logger.error( this.logger.error('Unable to store uploaded file', err);
'Web Channel Handler : Unable to store uploaded file',
err,
);
throw err; throw err;
} }
} }
@ -724,7 +683,7 @@ export default abstract class BaseWebChannelHandler<
): Promise<Attachment | null | undefined> { ): Promise<Attachment | null | undefined> {
// Check if any file is provided // Check if any file is provided
if (!req.session.web) { if (!req.session.web) {
this.logger.debug('Web Channel Handler : No session provided'); this.logger.debug('No session provided');
return null; return null;
} }
@ -784,7 +743,7 @@ export default abstract class BaseWebChannelHandler<
): void { ): void {
// @TODO: perform payload validation // @TODO: perform payload validation
if (!req.body) { if (!req.body) {
this.logger.debug('Web Channel Handler : Empty body'); this.logger.debug('Empty body');
res.status(400).json({ err: 'Web Channel Handler : Bad Request!' }); res.status(400).json({ err: 'Web Channel Handler : Bad Request!' });
return; return;
} else { } else {
@ -814,10 +773,7 @@ export default abstract class BaseWebChannelHandler<
}; };
} }
} catch (err) { } catch (err) {
this.logger.warn( this.logger.warn('Unable to upload file ', err);
'Web Channel Handler : Unable to upload file ',
err,
);
return res return res
.status(403) .status(403)
.json({ err: 'Web Channel Handler : File upload failed!' }); .json({ err: 'Web Channel Handler : File upload failed!' });
@ -849,10 +805,7 @@ export default abstract class BaseWebChannelHandler<
if (type) { if (type) {
this.eventEmitter.emit(`hook:chatbot:${type}`, event); this.eventEmitter.emit(`hook:chatbot:${type}`, event);
} else { } else {
this.logger.error( this.logger.error('Webhook received unknown event ', event);
'Web Channel Handler : Webhook received unknown event ',
event,
);
} }
res.status(200).json(event._adapter.raw); res.status(200).json(event._adapter.raw);
}); });
@ -883,9 +836,7 @@ export default abstract class BaseWebChannelHandler<
if (!this.isSocketRequest(req) && req.query._get) { if (!this.isSocketRequest(req) && req.query._get) {
switch (req.query._get) { switch (req.query._get) {
case 'settings': case 'settings':
this.logger.debug( this.logger.debug('connected .. sending settings');
'Web Channel Handler : connected .. sending settings',
);
try { try {
const menu = await this.menuService.getTree(); const menu = await this.menuService.getTree();
return res.status(200).json({ return res.status(200).json({
@ -894,19 +845,14 @@ export default abstract class BaseWebChannelHandler<
...settings, ...settings,
}); });
} catch (err) { } catch (err) {
this.logger.warn( this.logger.warn('Unable to retrieve menu ', err);
'Web Channel Handler : Unable to retrieve menu ',
err,
);
return res.status(500).json({ err: 'Unable to retrieve menu' }); return res.status(500).json({ err: 'Unable to retrieve menu' });
} }
case 'polling': case 'polling':
// Handle polling when user is not connected via websocket // Handle polling when user is not connected via websocket
return this.getMessageQueue(req, res as Response); return this.getMessageQueue(req, res as Response);
default: default:
this.logger.error( this.logger.error('Webhook received unknown command');
'Web Channel Handler : Webhook received unknown command',
);
return res return res
.status(500) .status(500)
.json({ err: 'Webhook received unknown command' }); .json({ err: 'Webhook received unknown command' });
@ -923,7 +869,7 @@ export default abstract class BaseWebChannelHandler<
return this._handleEvent(req, res); return this._handleEvent(req, res);
} }
} catch (err) { } catch (err) {
this.logger.warn('Web Channel Handler : Request check failed', err); this.logger.warn('Request check failed', err);
return res return res
.status(403) .status(403)
.json({ err: 'Web Channel Handler : Unauthorized!' }); .json({ err: 'Web Channel Handler : Unauthorized!' });
@ -1131,9 +1077,7 @@ export default abstract class BaseWebChannelHandler<
// Items count min check // Items count min check
if (!data.length) { if (!data.length) {
this.logger.error( this.logger.error('Unsufficient content count (must be >= 0 for list)');
'Web Channel Handler : Unsufficient content count (must be >= 0 for list)',
);
throw new Error('Unsufficient content count (list >= 0)'); throw new Error('Unsufficient content count (list >= 0)');
} }
@ -1181,7 +1125,7 @@ export default abstract class BaseWebChannelHandler<
// Items count min check // Items count min check
if (data.length === 0) { if (data.length === 0) {
this.logger.error( this.logger.error(
'Web Channel Handler : Unsufficient content count (must be > 0 for carousel)', 'Unsufficient content count (must be > 0 for carousel)',
); );
throw new Error('Unsufficient content count (carousel > 0)'); throw new Error('Unsufficient content count (carousel > 0)');
} }
@ -1293,10 +1237,7 @@ export default abstract class BaseWebChannelHandler<
await this.sendTypingIndicator(subscriber, timeout); await this.sendTypingIndicator(subscriber, timeout);
return next(); return next();
} catch (err) { } catch (err) {
this.logger.error( this.logger.error('Failed in sending typing indicator ', err);
'Web Channel Handler : Failed in sending typing indicator ',
err,
);
} }
} }

View File

@ -8,8 +8,9 @@
import path from 'path'; import path from 'path';
import { LoggerService, OnModuleInit } from '@nestjs/common'; import { OnModuleInit } from '@nestjs/common';
import { LoggerService } from '@/logger/logger.service';
import { SettingService } from '@/setting/services/setting.service'; import { SettingService } from '@/setting/services/setting.service';
import { Extension } from '@/utils/generics/extension'; import { Extension } from '@/utils/generics/extension';
import { HyphenToUnderscore } from '@/utils/types/extension'; import { HyphenToUnderscore } from '@/utils/types/extension';

View File

@ -1,11 +1,58 @@
/* /*
* Copyright © 2024 Hexastack. All rights reserved. * Copyright © 2025 Hexastack. All rights reserved.
* *
* Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms:
* 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission.
* 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file). * 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file).
*/ */
import { ConsoleLogger } from '@nestjs/common'; import {
ConsoleLogger,
Inject,
Injectable,
LogLevel,
Scope,
} from '@nestjs/common';
import { INQUIRER } from '@nestjs/core';
export class LoggerService extends ConsoleLogger {} @Injectable({ scope: Scope.TRANSIENT })
export class LoggerService extends ConsoleLogger {
constructor(@Inject(INQUIRER) private parentClass: object) {
super(parentClass.constructor.name, {
logLevels: process.env.NODE_ENV?.includes('dev')
? ['log', 'debug', 'error', 'verbose', 'fatal', 'warn']
: ['log', 'warn', 'error'],
});
}
log(message: string, ...args: any[]) {
this.logArguments('log', message, args);
}
error(message: string, ...args: any[]) {
this.logArguments('error', message, args);
}
warn(message: string, ...args: any[]) {
this.logArguments('warn', message, args);
}
debug(message: string, ...args: any[]) {
this.logArguments('debug', message, args);
}
verbose(message: string, ...args: any[]) {
this.logArguments('verbose', message, args);
}
fatal(message: string, ...args: any[]) {
this.logArguments('fatal', message, args);
}
private logArguments(type: LogLevel, message: string, args: any[]) {
super[type](message);
args.forEach((arg) => {
super[type](arg);
});
}
}

View File

@ -101,10 +101,11 @@ async function bootstrap() {
app.useWebSocketAdapter(redisIoAdapter); app.useWebSocketAdapter(redisIoAdapter);
} }
process.on('uncaughtException', (error) => { process.on('uncaughtException', async (error) => {
if (error.stack?.toLowerCase().includes('smtp')) if (error.stack?.toLowerCase().includes('smtp')) {
app.get(LoggerService).error('SMTP error', error.stack); const logger = await app.resolve(LoggerService);
else throw error; logger.error('SMTP error', error.stack);
} else throw error;
}); });
if (!isProduction) { if (!isProduction) {

View File

@ -77,7 +77,7 @@ describe('MigrationService', () => {
}).compile(); }).compile();
service = module.get<MigrationService>(MigrationService); service = module.get<MigrationService>(MigrationService);
loggerService = module.get<LoggerService>(LoggerService); loggerService = await module.resolve<LoggerService>(LoggerService);
metadataService = module.get<MetadataService>(MetadataService); metadataService = module.get<MetadataService>(MetadataService);
}); });

View File

@ -37,7 +37,7 @@ import { UserSeeder } from './user/seeds/user.seed';
import { userModels } from './user/seeds/user.seed-model'; import { userModels } from './user/seeds/user.seed-model';
export async function seedDatabase(app: INestApplicationContext) { export async function seedDatabase(app: INestApplicationContext) {
const logger = app.get(LoggerService); const logger = await app.resolve(LoggerService);
const modelSeeder = app.get(ModelSeeder); const modelSeeder = app.get(ModelSeeder);
const categorySeeder = app.get(CategorySeeder); const categorySeeder = app.get(CategorySeeder);
const contextVarSeeder = app.get(ContextVarSeeder); const contextVarSeeder = app.get(ContextVarSeeder);