apollo-server-express如何在Apollo自省Playground中启用链路追踪
Apollo Server Express 链路追踪实现方案
问题根因说明
- 你遇到的Playground耗时显示错误,核心原因是Apollo官方定义的
tracing扩展中duration字段要求单位为纳秒,你当前代码传的是毫秒值,所以展示数值会异常 - 你留空的
resolvers数组是Playground展示单字段耗时的依赖字段,需要填充对应解析器的执行数据才能展示完整链路信息
推荐开发环境轻量追踪方案
开发阶段不需要手动实现完整链路插件,直接使用官方内置的追踪插件即可,配置成本极低:
- 安装依赖:
npm install apollo-server-plugin-tracing
- 在ApolloServer配置中引入插件即可:
import { ApolloServerPluginTracing } from 'apollo-server-plugin-tracing'; const server = new ApolloServer({ // 其余配置省略 plugins: [ // 开发环境启用,生产环境可注释关闭 process.env.NODE_ENV === 'development' && ApolloServerPluginTracing(), // 你原来的Sentry插件可以保留,两者不冲突 sentryPlugin ].filter(Boolean) })
启用后Playground会自动展示全链路耗时、每个Resolver的执行时间,完全满足轻量调试需求。
现有自定义插件修复方案
如果你需要保留自定义实现逻辑,可以按以下方式修改原有代码:
/** * 修复后的链路追踪+Sentry集成插件 * */ import { ApolloServerPlugin, GraphQLFieldResolverParams, GraphQLRequestContextWillSendResponse, GraphQLRequestListener, } from 'apollo-server-plugin-base'; import {Context} from '../models'; const sentryPlugin: ApolloServerPlugin<Context> = { async requestDidStart({ request, context, }): Promise<GraphQLRequestListener<Context>> { const startTime = Date.now(); // 存储所有resolver的执行数据 const resolverTraces = []; if (request.operationName) context.sentryTransaction.setName(request.operationName!); return { async executionDidStart() { return { willResolveField( reqContext: GraphQLFieldResolverParams<any, Context> ) { const resolverStartTime = Date.now(); // hook for each new resolver const span = reqContext.context.sentryTransaction.startChild({ op: 'resolver', description: `${reqContext.info.parentType.name}.${reqContext.info.fieldName}`, }); return () => { // resolver执行结束后记录数据 const resolverEndTime = Date.now(); resolverTraces.push({ path: reqContext.info.path, parentType: reqContext.info.parentType.name, fieldName: reqContext.info.fieldName, returnType: reqContext.info.returnType.toString(), startOffset: (resolverStartTime - startTime) * 1000000, // 转纳秒 duration: (resolverEndTime - resolverStartTime) * 1000000, // 转纳秒 }) span.finish(); }; }, }; }, async willSendResponse( requestContext: GraphQLRequestContextWillSendResponse<Context> ) { const endTime = Date.now(); requestContext.response.extensions = { ...requestContext.response.extensions, tracing: { version: 1, startTime: new Date(startTime).toISOString(), endTime: new Date(endTime).toISOString(), duration: (endTime - startTime) * 1000000, // 毫秒转纳秒,修复显示错误 execution: { resolvers: resolverTraces, // 填充收集到的resolver执行数据 }, }, }; requestContext.context.sentryTransaction.finish(); }, }; }, }; export default sentryPlugin;
修复后自定义插件也可以正常在Playground显示完整的链路追踪数据。
内容的提问来源于stack exchange,提问作者Ahmed HAMEED
相关产品推荐
相关产品推荐

