diff --git a/src/app/module/chat/data/data-source/message/message-remote-data-source.service.ts b/src/app/module/chat/data/data-source/message/message-remote-data-source.service.ts index af654b5ff..a9654790e 100644 --- a/src/app/module/chat/data/data-source/message/message-remote-data-source.service.ts +++ b/src/app/module/chat/data/data-source/message/message-remote-data-source.service.ts @@ -25,6 +25,7 @@ export class MessageRemoteDataSourceService { return await this.httpService.post(`${this.baseUrl}/Messages/${id}/React`, reaction); } + @APIReturn(MessageOutPutDTOSchema, 'get/Messages') async getMessagesFromRoom(id: string): DataSourceReturn { return await this.httpService.get(`${this.baseUrl}/Room/${id}/Messages`); diff --git a/src/app/module/chat/data/dto/message/messageOutputDTO.ts b/src/app/module/chat/data/dto/message/messageOutputDTO.ts index de6f2cf20..6b96e927f 100644 --- a/src/app/module/chat/data/dto/message/messageOutputDTO.ts +++ b/src/app/module/chat/data/dto/message/messageOutputDTO.ts @@ -20,7 +20,7 @@ export const MessageOutPutDataDTOSchema = z.object({ wxFullName: z.string(), wxeMail: z.string(), userPhoto: z.string().optional() - }).nullable(), + }), message: z.string().nullable(), messageType: z.number(), sentAt: z.string(), diff --git a/src/app/module/chat/domain/use-case/socket/socket-message-create-use-case.service.ts b/src/app/module/chat/domain/use-case/socket/socket-message-create-use-case.service.ts index 57e3322fd..ab808bc2c 100644 --- a/src/app/module/chat/domain/use-case/socket/socket-message-create-use-case.service.ts +++ b/src/app/module/chat/domain/use-case/socket/socket-message-create-use-case.service.ts @@ -1,5 +1,8 @@ import { Injectable, Input } from '@angular/core'; import { MessageLocalDataSourceService } from '../../../data/data-source/message/message-local-data-source.service'; +import { TracingType, XTracerAsync } from 'src/app/services/monitoring/opentelemetry/tracer'; +import { ParamsValidation } from 'src/app/services/decorators/validate-schema.decorator'; +import { MessageOutPutDataDTOSchema } from '../../../data/dto/message/messageOutputDTO'; @Injectable({ providedIn: 'root' @@ -10,22 +13,29 @@ export class SocketMessageCreateUseCaseService { private messageLocalDataSourceService: MessageLocalDataSourceService, ) { } - async execute(input: any) { + @XTracerAsync({name:'Socket-Message-Create-UseCase', bugPrint: true}) + async execute(input: any, tracing?: TracingType) { + + ParamsValidation(MessageOutPutDataDTOSchema, input, tracing) const incomingMessage = { ...input, - sending: false, - roomId:input.chatRoomId + sending: false } - delete input.chatRoomId + console.log('create message', {incomingMessage}); - const result = await this.messageLocalDataSourceService.sendMessage(incomingMessage) + tracing?.addEvent("Message Create start") + const result = await this.messageLocalDataSourceService.createMessage(incomingMessage) + tracing?.addEvent("Message Create end") if(result.isOk()) { } else { - console.log(result.error) + tracing?.addEvent("error while creating message") + tracing.log("error while creating message", { + error: result.error + }) } } } diff --git a/src/app/module/chat/domain/use-case/socket/socket-message-update-use-case.service.ts b/src/app/module/chat/domain/use-case/socket/socket-message-update-use-case.service.ts index a3955ffb2..e7a7c0e0d 100644 --- a/src/app/module/chat/domain/use-case/socket/socket-message-update-use-case.service.ts +++ b/src/app/module/chat/domain/use-case/socket/socket-message-update-use-case.service.ts @@ -1,8 +1,9 @@ import { Injectable } from '@angular/core'; import { MessageLocalDataSourceService } from '../../../data/data-source/message/message-local-data-source.service'; import { MessageOutPutDataDTO, MessageOutPutDataDTOSchema } from '../../../data/dto/message/messageOutputDTO'; -import { SafeValidateSchema, ValidateSchema } from 'src/app/services/decorators/validate-schema.decorator'; +import { ParamsValidation, SafeValidateSchema, ValidateSchema } from 'src/app/services/decorators/validate-schema.decorator'; import { MessageInputDTOSchema } from '../../../data/dto/message/messageInputDtO'; +import { TracingType, XTracerAsync } from 'src/app/services/monitoring/opentelemetry/tracer'; @Injectable({ providedIn: 'root' @@ -14,8 +15,12 @@ export class SocketMessageUpdateUseCaseService { ) { } - @SafeValidateSchema(MessageOutPutDataDTOSchema, 'SocketMessageUpdateUseCaseService') - async execute(data: MessageOutPutDataDTO) { + @XTracerAsync({name:'Socket-Message-Update-UseCase', bugPrint: true}) + async execute(data: MessageOutPutDataDTO, tracing?: TracingType) { + + ParamsValidation(MessageOutPutDataDTOSchema, data, tracing) + + tracing?.addEvent("Message existe?") const result = await this.messageLocalDataSourceService.messageExist({id: data.id}) const incomingMessage = { @@ -23,14 +28,13 @@ export class SocketMessageUpdateUseCaseService { sending: false } - // delete data.chatRoomId - if(result.isOk()) { - console.log('message exist', result.value, incomingMessage) - return this.messageLocalDataSourceService.update(result.value.$id, incomingMessage) + tracing?.addEvent("Message found") + return await this.messageLocalDataSourceService.update(result.value.$id, incomingMessage) } else { - console.log('message else') + tracing?.addEvent("Message not found") } + tracing.setAttribute('outcome', 'success') } } diff --git a/src/app/pages/chat/chat.page.html b/src/app/pages/chat/chat.page.html index 7c6fb54f6..e06e6a283 100644 --- a/src/app/pages/chat/chat.page.html +++ b/src/app/pages/chat/chat.page.html @@ -133,7 +133,6 @@ (openGroupContacts)="openGroupContactsPage($event)" (openEditGroupPage)="openEditGroupPage($event)" - (getGroups)="getGroups($event)" [style.display]="showMessages ? 'flex' : 'none'" [roomId]="roomId" diff --git a/src/app/services/decorators/validate-schema.decorator.ts b/src/app/services/decorators/validate-schema.decorator.ts index ae43d5a64..ad20db702 100644 --- a/src/app/services/decorators/validate-schema.decorator.ts +++ b/src/app/services/decorators/validate-schema.decorator.ts @@ -1,4 +1,4 @@ -import { err } from 'neverthrow'; +import { err, ok } from 'neverthrow'; import { Schema, ZodError } from 'zod'; import { ColoredLoggerService } from '../logger/colored/service'; import { TracingType } from '../monitoring/opentelemetry/tracer'; @@ -73,3 +73,79 @@ export function SafeValidateSchema(schema: Schema, context: string) { }; } +// export function ParamsValidationSchema(schema:Schema, { either = false, context = "" }) { +// return ( +// target: unknown, +// propertyKey: string, +// descriptor: PropertyDescriptor, +// ) => { +// const originalMethod = descriptor.value; +// descriptor.value = function (...args: unknown[]) { + +// const tracing: TracingType = args[args.length - 1] as any; + +// context = context ? context : tracing?.name; + +// try { +// tracing.addEvent("Parameter Validation start") +// const model = schema.parse(args[0]); +// tracing.addEvent("Parameter Validation end") +// args[0] = model; +// return originalMethod.apply(this, args); +// } catch (e) { +// if (e instanceof ZodError) { +// // If validation fails, throw an error with the details +// // Capture the Zod validation error with additional context + +// tracing?.setAttribute?.('parameter.error', 'true') + +// let i = 0; +// for(const schema of e.errors) { +// tracing?.setAttribute?.('map.error.schema-'+i, JSON.stringify(schema)) +// } +// ColoredLoggerService.error(e.errors, 'Unexpected data structure '+ context,'..') +// console.error(args[0]) + +// tracing.addEvent("Validation parameter error") +// tracing.hasError("Invalid Parameter") +// if(either) { +// return err(e) +// } + +// } +// return originalMethod.apply(this, args); +// } +// }; +// }; +// } + + +export function ParamsValidation(schema:Schema, args, tracing: TracingType) { + try { + tracing.addEvent("Parameter Validation start") + const model = schema.parse(args); + tracing.addEvent("Parameter Validation end") + args = model; + return ok(true); + } catch (e) { + if (e instanceof ZodError) { + // If validation fails, throw an error with the details + // Capture the Zod validation error with additional context + let i = 0; + for(const schema of e.errors) { + tracing?.setAttribute?.('map.error.schema-'+i, JSON.stringify(schema)) + } + + tracing.log("zod error "+ tracing?.name, { + zodError: e + }) + ColoredLoggerService.error(e.errors, 'Unexpected data structure '+ tracing?.name,'..') + console.error(args) + + tracing.addEvent("Validation parameter error") + tracing.hasError("Invalid Parameter") + + } + return err(false) + } +} diff --git a/src/app/services/monitoring/opentelemetry/tracer.ts b/src/app/services/monitoring/opentelemetry/tracer.ts index 39612e4c4..128e0c384 100644 --- a/src/app/services/monitoring/opentelemetry/tracer.ts +++ b/src/app/services/monitoring/opentelemetry/tracer.ts @@ -7,13 +7,11 @@ import { SessionStore } from 'src/app/store/session.service'; import { environment } from 'src/environments/environment'; import { UseCaseCounter } from './matrix'; import { openTelemetryLogging } from './logging'; -// import { context, propagation } from '@opentelemetry/api'; import { SpanStatus, SpanStatusCode } from '@opentelemetry/api'; const tracerInstance = OpentelemetryAgendaProvider.getTracer('example-tracer-hole', '111', {}) const tracerNotificationInstance = OpentelemetryNotificationProvider.getTracer('example-tracer-hole', '111', {}) -// const logger: ILoggerAdapter = new ColoredLoggerService() let device: DeviceInfo; @@ -58,10 +56,12 @@ const createTracingInstance = ({bugPrint, name, module, autoFinish}): TracingTyp event: {}, tags: {}, status: {} as any, - logs:[] + logs:[], + errors: [] } const returnObject = { + name, span: span as any, tracer: tracerInstance, tracerId: requestId, @@ -69,12 +69,10 @@ const createTracingInstance = ({bugPrint, name, module, autoFinish}): TracingTyp setStatus: (status: SpanStatus) => { span.setStatus(status); }, - addEvent: (context: string, message?: any, obj?: any) => { + addEvent: (context: string, message: string = "") => { data.event[context] = message; - - const value = [JSON.stringify(message)] as any - span.addEvent(context, value); + span.addEvent(context, message as any); }, LocalLogEvent:(context: string, message: any, obj: any) => { data.tags[context] = message; @@ -84,7 +82,9 @@ const createTracingInstance = ({bugPrint, name, module, autoFinish}): TracingTyp span.setAttribute(key, value); if(key =='outcome' && value == 'failed') { - returnObject.hasError('error') + if(data.errors.length == 0) { + returnObject.hasError('error') + } if(!autoFinish) { returnObject.finish() } @@ -130,6 +130,7 @@ const createTracingInstance = ({bugPrint, name, module, autoFinish}): TracingTyp if(finish) return if(environment.apiURL != 'https://gdqas-api.oapr.gov.ao/api/') { + span.setAttribute('error.list', data.errors.join(',')) span.end(); UseCaseCounter.add(1, {user: SessionStore?.user?.FullName, outcome:data.tags['outcome'] || data.status?.code , usecase: name}) } @@ -141,11 +142,9 @@ const createTracingInstance = ({bugPrint, name, module, autoFinish}): TracingTyp finish = true }, hasError:(message: string) => { - if(data.status?.code != SpanStatusCode.ERROR) { - data.status = {code: SpanStatusCode.ERROR, message} - span.setStatus({code: SpanStatusCode.ERROR, message}) - span.setAttribute('outcome','failed') - } + data.errors.push(message) + data.status = {code: SpanStatusCode.ERROR, message} + span.setStatus({code: SpanStatusCode.ERROR, message}) }, createSpan: (name, parent?: any) => { return tracerInstance.startSpan(name, { root: false }, parent) as Span; @@ -239,6 +238,7 @@ export function XTracer({ name, bugPrint, module, autoFinish = true, daley =0 }) } export type TracingType = { + name: string, span: Span; tracer: Tracer; tracerId: string;