如何在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封装到Asyncpromise中以设置上下文,然后将该promise再次封装为rxjs管道的Observable(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;
}))

最新更新