如何在nestjs拦截器中检测控制器?
Posted
技术标签:
【中文标题】如何在nestjs拦截器中检测控制器?【英文标题】:How to instrument a controller in nestjs interceptor? 【发布时间】:2021-02-11 05:02:41 【问题描述】:我想为 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;
【问题讨论】:
您能否再解释一下您所说的仪器是什么意思? 当然,我的意思是:跟踪函数执行以确定执行时间(由例如en.wikipedia.org/wiki/Instrumentation_(computer_programming) 定义)并由 APM 解决方案提供,例如docs.datadoghq.com/tracing/guide/instrument_custom_method/… 啊,我明白了。好吧,从来没有使用过dd-trace
,但我确实有a custom logger 有一个日志拦截器,它可以以DataDog 友好的格式输出数据。同时我会调查dd-trace
这里远射,但我认为你想要而不是observable.subscribe()
是做observable.pipe(tap(resolve))
,其中tap
是从rxjs/operators
导入的。如果可行,我会为答案写一个详细的解释
我不会说这是 Nest 的问题,更像是 RxJS 的问题,因为 它是 的设计方式。不过,Nest 使用它的事实确实使它在这种情况下很不幸。我认为在这种情况下你必须做的是从d-trace
创建一个自定义的Span
对象并按照你的期望设置值。我在前面的评论中提到的自定义记录器有点这样做(我不知道我这样做了),所以你可以从中得到一些想法。如果您想进一步讨论这个问题,请随时reach out on Discord。用户名:PerfectOrphan31#6003
【参考方案1】:
使用OpenTelemetry-js 时遇到类似问题,为了设置正确的范围,我必须将handle()
Observable
包装成Async
承诺以设置上下文,然后再次将承诺包装为@ 987654325@ 用于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;
))
【讨论】:
以上是关于如何在nestjs拦截器中检测控制器?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 neo4j-graphql-js 端点中使用带有 nestjs 框架的拦截器?