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