From 6eb9b40e14cc847281e670fd20919b0b379e9628 Mon Sep 17 00:00:00 2001 From: Gsk54 Date: Fri, 23 Dec 2022 15:14:51 +0100 Subject: [PATCH] send logging messages --- .env | 2 -- .env.dist | 2 -- .../secondaries/prisma-repository.abstract.ts | 1 - .../adapters/primaries/users.controller.ts | 24 ++++++------- .../adapters/secondaries/logging.messager.ts | 14 ++++++++ .../adapters/secondaries/user.messager.ts | 12 +++---- .../users/domain/interfaces/user-messager.ts | 2 +- .../domain/usecases/create-user.usecase.ts | 24 +++++++++---- .../domain/usecases/delete-user.usecase.ts | 26 +++++++++----- .../domain/usecases/find-all-users.usecase.ts | 4 +-- .../usecases/find-user-by-uuid.usecase.ts | 22 ++++++++++-- .../domain/usecases/update-user.usecase.ts | 34 +++++++++++++------ .../tests/unit/create-user.usecase.spec.ts | 9 +++-- .../tests/unit/delete-user.usecase.spec.ts | 13 +++++-- .../unit/find-user-by-uuid.usecase.spec.ts | 9 +++++ .../tests/unit/update-user.usecase.spec.ts | 9 +++-- src/modules/users/users.module.ts | 10 ++++-- 17 files changed, 151 insertions(+), 66 deletions(-) create mode 100644 src/modules/users/adapters/secondaries/logging.messager.ts diff --git a/.env b/.env index 562a4ba..1f38b39 100644 --- a/.env +++ b/.env @@ -7,8 +7,6 @@ SERVICE_PORT=5001 DATABASE_URL="postgresql://user:user@v3-user-db:5432/user?schema=public" # RABBIT MQ -RMQ_EXCHANGE_NAME=user -RMQ_EXCHANGE_TYPE=topic RMQ_URI=amqp://v3-gateway-broker:5672 # POSTGRES diff --git a/.env.dist b/.env.dist index 7ca933f..085e9bb 100644 --- a/.env.dist +++ b/.env.dist @@ -7,8 +7,6 @@ SERVICE_PORT=5001 DATABASE_URL="postgresql://user:user@v3-user-db:5432/user?schema=public" # RABBIT MQ -RMQ_EXCHANGES=user -RMQ_EXCHANGE_TYPE=topic RMQ_URI=amqp://localhost:5672 # POSTGRES diff --git a/src/modules/database/src/adapters/secondaries/prisma-repository.abstract.ts b/src/modules/database/src/adapters/secondaries/prisma-repository.abstract.ts index 4b9cd4e..10f7b10 100644 --- a/src/modules/database/src/adapters/secondaries/prisma-repository.abstract.ts +++ b/src/modules/database/src/adapters/secondaries/prisma-repository.abstract.ts @@ -149,7 +149,6 @@ export abstract class PrismaRepository implements IRepository { const entity = await this._prisma[this._model].delete({ where: { uuid }, }); - return entity; } catch (e) { if (e instanceof PrismaClientKnownRequestError) { diff --git a/src/modules/users/adapters/primaries/users.controller.ts b/src/modules/users/adapters/primaries/users.controller.ts index 2428e14..717b683 100644 --- a/src/modules/users/adapters/primaries/users.controller.ts +++ b/src/modules/users/adapters/primaries/users.controller.ts @@ -1,11 +1,6 @@ import { Mapper } from '@automapper/core'; import { InjectMapper } from '@automapper/nestjs'; -import { - Controller, - UsePipes, - ValidationError, - ValidationPipe, -} from '@nestjs/common'; +import { Controller, UsePipes } from '@nestjs/common'; import { CommandBus, QueryBus } from '@nestjs/cqrs'; import { GrpcMethod, RpcException } from '@nestjs/microservices'; import { DatabaseException } from 'src/modules/database/src/exceptions/DatabaseException'; @@ -46,16 +41,17 @@ export class UsersController { @GrpcMethod('UsersService', 'FindOneByUuid') async findOneByUuid(data: FindUserByUuidRequest): Promise { - const user = await this._queryBus.execute( - new FindUserByUuidQuery(data.uuid), - ); - if (user) { + try { + const user = await this._queryBus.execute( + new FindUserByUuidQuery(data.uuid), + ); return this._mapper.map(user, User, UserPresenter); + } catch (error) { + throw new RpcException({ + code: 5, + message: 'User not found', + }); } - throw new RpcException({ - code: 5, - message: 'User not found', - }); } @GrpcMethod('UsersService', 'Create') diff --git a/src/modules/users/adapters/secondaries/logging.messager.ts b/src/modules/users/adapters/secondaries/logging.messager.ts new file mode 100644 index 0000000..7d95c7c --- /dev/null +++ b/src/modules/users/adapters/secondaries/logging.messager.ts @@ -0,0 +1,14 @@ +import { AmqpConnection } from '@golevelup/nestjs-rabbitmq'; +import { Injectable } from '@nestjs/common'; +import { IMessageBroker } from '../../domain/interfaces/user-messager'; + +@Injectable() +export class LoggingMessager extends IMessageBroker { + constructor(private readonly _amqpConnection: AmqpConnection) { + super('logging'); + } + + publish(routingKey: string, message: string): void { + this._amqpConnection.publish(this.exchange, routingKey, message); + } +} diff --git a/src/modules/users/adapters/secondaries/user.messager.ts b/src/modules/users/adapters/secondaries/user.messager.ts index 2ce98c5..f807d6d 100644 --- a/src/modules/users/adapters/secondaries/user.messager.ts +++ b/src/modules/users/adapters/secondaries/user.messager.ts @@ -1,15 +1,11 @@ import { AmqpConnection } from '@golevelup/nestjs-rabbitmq'; import { Injectable } from '@nestjs/common'; -import { ConfigService } from '@nestjs/config'; -import { IMessageUser } from '../../domain/interfaces/user-messager'; +import { IMessageBroker } from '../../domain/interfaces/user-messager'; @Injectable() -export class UserMessager extends IMessageUser { - constructor( - private readonly _configService: ConfigService, - private readonly _amqpConnection: AmqpConnection, - ) { - super(_configService.get('RMQ_EXCHANGE_NAME')); +export class UserMessager extends IMessageBroker { + constructor(private readonly _amqpConnection: AmqpConnection) { + super('user'); } publish(routingKey: string, message: string): void { diff --git a/src/modules/users/domain/interfaces/user-messager.ts b/src/modules/users/domain/interfaces/user-messager.ts index 98ad7c2..594aa43 100644 --- a/src/modules/users/domain/interfaces/user-messager.ts +++ b/src/modules/users/domain/interfaces/user-messager.ts @@ -1,7 +1,7 @@ import { Injectable } from '@nestjs/common'; @Injectable() -export abstract class IMessageUser { +export abstract class IMessageBroker { exchange: string; constructor(exchange: string) { diff --git a/src/modules/users/domain/usecases/create-user.usecase.ts b/src/modules/users/domain/usecases/create-user.usecase.ts index e2b5ded..d1ef4e4 100644 --- a/src/modules/users/domain/usecases/create-user.usecase.ts +++ b/src/modules/users/domain/usecases/create-user.usecase.ts @@ -1,6 +1,7 @@ import { Mapper } from '@automapper/core'; import { InjectMapper } from '@automapper/nestjs'; import { CommandHandler } from '@nestjs/cqrs'; +import { LoggingMessager } from '../../adapters/secondaries/logging.messager'; import { UserMessager } from '../../adapters/secondaries/user.messager'; import { UsersRepository } from '../../adapters/secondaries/users.repository'; import { CreateUserCommand } from '../../commands/create-user.command'; @@ -11,7 +12,8 @@ import { User } from '../entities/user'; export class CreateUserUseCase { constructor( private readonly _repository: UsersRepository, - private readonly _messager: UserMessager, + private readonly _userMessager: UserMessager, + private readonly _loggingMessager: LoggingMessager, @InjectMapper() private readonly _mapper: Mapper, ) {} @@ -22,12 +24,20 @@ export class CreateUserUseCase { User, ); - const user = await this._repository.create(entity); - - if (user) { - this._messager.publish('user.create', JSON.stringify(user)); + try { + const user = await this._repository.create(entity); + this._userMessager.publish('create', JSON.stringify(user)); + this._loggingMessager.publish('user.create.info', JSON.stringify(user)); + return user; + } catch (error) { + this._loggingMessager.publish( + 'user.create.critical', + JSON.stringify({ + command, + error, + }), + ); + throw error; } - - return user; } } diff --git a/src/modules/users/domain/usecases/delete-user.usecase.ts b/src/modules/users/domain/usecases/delete-user.usecase.ts index 1d27849..71f84ce 100644 --- a/src/modules/users/domain/usecases/delete-user.usecase.ts +++ b/src/modules/users/domain/usecases/delete-user.usecase.ts @@ -1,4 +1,5 @@ import { CommandHandler } from '@nestjs/cqrs'; +import { LoggingMessager } from '../../adapters/secondaries/logging.messager'; import { UserMessager } from '../../adapters/secondaries/user.messager'; import { UsersRepository } from '../../adapters/secondaries/users.repository'; import { DeleteUserCommand } from '../../commands/delete-user.command'; @@ -8,19 +9,28 @@ import { User } from '../entities/user'; export class DeleteUserUseCase { constructor( private readonly _repository: UsersRepository, - private readonly _messager: UserMessager, + private readonly _userMessager: UserMessager, + private readonly _loggingMessager: LoggingMessager, ) {} async execute(command: DeleteUserCommand): Promise { - const user = await this._repository.delete(command.uuid); - - if (user) { - this._messager.publish( - 'user.delete', + try { + const user = await this._repository.delete(command.uuid); + this._userMessager.publish('delete', JSON.stringify({ uuid: user.uuid })); + this._loggingMessager.publish( + 'delete', JSON.stringify({ uuid: user.uuid }), ); + return user; + } catch (error) { + this._loggingMessager.publish( + 'user.delete.critical', + JSON.stringify({ + command, + error, + }), + ); + throw error; } - - return user; } } diff --git a/src/modules/users/domain/usecases/find-all-users.usecase.ts b/src/modules/users/domain/usecases/find-all-users.usecase.ts index df2608f..971dde2 100644 --- a/src/modules/users/domain/usecases/find-all-users.usecase.ts +++ b/src/modules/users/domain/usecases/find-all-users.usecase.ts @@ -6,12 +6,12 @@ import { User } from '../entities/user'; @QueryHandler(FindAllUsersQuery) export class FindAllUsersUseCase { - constructor(private readonly _usersRepository: UsersRepository) {} + constructor(private readonly _repository: UsersRepository) {} async execute( findAllUsersQuery: FindAllUsersQuery, ): Promise> { - return this._usersRepository.findAll( + return this._repository.findAll( findAllUsersQuery.page, findAllUsersQuery.perPage, ); diff --git a/src/modules/users/domain/usecases/find-user-by-uuid.usecase.ts b/src/modules/users/domain/usecases/find-user-by-uuid.usecase.ts index 9ed13b0..a49fe3f 100644 --- a/src/modules/users/domain/usecases/find-user-by-uuid.usecase.ts +++ b/src/modules/users/domain/usecases/find-user-by-uuid.usecase.ts @@ -1,13 +1,31 @@ +import { NotFoundException } from '@nestjs/common'; import { QueryHandler } from '@nestjs/cqrs'; +import { LoggingMessager } from '../../adapters/secondaries/logging.messager'; import { UsersRepository } from '../../adapters/secondaries/users.repository'; import { FindUserByUuidQuery } from '../../queries/find-user-by-uuid.query'; import { User } from '../entities/user'; @QueryHandler(FindUserByUuidQuery) export class FindUserByUuidUseCase { - constructor(private readonly _usersRepository: UsersRepository) {} + constructor( + private readonly _repository: UsersRepository, + private readonly _loggingMessager: LoggingMessager, + ) {} async execute(findUserByUuid: FindUserByUuidQuery): Promise { - return this._usersRepository.findOneByUuid(findUserByUuid.uuid); + try { + const user = await this._repository.findOneByUuid(findUserByUuid.uuid); + if (!user) throw new NotFoundException(); + return user; + } catch (error) { + this._loggingMessager.publish( + 'user.read.warning', + JSON.stringify({ + query: findUserByUuid, + error, + }), + ); + throw error; + } } } diff --git a/src/modules/users/domain/usecases/update-user.usecase.ts b/src/modules/users/domain/usecases/update-user.usecase.ts index bd3aab8..4b83369 100644 --- a/src/modules/users/domain/usecases/update-user.usecase.ts +++ b/src/modules/users/domain/usecases/update-user.usecase.ts @@ -1,6 +1,7 @@ import { Mapper } from '@automapper/core'; import { InjectMapper } from '@automapper/nestjs'; import { CommandHandler } from '@nestjs/cqrs'; +import { LoggingMessager } from '../../adapters/secondaries/logging.messager'; import { UserMessager } from '../../adapters/secondaries/user.messager'; import { UsersRepository } from '../../adapters/secondaries/users.repository'; import { UpdateUserCommand } from '../../commands/update-user.command'; @@ -11,7 +12,8 @@ import { User } from '../entities/user'; export class UpdateUserUseCase { constructor( private readonly _repository: UsersRepository, - private readonly _messager: UserMessager, + private readonly _userMessager: UserMessager, + private readonly _loggingMessager: LoggingMessager, @InjectMapper() private readonly _mapper: Mapper, ) {} @@ -22,17 +24,29 @@ export class UpdateUserUseCase { User, ); - const user = await this._repository.update( - command.updateUserRequest.uuid, - entity, - ); - - if (user) { - this._messager.publish( - 'user.update', + try { + const user = await this._repository.update( + command.updateUserRequest.uuid, + entity, + ); + this._userMessager.publish( + 'update', JSON.stringify(command.updateUserRequest), ); + this._loggingMessager.publish( + 'user.update.info', + JSON.stringify(command.updateUserRequest), + ); + return user; + } catch (error) { + this._loggingMessager.publish( + 'user.update.critical', + JSON.stringify({ + command, + error, + }), + ); + throw error; } - return user; } } diff --git a/src/modules/users/tests/unit/create-user.usecase.spec.ts b/src/modules/users/tests/unit/create-user.usecase.spec.ts index cf85f13..d0bed6e 100644 --- a/src/modules/users/tests/unit/create-user.usecase.spec.ts +++ b/src/modules/users/tests/unit/create-user.usecase.spec.ts @@ -1,6 +1,7 @@ import { classes } from '@automapper/classes'; import { AutomapperModule } from '@automapper/nestjs'; import { Test, TestingModule } from '@nestjs/testing'; +import { LoggingMessager } from '../../adapters/secondaries/logging.messager'; import { UserMessager } from '../../adapters/secondaries/user.messager'; import { UsersRepository } from '../../adapters/secondaries/users.repository'; import { CreateUserCommand } from '../../commands/create-user.command'; @@ -24,7 +25,7 @@ const mockUsersRepository = { }), }; -const mockUserMessager = { +const mockMessager = { publish: jest.fn().mockImplementation(), }; @@ -43,7 +44,11 @@ describe('CreateUserUseCase', () => { UserProfile, { provide: UserMessager, - useValue: mockUserMessager, + useValue: mockMessager, + }, + { + provide: LoggingMessager, + useValue: mockMessager, }, ], }).compile(); diff --git a/src/modules/users/tests/unit/delete-user.usecase.spec.ts b/src/modules/users/tests/unit/delete-user.usecase.spec.ts index 02cb5be..913b9ef 100644 --- a/src/modules/users/tests/unit/delete-user.usecase.spec.ts +++ b/src/modules/users/tests/unit/delete-user.usecase.spec.ts @@ -1,4 +1,5 @@ import { Test, TestingModule } from '@nestjs/testing'; +import { LoggingMessager } from '../../adapters/secondaries/logging.messager'; import { UserMessager } from '../../adapters/secondaries/user.messager'; import { UsersRepository } from '../../adapters/secondaries/users.repository'; import { DeleteUserCommand } from '../../commands/delete-user.command'; @@ -30,16 +31,18 @@ const mockUsers = [ const mockUsersRepository = { delete: jest.fn().mockImplementation((uuid: string) => { + let savedUser = {}; mockUsers.forEach((user, index) => { if (user.uuid === uuid) { + savedUser = { ...user }; mockUsers.splice(index, 1); - return Promise.resolve(); } }); + return savedUser; }), }; -const mockUserMessager = { +const mockMessager = { publish: jest.fn().mockImplementation(), }; @@ -56,7 +59,11 @@ describe('DeleteUserUseCase', () => { DeleteUserUseCase, { provide: UserMessager, - useValue: mockUserMessager, + useValue: mockMessager, + }, + { + provide: LoggingMessager, + useValue: mockMessager, }, ], }).compile(); diff --git a/src/modules/users/tests/unit/find-user-by-uuid.usecase.spec.ts b/src/modules/users/tests/unit/find-user-by-uuid.usecase.spec.ts index 81673c5..0752576 100644 --- a/src/modules/users/tests/unit/find-user-by-uuid.usecase.spec.ts +++ b/src/modules/users/tests/unit/find-user-by-uuid.usecase.spec.ts @@ -1,4 +1,5 @@ import { Test, TestingModule } from '@nestjs/testing'; +import { LoggingMessager } from '../../adapters/secondaries/logging.messager'; import { UsersRepository } from '../../adapters/secondaries/users.repository'; import { FindUserByUuidUseCase } from '../../domain/usecases/find-user-by-uuid.usecase'; import { FindUserByUuidQuery } from '../../queries/find-user-by-uuid.query'; @@ -18,6 +19,10 @@ const mockUserRepository = { }), }; +const mockMessager = { + publish: jest.fn().mockImplementation(), +}; + describe('FindUserByUuidUseCase', () => { let findUserByUuidUseCase: FindUserByUuidUseCase; @@ -29,6 +34,10 @@ describe('FindUserByUuidUseCase', () => { provide: UsersRepository, useValue: mockUserRepository, }, + { + provide: LoggingMessager, + useValue: mockMessager, + }, FindUserByUuidUseCase, ], }).compile(); diff --git a/src/modules/users/tests/unit/update-user.usecase.spec.ts b/src/modules/users/tests/unit/update-user.usecase.spec.ts index ed68fda..4cb17fb 100644 --- a/src/modules/users/tests/unit/update-user.usecase.spec.ts +++ b/src/modules/users/tests/unit/update-user.usecase.spec.ts @@ -1,6 +1,7 @@ import { classes } from '@automapper/classes'; import { AutomapperModule } from '@automapper/nestjs'; import { Test, TestingModule } from '@nestjs/testing'; +import { LoggingMessager } from '../../adapters/secondaries/logging.messager'; import { UserMessager } from '../../adapters/secondaries/user.messager'; import { UsersRepository } from '../../adapters/secondaries/users.repository'; import { UpdateUserCommand } from '../../commands/update-user.command'; @@ -30,7 +31,7 @@ const mockUsersRepository = { }), }; -const mockUserMessager = { +const mockMessager = { publish: jest.fn().mockImplementation(), }; @@ -50,7 +51,11 @@ describe('UpdateUserUseCase', () => { UserProfile, { provide: UserMessager, - useValue: mockUserMessager, + useValue: mockMessager, + }, + { + provide: LoggingMessager, + useValue: mockMessager, }, ], }).compile(); diff --git a/src/modules/users/users.module.ts b/src/modules/users/users.module.ts index 47fec5c..1192751 100644 --- a/src/modules/users/users.module.ts +++ b/src/modules/users/users.module.ts @@ -4,6 +4,7 @@ import { ConfigModule, ConfigService } from '@nestjs/config'; import { CqrsModule } from '@nestjs/cqrs'; import { DatabaseModule } from '../database/database.module'; import { UsersController } from './adapters/primaries/users.controller'; +import { LoggingMessager } from './adapters/secondaries/logging.messager'; import { UserMessager } from './adapters/secondaries/user.messager'; import { UsersRepository } from './adapters/secondaries/users.repository'; import { CreateUserUseCase } from './domain/usecases/create-user.usecase'; @@ -22,8 +23,12 @@ import { UserProfile } from './mappers/user.profile'; useFactory: async (configService: ConfigService) => ({ exchanges: [ { - name: configService.get('RMQ_EXCHANGE_NAME'), - type: configService.get('RMQ_EXCHANGE_TYPE'), + name: 'user', + type: 'topic', + }, + { + name: 'logging', + type: 'topic', }, ], uri: configService.get('RMQ_URI'), @@ -36,6 +41,7 @@ import { UserProfile } from './mappers/user.profile'; UserProfile, UsersRepository, UserMessager, + LoggingMessager, FindAllUsersUseCase, FindUserByUuidUseCase, CreateUserUseCase,