introduce the logging module
This commit is contained in:
		| @@ -4,6 +4,7 @@ import { MongooseModule } from '@nestjs/mongoose'; | ||||
| import Configuration from './config/configuration'; | ||||
| import { VersioningModule } from './versioning/versioning.module'; | ||||
| import { PerformanceModule } from './performance/performance.module'; | ||||
| import { LoggingModule } from './logging/logging.module'; | ||||
|  | ||||
| @Module({ | ||||
|   imports: [ | ||||
| @@ -24,6 +25,7 @@ import { PerformanceModule } from './performance/performance.module'; | ||||
|     }), | ||||
|     VersioningModule, | ||||
|     PerformanceModule, | ||||
|     LoggingModule, | ||||
|   ], | ||||
| }) | ||||
| export class AppModule {} | ||||
|   | ||||
							
								
								
									
										32
									
								
								src/logging/dto/logentry.dto.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/logging/dto/logentry.dto.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| import { IsNotEmpty } from 'class-validator'; | ||||
| import { ApiProperty } from '@nestjs/swagger'; | ||||
|  | ||||
| export class LogEntryDto { | ||||
|   @IsNotEmpty() | ||||
|   @ApiProperty({ | ||||
|     description: 'The component which logged the message', | ||||
|     example: 'optimizer', | ||||
|   }) | ||||
|   component: string; | ||||
|  | ||||
|   @IsNotEmpty() | ||||
|   @ApiProperty({ | ||||
|     description: 'The defined log level of this message', | ||||
|     example: 'DEBUG', | ||||
|   }) | ||||
|   level: string; | ||||
|  | ||||
|   @IsNotEmpty() | ||||
|   @ApiProperty({ | ||||
|     description: 'The timestamp when the message was logged', | ||||
|     example: 'Wed, 14 Jun 2017 07:00:00 GMT', | ||||
|   }) | ||||
|   timestamp: string; | ||||
|  | ||||
|   @IsNotEmpty() | ||||
|   @ApiProperty({ | ||||
|     description: 'The logged message', | ||||
|     example: 'This is a log message.', | ||||
|   }) | ||||
|   message: string; | ||||
| } | ||||
							
								
								
									
										18
									
								
								src/logging/logging.controller.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/logging/logging.controller.spec.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| import { Test, TestingModule } from '@nestjs/testing'; | ||||
| import { LoggingController } from './logging.controller'; | ||||
|  | ||||
| describe('LoggingController', () => { | ||||
|   let controller: LoggingController; | ||||
|  | ||||
|   beforeEach(async () => { | ||||
|     const module: TestingModule = await Test.createTestingModule({ | ||||
|       controllers: [LoggingController], | ||||
|     }).compile(); | ||||
|  | ||||
|     controller = module.get<LoggingController>(LoggingController); | ||||
|   }); | ||||
|  | ||||
|   it('should be defined', () => { | ||||
|     expect(controller).toBeDefined(); | ||||
|   }); | ||||
| }); | ||||
							
								
								
									
										110
									
								
								src/logging/logging.controller.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								src/logging/logging.controller.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,110 @@ | ||||
| import { | ||||
|   Controller, | ||||
|   Get, | ||||
|   Delete, | ||||
|   Query, | ||||
|   HttpException, | ||||
|   HttpStatus, | ||||
| } from '@nestjs/common'; | ||||
| import { ApiQuery, ApiResponse } from '@nestjs/swagger'; | ||||
| import { LogEntryDto } from './dto/logentry.dto'; | ||||
| import { LoggingService } from './logging.service'; | ||||
| import { LogEntry } from './models/logentry.model'; | ||||
|  | ||||
| @Controller('logging') | ||||
| export class LoggingController { | ||||
|   constructor(private readonly loggingService: LoggingService) {} | ||||
|  | ||||
|   private static logEntryToDto(entry: LogEntry): LogEntryDto { | ||||
|     return { | ||||
|       component: entry.component, | ||||
|       level: entry.level, | ||||
|       timestamp: entry.timestamp, | ||||
|       message: entry.message, | ||||
|     }; | ||||
|   } | ||||
|  | ||||
|   @Get('/all') | ||||
|   @ApiResponse({ | ||||
|     status: 201, | ||||
|     description: 'All log entries', | ||||
|     type: [LogEntryDto], | ||||
|   }) | ||||
|   @ApiResponse({ | ||||
|     status: 404, | ||||
|     description: 'No messages found', | ||||
|   }) | ||||
|   async allMessages(): Promise<LogEntryDto[]> { | ||||
|     return this.loggingService.allMessages().then((response) => { | ||||
|       if (response === null) { | ||||
|         throw new HttpException( | ||||
|           'Unable to find the log messages', | ||||
|           HttpStatus.NOT_FOUND, | ||||
|         ); | ||||
|       } | ||||
|  | ||||
|       const messages: LogEntryDto[] = []; | ||||
|       response.forEach((entry) => | ||||
|         messages.push(LoggingController.logEntryToDto(entry)), | ||||
|       ); | ||||
|       return messages; | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   @Get('/component') | ||||
|   @ApiQuery({ | ||||
|     name: 'component', | ||||
|     description: 'The component filter for the messages', | ||||
|     type: String, | ||||
|   }) | ||||
|   @ApiResponse({ | ||||
|     status: 201, | ||||
|     description: 'All log entries', | ||||
|     type: [LogEntryDto], | ||||
|   }) | ||||
|   @ApiResponse({ | ||||
|     status: 404, | ||||
|     description: 'No messages found', | ||||
|   }) | ||||
|   async componentMessages( | ||||
|     @Query('component') component: string, | ||||
|   ): Promise<LogEntryDto[]> { | ||||
|     return this.loggingService.componentMessages(component).then((response) => { | ||||
|       if (response === null) { | ||||
|         throw new HttpException( | ||||
|           'Unable to find the log messages', | ||||
|           HttpStatus.NOT_FOUND, | ||||
|         ); | ||||
|       } | ||||
|  | ||||
|       const messages: LogEntryDto[] = []; | ||||
|       response.forEach((entry) => | ||||
|         messages.push(LoggingController.logEntryToDto(entry)), | ||||
|       ); | ||||
|       return messages; | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   @Delete('/deleteAll') | ||||
|   @ApiResponse({ | ||||
|     status: 200, | ||||
|     description: 'All log entries are deleted', | ||||
|   }) | ||||
|   async deleteAll(): Promise<void> { | ||||
|     return this.loggingService.deleteAllMessages(); | ||||
|   } | ||||
|  | ||||
|   @Delete('/deleteComponent') | ||||
|   @ApiQuery({ | ||||
|     name: 'component', | ||||
|     description: 'The component filter for the messages', | ||||
|     type: String, | ||||
|   }) | ||||
|   @ApiResponse({ | ||||
|     status: 200, | ||||
|     description: 'All log entries are deleted', | ||||
|   }) | ||||
|   async deleteComponent(@Query('component') component: string): Promise<void> { | ||||
|     return this.loggingService.deleteComponentMessages(component); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										15
									
								
								src/logging/logging.module.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/logging/logging.module.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| import { Module } from '@nestjs/common'; | ||||
| import { MongooseModule } from '@nestjs/mongoose'; | ||||
| import { LoggingService } from './logging.service'; | ||||
| import { LoggingController } from './logging.controller'; | ||||
| import { LogEntrySchema } from './models/logentry.model'; | ||||
|  | ||||
| @Module({ | ||||
|   imports: [ | ||||
|     MongooseModule.forFeature([{ name: 'logging', schema: LogEntrySchema }]), | ||||
|   ], | ||||
|   providers: [LoggingService], | ||||
|   controllers: [LoggingController], | ||||
|   exports: [MongooseModule, LoggingService], | ||||
| }) | ||||
| export class LoggingModule {} | ||||
							
								
								
									
										18
									
								
								src/logging/logging.service.spec.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/logging/logging.service.spec.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| import { Test, TestingModule } from '@nestjs/testing'; | ||||
| import { LoggingService } from './logging.service'; | ||||
|  | ||||
| describe('LoggingService', () => { | ||||
|   let service: LoggingService; | ||||
|  | ||||
|   beforeEach(async () => { | ||||
|     const module: TestingModule = await Test.createTestingModule({ | ||||
|       providers: [LoggingService], | ||||
|     }).compile(); | ||||
|  | ||||
|     service = module.get<LoggingService>(LoggingService); | ||||
|   }); | ||||
|  | ||||
|   it('should be defined', () => { | ||||
|     expect(service).toBeDefined(); | ||||
|   }); | ||||
| }); | ||||
							
								
								
									
										61
									
								
								src/logging/logging.service.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/logging/logging.service.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | ||||
| import { Injectable } from '@nestjs/common'; | ||||
| import { InjectModel } from '@nestjs/mongoose'; | ||||
| import { Model } from 'mongoose'; | ||||
| import { LogEntry, LogEntryDocument } from './models/logentry.model'; | ||||
|  | ||||
| @Injectable() | ||||
| export class LoggingService { | ||||
|   constructor( | ||||
|     @InjectModel('logging') | ||||
|     private readonly logEntryModel: Model<LogEntryDocument>, | ||||
|   ) {} | ||||
|  | ||||
|   private async addLogMessage( | ||||
|     component: string, | ||||
|     level: string, | ||||
|     message: string, | ||||
|   ): Promise<void> { | ||||
|     await this.logEntryModel.create({ | ||||
|       component, | ||||
|       level, | ||||
|       timestamp: new Date().toUTCString(), | ||||
|       message, | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   async addDebugMessage(component: string, message: string): Promise<void> { | ||||
|     await this.addLogMessage(component, 'DEBUG', message); | ||||
|   } | ||||
|  | ||||
|   async addInfoMessage(component: string, message: string): Promise<void> { | ||||
|     await this.addLogMessage(component, 'INFO', message); | ||||
|   } | ||||
|  | ||||
|   async addWarningMessage(component: string, message: string): Promise<void> { | ||||
|     await this.addLogMessage(component, 'WARNING', message); | ||||
|   } | ||||
|  | ||||
|   async addErrorMessage(component: string, message: string): Promise<void> { | ||||
|     await this.addLogMessage(component, 'ERROR', message); | ||||
|   } | ||||
|  | ||||
|   async addCriticalMessage(component: string, message: string): Promise<void> { | ||||
|     await this.addLogMessage(component, 'CRITICAL', message); | ||||
|   } | ||||
|  | ||||
|   async deleteComponentMessages(component: string): Promise<void> { | ||||
|     this.logEntryModel.deleteMany({ component }); | ||||
|   } | ||||
|  | ||||
|   async deleteAllMessages(): Promise<void> { | ||||
|     this.logEntryModel.deleteMany({}); | ||||
|   } | ||||
|  | ||||
|   async componentMessages(component: string): Promise<LogEntry[]> { | ||||
|     return this.logEntryModel.find({ component }); | ||||
|   } | ||||
|  | ||||
|   async allMessages(): Promise<LogEntry[]> { | ||||
|     return this.logEntryModel.find({}); | ||||
|   } | ||||
| } | ||||
							
								
								
									
										34
									
								
								src/logging/models/logentry.model.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/logging/models/logentry.model.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; | ||||
| import { Document } from 'mongoose'; | ||||
|  | ||||
| export type LogEntryDocument = LogEntry & Document; | ||||
|  | ||||
| @Schema() | ||||
| export class LogEntry { | ||||
|   @Prop({ | ||||
|     required: true, | ||||
|     type: String, | ||||
|   }) | ||||
|   component: string; | ||||
|  | ||||
|   @Prop({ | ||||
|     required: true, | ||||
|     enum: ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'], | ||||
|     type: String, | ||||
|   }) | ||||
|   level: string; | ||||
|  | ||||
|   @Prop({ | ||||
|     required: true, | ||||
|     type: String, | ||||
|   }) | ||||
|   timestamp: string; | ||||
|  | ||||
|   @Prop({ | ||||
|     required: true, | ||||
|     type: String, | ||||
|   }) | ||||
|   message: string; | ||||
| } | ||||
|  | ||||
| export const LogEntrySchema = SchemaFactory.createForClass(LogEntry); | ||||
		Reference in New Issue
	
	Block a user