Skip to content

Commit

Permalink
Merge branch 'main' into feat/common-graphql-error-handler
Browse files Browse the repository at this point in the history
  • Loading branch information
kshitij-k-osmosys authored Jan 17, 2025
2 parents cc599af + ca08424 commit 5c40d2d
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 9 deletions.
7 changes: 7 additions & 0 deletions apps/api/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ MAX_RETRY_COUNT=3 # Max retry count, default is 3
ARCHIVE_LIMIT=1000 # Max notifications to archive, default is 1000
ARCHIVE_INTERVAL=3600 # Interval (in seconds) for archiving notifications, default 3600 (every 1 hour)

# Slogger configuration
SLOGGER_LOG_TYPE=
SLOGGER_LOG_LEVEL=error #Log level, default is error
SLOGERR_API_ENDPOINT= #Slogger log api url
SLOGERR_API_TOKEN= #Slogger api token
ENABLE_SLOGERR=false #default set to false

# Logger configuration
LOG_LEVEL=info # Log level, default is info
COMBINED_LOG_MAX_SIZE=150m # Max file size for combined logs. Set 0 for no size limit, default 150m
Expand Down
4 changes: 2 additions & 2 deletions apps/api/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion apps/api/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "osmox",
"version": "4.2.0",
"version": "4.2.1",
"description": "Centralized multi-channel notification management component for streamlined communication across email, SMS, WhatsApp, and push notifications.",
"author": "Osmosys Software Solutions Private Limited",
"license": "MIT",
Expand Down
81 changes: 81 additions & 0 deletions apps/api/src/common/logger/slogerr.transport.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { HttpService } from '@nestjs/axios';
import TransportStream = require('winston-transport');
import { TransportStreamOptions } from 'winston-transport';
import { ConfigService } from '@nestjs/config';
import { Logger } from '@nestjs/common/services/logger.service';
import { firstValueFrom } from 'rxjs';

interface CustomTransportOptions extends TransportStreamOptions {
httpService: HttpService;
configService: ConfigService;
}

interface LogInfo {
level: string;
message: string;
timestamp?: string;
context?: string;
stack?: string;
severity: string;
}

export class SlogerrTransport extends TransportStream {
private readonly httpService: HttpService;
private readonly configService: ConfigService;
private readonly logger = new Logger(SlogerrTransport.name);

constructor(options: CustomTransportOptions) {
super(options);
this.httpService = options.httpService;
this.configService = options.configService;
}

async log(info: LogInfo, callback: () => void): Promise<void> {
const allowedLevels = (this.configService.get<string>('SLOGGER_LOG_LEVEL') || 'error')
.split(',')
.map((level) => level.trim());
const logType = this.configService.get<string>('SLOGGER_LOG_TYPE') || 'Exceptions';

if (allowedLevels.includes(info.level)) {
const apiEndpoint = this.configService.get<string>('SLOGERR_API_ENDPOINT');
const apiKey = this.configService.get<string>('SLOGERR_API_TOKEN');

this.logger.log(`Log Info: ${JSON.stringify(info)}`);

const logCreatedOn = info.timestamp || new Date().toISOString();

try {
const response = await firstValueFrom(
this.httpService.post(
apiEndpoint,
{
moduleName: info.context || 'Unknown Module',
logDescription: info.message,
logType: logType,
logCreatedOn: logCreatedOn,
severity: info.severity,
logData: {
message: info.message,
stack: info.stack,
context: info.context,
},
},
{ headers: { 'slogerr-secure-api-key': apiKey } },
),
);

if (response.status !== 200) {
this.logger.error(
`Failed to send log to Slogerr. Status: ${response.status}, Message: ${response.statusText}`,
);
} else {
this.logger.log('Error log successfully sent to Slogerr', response);
}
} catch (error) {
this.logger.error('Failed to send log to Slogerr', error.message);
}
}

callback();
}
}
11 changes: 11 additions & 0 deletions apps/api/src/config/logger.config.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
import { WinstonModule, utilities as nestWinstonModuleUtilities } from 'nest-winston';
import { transports, format } from 'winston';
import { join } from 'path';
import { HttpService } from '@nestjs/axios';
import { v4 as uuidv4 } from 'uuid';
import 'winston-daily-rotate-file';
import { ConfigService } from '@nestjs/config';
import { name as applicationName } from 'package.json';
import DailyRotateFile from 'winston-daily-rotate-file';
import { SlogerrTransport } from 'src/common/logger/slogerr.transport';

const configService = new ConfigService();
const httpService = new HttpService();

const logDir = 'logs';

// Fetch maxSize values from environment variables or use defaults
const combinedLogMaxSize = configService.get<string>('COMBINED_LOG_MAX_SIZE');
const errorLogMaxSize = configService.get<string>('ERROR_LOG_MAX_SIZE');

const enableSlogger = configService.get<string>('ENABLE_SLOGERR') || 'false';

const logFormat = format.combine(
format.timestamp(),
format.printf((info) => {
Expand Down Expand Up @@ -77,6 +82,11 @@ if (errorLogMaxSize === '0') {
errorLogOptions.maxSize = '20m';
}

const slogerrTransport = new SlogerrTransport({
httpService,
configService,
});

const transportsConfig = [
new transports.Console({
format: format.combine(
Expand All @@ -87,6 +97,7 @@ const transportsConfig = [
}),
new transports.DailyRotateFile(combinedLogOptions),
new transports.DailyRotateFile(errorLogOptions),
...(enableSlogger === 'true' ? [slogerrTransport] : []),
];

export const loggerConfig = WinstonModule.createLogger({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,27 @@
import { Controller, Post } from '@nestjs/common';
import { Controller, HttpException, Logger, Post } from '@nestjs/common';
import { ArchivedNotificationsService } from './archived-notifications.service';

@Controller('archived-notifications')
export class ArchivedNotificationsController {
constructor(private readonly archivedNotificationService: ArchivedNotificationsService) {}
constructor(
private readonly archivedNotificationService: ArchivedNotificationsService,
private logger: Logger = new Logger(ArchivedNotificationsController.name),
) {}

@Post('archive')
async addNotificationsToQueue(): Promise<void> {
this.archivedNotificationService.archiveCompletedNotificationsCron();
try {
this.logger.debug('Archiving completed notifications...');
await this.archivedNotificationService.archiveCompletedNotificationsCron();
this.logger.log('Notifications archived successfully.');
} catch (error) {
if (error instanceof HttpException) {
throw error;
}

this.logger.error('Error while archiving notifications');
this.logger.error(JSON.stringify(error, ['message', 'stack'], 2));
throw error;
}
}
}
4 changes: 2 additions & 2 deletions apps/portal/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion apps/portal/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "osmox-portal",
"version": "4.2.0",
"version": "4.2.1",
"scripts": {
"ng": "ng",
"start": "ng serve",
Expand Down

0 comments on commit 5c40d2d

Please sign in to comment.