introduce the logging module
This commit is contained in:
@@ -4,6 +4,7 @@ import { MongooseModule } from '@nestjs/mongoose';
|
|||||||
import Configuration from './config/configuration';
|
import Configuration from './config/configuration';
|
||||||
import { VersioningModule } from './versioning/versioning.module';
|
import { VersioningModule } from './versioning/versioning.module';
|
||||||
import { PerformanceModule } from './performance/performance.module';
|
import { PerformanceModule } from './performance/performance.module';
|
||||||
|
import { LoggingModule } from './logging/logging.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -24,6 +25,7 @@ import { PerformanceModule } from './performance/performance.module';
|
|||||||
}),
|
}),
|
||||||
VersioningModule,
|
VersioningModule,
|
||||||
PerformanceModule,
|
PerformanceModule,
|
||||||
|
LoggingModule,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class AppModule {}
|
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