diff --git a/packages/apollo-engine-reporting/src/agent.ts b/packages/apollo-engine-reporting/src/agent.ts index d3b0be2d1c4..574e94d4c84 100644 --- a/packages/apollo-engine-reporting/src/agent.ts +++ b/packages/apollo-engine-reporting/src/agent.ts @@ -12,7 +12,7 @@ import { fetch, RequestAgent, Response } from 'apollo-server-env'; import retry from 'async-retry'; import { EngineReportingExtension } from './extension'; -import { GraphQLRequestContext } from 'apollo-server-types'; +import { GraphQLRequestContext, Logger } from 'apollo-server-types'; import { InMemoryLRUCache } from 'apollo-server-caching'; import { defaultEngineReportingSignature } from 'apollo-graphql'; @@ -185,6 +185,13 @@ export interface EngineReportingOptions { * Creates the client information for operation traces. */ generateClientInfo?: GenerateClientInfo; + + /** + * A logger interface to be used for output and errors. When not provided + * it will default to the server's own `logger` implementation and use + * `console` when that is not available. + */ + logger?: Logger; } export interface AddTraceArgs { @@ -209,6 +216,7 @@ const serviceHeaderDefaults = { // to the Engine server. export class EngineReportingAgent { private options: EngineReportingOptions; + private logger: Logger = console; private apiKey: string; private reports: { [schemaHash: string]: FullTracesReport } = Object.create( null, @@ -226,6 +234,7 @@ export class EngineReportingAgent { public constructor(options: EngineReportingOptions = {}) { this.options = options; + if (options.logger) this.logger = options.logger; this.apiKey = options.apiKey || process.env.ENGINE_API_KEY || ''; if (!this.apiKey) { throw new Error( @@ -236,7 +245,7 @@ export class EngineReportingAgent { // Since calculating the signature for Engine reporting is potentially an // expensive operation, we'll cache the signatures we generate and re-use // them based on repeated traces for the same `queryHash`. - this.signatureCache = createSignatureCache(); + this.signatureCache = createSignatureCache({ logger: this.logger }); this.sendReportsImmediately = options.sendReportsImmediately; if (!this.sendReportsImmediately) { @@ -353,7 +362,9 @@ export class EngineReportingAgent { await Promise.resolve(); if (this.options.debugPrintReports) { - console.log(`Engine sending report: ${JSON.stringify(report.toJSON())}`); + this.logger.debug( + `Engine sending report: ${JSON.stringify(report.toJSON())}`, + ); } const protobufError = FullTracesReport.verify(report); @@ -430,7 +441,7 @@ export class EngineReportingAgent { ); } if (this.options.debugPrintReports) { - console.log(`Engine report: status ${response.status}`); + this.logger.debug(`Engine report: status ${response.status}`); } } @@ -516,7 +527,7 @@ export class EngineReportingAgent { if (this.options.reportErrorFunction) { this.options.reportErrorFunction(err); } else { - console.error(err.message); + this.logger.error(err.message); } }); } @@ -529,7 +540,11 @@ export class EngineReportingAgent { } } -function createSignatureCache(): InMemoryLRUCache { +function createSignatureCache({ + logger, +}: { + logger: Logger; +}): InMemoryLRUCache { let lastSignatureCacheWarn: Date; let lastSignatureCacheDisposals: number = 0; return new InMemoryLRUCache({ @@ -558,7 +573,7 @@ function createSignatureCache(): InMemoryLRUCache { ) { // Log the time that we last displayed the message. lastSignatureCacheWarn = new Date(); - console.warn( + logger.warn( [ 'This server is processing a high number of unique operations. ', `A total of ${lastSignatureCacheDisposals} records have been `, diff --git a/packages/apollo-engine-reporting/src/extension.ts b/packages/apollo-engine-reporting/src/extension.ts index 0fd804df7f7..a9199e88fd4 100644 --- a/packages/apollo-engine-reporting/src/extension.ts +++ b/packages/apollo-engine-reporting/src/extension.ts @@ -1,4 +1,4 @@ -import { GraphQLRequestContext, WithRequired } from 'apollo-server-types'; +import { GraphQLRequestContext, WithRequired, Logger } from 'apollo-server-types'; import { Request, Headers } from 'apollo-server-env'; import { GraphQLResolveInfo, @@ -30,6 +30,7 @@ const clientVersionHeaderKey = 'apollographql-client-version'; // Its public methods all implement the GraphQLExtension interface. export class EngineReportingExtension implements GraphQLExtension { + private logger: Logger = console; private treeBuilder: EngineReportingTreeBuilder; private explicitOperationName?: string | null; private queryString?: string; @@ -46,12 +47,14 @@ export class EngineReportingExtension this.options = { ...options, }; + if (options.logger) this.logger = options.logger; this.addTrace = addTrace; this.generateClientInfo = options.generateClientInfo || defaultGenerateClientInfo; this.treeBuilder = new EngineReportingTreeBuilder({ rewriteError: options.rewriteError, + logger: this.logger, }); } diff --git a/packages/apollo-engine-reporting/src/treeBuilder.ts b/packages/apollo-engine-reporting/src/treeBuilder.ts index 448c180f81c..90854a45d64 100644 --- a/packages/apollo-engine-reporting/src/treeBuilder.ts +++ b/packages/apollo-engine-reporting/src/treeBuilder.ts @@ -9,7 +9,7 @@ import { PersistedQueryNotFoundError, PersistedQueryNotSupportedError, } from 'apollo-server-errors'; -import { InvalidGraphQLRequestError } from 'apollo-server-types'; +import { InvalidGraphQLRequestError, Logger } from 'apollo-server-types'; function internalError(message: string) { return new Error(`[internal apollo-server error] ${message}`); @@ -17,6 +17,7 @@ function internalError(message: string) { export class EngineReportingTreeBuilder { private rootNode = new Trace.Node(); + private logger: Logger = console; public trace = new Trace({ root: this.rootNode }); public startHrTime?: [number, number]; private stopped = false; @@ -26,9 +27,11 @@ export class EngineReportingTreeBuilder { private rewriteError?: (err: GraphQLError) => GraphQLError | null; public constructor(options: { + logger?: Logger; rewriteError?: (err: GraphQLError) => GraphQLError | null; }) { this.rewriteError = options.rewriteError; + if (options.logger) this.logger = options.logger; } public startTiming() { @@ -137,7 +140,7 @@ export class EngineReportingTreeBuilder { if (specificNode) { node = specificNode; } else { - console.warn( + this.logger.warn( `Could not find node with path ${path.join( '.', )}; defaulting to put errors on root node.`,