Jelajahi Sumber

introduce the logging module

Sven Czarnian 2 tahun lalu
induk
melakukan
ab623c8cb6

+ 2 - 0
src/app.module.ts

@@ -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 - 0
src/logging/dto/logentry.dto.ts

@@ -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 - 0
src/logging/logging.controller.spec.ts

@@ -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 - 0
src/logging/logging.controller.ts

@@ -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 - 0
src/logging/logging.module.ts

@@ -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 - 0
src/logging/logging.service.spec.ts

@@ -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 - 0
src/logging/logging.service.ts

@@ -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 - 0
src/logging/models/logentry.model.ts

@@ -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);