From c5c922ef386252b9f6590a9d112f67ad6faaa6bf Mon Sep 17 00:00:00 2001 From: AbhilashKD <124042593+AbhilashKD@users.noreply.github.com> Date: Fri, 23 Aug 2024 11:15:36 +0530 Subject: [PATCH 1/5] Update event-service.yaml --- manifest/event-service.yaml | 30 +++++++----------------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/manifest/event-service.yaml b/manifest/event-service.yaml index 9ce2621..ef02ad7 100644 --- a/manifest/event-service.yaml +++ b/manifest/event-service.yaml @@ -1,54 +1,38 @@ apiVersion: apps/v1 kind: Deployment metadata: - annotations: - kompose.cmd: /snap/kompose/19/kompose-linux-amd64 convert -f event.yaml - kompose.version: 1.21.0 (992df58d8) - creationTimestamp: null labels: - io.kompose.service: eventmanagement + app: eventmanagement name: eventmanagement spec: replicas: 1 selector: matchLabels: - io.kompose.service: eventmanagement - strategy: {} + app: eventmanagement template: metadata: - annotations: - kompose.cmd: /snap/kompose/19/kompose-linux-amd64 convert -f event.yaml - kompose.version: 1.21.0 (992df58d8) - creationTimestamp: null labels: - io.kompose.service: eventmanagement + app: eventmanagement spec: containers: - image: ${ECR_REPOSITORY}:${IMAGE_TAG} - imagePullPolicy: "" + imagePullPolicy: "Always" name: event-management-service - ports: - - containerPort: 3000 envFrom: - configMapRef: name: event-service-config + ports: + - containerPort: 3000 resources: {} - restartPolicy: Always - serviceAccountName: "" - volumes: null -status: {} --- apiVersion: v1 kind: Service metadata: name: eventmanagement - labels: - app: eventmanagement spec: type: ClusterIP ports: - - name: http-tracking + - port: 3000 protocol: TCP - port: 3000 selector: app: eventmanagement From f0566c5a460a325b30d4daedb61f9bca843519ec Mon Sep 17 00:00:00 2001 From: AbhilashKD <124042593+AbhilashKD@users.noreply.github.com> Date: Fri, 13 Sep 2024 11:57:47 +0530 Subject: [PATCH 2/5] Update eks-pratham-deployment.yaml --- .github/workflows/eks-pratham-deployment.yaml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/eks-pratham-deployment.yaml b/.github/workflows/eks-pratham-deployment.yaml index d9d5cd6..5a50ae2 100644 --- a/.github/workflows/eks-pratham-deployment.yaml +++ b/.github/workflows/eks-pratham-deployment.yaml @@ -3,10 +3,6 @@ on: push: branches: - main -# pull_request_target: -# types: [closed] -# branches: -# - main env: ECR_REPOSITORY: ${{ secrets.ECR_REPOSITORY }} EKS_CLUSTER_NAME: ${{ secrets.EKS_CLUSTER_NAME }} From 68a2137ab89848e165eb31808c5c06197a52ca21 Mon Sep 17 00:00:00 2001 From: Kshitija Kadam <65657373+Xitija@users.noreply.github.com> Date: Tue, 5 Nov 2024 13:54:32 +0530 Subject: [PATCH 3/5] feat : added logger --- package.json | 4 +- src/common/filters/exception.filter.ts | 16 +++++- src/common/logger/logger.util.ts | 80 ++++++++++++++++++++++++++ src/modules/event/event.service.ts | 11 ++++ 4 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 src/common/logger/logger.util.ts diff --git a/package.json b/package.json index 92b75a6..73f35b8 100644 --- a/package.json +++ b/package.json @@ -31,9 +31,11 @@ "class-transformer": "^0.5.1", "class-validator": "^0.14.1", "moment-timezone": "^0.5.45", + "nest-winston": "^1.9.7", "pg": "^8.13.0", "reflect-metadata": "^0.1.13", - "rxjs": "^7.8.1" + "rxjs": "^7.8.1", + "winston": "^3.16.0" }, "devDependencies": { "@nestjs/cli": "^10.0.0", diff --git a/src/common/filters/exception.filter.ts b/src/common/filters/exception.filter.ts index 2003a17..2ba9b68 100644 --- a/src/common/filters/exception.filter.ts +++ b/src/common/filters/exception.filter.ts @@ -9,6 +9,7 @@ import { QueryFailedError } from 'typeorm'; import { Response } from 'express'; import APIResponse from '../utils/response'; import { ERROR_MESSAGES } from '../utils/constants.util'; +import { LoggerWinston } from '../logger/logger.util'; @Catch() export class AllExceptionsFilter implements ExceptionFilter { @@ -20,6 +21,8 @@ export class AllExceptionsFilter implements ExceptionFilter { ) { const ctx = host.switchToHttp(); const response = ctx.getResponse(); + const request = ctx.getRequest(); + const status = exception instanceof HttpException ? exception.getStatus() : 500; @@ -34,6 +37,12 @@ export class AllExceptionsFilter implements ExceptionFilter { ERROR_MESSAGES.BAD_REQUEST, statusCode.toString(), ); + LoggerWinston.error( + `Error occurred on API: ${request.url}`, + errorMessage, + request.method, + ); + return response.status(statusCode).json(errorResponse); } else if (exception instanceof QueryFailedError) { const statusCode = HttpStatus.UNPROCESSABLE_ENTITY; @@ -43,10 +52,15 @@ export class AllExceptionsFilter implements ExceptionFilter { ERROR_MESSAGES.INTERNAL_SERVER_ERROR, statusCode.toString(), ); + LoggerWinston.error( + `Database Query Failed on API: ${request.url}`, + (exception as QueryFailedError).message, + request.method, + // user + ); return response.status(statusCode).json(errorResponse); } const detailedErrorMessage = `${errorMessage}`; - console.log('detailedErrorMessage', detailedErrorMessage); const errorResponse = APIResponse.error( this.apiId, detailedErrorMessage, diff --git a/src/common/logger/logger.util.ts b/src/common/logger/logger.util.ts new file mode 100644 index 0000000..0bedab1 --- /dev/null +++ b/src/common/logger/logger.util.ts @@ -0,0 +1,80 @@ +import * as winston from 'winston'; + +export class LoggerWinston { + private static logger: winston.Logger; + + static getLogger() { + if (!this.logger) { + const customFormat = winston.format.printf( + ({ timestamp, level, message, context, user, error }) => { + return JSON.stringify({ + timestamp: timestamp, + context: context, + user: user, + level: level, + message: message, + error: error, + }); + }, + ); + + this.logger = winston.createLogger({ + level: 'info', + format: winston.format.combine( + winston.format.timestamp(), + customFormat, + ), + transports: [ + new winston.transports.Console(), + new winston.transports.File({ + filename: 'error.log', + level: 'error', + }), + new winston.transports.File({ filename: 'combined.log' }), + ], + }); + } + return this.logger; + } + static log(message: string, context?: string, user?: string) { + this.getLogger().log({ + level: 'info', + message: message, + context: context, + user: user, + timestamp: new Date().toISOString(), + }); + } + + static error( + message: string, + error?: string, + context?: string, + user?: string, + ) { + this.getLogger().error({ + level: 'error', + message: message, + error: error, + context: context, + user: user, + timestamp: new Date().toISOString(), + }); + } + + static warn(message: string, context?: string) { + this.getLogger().warn({ + message: message, + context: context, + timestamp: new Date().toISOString(), + }); + } + + static debug(message: string, context?: string) { + this.getLogger().debug({ + message: message, + context: context, + timestamp: new Date().toISOString(), + }); + } +} diff --git a/src/modules/event/event.service.ts b/src/modules/event/event.service.ts index 4e48b29..7293fa3 100644 --- a/src/modules/event/event.service.ts +++ b/src/modules/event/event.service.ts @@ -41,6 +41,8 @@ import { } from 'src/common/pipes/event-validation.pipe'; import { compareArrays } from 'src/common/utils/functions.util'; import * as moment from 'moment-timezone'; +import { LoggerWinston } from 'src/common/logger/logger.util'; + @Injectable() export class EventService { private readonly eventCreationLimit: number; @@ -104,6 +106,12 @@ export class EventService { // } } + LoggerWinston.log( + `Event created with ID: ${createdEvent.res.eventId}`, + apiId, + 'user', + ); + return response .status(HttpStatus.CREATED) .json(APIResponse.success(apiId, createdEvent.res, 'Created')); @@ -164,6 +172,7 @@ export class EventService { if (finalResult.length === 0) { throw new NotFoundException(ERROR_MESSAGES.EVENT_NOT_FOUND); } + LoggerWinston.log(`Successfully fetched events`, apiId, 'info'); return response .status(HttpStatus.OK) .json( @@ -310,6 +319,8 @@ export class EventService { eventRepetition, ); } + + LoggerWinston.log(`Successfully updated events`, apiId, 'user'); return response .status(HttpStatus.OK) .json(APIResponse.success(apiId, result, 'OK')); From e2970ea412a8b6c16233dd57982a78ec85a4dd20 Mon Sep 17 00:00:00 2001 From: Kshitija Kadam <65657373+Xitija@users.noreply.github.com> Date: Tue, 5 Nov 2024 18:20:07 +0530 Subject: [PATCH 4/5] chore : stop log on console --- src/common/logger/logger.util.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/common/logger/logger.util.ts b/src/common/logger/logger.util.ts index 0bedab1..61c4b1b 100644 --- a/src/common/logger/logger.util.ts +++ b/src/common/logger/logger.util.ts @@ -25,7 +25,6 @@ export class LoggerWinston { customFormat, ), transports: [ - new winston.transports.Console(), new winston.transports.File({ filename: 'error.log', level: 'error', From d05026397960bd3be2e3690d5c08d08ea827c40f Mon Sep 17 00:00:00 2001 From: Kshitija Kadam <65657373+Xitija@users.noreply.github.com> Date: Wed, 6 Nov 2024 09:36:41 +0530 Subject: [PATCH 5/5] feat : createdby amd updated by from query --- src/common/filters/exception.filter.ts | 15 +++++++++++---- src/common/utils/constants.util.ts | 8 ++++++++ src/common/utils/functions.util.ts | 14 ++++++++++++++ src/modules/event/dto/create-event.dto.ts | 10 ---------- src/modules/event/dto/update-event.dto.ts | 11 ----------- src/modules/event/event.controller.ts | 21 ++++++++++++++++++--- src/modules/event/event.service.ts | 20 ++++++++++++++------ 7 files changed, 65 insertions(+), 34 deletions(-) diff --git a/src/common/filters/exception.filter.ts b/src/common/filters/exception.filter.ts index 2ba9b68..c4699d1 100644 --- a/src/common/filters/exception.filter.ts +++ b/src/common/filters/exception.filter.ts @@ -6,7 +6,7 @@ import { HttpStatus, } from '@nestjs/common'; import { QueryFailedError } from 'typeorm'; -import { Response } from 'express'; +import { Request, Response } from 'express'; import APIResponse from '../utils/response'; import { ERROR_MESSAGES } from '../utils/constants.util'; import { LoggerWinston } from '../logger/logger.util'; @@ -38,9 +38,10 @@ export class AllExceptionsFilter implements ExceptionFilter { statusCode.toString(), ); LoggerWinston.error( - `Error occurred on API: ${request.url}`, + ERROR_MESSAGES.API_REQ_FAILURE(request.url), errorMessage, request.method, + typeof request.query === 'string' ? request.query : '', ); return response.status(statusCode).json(errorResponse); @@ -53,10 +54,10 @@ export class AllExceptionsFilter implements ExceptionFilter { statusCode.toString(), ); LoggerWinston.error( - `Database Query Failed on API: ${request.url}`, + ERROR_MESSAGES.DB_QUERY_FAILURE(request.url), (exception as QueryFailedError).message, request.method, - // user + typeof request.query === 'string' ? request.query : '', ); return response.status(statusCode).json(errorResponse); } @@ -69,6 +70,12 @@ export class AllExceptionsFilter implements ExceptionFilter { : ERROR_MESSAGES.INTERNAL_SERVER_ERROR, status.toString(), ); + LoggerWinston.error( + ERROR_MESSAGES.API_FAILURE(request.url), + errorResponse.result, + request.method, + typeof request.query === 'string' ? request.query : '', + ); return response.status(status).json(errorResponse); } } diff --git a/src/common/utils/constants.util.ts b/src/common/utils/constants.util.ts index 9f9381c..68d7b54 100644 --- a/src/common/utils/constants.util.ts +++ b/src/common/utils/constants.util.ts @@ -87,6 +87,11 @@ export const ERROR_MESSAGES = { END_CONDITION_BY_OCCURENCES: 'End condition by occurrences is not implemented yet', EVENT_TYPE_CHANGE_NOT_SUPPORTED: 'Event type change not supported', + USERID_INVALID: 'Invalid UserId', + PROVIDE_ONE_USERID_IN_QUERY: 'Please provide only one userid in query', + API_REQ_FAILURE: (url: string) => `Error occurred on API Request: ${url}`, + DB_QUERY_FAILURE: (url: string) => `Database Query Failed on API: ${url}`, + API_FAILURE: (url: string) => `API Failure: ${url}`, }; export const SUCCESS_MESSAGES = { @@ -102,6 +107,9 @@ export const SUCCESS_MESSAGES = { 'Event attendee history item updated successfully', EVENT_ATTENDEE_HISTORY_ITEM_DELETED: 'Event attendee history item deleted successfully', + EVENT_CREATED_LOG: (url: string) => `Event created with ID: ${url}`, + EVENTS_FETCHED_LOG: 'Successfully fetched events', + EVENT_UPDATED_LOG: 'Successfully updated events', }; export const API_ID = { diff --git a/src/common/utils/functions.util.ts b/src/common/utils/functions.util.ts index 709ee5d..eb55a1f 100644 --- a/src/common/utils/functions.util.ts +++ b/src/common/utils/functions.util.ts @@ -1,3 +1,7 @@ +import { BadRequestException } from '@nestjs/common'; +import { isUUID } from 'class-validator'; +import { ERROR_MESSAGES } from './constants.util'; + export const compareArrays = (a: number[], b: number[]): boolean => { if (a.length !== b.length) { return false; @@ -22,3 +26,13 @@ export const getNextDay = (currentDate: Date): Date => { return nextDay; }; + +export const checkValidUserId = (userId: any): string => { + if (typeof userId !== 'string') { + throw new BadRequestException(ERROR_MESSAGES.PROVIDE_ONE_USERID_IN_QUERY); + } + if (!userId || !isUUID(userId)) { + throw new BadRequestException(ERROR_MESSAGES.USERID_INVALID); + } + return userId; +}; diff --git a/src/modules/event/dto/create-event.dto.ts b/src/modules/event/dto/create-event.dto.ts index 1e7853b..87efe58 100644 --- a/src/modules/event/dto/create-event.dto.ts +++ b/src/modules/event/dto/create-event.dto.ts @@ -347,18 +347,8 @@ export class CreateEventDto { @IsNotEmpty() status: string; - @ApiProperty({ - type: String, - description: 'createdBy', - example: 'eff008a8-2573-466d-b877-fddf6a4fc13e', - }) createdBy: string; - @ApiProperty({ - type: String, - description: 'updatedBy', - example: 'eff008a8-2573-466d-b877-fddf6a4fc13e', - }) updatedBy: string; @ApiProperty({ diff --git a/src/modules/event/dto/update-event.dto.ts b/src/modules/event/dto/update-event.dto.ts index 6a6cb6f..21c5210 100644 --- a/src/modules/event/dto/update-event.dto.ts +++ b/src/modules/event/dto/update-event.dto.ts @@ -187,17 +187,6 @@ export class UpdateEventDto { @IsIn(['Zoom', 'GoogleMeet']) onlineProvider: string; - // @IsString() - // @IsOptional() - // createdBy: string; - - @ApiProperty({ - type: String, - description: 'updatedBy', - example: 'eff008a8-2573-466d-b877-fddf6a4fc13e', - }) - @IsString() - // @IsOptional() updatedBy: string; @IsOptional() diff --git a/src/modules/event/event.controller.ts b/src/modules/event/event.controller.ts index b2e9ea2..6dcb84e 100644 --- a/src/modules/event/event.controller.ts +++ b/src/modules/event/event.controller.ts @@ -6,6 +6,7 @@ import { Param, UsePipes, Res, + Req, ValidationPipe, BadRequestException, UseFilters, @@ -21,8 +22,9 @@ import { ApiOkResponse, ApiResponse, ApiTags, + ApiQuery, } from '@nestjs/swagger'; -import { Response } from 'express'; +import { Request, Response } from 'express'; import { SearchFilterDto } from './dto/search-event.dto'; import { DateValidationPipe, @@ -38,6 +40,7 @@ import { ERROR_MESSAGES, SUCCESS_MESSAGES, } from 'src/common/utils/constants.util'; +import { checkValidUserId } from 'src/common/utils/functions.util'; @Controller('event/v1') @ApiTags('Create Event') @@ -50,6 +53,7 @@ export class EventController { @UseFilters(new AllExceptionsFilter(API_ID.CREATE_EVENT)) @Post('/create') @ApiBody({ type: CreateEventDto }) + @ApiQuery({ name: 'userid', required: true }) @UsePipes( new ValidationPipe({ transform: true }), new DateValidationPipe(), @@ -67,13 +71,18 @@ export class EventController { async create( @Body() createEventDto: CreateEventDto, @Res() response: Response, + @Req() request: Request, ) { + const userId: string = checkValidUserId(request.query.userid); + createEventDto.createdBy = userId; + createEventDto.updatedBy = userId; return this.eventService.createEvent(createEventDto, response); } @UseFilters(new AllExceptionsFilter(API_ID.GET_EVENTS)) @Post('/list') @ApiBody({ type: SearchFilterDto }) + @ApiQuery({ name: 'userid', required: true }) @ApiInternalServerErrorResponse({ description: ERROR_MESSAGES.INTERNAL_SERVER_ERROR, }) @@ -86,15 +95,18 @@ export class EventController { status: 200, }) async findAll( - @Res() response: Response, @Body() requestBody: SearchFilterDto, + @Res() response: Response, + @Req() request: Request, ) { - return this.eventService.getEvents(response, requestBody); + const userId: string = checkValidUserId(request.query.userid); + return this.eventService.getEvents(response, requestBody, userId); } @UseFilters(new AllExceptionsFilter(API_ID.UPDATE_EVENT)) @Patch('/:id') @ApiBody({ type: UpdateEventDto }) + @ApiQuery({ name: 'userid', required: true }) @ApiResponse({ status: 200, description: SUCCESS_MESSAGES.EVENT_UPDATED }) @ApiInternalServerErrorResponse({ description: ERROR_MESSAGES.INTERNAL_SERVER_ERROR, @@ -104,10 +116,13 @@ export class EventController { @Body(new ValidationPipe({ transform: true })) updateEventDto: UpdateEventDto, @Res() response: Response, + @Req() request: Request, ) { if (!updateEventDto || Object.keys(updateEventDto).length === 0) { throw new BadRequestException(ERROR_MESSAGES.INVALID_REQUEST_BODY); } + const userId: string = checkValidUserId(request.query.userid); + updateEventDto.updatedBy = userId; return this.eventService.updateEvent(id, updateEventDto, response); } } diff --git a/src/modules/event/event.service.ts b/src/modules/event/event.service.ts index 7293fa3..c31b5ad 100644 --- a/src/modules/event/event.service.ts +++ b/src/modules/event/event.service.ts @@ -24,7 +24,11 @@ import { Response } from 'express'; import APIResponse from 'src/common/utils/response'; import { AttendeesService } from '../attendees/attendees.service'; import { EventDetail } from './entities/eventDetail.entity'; -import { API_ID, ERROR_MESSAGES } from 'src/common/utils/constants.util'; +import { + API_ID, + ERROR_MESSAGES, + SUCCESS_MESSAGES, +} from 'src/common/utils/constants.util'; import { EventRepetition } from './entities/eventRepetition.entity'; import { DaysOfWeek, @@ -107,9 +111,9 @@ export class EventService { } LoggerWinston.log( - `Event created with ID: ${createdEvent.res.eventId}`, + SUCCESS_MESSAGES.EVENT_CREATED_LOG(createdEvent.res?.eventId), apiId, - 'user', + createEventDto.createdBy, ); return response @@ -117,7 +121,7 @@ export class EventService { .json(APIResponse.success(apiId, createdEvent.res, 'Created')); } - async getEvents(response, requestBody) { + async getEvents(response, requestBody, userId: string) { const apiId = API_ID.GET_EVENTS; this.validateTimezone(); @@ -172,7 +176,7 @@ export class EventService { if (finalResult.length === 0) { throw new NotFoundException(ERROR_MESSAGES.EVENT_NOT_FOUND); } - LoggerWinston.log(`Successfully fetched events`, apiId, 'info'); + LoggerWinston.log(SUCCESS_MESSAGES.EVENTS_FETCHED_LOG, apiId, userId); return response .status(HttpStatus.OK) .json( @@ -320,7 +324,11 @@ export class EventService { ); } - LoggerWinston.log(`Successfully updated events`, apiId, 'user'); + LoggerWinston.log( + SUCCESS_MESSAGES.EVENT_UPDATED_LOG, + apiId, + updateBody.updatedBy, + ); return response .status(HttpStatus.OK) .json(APIResponse.success(apiId, result, 'OK'));