如何解决如何在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
承诺中以设置上下文,然后再次将承诺包装为 Observable
的 rxjs
管道 (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 举报,一经查实,本站将立刻删除。