如何编写 Apollo Server 插件来记录请求及其持续时间
How do I write a Apollo Server plugin to log the request and its duration
我很惊讶我找不到库或示例来执行以下操作:
我想要一个简单的服务器日志,记录对服务器的每个请求,其中将说明请求的查询或变更,以及完成请求所花费的时间
我知道有 plugin and extension 框架。但我不确定在两个回调之间保持状态的最佳做法是什么:requestDidStart
和 willSendResponse
会吐出来的东西:
path="createAccountMutation" service=20ms
额外的功劳是显示有效载荷的大小
path="createAccountMutation" service=20ms bytes=355
希望看到打字稿中的解决方案
注意:我找到了 apollo-log -- 但它不执行请求持续时间
谢谢!
requestDidStart
每个请求调用一次,returns 请求生命周期挂钩映射,因此您可以初始化挂钩之间持久存在的任何状态。
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`
)
}
}
},
}
请注意,这仅适用于每个请求。如果您需要更精细的东西,例如跟踪单个字段需要多长时间才能解决,则需要使用 directive or middleware
这是打字稿
import {
ApolloServerPlugin,
} from 'apollo-server-plugin-base';
import { GraphQLRequestContext } from 'apollo-server-types';
import { GraphQLRequestListener } from 'apollo-server-plugin-base/src/index'
//
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}`
)
}
}
},
}
所有功劳归功于 Daniel Rearden
我扩展了 Daniel Rearden 和 Jonathan 的答案,使其对我有用。 ApolloServerPlugin
类型需要异步调用。也许那是因为我使用的是 ApolloClient v.3?此外,操作变量必须键入 null
,因为它被初始化为 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) {},
}
我很惊讶我找不到库或示例来执行以下操作:
我想要一个简单的服务器日志,记录对服务器的每个请求,其中将说明请求的查询或变更,以及完成请求所花费的时间
我知道有 plugin and extension 框架。但我不确定在两个回调之间保持状态的最佳做法是什么:requestDidStart
和 willSendResponse
会吐出来的东西:
path="createAccountMutation" service=20ms
额外的功劳是显示有效载荷的大小
path="createAccountMutation" service=20ms bytes=355
希望看到打字稿中的解决方案
注意:我找到了 apollo-log -- 但它不执行请求持续时间
谢谢!
requestDidStart
每个请求调用一次,returns 请求生命周期挂钩映射,因此您可以初始化挂钩之间持久存在的任何状态。
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`
)
}
}
},
}
请注意,这仅适用于每个请求。如果您需要更精细的东西,例如跟踪单个字段需要多长时间才能解决,则需要使用 directive or middleware
这是打字稿
import {
ApolloServerPlugin,
} from 'apollo-server-plugin-base';
import { GraphQLRequestContext } from 'apollo-server-types';
import { GraphQLRequestListener } from 'apollo-server-plugin-base/src/index'
//
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}`
)
}
}
},
}
所有功劳归功于 Daniel Rearden
我扩展了 Daniel Rearden 和 Jonathan 的答案,使其对我有用。 ApolloServerPlugin
类型需要异步调用。也许那是因为我使用的是 ApolloClient v.3?此外,操作变量必须键入 null
,因为它被初始化为 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) {},
}