Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to filter errors from being reported #1639

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

- Allow an optional function to resolve the `rootValue`, passing the `DocumentNode` AST to determine the value. [PR #1555](https://github.com/apollographql/apollo-server/pull/1555)
- Follow-up on the work in [PR #1516](https://github.com/apollographql/apollo-server/pull/1516) to also fix missing insertion cursor/caret when a custom GraphQL configuration is specified which doesn't specify its own `cursorShape` property. [PR #1607](https://github.com/apollographql/apollo-server/pull/1607)
- Add option to filter errors from being reported [#1639](https://github.com/apollographql/apollo-server/pull/1639)

### v2.1.0

Expand Down
7 changes: 5 additions & 2 deletions docs/source/api/apollo-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,9 @@ addMockFunctionsToSchema({
'sendReport()' on other signals if you'd like. Note that 'sendReport()'
does not run synchronously so it cannot work usefully in an 'exit' handler.

* `maskErrorDetails`: boolean
* `filterErrors`: (err: Error) => Error | null
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @martijnwalraven that it would be nice if this type could also be a "boolean" so that we could introduce a sane default for masking error details such as removing all string literals other than the approved ApolloError code.


Set to true to remove error details from the traces sent to Apollo's servers. Defaults to false.
By default, all errors get reported to Engine servers. You can specify a
a filter function to exclude specific errors from being reported by
returning null, or you can mask certain details of the error and return the
error to be reported.
10 changes: 7 additions & 3 deletions packages/apollo-engine-reporting/src/agent.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import os from 'os';
import { gzip } from 'zlib';
import { DocumentNode } from 'graphql';
import { DocumentNode, GraphQLError } from 'graphql';
import {
FullTracesReport,
ReportHeader,
Expand Down Expand Up @@ -86,8 +86,12 @@ export interface EngineReportingOptions {
handleSignals?: boolean;
// Sends the trace report immediately. This options is useful for stateless environments
sendReportsImmediately?: boolean;
// To remove the error message from traces, set this to true. Defaults to false
maskErrorDetails?: boolean;
// By default, all errors get reported to Engine servers. You can specify a
// a filter function to exclude specific errors from being reported by
// returning null, or you can mask certain details of the error and return the
// error to be reported.
// If set to 'true' instead of a function, it will mask the error details.
filterErrors?: ((err: GraphQLError) => GraphQLError | null) | boolean;

/**
* (Experimental) Creates the client information for operation traces.
Expand Down
37 changes: 25 additions & 12 deletions packages/apollo-engine-reporting/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,18 @@ export class EngineReportingExtension<TContext = any>
options: EngineReportingOptions,
addTrace: (signature: string, operationName: string, trace: Trace) => void,
) {
const filterErrors = (() => {
if (options.filterErrors === true) {
return (error: GraphQLError) => new GraphQLError('masked', error.nodes);
} else if (options.filterErrors) {
return options.filterErrors;
} else {
return (error: GraphQLError) => error;
}
})();

this.options = {
maskErrorDetails: false,
filterErrors,
...options,
};
this.addTrace = addTrace;
Expand Down Expand Up @@ -261,18 +271,21 @@ export class EngineReportingExtension<TContext = any>
}
}

// Always send the trace errors, so that the UI acknowledges that there is an error.
const errorInfo = this.options.maskErrorDetails
? { message: '<masked>' }
: {
message: error.message,
location: (error.locations || []).map(
({ line, column }) => new Trace.Location({ line, column }),
),
json: JSON.stringify(error),
};
const filteredError = this.options.filterErrors
? this.options.filterErrors(error)
: error;

node!.error!.push(new Trace.Error(errorInfo));
if (filteredError) {
const errorInfo = {
message: filteredError.message,
location: (filteredError.locations || []).map(
({ line, column }) => new Trace.Location({ line, column }),
),
json: JSON.stringify(filteredError),
};

node!.error!.push(new Trace.Error(errorInfo));
}
});
}
}
Expand Down