From a432d50d93201b66c7b1c7ff09d2a7395ab2017e Mon Sep 17 00:00:00 2001 From: Krishna Waske Date: Mon, 10 Nov 2025 19:03:27 +0530 Subject: [PATCH 1/4] feat: trace contextId across services, including passed from headers of http request Signed-off-by: Krishna Waske --- .../agent-service/src/agent-service.module.ts | 14 +++- apps/api-gateway/src/app.module.ts | 6 ++ apps/api-gateway/src/main.ts | 2 - .../oid4vc-verification.controller.ts | 2 +- .../oid4vc-verification.service.ts | 11 ++- apps/oid4vc-verification/src/main.ts | 4 +- .../src/oid4vc-verification.controller.ts | 6 +- .../src/oid4vc-verification.module.ts | 36 ++++++--- .../src/oid4vc-verification.service.ts | 76 ++++++++----------- libs/common/src/nats.interceptor.ts | 30 +++++++- libs/context/src/contextInterceptorModule.ts | 41 ++++++---- libs/context/src/contextModule.ts | 10 ++- libs/logger/src/logging.interceptor.ts | 14 ++-- 13 files changed, 157 insertions(+), 95 deletions(-) diff --git a/apps/agent-service/src/agent-service.module.ts b/apps/agent-service/src/agent-service.module.ts index d8fe46193..85aa5ad31 100644 --- a/apps/agent-service/src/agent-service.module.ts +++ b/apps/agent-service/src/agent-service.module.ts @@ -1,4 +1,4 @@ -import { CommonModule } from '@credebl/common'; +import { CommonModule, NatsInterceptor } from '@credebl/common'; import { PrismaService } from '@credebl/prisma-service'; import { Logger, Module } from '@nestjs/common'; import { ClientsModule, Transport } from '@nestjs/microservices'; @@ -17,13 +17,15 @@ import { ConfigModule as PlatformConfig } from '@credebl/config/config.module'; import { GlobalConfigModule } from '@credebl/config/global-config.module'; import { ContextInterceptorModule } from '@credebl/context/contextInterceptorModule'; import { NATSClient } from '@credebl/common/NATSClient'; - +import { APP_INTERCEPTOR } from '@nestjs/core'; @Module({ imports: [ ConfigModule.forRoot(), GlobalConfigModule, - LoggerModule, PlatformConfig, ContextInterceptorModule, + LoggerModule, + PlatformConfig, + ContextInterceptorModule, ClientsModule.register([ { name: 'NATS_CLIENT', @@ -47,7 +49,11 @@ import { NATSClient } from '@credebl/common/NATSClient'; provide: MICRO_SERVICE_NAME, useValue: 'Agent-service' }, - NATSClient + NATSClient, + { + provide: APP_INTERCEPTOR, + useClass: NatsInterceptor + } ], exports: [AgentServiceService, AgentServiceRepository, AgentServiceModule] }) diff --git a/apps/api-gateway/src/app.module.ts b/apps/api-gateway/src/app.module.ts index 5cc672d0d..983d8e235 100644 --- a/apps/api-gateway/src/app.module.ts +++ b/apps/api-gateway/src/app.module.ts @@ -33,6 +33,8 @@ import { ConfigModule as PlatformConfig } from '@credebl/config/config.module'; import { Oid4vcIssuanceModule } from './oid4vc-issuance/oid4vc-issuance.module'; import { X509Module } from './x509/x509.module'; import { Oid4vpModule } from './oid4vc-verification/oid4vc-verification.module'; +import { APP_INTERCEPTOR } from '@nestjs/core'; +import { NatsInterceptor } from '@credebl/common'; @Module({ imports: [ @@ -76,6 +78,10 @@ import { Oid4vpModule } from './oid4vc-verification/oid4vc-verification.module'; { provide: MICRO_SERVICE_NAME, useValue: 'APIGATEWAY' + }, + { + provide: APP_INTERCEPTOR, + useClass: NatsInterceptor } ], exports: [CacheModule] diff --git a/apps/api-gateway/src/main.ts b/apps/api-gateway/src/main.ts index e92468ce8..2b7239725 100644 --- a/apps/api-gateway/src/main.ts +++ b/apps/api-gateway/src/main.ts @@ -14,7 +14,6 @@ import { getNatsOptions } from '@credebl/common/nats.config'; import helmet from 'helmet'; import { CommonConstants } from '@credebl/common/common.constant'; import NestjsLoggerServiceAdapter from '@credebl/logger/nestjsLoggerServiceAdapter'; -import { NatsInterceptor } from '@credebl/common'; import { UpdatableValidationPipe } from '@credebl/common/custom-overrideable-validation-pipe'; import * as useragent from 'express-useragent'; @@ -117,7 +116,6 @@ async function bootstrap(): Promise { xssFilter: true }) ); - app.useGlobalInterceptors(new NatsInterceptor()); await app.listen(process.env.API_GATEWAY_PORT, `${process.env.API_GATEWAY_HOST}`); Logger.log(`API Gateway is listening on port ${process.env.API_GATEWAY_PORT}`); } diff --git a/apps/api-gateway/src/oid4vc-verification/oid4vc-verification.controller.ts b/apps/api-gateway/src/oid4vc-verification/oid4vc-verification.controller.ts index 6c9edfa2b..cb34de253 100644 --- a/apps/api-gateway/src/oid4vc-verification/oid4vc-verification.controller.ts +++ b/apps/api-gateway/src/oid4vc-verification/oid4vc-verification.controller.ts @@ -52,7 +52,7 @@ import { PresentationRequestDto, VerificationPresentationQueryDto } from './dtos @ApiUnauthorizedResponse({ description: 'Unauthorized', type: UnauthorizedErrorDto }) @ApiForbiddenResponse({ description: 'Forbidden', type: ForbiddenErrorDto }) export class Oid4vcVerificationController { - private readonly logger = new Logger('Oid4vpVerificationController'); + private readonly logger = new Logger('Oid4vcVerificationController'); constructor(private readonly oid4vcVerificationService: Oid4vcVerificationService) {} /** diff --git a/apps/api-gateway/src/oid4vc-verification/oid4vc-verification.service.ts b/apps/api-gateway/src/oid4vc-verification/oid4vc-verification.service.ts index a2bd17b30..9819cf44f 100644 --- a/apps/api-gateway/src/oid4vc-verification/oid4vc-verification.service.ts +++ b/apps/api-gateway/src/oid4vc-verification/oid4vc-verification.service.ts @@ -1,20 +1,19 @@ import { NATSClient } from '@credebl/common/NATSClient'; -import { Inject, Injectable } from '@nestjs/common'; +import { Inject, Injectable, Logger } from '@nestjs/common'; import { ClientProxy } from '@nestjs/microservices'; -import { BaseService } from 'libs/service/base.service'; // eslint-disable-next-line camelcase import { oid4vp_verifier, user } from '@prisma/client'; import { CreateVerifierDto, UpdateVerifierDto } from './dtos/oid4vc-verifier.dto'; import { VerificationPresentationQueryDto } from './dtos/oid4vc-verifier-presentation.dto'; @Injectable() -export class Oid4vcVerificationService extends BaseService { +export class Oid4vcVerificationService { + private readonly logger = new Logger('Oid4vcVerificationService'); + constructor( @Inject('NATS_CLIENT') private readonly oid4vpProxy: ClientProxy, private readonly natsClient: NATSClient - ) { - super('Oid4vcVerificationService'); - } + ) {} async oid4vpCreateVerifier( createVerifier: CreateVerifierDto, diff --git a/apps/oid4vc-verification/src/main.ts b/apps/oid4vc-verification/src/main.ts index fbb4b7b91..e414e6a3f 100644 --- a/apps/oid4vc-verification/src/main.ts +++ b/apps/oid4vc-verification/src/main.ts @@ -1,5 +1,4 @@ import { NestFactory } from '@nestjs/core'; -import { HttpExceptionFilter } from 'libs/http-exception.filter'; import { Logger } from '@nestjs/common'; import { MicroserviceOptions, Transport } from '@nestjs/microservices'; import { getNatsOptions } from '@credebl/common/nats.config'; @@ -15,7 +14,8 @@ async function bootstrap(): Promise { options: getNatsOptions(CommonConstants.OIDC4VC_VERIFICATION_SERVICE, process.env.Verification_NKEY_SEED) }); app.useLogger(app.get(NestjsLoggerServiceAdapter)); - app.useGlobalFilters(new HttpExceptionFilter()); + // TODO: Not sure if we want the below + // app.useGlobalFilters(new HttpExceptionFilter()); await app.listen(); logger.log('OID4VC-Verification-Service Microservice is listening to NATS '); diff --git a/apps/oid4vc-verification/src/oid4vc-verification.controller.ts b/apps/oid4vc-verification/src/oid4vc-verification.controller.ts index 69c73018d..1bb4a54a0 100644 --- a/apps/oid4vc-verification/src/oid4vc-verification.controller.ts +++ b/apps/oid4vc-verification/src/oid4vc-verification.controller.ts @@ -7,8 +7,10 @@ import { VerificationSessionQuery } from '../interfaces/oid4vp-verifier.interfac @Controller() export class Oid4vpVerificationController { - private readonly logger = new Logger('Oid4vpVerificationController'); - constructor(private readonly oid4vpVerificationService: Oid4vpVerificationService) {} + constructor( + private readonly oid4vpVerificationService: Oid4vpVerificationService, + private logger: Logger + ) {} @MessagePattern({ cmd: 'oid4vp-verifier-create' }) async oid4vpCreateVerifier(payload: { diff --git a/apps/oid4vc-verification/src/oid4vc-verification.module.ts b/apps/oid4vc-verification/src/oid4vc-verification.module.ts index 78b37ac7e..5efccb906 100644 --- a/apps/oid4vc-verification/src/oid4vc-verification.module.ts +++ b/apps/oid4vc-verification/src/oid4vc-verification.module.ts @@ -3,19 +3,26 @@ import { Oid4vpVerificationController } from './oid4vc-verification.controller'; import { Oid4vpVerificationService } from './oid4vc-verification.service'; import { ClientsModule, Transport } from '@nestjs/microservices'; import { getNatsOptions } from '@credebl/common/nats.config'; -import { CommonModule } from '@credebl/common'; -import { CommonConstants } from '@credebl/common/common.constant'; +import { CommonModule, NatsInterceptor } from '@credebl/common'; +import { CommonConstants, MICRO_SERVICE_NAME } from '@credebl/common/common.constant'; import { GlobalConfigModule } from '@credebl/config'; import { ContextInterceptorModule } from '@credebl/context'; -import { LoggerModule } from '@credebl/logger'; +import { LoggerModule } from '@credebl/logger/logger.module'; import { CacheModule } from '@nestjs/cache-manager'; import { ConfigModule as PlatformConfig } from '@credebl/config/config.module'; import { NATSClient } from '@credebl/common/NATSClient'; -import { PrismaService } from '@credebl/prisma-service'; +import { PrismaService, PrismaServiceModule } from '@credebl/prisma-service'; import { Oid4vpRepository } from './oid4vc-verification.repository'; +import { APP_INTERCEPTOR } from '@nestjs/core'; +import { ConfigModule } from '@nestjs/config'; @Module({ imports: [ + ConfigModule.forRoot(), + ContextInterceptorModule, + PlatformConfig, + LoggerModule, + CacheModule.register(), ClientsModule.register([ { name: 'NATS_CLIENT', @@ -28,12 +35,23 @@ import { Oid4vpRepository } from './oid4vc-verification.repository'; ]), CommonModule, GlobalConfigModule, - LoggerModule, - PlatformConfig, - ContextInterceptorModule, - CacheModule.register() + PrismaServiceModule ], controllers: [Oid4vpVerificationController], - providers: [Oid4vpVerificationService, Oid4vpRepository, PrismaService, Logger, NATSClient] + providers: [ + Oid4vpVerificationService, + Oid4vpRepository, + PrismaService, + Logger, + NATSClient, + { + provide: MICRO_SERVICE_NAME, + useValue: 'Oid4vc-verification-service' + }, + { + provide: APP_INTERCEPTOR, + useClass: NatsInterceptor + } + ] }) export class Oid4vpModule {} diff --git a/apps/oid4vc-verification/src/oid4vc-verification.service.ts b/apps/oid4vc-verification/src/oid4vc-verification.service.ts index 88f07e616..922acfe96 100644 --- a/apps/oid4vc-verification/src/oid4vc-verification.service.ts +++ b/apps/oid4vc-verification/src/oid4vc-verification.service.ts @@ -6,15 +6,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/naming-convention, @typescript-eslint/explicit-function-return-type, @typescript-eslint/explicit-module-boundary-types, camelcase */ -import { - ConflictException, - HttpException, - Inject, - Injectable, - InternalServerErrorException, - Logger, - NotFoundException -} from '@nestjs/common'; +import { ConflictException, Inject, Injectable, InternalServerErrorException, NotFoundException } from '@nestjs/common'; import { Oid4vpRepository } from './oid4vc-verification.repository'; import { CommonConstants } from '@credebl/common/common.constant'; import { ResponseMessages } from '@credebl/common/response-messages'; @@ -27,11 +19,13 @@ import { buildUrlWithQuery } from '@credebl/common/cast.helper'; import { VerificationSessionQuery } from '../interfaces/oid4vp-verifier.interfaces'; import { RequestSignerMethod } from '@credebl/enum/enum'; import { BaseService } from 'libs/service/base.service'; +import { NATSClient } from '@credebl/common/NATSClient'; @Injectable() export class Oid4vpVerificationService extends BaseService { constructor( @Inject('NATS_CLIENT') private readonly oid4vpVerificationServiceProxy: ClientProxy, + private readonly natsClient: NATSClient, private readonly oid4vpRepository: Oid4vpRepository ) { super('Oid4vpVerificationService'); @@ -301,9 +295,12 @@ export class Oid4vpVerificationService extends BaseService { async _createOid4vpVerifier(verifierDetails: CreateVerifier, url: string, orgId: string): Promise { this.logger.debug(`[_createOid4vpVerifier] sending NATS message for orgId=${orgId}`); try { - const pattern = { cmd: 'agent-create-oid4vp-verifier' }; const payload = { verifierDetails, url, orgId }; - const response = await this.natsCall(pattern, payload); + const response = await this.natsClient.sendNatsMessage( + this.oid4vpVerificationServiceProxy, + 'agent-create-oid4vp-verifier', + payload + ); this.logger.debug(`[_createOid4vpVerifier] NATS response received`); return response; } catch (error) { @@ -317,9 +314,12 @@ export class Oid4vpVerificationService extends BaseService { async _deleteOid4vpVerifier(url: string, orgId: string): Promise { this.logger.debug(`[_deleteOid4vpVerifier] sending NATS message for orgId=${orgId}`); try { - const pattern = { cmd: 'agent-delete-oid4vp-verifier' }; const payload = { url, orgId }; - const response = await this.natsCall(pattern, payload); + const response = await this.natsClient.sendNatsMessage( + this.oid4vpVerificationServiceProxy, + 'agent-delete-oid4vp-verifier', + payload + ); this.logger.debug(`[_deleteOid4vpVerifier] NATS response received`); return response; } catch (error) { @@ -333,9 +333,12 @@ export class Oid4vpVerificationService extends BaseService { async _updateOid4vpVerifier(verifierDetails: UpdateVerifier, url: string, orgId: string): Promise { this.logger.debug(`[_updateOid4vpVerifier] sending NATS message for orgId=${orgId}`); try { - const pattern = { cmd: 'agent-update-oid4vp-verifier' }; const payload = { verifierDetails, url, orgId }; - const response = await this.natsCall(pattern, payload); + const response = await this.natsClient.sendNatsMessage( + this.oid4vpVerificationServiceProxy, + 'agent-update-oid4vp-verifier', + payload + ); this.logger.debug(`[_updateOid4vpVerifier] NATS response received`); return response; } catch (error) { @@ -349,9 +352,12 @@ export class Oid4vpVerificationService extends BaseService { async _createVerificationSession(sessionRequest: any, url: string, orgId: string): Promise { this.logger.debug(`[_createVerificationSession] sending NATS message for orgId=${orgId}`); try { - const pattern = { cmd: 'agent-create-oid4vp-verification-session' }; const payload = { sessionRequest, url, orgId }; - const response = await this.natsCall(pattern, payload); + const response = await this.natsClient.sendNatsMessage( + this.oid4vpVerificationServiceProxy, + 'agent-create-oid4vp-verification-session', + payload + ); this.logger.debug(`[_createVerificationSession] NATS response received`); return response; } catch (error) { @@ -365,9 +371,12 @@ export class Oid4vpVerificationService extends BaseService { async _getOid4vpVerifierSession(url: string, orgId: string): Promise { this.logger.debug(`[_getOid4vpVerifierSession] sending NATS message for orgId=${orgId}`); try { - const pattern = { cmd: 'agent-get-oid4vp-verifier-session' }; const payload = { url, orgId }; - const response = await this.natsCall(pattern, payload); + const response = await this.natsClient.sendNatsMessage( + this.oid4vpVerificationServiceProxy, + 'agent-get-oid4vp-verifier-session', + payload + ); this.logger.debug(`[_getOid4vpVerifierSession] NATS response received`); return response; } catch (error) { @@ -381,9 +390,12 @@ export class Oid4vpVerificationService extends BaseService { async _getVerificationSessionResponse(url: string, orgId: string): Promise { this.logger.debug(`[_getVerificationSessionResponse] sending NATS message for orgId=${orgId}`); try { - const pattern = { cmd: 'agent-get-oid4vp-verifier-session' }; const payload = { url, orgId }; - const response = await this.natsCall(pattern, payload); + const response = await this.natsClient.sendNatsMessage( + this.oid4vpVerificationServiceProxy, + 'agent-get-oid4vp-verifier-session', + payload + ); this.logger.debug(`[_getVerificationSessionResponse] NATS response received`); return response; } catch (error) { @@ -393,26 +405,4 @@ export class Oid4vpVerificationService extends BaseService { throw error; } } - - async natsCall(pattern: object, payload: object): Promise { - try { - return this.oid4vpVerificationServiceProxy - .send(pattern, payload) - .pipe(map((response) => response)) - .toPromise() - .catch((error) => { - this.logger.error(`catch: ${JSON.stringify(error)}`); - throw new HttpException( - { - status: error.statusCode, - error: error.message - }, - error.error - ); - }); - } catch (error) { - this.logger.error(`[natsCall] - error in nats call : ${JSON.stringify(error)}`); - throw error; - } - } } diff --git a/libs/common/src/nats.interceptor.ts b/libs/common/src/nats.interceptor.ts index a26c54faf..81a76156d 100644 --- a/libs/common/src/nats.interceptor.ts +++ b/libs/common/src/nats.interceptor.ts @@ -1,13 +1,39 @@ -import { ResponseMessages } from '@credebl/common/response-messages'; -import { CallHandler, ExecutionContext, Injectable, NestInterceptor, HttpException, Logger } from '@nestjs/common'; +import { Injectable, NestInterceptor, ExecutionContext, CallHandler, HttpException, Inject } from '@nestjs/common'; import { Observable, throwError } from 'rxjs'; import { catchError } from 'rxjs/operators'; +import { ResponseMessages } from '@credebl/common/response-messages'; +import ContextStorageService, { ContextStorageServiceKey } from '@credebl/context/contextStorageService.interface'; +import { v4 as uuid } from 'uuid'; +import { Logger } from '@nestjs/common'; @Injectable() export class NatsInterceptor implements NestInterceptor { private readonly logger = new Logger(NatsInterceptor.name); + constructor( + @Inject(ContextStorageServiceKey) + private readonly contextStorageService: ContextStorageService + ) {} + intercept(context: ExecutionContext, next: CallHandler): Observable { + try { + const rpcContext = context.switchToRpc().getContext?.() ?? {}; + const headers = rpcContext.getHeaders?.() ?? rpcContext?.headers ?? {}; + this.logger.debug(`headers in NatsInterceptor: ${JSON.stringify(headers.get('contextId'))}`); + + // Support different header shapes and names (compat) + const correlationId = + // TODO: Probably change 'x-correlation-id' to 'contextId' only. Coz even if we get 'x-correlation-id' for http requests, we'll probably convert it to 'contextId' afterwards + headers.get?.('x-correlation-id') ?? headers.get('contextId') ?? uuid(); + + // Set CLS ID so logger & rest of code can read it via ContextStorageService + this.contextStorageService.setContextId(correlationId); + this.logger.debug(`NATS correlationId set to: ${correlationId}`); + } catch (err) { + // Do not throw here — just log and continue + this.logger.warn(`Failed to extract/set NATS correlationId: ${(err as Error).message}`); + } + return next.handle().pipe( catchError((error) => { if (error?.message && error?.message.includes(ResponseMessages.nats.error.natsConnect)) { diff --git a/libs/context/src/contextInterceptorModule.ts b/libs/context/src/contextInterceptorModule.ts index a80a712f9..c768d5106 100644 --- a/libs/context/src/contextInterceptorModule.ts +++ b/libs/context/src/contextInterceptorModule.ts @@ -1,13 +1,13 @@ -import { ExecutionContext, Global, Module} from '@nestjs/common'; -import { v4 } from 'uuid'; +import { ExecutionContext, Global, Logger, Module } from '@nestjs/common'; +import { v4 as uuid } from 'uuid'; import { ClsModule } from 'nestjs-cls'; import { ContextStorageServiceKey } from './contextStorageService.interface'; import NestjsClsContextStorageService from './nestjsClsContextStorageService'; - // eslint-disable-next-line @typescript-eslint/no-explicit-any -const isNullUndefinedOrEmpty = (obj: any): boolean => null === obj || obj === undefined || ('object' === typeof obj && 0 === Object.keys(obj).length); +const isNullUndefinedOrEmpty = (obj: any): boolean => + null === obj || obj === undefined || ('object' === typeof obj && 0 === Object.keys(obj).length); @Global() @Module({ @@ -17,17 +17,28 @@ const isNullUndefinedOrEmpty = (obj: any): boolean => null === obj || obj === un interceptor: { mount: true, - generateId: true, - idGenerator: (context: ExecutionContext) => { - const rpcContext = context.switchToRpc().getContext(); - const headers = rpcContext.getHeaders(); - if (!isNullUndefinedOrEmpty(headers)) { - return context.switchToRpc().getContext().getHeaders()['_description']; - } else { - return v4(); + generateId: true, + idGenerator: (context: ExecutionContext) => { + try { + const logger = new Logger('ContextInterceptorModule'); + const rpcContext = context.switchToRpc().getContext(); + const headers = rpcContext.getHeaders(); + if (!isNullUndefinedOrEmpty(headers)) { + logger.debug('[idGenerator] Received contextId in header: ', headers.get('contextId')); + return headers.get('contextId'); + } else { + const uuidGenerated = uuid(); + logger.debug( + '[idGenerator] Did not receive contextId in header, generated new contextId: ', + uuidGenerated + ); + return uuidGenerated; + } + } catch (error) { + // eslint-disable-next-line no-console + console.log('[idGenerator] Error in idGenerator: ', error); } - } - + } } }) ], @@ -40,6 +51,4 @@ const isNullUndefinedOrEmpty = (obj: any): boolean => null === obj || obj === un ], exports: [ContextStorageServiceKey] }) - export class ContextInterceptorModule {} - diff --git a/libs/context/src/contextModule.ts b/libs/context/src/contextModule.ts index 4bfb9e2c3..8d3f25b2e 100644 --- a/libs/context/src/contextModule.ts +++ b/libs/context/src/contextModule.ts @@ -1,4 +1,4 @@ -import { Global, Module } from '@nestjs/common'; +import { Global, Logger, Module } from '@nestjs/common'; import { v4 } from 'uuid'; import { ClsModule } from 'nestjs-cls'; @@ -13,7 +13,13 @@ import NestjsClsContextStorageService from './nestjsClsContextStorageService'; middleware: { mount: true, generateId: true, - idGenerator: (req: Request) => req.headers['x-correlation-id'] ?? v4() + idGenerator: (req: Request) => { + const logger = new Logger('ContextInterceptorModule'); + // TODO: Check if we want the x-correlation-id or the correlationId + const headers = req.headers['contextId'] ?? req.headers['x-correlation-id'] ?? v4(); + logger.log('Headers received/generated::::', headers); + return headers; + } } }) ], diff --git a/libs/logger/src/logging.interceptor.ts b/libs/logger/src/logging.interceptor.ts index 6ac3a0611..74b7db289 100644 --- a/libs/logger/src/logging.interceptor.ts +++ b/libs/logger/src/logging.interceptor.ts @@ -17,26 +17,28 @@ export class LoggingInterceptor implements NestInterceptor { private readonly clsService: ClsService, @Inject(ContextStorageServiceKey) private readonly contextStorageService: ContextStorageService, - @Inject(LoggerKey) private readonly _logger: Logger + @Inject(LoggerKey) private readonly logger: Logger ) {} // eslint-disable-next-line @typescript-eslint/no-explicit-any intercept(context: ExecutionContext, next: CallHandler): Observable { return this.clsService.run(() => { - this._logger.info('In LoggingInterceptor configuration'); + this.logger.info('In LoggingInterceptor configuration'); const rpcContext = context.switchToRpc().getContext(); const headers = rpcContext.getHeaders(); - if (!isNullUndefinedOrEmpty(headers) && headers._description) { - this.contextStorageService.set('x-correlation-id', headers._description); - this.contextStorageService.setContextId(headers._description); + if (!isNullUndefinedOrEmpty(headers)) { + this.logger.debug('We found context Id in header of logger Interceptor', headers.get('contextId')); + this.contextStorageService.setContextId(headers.get('contextId')); } else { const newContextId = v4(); + this.logger.debug('Not found context Id in header of logger Interceptor, generating a new one: ', newContextId); this.contextStorageService.set('x-correlation-id', newContextId); + this.contextStorageService.set('contextId', newContextId); this.contextStorageService.setContextId(newContextId); } return next.handle().pipe( catchError((err) => { - this._logger.error(err); + this.logger.error('[intercept] Error in LoggingInterceptor', err); return throwError(() => err); }) ); From 60f0d4a1b94b3910d54257a6112a440f16cd7d98 Mon Sep 17 00:00:00 2001 From: Krishna Waske Date: Mon, 10 Nov 2025 19:14:29 +0530 Subject: [PATCH 2/4] fix: import issues caused by merge Signed-off-by: Krishna Waske --- .../src/oid4vc-verification.service.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/oid4vc-verification/src/oid4vc-verification.service.ts b/apps/oid4vc-verification/src/oid4vc-verification.service.ts index 662a1df48..de17c4dc9 100644 --- a/apps/oid4vc-verification/src/oid4vc-verification.service.ts +++ b/apps/oid4vc-verification/src/oid4vc-verification.service.ts @@ -6,7 +6,14 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/naming-convention, @typescript-eslint/explicit-function-return-type, @typescript-eslint/explicit-module-boundary-types, camelcase */ -import { ConflictException, Inject, Injectable, InternalServerErrorException, NotFoundException } from '@nestjs/common'; +import { + BadRequestException, + ConflictException, + Inject, + Injectable, + InternalServerErrorException, + NotFoundException +} from '@nestjs/common'; import { Oid4vpRepository } from './oid4vc-verification.repository'; import { CommonConstants } from '@credebl/common/common.constant'; import { ResponseMessages } from '@credebl/common/response-messages'; From 4b267421328245596897e04ba094c9e21bfeb085 Mon Sep 17 00:00:00 2001 From: Krishna Waske Date: Tue, 11 Nov 2025 18:37:52 +0530 Subject: [PATCH 3/4] fix: contextId refactoring and coderabbit resolve Signed-off-by: Krishna Waske --- apps/api-gateway/src/app.module.ts | 6 ---- .../src/oid4vc-verification.module.ts | 7 +---- libs/common/src/nats.interceptor.ts | 30 ++----------------- libs/context/src/contextInterceptorModule.ts | 4 +-- libs/context/src/contextModule.ts | 21 +++++++++---- 5 files changed, 21 insertions(+), 47 deletions(-) diff --git a/apps/api-gateway/src/app.module.ts b/apps/api-gateway/src/app.module.ts index 983d8e235..5cc672d0d 100644 --- a/apps/api-gateway/src/app.module.ts +++ b/apps/api-gateway/src/app.module.ts @@ -33,8 +33,6 @@ import { ConfigModule as PlatformConfig } from '@credebl/config/config.module'; import { Oid4vcIssuanceModule } from './oid4vc-issuance/oid4vc-issuance.module'; import { X509Module } from './x509/x509.module'; import { Oid4vpModule } from './oid4vc-verification/oid4vc-verification.module'; -import { APP_INTERCEPTOR } from '@nestjs/core'; -import { NatsInterceptor } from '@credebl/common'; @Module({ imports: [ @@ -78,10 +76,6 @@ import { NatsInterceptor } from '@credebl/common'; { provide: MICRO_SERVICE_NAME, useValue: 'APIGATEWAY' - }, - { - provide: APP_INTERCEPTOR, - useClass: NatsInterceptor } ], exports: [CacheModule] diff --git a/apps/oid4vc-verification/src/oid4vc-verification.module.ts b/apps/oid4vc-verification/src/oid4vc-verification.module.ts index 5efccb906..398b3482e 100644 --- a/apps/oid4vc-verification/src/oid4vc-verification.module.ts +++ b/apps/oid4vc-verification/src/oid4vc-verification.module.ts @@ -3,7 +3,7 @@ import { Oid4vpVerificationController } from './oid4vc-verification.controller'; import { Oid4vpVerificationService } from './oid4vc-verification.service'; import { ClientsModule, Transport } from '@nestjs/microservices'; import { getNatsOptions } from '@credebl/common/nats.config'; -import { CommonModule, NatsInterceptor } from '@credebl/common'; +import { CommonModule } from '@credebl/common'; import { CommonConstants, MICRO_SERVICE_NAME } from '@credebl/common/common.constant'; import { GlobalConfigModule } from '@credebl/config'; import { ContextInterceptorModule } from '@credebl/context'; @@ -13,7 +13,6 @@ import { ConfigModule as PlatformConfig } from '@credebl/config/config.module'; import { NATSClient } from '@credebl/common/NATSClient'; import { PrismaService, PrismaServiceModule } from '@credebl/prisma-service'; import { Oid4vpRepository } from './oid4vc-verification.repository'; -import { APP_INTERCEPTOR } from '@nestjs/core'; import { ConfigModule } from '@nestjs/config'; @Module({ @@ -47,10 +46,6 @@ import { ConfigModule } from '@nestjs/config'; { provide: MICRO_SERVICE_NAME, useValue: 'Oid4vc-verification-service' - }, - { - provide: APP_INTERCEPTOR, - useClass: NatsInterceptor } ] }) diff --git a/libs/common/src/nats.interceptor.ts b/libs/common/src/nats.interceptor.ts index 81a76156d..a26c54faf 100644 --- a/libs/common/src/nats.interceptor.ts +++ b/libs/common/src/nats.interceptor.ts @@ -1,39 +1,13 @@ -import { Injectable, NestInterceptor, ExecutionContext, CallHandler, HttpException, Inject } from '@nestjs/common'; +import { ResponseMessages } from '@credebl/common/response-messages'; +import { CallHandler, ExecutionContext, Injectable, NestInterceptor, HttpException, Logger } from '@nestjs/common'; import { Observable, throwError } from 'rxjs'; import { catchError } from 'rxjs/operators'; -import { ResponseMessages } from '@credebl/common/response-messages'; -import ContextStorageService, { ContextStorageServiceKey } from '@credebl/context/contextStorageService.interface'; -import { v4 as uuid } from 'uuid'; -import { Logger } from '@nestjs/common'; @Injectable() export class NatsInterceptor implements NestInterceptor { private readonly logger = new Logger(NatsInterceptor.name); - constructor( - @Inject(ContextStorageServiceKey) - private readonly contextStorageService: ContextStorageService - ) {} - intercept(context: ExecutionContext, next: CallHandler): Observable { - try { - const rpcContext = context.switchToRpc().getContext?.() ?? {}; - const headers = rpcContext.getHeaders?.() ?? rpcContext?.headers ?? {}; - this.logger.debug(`headers in NatsInterceptor: ${JSON.stringify(headers.get('contextId'))}`); - - // Support different header shapes and names (compat) - const correlationId = - // TODO: Probably change 'x-correlation-id' to 'contextId' only. Coz even if we get 'x-correlation-id' for http requests, we'll probably convert it to 'contextId' afterwards - headers.get?.('x-correlation-id') ?? headers.get('contextId') ?? uuid(); - - // Set CLS ID so logger & rest of code can read it via ContextStorageService - this.contextStorageService.setContextId(correlationId); - this.logger.debug(`NATS correlationId set to: ${correlationId}`); - } catch (err) { - // Do not throw here — just log and continue - this.logger.warn(`Failed to extract/set NATS correlationId: ${(err as Error).message}`); - } - return next.handle().pipe( catchError((error) => { if (error?.message && error?.message.includes(ResponseMessages.nats.error.natsConnect)) { diff --git a/libs/context/src/contextInterceptorModule.ts b/libs/context/src/contextInterceptorModule.ts index c768d5106..c0c959eed 100644 --- a/libs/context/src/contextInterceptorModule.ts +++ b/libs/context/src/contextInterceptorModule.ts @@ -22,9 +22,9 @@ const isNullUndefinedOrEmpty = (obj: any): boolean => try { const logger = new Logger('ContextInterceptorModule'); const rpcContext = context.switchToRpc().getContext(); - const headers = rpcContext.getHeaders(); + const headers = rpcContext.getHeaders() ?? {}; if (!isNullUndefinedOrEmpty(headers)) { - logger.debug('[idGenerator] Received contextId in header: ', headers.get('contextId')); + logger.debug(`[idGenerator] Received contextId in headers: ${headers.get('contextId')}`); return headers.get('contextId'); } else { const uuidGenerated = uuid(); diff --git a/libs/context/src/contextModule.ts b/libs/context/src/contextModule.ts index 8d3f25b2e..a03d046d1 100644 --- a/libs/context/src/contextModule.ts +++ b/libs/context/src/contextModule.ts @@ -1,4 +1,4 @@ -import { Global, Logger, Module } from '@nestjs/common'; +import { Global, Module } from '@nestjs/common'; import { v4 } from 'uuid'; import { ClsModule } from 'nestjs-cls'; @@ -14,11 +14,22 @@ import NestjsClsContextStorageService from './nestjsClsContextStorageService'; mount: true, generateId: true, idGenerator: (req: Request) => { - const logger = new Logger('ContextInterceptorModule'); // TODO: Check if we want the x-correlation-id or the correlationId - const headers = req.headers['contextId'] ?? req.headers['x-correlation-id'] ?? v4(); - logger.log('Headers received/generated::::', headers); - return headers; + const contextIdHeader = req.headers['contextid'] ?? req.headers['context-id'] ?? req.headers['contextId']; + const correlationIdHeader = req.headers['x-correlation-id']; + let resolvedContextId = + (Array.isArray(contextIdHeader) ? contextIdHeader[0] : contextIdHeader) ?? + (Array.isArray(correlationIdHeader) ? correlationIdHeader[0] : correlationIdHeader); + + if (resolvedContextId) { + // eslint-disable-next-line no-console + console.log('ContextId received in request headers::::', resolvedContextId); + } else { + resolvedContextId = v4(); + // eslint-disable-next-line no-console + console.log('ContextId not received in request headers, generated a new one::::', resolvedContextId); + } + return resolvedContextId; } } }) From f69bd0a733fae591953c95048576af0c8dc596cc Mon Sep 17 00:00:00 2001 From: Krishna Waske Date: Wed, 12 Nov 2025 11:58:12 +0530 Subject: [PATCH 4/4] fix: make contextInterceptorModule resilient Signed-off-by: Krishna Waske --- libs/context/src/contextInterceptorModule.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/libs/context/src/contextInterceptorModule.ts b/libs/context/src/contextInterceptorModule.ts index c0c959eed..e9ff13139 100644 --- a/libs/context/src/contextInterceptorModule.ts +++ b/libs/context/src/contextInterceptorModule.ts @@ -5,10 +5,6 @@ import { ClsModule } from 'nestjs-cls'; import { ContextStorageServiceKey } from './contextStorageService.interface'; import NestjsClsContextStorageService from './nestjsClsContextStorageService'; -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const isNullUndefinedOrEmpty = (obj: any): boolean => - null === obj || obj === undefined || ('object' === typeof obj && 0 === Object.keys(obj).length); - @Global() @Module({ imports: [ @@ -23,9 +19,11 @@ const isNullUndefinedOrEmpty = (obj: any): boolean => const logger = new Logger('ContextInterceptorModule'); const rpcContext = context.switchToRpc().getContext(); const headers = rpcContext.getHeaders() ?? {}; - if (!isNullUndefinedOrEmpty(headers)) { - logger.debug(`[idGenerator] Received contextId in headers: ${headers.get('contextId')}`); - return headers.get('contextId'); + const contextId = headers.get?.('contextId'); + + if (contextId) { + logger.debug(`[idGenerator] Received contextId in headers: ${contextId}`); + return contextId; } else { const uuidGenerated = uuid(); logger.debug(