微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何在NestJS拦截器中检测控制器?

如何解决如何在NestJS拦截器中检测控制器?

我想检测用于APM的nestjs控制器的每种方法。 我编写了以下拦截器,以检测控制器的调用

但是,我不知道如何正确包装对next.handle()调用
我没有使用RxJS Observables的经验。

问题:是否可以正确包装调用?如果可以,如何包装?

当前的方法似乎可以衡量控制器的执行时间,但不能为控制器的方法设置正确的跟踪范围。我想问题是next.handle()也必须包装。

import { CallHandler,ExecutionContext,Injectable,nestInterceptor } from "@nestjs/common";
import { Reflector } from "@nestjs/core";
import { Observable } from "rxjs";
import { PATH_MetaDATA } from '@nestjs/common/constants';
import tracer from "dd-trace";

@Injectable()
export class ApmInterceptor implements nestInterceptor {
    constructor(private readonly reflector: Reflector) {}
    
    public intercept(context: ExecutionContext,next: CallHandler): Observable<unkNown> {
        const request: Request = context.switchToHttp().getRequest();

        const path = this.reflector.get<string[]>(PATH_MetaDATA,context.getHandler()); 
        const method = request.method;

        const observable = next.handle();

        tracer.trace(`[${method}] ${path}`,() => new Promise((resolve,reject) => {
            observable.subscribe({
                complete: resolve,});
        }));

        return observable;
    }
}

解决方法

使用 OpenTelemetry-js 时遇到了类似的问题,为了设置正确的范围,我必须将 handle() Observable 包装到 Async 承诺中以设置上下文,然后再次将承诺包装为 Observablerxjs 管道 (Observable -> Promise -> Observable)

import {from,Observable} from 'rxjs';
...

 async intercept(executionContext: ExecutionContext,next: CallHandler): Promise<Observable<any>> {
    const request: Request = context.switchToHttp().getRequest();

    const path = this.reflector.get<string[]>(PATH_METADATA,context.getHandler()); 
    const method = request.method;

    const observable = tracer.trace(`[${method}] ${path}`,() => new Promise((resolve,reject) => {
      return next.handle().toPromise();
    }));
    return observable.pipe(
        map(value => {
          // Here you can stop your trace manually
          return value;
        }),catchError(error => {
          // Here you can stop your trace manually
          throw error;
        }))
}

对于 OpenTelemetry,您必须创建/停止跨度并设置正确的上下文:

const span = trace.getTracer('default').startSpan(spanName);
const observable = from(context.with(trace.setSpan(context.active(),span),async () => {
  return next.handle().toPromise();
}));
return observable.pipe(
    map(value => {
      span.stop();
      return value;
    }),catchError(error => {
      span.addEvent('error',{error: error});
      span.stop();
      throw error;
    }))

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。