diff --git a/.gitignore b/.gitignore
index ebd2d84..4358e8c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
node_modules/
.nyc_output/
+coverage/
src/**/*.js
test/**/*.js
diff --git a/README.md b/README.md
index cbc5615..4730e54 100644
--- a/README.md
+++ b/README.md
@@ -36,3 +36,20 @@ AWS has a 64K upload limit when submitting segements to AWS see [AWSXRay concept
If you try and submit more than this limit you will see the following aws error message
**" [ERROR] Segment too large to send: { ./.nyc_output/lcov.info",
+ "coverage_report": "nyc --reporter=lcov --reporter=text-summary ava",
"prepublishOnly": "yarn tsc",
"cleanTypes": "rm -rf test/__generated__"
},
diff --git a/src/traceResolvers.ts b/src/traceResolvers.ts
index 982d55b..c2f533f 100644
--- a/src/traceResolvers.ts
+++ b/src/traceResolvers.ts
@@ -14,20 +14,32 @@ function fieldPathFromInfo (info: GraphQLResolveInfo) {
return segments.join('.');
}
-export default (schema: GraphQLSchema): GraphQLSchemaWithFragmentReplacements => {
+export interface TraceOptions {
+ enabled: boolean;
+}
+
+const DefaultOptions: TraceOptions = {
+ enabled: true
+};
+
+export default (schema: GraphQLSchema, options: TraceOptions = DefaultOptions): GraphQLSchemaWithFragmentReplacements => {
const tracer: IMiddlewareResolver = async (resolver, _parent, _args, _ctx, info) => {
- const fieldPath = fieldPathFromInfo(info);
- return AWSXRay.captureAsyncFunc(`GraphQL ${fieldPath}`, async (subsegment) => {
- // When AWS_XRAY_CONTEXT_MISSING is set to LOG_MISSING and no context is found then subsegment is undefined.
- try {
- const result = await resolver();
- subsegment?.close();
- return result;
- } catch (error: any) {
- subsegment?.close(error);
- throw error;
- }
- });
+ if (options.enabled) {
+ const fieldPath = fieldPathFromInfo(info);
+ return AWSXRay.captureAsyncFunc(`GraphQL ${fieldPath}`, async (subsegment) => {
+ // When AWS_XRAY_CONTEXT_MISSING is set to LOG_MISSING and no context is found then subsegment is undefined.
+ try {
+ const result = await resolver();
+ subsegment?.close();
+ return result;
+ } catch (error: any) {
+ subsegment?.close(error);
+ throw error;
+ }
+ });
+ } else {
+ return resolver();
+ }
};
return applyMiddlewareToDeclaredResolvers(schema, tracer);
diff --git a/test/helpers/schema.ts b/test/helpers/schema.ts
index 779bf7d..df3a06f 100644
--- a/test/helpers/schema.ts
+++ b/test/helpers/schema.ts
@@ -2,7 +2,7 @@ import { makeExecutableSchema } from 'graphql-tools';
import { v4 as uuid } from 'uuid';
import { loadFiles } from '@graphql-toolkit/file-loading';
import path from 'path';
-import traceResolvers from '../../src/traceResolvers';
+import traceResolvers, { TraceOptions } from '../../src/traceResolvers';
const blocked = new Map();
@@ -80,10 +80,14 @@ const resolvers = {
}
};
-export function traceSchema () {
+export function traceSchema (options: TraceOptions|null) {
const schema = makeExecutableSchema({
typeDefs: loadFiles(path.join(__dirname, '**/*.graphql')),
resolvers
});
+
+ if (options) {
+ return traceResolvers(schema, options);
+ }
return traceResolvers(schema);
}
diff --git a/test/traceResolvers-contextMissing.test.ts b/test/traceResolvers-contextMissing.test.ts
index 38997b9..01eb355 100644
--- a/test/traceResolvers-contextMissing.test.ts
+++ b/test/traceResolvers-contextMissing.test.ts
@@ -1,5 +1,6 @@
import { graphql, GraphQLError, Source } from 'graphql';
import { traceSchema } from './helpers/schema';
+import { TraceOptions } from '../src/traceResolvers';
import nock from 'nock';
import anyTest, { TestInterface } from 'ava';
import AWSXRay from 'aws-xray-sdk-core';
@@ -25,11 +26,14 @@ interface TestContext {
}
const test = anyTest as TestInterface;
+const traceOptions: TraceOptions = {
+ enabled: true
+};
test.beforeEach((t) => {
nock.disableNetConnect();
nock.enableNetConnect('127.0.0.1');
- const schema = traceSchema();
+ const schema = traceSchema(traceOptions);
t.context.graphql = (query) => graphql(schema, query);
});
diff --git a/test/traceResolvers-withOptions.test.ts b/test/traceResolvers-withOptions.test.ts
new file mode 100644
index 0000000..5d0c31a
--- /dev/null
+++ b/test/traceResolvers-withOptions.test.ts
@@ -0,0 +1,114 @@
+import { graphql } from 'graphql';
+import { traceSchema } from './helpers/schema';
+import { TraceOptions } from '../src/traceResolvers';
+import nock from 'nock';
+import anyTest, { TestInterface } from 'ava';
+import AWSXRay, { Segment } from 'aws-xray-sdk-core';
+import { ExecutionResult, ExecutionResultDataDefault } from 'graphql/execution/execute';
+
+AWSXRay.capturePromise();
+
+type GraphQlQuery = Parameters[1];
+type Namespace = ReturnType;
+
+interface TestContext {
+ ns: Namespace;
+ segment: Segment;
+ graphql: (query: GraphQlQuery) => Promise>;
+}
+
+const test = anyTest as TestInterface;
+const traceOptions: TraceOptions = {
+ enabled: true
+};
+
+test.beforeEach(function (test) {
+ const schema = traceSchema(traceOptions);
+ nock.disableNetConnect();
+ nock.enableNetConnect('127.0.0.1');
+
+ const ns: Namespace = AWSXRay.getNamespace();
+ test.context.ns = ns;
+
+ const segment = new AWSXRay.Segment('parent');
+ test.context.segment = segment;
+
+ test.context.graphql = ns.bind(function (query: GraphQlQuery) {
+ AWSXRay.setSegment(segment);
+ try {
+ return graphql(schema, query);
+ } finally {
+ segment.close();
+ }
+ });
+});
+
+test.afterEach.always(() => {
+ nock.enableNetConnect();
+ nock.cleanAll();
+});
+
+test('Trace segments are not created for resolvers when enabled is not true', async function (test) {
+ try {
+ traceOptions.enabled = false;
+ const { segment, graphql } = test.context;
+ const result = await graphql('{ hello }');
+
+ if (result.errors) {
+ throw result.errors[0];
+ }
+ test.deepEqual(result, {
+ data: {
+ hello: 'world'
+ }
+ });
+
+ test.is(segment.subsegments, undefined);
+ } finally {
+ traceOptions.enabled = true;
+ }
+});
+
+const pre = (test: any, options: TraceOptions|null) => {
+ const schema = traceSchema(options);
+ nock.disableNetConnect();
+ nock.enableNetConnect('127.0.0.1');
+
+ const ns: Namespace = AWSXRay.getNamespace();
+ test.context.ns = ns;
+
+ const segment = new AWSXRay.Segment('parent');
+ test.context.segment = segment;
+
+ test.context.graphql = ns.bind(function (query: GraphQlQuery) {
+ AWSXRay.setSegment(segment);
+ try {
+ return graphql(schema, query);
+ } finally {
+ segment.close();
+ }
+ });
+};
+
+test('Trace segments are created for resolvers when defaults are used', async function (test) {
+ try {
+ pre(test, null);
+
+ const { segment, graphql } = test.context;
+ const result = await graphql('{ hello }');
+
+ if (result.errors) {
+ throw result.errors[0];
+ }
+ test.deepEqual(result, {
+ data: {
+ hello: 'world'
+ }
+ });
+
+ test.is(segment.subsegments?.length, 1);
+ } finally {
+ nock.enableNetConnect();
+ nock.cleanAll();
+ }
+});
diff --git a/test/traceResolvers.test.ts b/test/traceResolvers.test.ts
index e0660bd..d9236cf 100644
--- a/test/traceResolvers.test.ts
+++ b/test/traceResolvers.test.ts
@@ -1,5 +1,6 @@
import { graphql } from 'graphql';
import { traceSchema } from './helpers/schema';
+import { TraceOptions } from '../src/traceResolvers';
import nock from 'nock';
import anyTest, { ExecutionContext, TestInterface } from 'ava';
import AWSXRay, { Segment, Subsegment } from 'aws-xray-sdk-core';
@@ -19,9 +20,12 @@ interface TestContext {
}
const test = anyTest as TestInterface;
+const traceOptions: TraceOptions = {
+ enabled: true
+};
test.beforeEach(function (test) {
- const schema = traceSchema();
+ const schema = traceSchema(traceOptions);
nock.disableNetConnect();
nock.enableNetConnect('127.0.0.1');