【问题标题】:How do I write a Apollo Server plugin to log the request and its duration如何编写 Apollo Server 插件来记录请求及其持续时间
【发布时间】:2020-05-16 05:43:48
【问题描述】:

我很惊讶我找不到执行以下操作的库或示例:

我想要一个简单的服务器日志,记录对服务器的每个请求,其中将说明请求的查询或突变,以及完成请求所用的时间

我知道有 plugin and extension 框架。但我不确定在两个回调之间保持状态的最佳做法是什么:requestDidStartwillSendResponse

会吐出来的东西:

path="createAccountMutation" service=20ms

额外的功劳是显示有效负载的大小

path="createAccountMutation" service=20ms bytes=355

希望看到打字稿中的解决方案

注意:我找到了apollo-log——但它没有请求持续时间

谢谢!

【问题讨论】:

    标签: typescript graphql apollo apollo-server


    【解决方案1】:

    requestDidStart 在每个请求中调用一次,并返回请求生命周期钩子的映射,因此您可以初始化在钩子之间持久存在的任何状态。

    const LogPlugin = {
      requestDidStart(requestContext) {
        const start = Date.now()
        let op
    
        return {
          didResolveOperation (context) {
            op = context.operationName
          },
          willSendResponse (context) {
            const stop = Date.now()
            const elapsed = stop - start
            const size = JSON.stringify(context.response).length * 2
            console.log(
              `Operation ${op} completed in ${elapsed} ms and returned ${size} bytes`
            )
          }
        }
      },
    }
    

    请注意,这仅适用于每个请求。如果您需要更精细的信息,例如跟踪单个字段需要多长时间来解析,您需要使用 directivemiddleware

    【讨论】:

    • 老兄——这看起来很棒。 (如果你把它做成打字稿的话,还有额外的拳头碰撞;-))[但我真的打赌我能弄明白]!谢谢 。 (一旦我证明它有效,我会检查它)
    • 是否可以只在 willSendResponse 中捕获任何“突变”?
    • 不要忘记为 apollo v3 制作 "async requestDidStart" 、 "async didResolveOperation" 和 "async willSendResponse"
    【解决方案2】:

    这是打字稿

    import {
      ApolloServerPlugin,
    } from 'apollo-server-plugin-base';
    
    import { GraphQLRequestContext } from 'apollo-server-types';
    import { GraphQLRequestListener } from 'apollo-server-plugin-base/src/index'
    
    
    
    // https://stackoverflow.com/questions/59988906/how-do-i-write-a-apollo-server-plugin-to-log-the-request-and-its-duration
    export const LogPlugin: ApolloServerPlugin  = {
      requestDidStart<TContext>(_: GraphQLRequestContext<TContext>): GraphQLRequestListener<TContext> {
        const start = Date.now()
        let op: string
    
        return {
          didResolveOperation (context) {
            op = context.operationName
          },
          willSendResponse (context) {
            const stop = Date.now()
            const elapsed = stop - start
            const size = JSON.stringify(context.response).length * 2
            console.log(
              `operataion=${op} duration=${elapsed}ms bytes=${size}`
            )
          }
        }
      },
    }
    

    所有功劳归功于丹尼尔·里尔登

    【讨论】:

      【解决方案3】:

      我扩展了 Daniel Rearden 和 Jonathan 的答案,使其对我有用。 ApolloServerPlugin 类型需要异步调用。也许那是因为我使用的是 ApolloClient v.3?此外,操作变量必须键入null,因为它被初始化为空。

      无论如何,这是我所做的一个工作示例。我还冒昧地重命名了插件、操作变量、添加错误记录器并使用performance.now() 而不是Date.now()

      还要注意MyApolloContext 是您自己定义的上下文(至少在使用apollo-server-express 时)

      import { MyModels } from './models'
      import {
        ApolloServerPlugin,
      } from 'apollo-server-plugin-base';
      
      import { GraphQLRequestContext } from 'apollo-server-types';
      import { GraphQLRequestListener } from 'apollo-server-plugin-base/src/index'
      import { performance } from 'perf_hooks'
      
      
      export interface MyApolloContext {
        models: MyModels 
      }
      
      export const myDebugLoggerPlugin: ApolloServerPlugin = {
        async requestDidStart<MyApolloContext >(
          requestContext: GraphQLRequestContext<MyApolloContext >,
        ): Promise<GraphQLRequestListener<MyApolloContext >> {
          const start = performance.now()
          let operation: string | null
      
          return {
            // Apollo server lifetime methods that you can use. https://www.apollographql.com/docs/apollo-server/integrations/plugins/#responding-to-request-lifecycle-events
            async didResolveOperation(context) {
              operation = context.operationName
            },
            async willSendResponse(context) {
              const elapsed = Math.round(performance.now() - start)
              const size = JSON.stringify(context.response).length * 2
              console.log(
                `ApolloServer log: operataion=${operation} duration=${elapsed}ms bytes=${size}`,
              )
            },
            async didEncounterErrors(context) {
              console.log('Did encounter error: ', context)
            },
          }
        },
        async serverWillStart(_context) {},
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-01-22
        • 1970-01-01
        • 2012-08-09
        • 1970-01-01
        • 2019-06-13
        • 1970-01-01
        相关资源
        最近更新 更多