Search code examples
typescriptdecoratornestjs

NestJS: How to automatically log @MessagePattern's input data with another decorator?


I have a Controller, which is called by external microservices using the ClientProxy.send<>() method, which sends a command that is recognized by the accompanying @MessagePattern decorator and executes that Controller function:

@Controller()
export class DataController {

  @CustomLogger()
  @MessagePattern({ cmd: 'storeData' })
  storeData(
    owner: string,
    dataType: string,
  ): void {

  }
}

Now, every time this Controller is called, I want to log exactly which command was called. I could simply hardcode Logger.log('storeData') in the storeData() function and do that for every next function, but is it possible to log the input of the @MessagePattern() with another decorator automatically, like for example with @CustomLogger which I would define myself? And if so, how?


Solution

  • It is possible to combine decorators with applyDecorators().

    In your case you could create a LogMessage Decorator like this:

    // LogMessage.ts
    const LogMessage = (cmd: string) => {
      const logger = new Logger('MessageLogger');
      return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
        const targetFunc = descriptor.value;
        descriptor.value = function (...args: any[]) {
          logger.log(`Message: ${cmd}`);
          targetFunc.apply(this, args);
        };
        return descriptor;
      };
    };
    
    export default LogMessage;
    

    and combine it with MessagePattern inside a new decorator MessagePatternWithLog:

    // MessagePatternWithLog.ts
    const MessagePatternWithLog = ({cmd: string}) => {
      return applyDecorators(LogMessage(cmd), MessagePattern({cmd}));
    };
    
    export default MessagePatternWithLog;
    
    

    After that you can use it like every other Decorator:

    @Controller()
    export class DataController {
    
      @MessagePatternWithLog({cmd: 'storeData'})
      storeData(
        owner: string,
        dataType: string,
      ): void {
    
      }
    }
    

    This code is not tested but derived from a working example.