/* eslint no-shadow: ["error", { "allow": ["requestContext"] }] */ import prettier from 'prettier'; import { ApolloServerPlugin, GraphQLRequestContext, GraphQLRequestListener, } from 'apollo-server-plugin-base'; import { Logger } from 'pino'; const DEFAULT_TRUNCATE_LENGTH = 4096; function truncate(str: string, l = DEFAULT_TRUNCATE_LENGTH): string { if (str == null) { return ''; } if (str.length <= l) { return str; } return `${str.slice(0, l)}...`; } export default class ApolloLogger implements ApolloServerPlugin { constructor(private logger: Logger) {} async requestDidStart( requestContext: GraphQLRequestContext ): Promise<GraphQLRequestListener> { const { logger } = this; const logProps = requestContext.context.logProps || {}; if (requestContext.request.query?.startsWith('query IntrospectionQuery')) { return {}; } let q = ''; try { q = prettier.format(requestContext.request.query || '', { parser: 'graphql', }); } catch (e) { const el = truncate(requestContext.request.query || ''); logger.debug(`invalid query provided: ${el}`); } const query = truncate(q); const vars = truncate( JSON.stringify(requestContext.request.variables || {}, null, 2) ); logger.debug( logProps, `GraphQL request started:\n${query}\nvariables:\n${vars}` ); return { async didEncounterErrors( requestContext: GraphQLRequestContext ): Promise<void> { const errors = truncate(JSON.stringify(requestContext.errors)); logger.error(logProps, `GraphQL encountered errors:\n${errors}`); }, async willSendResponse( requestContext: GraphQLRequestContext ): Promise<void> { const respData = truncate( JSON.stringify(requestContext.response?.data) ); logger.debug(logProps, `GraphQL request completed:\n${respData}`); }, }; } }