Skip to content

Commit 0b2307e

Browse files
committed
progress
1 parent 209c3cd commit 0b2307e

File tree

1 file changed

+44
-38
lines changed
  • packages/plugins/apollo-inline-trace/src

1 file changed

+44
-38
lines changed

packages/plugins/apollo-inline-trace/src/index.ts

Lines changed: 44 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ import { isAsyncIterable, Plugin } from '@envelop/core';
22
import { GraphQLError, ResponsePath } from 'graphql';
33
import { google, Trace } from 'apollo-reporting-protobuf';
44

5-
interface ApolloInlineTracer {
5+
const ctxKey = Symbol('ApolloInlineTracePluginContextKey');
6+
7+
interface ApolloInlineTracePluginContext {
68
startHrTime: [number, number];
79
rootNode: Trace.Node;
810
trace: Trace;
@@ -45,64 +47,68 @@ export interface ApolloInlineTracePluginOptions<PluginContext extends Record<str
4547
export function useApolloInlineTrace<PluginContext extends Record<string, any> = {}>({
4648
shouldTrace,
4749
rewriteError,
48-
}: ApolloInlineTracePluginOptions<PluginContext>): Plugin<PluginContext> {
49-
const tracerForCtx = new WeakMap<PluginContext, ApolloInlineTracer>();
50+
}: ApolloInlineTracePluginOptions<PluginContext>): Plugin<
51+
PluginContext & { [ctxKey]: ApolloInlineTracePluginContext }
52+
> {
5053
return {
51-
onEnveloped({ context }) {
54+
onEnveloped({ context, extendContext }) {
5255
if (!context) {
5356
throw new Error("Context must be set for Apollo's inline tracing plugin");
5457
}
5558

5659
if (shouldTrace(context)) {
5760
const startHrTime = process.hrtime();
5861
const rootNode = new Trace.Node();
59-
tracerForCtx.set(context, {
60-
startHrTime,
61-
rootNode,
62-
trace: new Trace({
63-
root: rootNode,
64-
fieldExecutionWeight: 1, // Why 1? See: https://github.com/apollographql/apollo-server/blob/9389da785567a56e989430962564afc71e93bd7f/packages/apollo-server-core/src/plugin/traceTreeBuilder.ts#L16-L23
65-
startTime: nowTimestamp(),
66-
}),
67-
nodes: new Map([[responsePathToString(), rootNode]]),
68-
stopped: false,
62+
extendContext({
63+
...context,
64+
[ctxKey]: {
65+
startHrTime,
66+
rootNode,
67+
trace: new Trace({
68+
root: rootNode,
69+
fieldExecutionWeight: 1, // Why 1? See: https://github.com/apollographql/apollo-server/blob/9389da785567a56e989430962564afc71e93bd7f/packages/apollo-server-core/src/plugin/traceTreeBuilder.ts#L16-L23
70+
startTime: nowTimestamp(),
71+
}),
72+
nodes: new Map([[responsePathToString(), rootNode]]),
73+
stopped: false,
74+
},
6975
});
7076
}
7177
},
7278
onResolverCalled({ context, info }) {
73-
const tracer = tracerForCtx.get(context);
74-
if (!tracer) return;
79+
const ctx = context[ctxKey];
80+
if (!ctx) return;
7581

76-
// result was already shipped (see ApolloInlineTracer.stopped)
77-
if (tracer.stopped) {
82+
// result was already shipped (see ApolloInlineTracePluginContext.stopped)
83+
if (ctx.stopped) {
7884
return () => {
7985
// noop
8086
};
8187
}
8288

83-
const node = newTraceNode(tracer, info.path);
89+
const node = newTraceNode(ctx, info.path);
8490
node.type = info.returnType.toString();
8591
node.parentType = info.parentType.toString();
86-
node.startTime = hrTimeToDurationInNanos(process.hrtime(tracer.startHrTime));
92+
node.startTime = hrTimeToDurationInNanos(process.hrtime(ctx.startHrTime));
8793
if (typeof info.path.key === 'string' && info.path.key !== info.fieldName) {
8894
// field was aliased, send the original field name too
8995
node.originalFieldName = info.fieldName;
9096
}
9197

9298
return () => {
93-
node.endTime = hrTimeToDurationInNanos(process.hrtime(tracer.startHrTime));
99+
node.endTime = hrTimeToDurationInNanos(process.hrtime(ctx.startHrTime));
94100
};
95101
},
96102
onParse() {
97103
return ({ context, result }) => {
98-
const tracer = tracerForCtx.get(context);
99-
if (!tracer) return;
104+
const ctx = context[ctxKey];
105+
if (!ctx) return;
100106

101107
if (result instanceof GraphQLError) {
102-
handleErrors(tracer, [result], rewriteError);
108+
handleErrors(ctx, [result], rewriteError);
103109
} else if (result instanceof Error) {
104110
handleErrors(
105-
tracer,
111+
ctx,
106112
[
107113
new GraphQLError(result.message, {
108114
originalError: result,
@@ -116,16 +122,16 @@ export function useApolloInlineTrace<PluginContext extends Record<string, any> =
116122
onValidate() {
117123
return ({ context, result: errors }) => {
118124
if (errors.length) {
119-
const tracer = tracerForCtx.get(context);
120-
if (tracer) handleErrors(tracer, errors, rewriteError);
125+
const ctx = context[ctxKey];
126+
if (ctx) handleErrors(ctx, errors, rewriteError);
121127
}
122128
};
123129
},
124130
onExecute() {
125131
return {
126132
onExecuteDone({ args: { contextValue }, result, setResult }) {
127-
const tracer = tracerForCtx.get(contextValue);
128-
if (!tracer) return;
133+
const ctx = contextValue[ctxKey];
134+
if (!ctx) return;
129135

130136
// TODO: should handle streaming results? how?
131137
if (isAsyncIterable(result)) return;
@@ -135,17 +141,17 @@ export function useApolloInlineTrace<PluginContext extends Record<string, any> =
135141
}
136142

137143
if (result.errors?.length) {
138-
handleErrors(tracer, result.errors, rewriteError);
144+
handleErrors(ctx, result.errors, rewriteError);
139145
}
140146

141147
// onResultProcess will be called only once since we disallow async iterables
142-
if (tracer.stopped) throw new Error('Trace stopped multiple times');
148+
if (ctx.stopped) throw new Error('Trace stopped multiple times');
143149

144-
tracer.stopped = true;
145-
tracer.trace.durationNs = hrTimeToDurationInNanos(process.hrtime(tracer.startHrTime));
146-
tracer.trace.endTime = nowTimestamp();
150+
ctx.stopped = true;
151+
ctx.trace.durationNs = hrTimeToDurationInNanos(process.hrtime(ctx.startHrTime));
152+
ctx.trace.endTime = nowTimestamp();
147153

148-
const encodedUint8Array = Trace.encode(tracer.trace).finish();
154+
const encodedUint8Array = Trace.encode(ctx.trace).finish();
149155
const encodedBuffer = Buffer.from(
150156
encodedUint8Array,
151157
encodedUint8Array.byteOffset,
@@ -211,14 +217,14 @@ function responsePathToString(path?: ResponsePath): string {
211217
return res;
212218
}
213219

214-
function ensureParentTraceNode(ctx: ApolloInlineTracer, path: ResponsePath): Trace.Node {
220+
function ensureParentTraceNode(ctx: ApolloInlineTracePluginContext, path: ResponsePath): Trace.Node {
215221
const parentNode = ctx.nodes.get(responsePathToString(path.prev));
216222
if (parentNode) return parentNode;
217223
// path.prev isn't undefined because we set up the root path in ctx.nodes
218224
return newTraceNode(ctx, path.prev!);
219225
}
220226

221-
function newTraceNode(ctx: ApolloInlineTracer, path: ResponsePath) {
227+
function newTraceNode(ctx: ApolloInlineTracePluginContext, path: ResponsePath) {
222228
const node = new Trace.Node();
223229
const id = path.key;
224230
if (typeof id === 'number') {
@@ -233,7 +239,7 @@ function newTraceNode(ctx: ApolloInlineTracer, path: ResponsePath) {
233239
}
234240

235241
function handleErrors(
236-
ctx: ApolloInlineTracer,
242+
ctx: ApolloInlineTracePluginContext,
237243
errors: readonly GraphQLError[],
238244
rewriteError: ApolloInlineTracePluginOptions['rewriteError']
239245
) {

0 commit comments

Comments
 (0)