Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion apps/sample/src/app/app.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import { AppService } from './app.service';
@ApiTags('App')
@ApiBearerAuth(APP.JWT_BEARER)
export class AppController {
constructor(private readonly appService: AppService) {}
constructor(
private readonly appService: AppService,
) { }

// @CheckAbilities({ actions: ACTIONS.READ, subject: SUBJECTS.USER })
// @UseGuards(JwtGuard, AbilitiesGuard)
Expand Down
5 changes: 3 additions & 2 deletions apps/sample/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { PrismaModule } from '@rumsan/prisma';
import { ConfigModule } from '@nestjs/config';
import { EventEmitterModule } from '@nestjs/event-emitter';
import { RSExceptionModule } from '@rumsan/extensions/exceptions';
import { LoggerModule } from '@rumsan/extensions/logger';
import { SettingsModule } from '@rumsan/extensions/settings';
import {
AbilityModule,
Expand All @@ -20,7 +21,6 @@ import { ListenerModule } from '../listener/listener.module';
import { AppUsersModule } from '../user/user.module';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true }),
Expand All @@ -40,8 +40,9 @@ import { AppService } from './app.service';
RSExceptionModule.forRoot({ errorSet: ERRORS }),
AbilityModule.forRoot({ subjects: APP_SUBJECTS }),
SettingsModule,
LoggerModule
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
export class AppModule { }
6 changes: 4 additions & 2 deletions apps/sample/src/app/app.service.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { Injectable } from '@nestjs/common';
import { Inject, Injectable } from '@nestjs/common';
import { Logger, LoggerKey } from '@rumsan/extensions/logger';
import { SettingsService } from '@rumsan/extensions/settings';
import { PrismaService } from '@rumsan/prisma';

@Injectable()
export class AppService {
constructor(private prisma: PrismaService) {}
constructor(private prisma: PrismaService,
@Inject(LoggerKey) private logger: Logger) { }
async getData() {
//throw ERRORS.NO_MATCH_IP;
//return AbilitySubject.list();
Expand Down
10 changes: 5 additions & 5 deletions apps/sample/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@ import { NestFastifyApplication } from '@nestjs/platform-fastify';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { RsExceptionFilter } from '@rumsan/extensions/exceptions';
import { ResponseTransformInterceptor } from '@rumsan/extensions/interceptors';
import { WinstonModule } from 'nest-winston';
import NestjsLoggerServiceAdapter from '@rumsan/extensions/logger/infrastructure/nestjs/nestjsLoggerServiceAdapter';
import { AppModule } from './app/app.module';
import { APP } from './constants';
import { loggerInstance } from './logger/winston.logger';


async function bootstrap() {
const app = await NestFactory.create<NestFastifyApplication>(AppModule, {
logger: WinstonModule.createLogger({
instance: loggerInstance,
}),
bufferLogs: true
});

app.useLogger(app.get(NestjsLoggerServiceAdapter))
const globalPrefix = 'v1';
app.enableCors();

Expand Down
2 changes: 2 additions & 0 deletions libs/extensions/src/logger/domain/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './log';
export * from './logger';
34 changes: 34 additions & 0 deletions libs/extensions/src/logger/domain/log.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
export enum LogLevel {
Emergency = 'emergency',
Fatal = 'fatal',
Error = 'error',
Warn = 'warn',
Info = 'info',
Debug = 'debug',
}

export interface Log {
timestamp: number;
level: LogLevel;
message: string;
data: LogData;
}

export interface LogData {
organization?: string;
context?: string;
app?: string;
sourceClass?: string;
correlationId?: string;
error?: Error;
props?: NodeJS.Dict<any>;
}

export const ContextStorageServiceKey = 'CONTEXT_STORAGE_SERVICE_KEY';

export interface ContextStorageService {
setContextId(contextId: string): void;
getContextId(): string;
get<T>(key: string): T | undefined;
set<T>(key: string, value: T): void;
}
80 changes: 80 additions & 0 deletions libs/extensions/src/logger/domain/logger.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { Inject } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { INQUIRER } from '@nestjs/core';
import {
LogData,
LogLevel
} from './log';
import { Logger, LoggerBaseKey } from './logger';

export default class LoggerService implements Logger {
private sourceClass: string;
private organization: string;
private context: string;
private app: string;

public constructor(
@Inject(LoggerBaseKey) private logger: Logger,
configService: ConfigService,
@Inject(INQUIRER) parentClass: object,

) {
this.sourceClass = parentClass?.constructor?.name;
this.organization =
configService?.get<string>('ORGANIZATION') ?? 'ORGANIZATION';
this.context = configService?.get<string>('CONTEXT') ?? 'CONTEXT';
this.app = configService?.get<string>('APP') ?? 'APP';
}

public log(
level: LogLevel,
message: string | Error,
data: LogData,
profile?: string,
): void {
return this.logger.log(level, message, this.getLogData(data), profile);
}

public debug(message: string, data?: LogData, profile?: string) {
return this.logger.debug(message, this.getLogData(data), profile);
}

public info(message: string, data?: LogData, profile?: string) {
return this.logger.info(message, this.getLogData(data), profile);
}

public warn(message: string | Error, data?: LogData, profile?: string) {
return this.logger.warn(message, this.getLogData(data), profile);
}

public error(message: string | Error, data?: LogData, profile?: string) {
return this.logger.error(message, this.getLogData(data), profile);
}

public fatal(message: string | Error, data?: LogData, profile?: string) {
return this.logger.fatal(message, this.getLogData(data), profile);
}

public emergency(
message: string | Error,
data?: LogData | undefined,
profile?: string | undefined,
) {
return this.logger.emergency(message, this.getLogData(data), profile);
}

private getLogData(data?: LogData): LogData {
return {
...data,
organization: data?.organization || this.organization,
context: data?.context || this.context,
app: data?.app || this.app,
sourceClass: data?.sourceClass || this.sourceClass,

};
}

public startProfile(id: string): void {
this.logger.startProfile(id);
}
}
21 changes: 21 additions & 0 deletions libs/extensions/src/logger/domain/logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { LogData, LogLevel } from '.';

export const LoggerBaseKey = 'LOGGER_BASE_KEY';
export const LoggerKey = 'LOGGER_KEY';
export const WinstonLoggerTransportsKey = 'WINSTON_LOGGER_TRANSPORTS_KEY';

export interface Logger {
log(
level: LogLevel,
message: string | Error,
data?: LogData,
profile?: string,
): void;
debug(message: string, data?: LogData, profile?: string): void;
info(message: string, data?: LogData, profile?: string): void;
warn(message: string | Error, data?: LogData, profile?: string): void;
error(message: string | Error, data?: LogData, profile?: string): void;
fatal(message: string | Error, data?: LogData, profile?: string): void;
emergency(message: string | Error, data?: LogData, profile?: string): void;
startProfile(id: string): void;
}
3 changes: 3 additions & 0 deletions libs/extensions/src/logger/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './domain';
export * from './infrastructure';

2 changes: 2 additions & 0 deletions libs/extensions/src/logger/infrastructure/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './nestjs'
export * from './winston'
2 changes: 2 additions & 0 deletions libs/extensions/src/logger/infrastructure/nestjs/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './logger.module'
export * from './nestjsLoggerServiceAdapter'
86 changes: 86 additions & 0 deletions libs/extensions/src/logger/infrastructure/nestjs/logger.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import {
Global,
Inject,
MiddlewareConsumer,
Module,
NestModule
} from '@nestjs/common';
import { ConfigModule, ConfigService } from '../../../config';
import {
Logger,
LoggerBaseKey,
LoggerKey,
WinstonLoggerTransportsKey,
} from '../../domain';
import LoggerService from '../../domain/logger.service';
import ConsoleTransport from '../winston/transports/consoleTransport';
import FileTransport from '../winston/transports/fileTransport';
import SlackTransport from '../winston/transports/slackTransport';
import { WinstonLogger } from '../winston/winston.logger';
import NestjsLoggerServiceAdapter from './nestjsLoggerServiceAdapter';
import morgan = require('morgan');

@Global()
@Module({

imports: [ConfigModule],
controllers: [],
providers: [
{
provide: LoggerBaseKey,
useClass: WinstonLogger,
},
{
provide: LoggerKey,
useClass: LoggerService,
},
{
provide: NestjsLoggerServiceAdapter,
useFactory: (logger: Logger) => new NestjsLoggerServiceAdapter(logger),
inject: [LoggerKey],
},
{
provide: WinstonLoggerTransportsKey,
useFactory: (configService: ConfigService) => {
const transports = [];

transports.push(ConsoleTransport.createColorize());
transports.push(FileTransport.create());
if (configService.isProduction) {
if (configService.slackWebhookUrl) {

transports.push(
SlackTransport.create(configService.slackWebhookUrl),
);
}
}

return transports;
},
inject: [ConfigService],
},
],
exports: [LoggerKey, NestjsLoggerServiceAdapter],
})
export class LoggerModule implements NestModule {
public constructor(
@Inject(LoggerKey) private logger: Logger,
private configService: ConfigService,
) { }

public configure(consumer: MiddlewareConsumer): void {
consumer
.apply(
morgan(this.configService.isProduction ? 'combined' : 'dev', {
stream: {
write: (message: string) => {
this.logger.debug(message, {
sourceClass: 'RequestLogger',
});
},
},
}),
)
.forRoutes('*');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { ConsoleLogger, LoggerService } from '@nestjs/common';
import { Logger } from '../../domain';

export default class NestjsLoggerServiceAdapter
extends ConsoleLogger
implements LoggerService
{
public constructor(private logger: Logger) {
super();
}

public override log(message: any, ...optionalParams: any[]) {
return this.logger.info(message, this.getLogData(optionalParams));
}

public override error(message: any, ...optionalParams: any[]) {
return this.logger.error(message, this.getLogData(optionalParams));
}

public override warn(message: any, ...optionalParams: any[]) {
return this.logger.warn(message, this.getLogData(optionalParams));
}

public override debug(message: any, ...optionalParams: any[]) {
return this.logger.debug(message, this.getLogData(optionalParams));
}

public override verbose(message: any, ...optionalParams: any[]) {
return this.logger.info(message, this.getLogData(optionalParams));
}

private getLogData(...optionalParams: any[]) {
return {
sourceClass: optionalParams[0] ? optionalParams[0] : undefined,
};
}
}
2 changes: 2 additions & 0 deletions libs/extensions/src/logger/infrastructure/winston/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './transports'
export * from './winston.logger'
Loading