1 | import { Tracer, Span, SpanKind } from "@opencensus/core";
|
2 | import {
|
3 | GraphQLResolveInfo,
|
4 | ResponsePath,
|
5 | GraphQLFieldResolver
|
6 | } from "graphql";
|
7 |
|
8 | export const openCensusTracer = Symbol("OpenCensus Tracer");
|
9 | export const openCensusSpanMap = Symbol("OpenCensus Span Map");
|
10 |
|
11 | export async function openCensusTracingGraphQLMiddleware(
|
12 | resolve: GraphQLFieldResolver<any, any, any>,
|
13 | parent: unknown,
|
14 | args: unknown,
|
15 | context: {
|
16 | [openCensusTracer]?: Tracer;
|
17 | [openCensusSpanMap]?: Map<ResponsePath, Span>;
|
18 | },
|
19 | info: GraphQLResolveInfo
|
20 | ): Promise<any> {
|
21 | const tracer = context[openCensusTracer];
|
22 | if (!tracer || !tracer.currentRootSpan) {
|
23 | return resolve(parent, args, context, info);
|
24 | }
|
25 |
|
26 | let span;
|
27 | const spanMap = (context[openCensusSpanMap] =
|
28 | context[openCensusSpanMap] || new Map());
|
29 | const parentSpan = info.path.prev && spanMap.get(info.path.prev);
|
30 | if (parentSpan) {
|
31 | span = tracer.startChildSpan({
|
32 | name: info.fieldName,
|
33 | kind: SpanKind.UNSPECIFIED,
|
34 | childOf: parentSpan
|
35 | });
|
36 |
|
37 | const parentId =
|
38 | (typeof parent === "object" &&
|
39 | parent &&
|
40 | typeof (parent as { [key: string]: unknown }).id === "string" &&
|
41 | (parent as { id: string }).id) ||
|
42 | null;
|
43 |
|
44 | if (parentId) {
|
45 | span.addAttribute("parentId", parentId);
|
46 | }
|
47 | span.addAttribute("parentType", info.parentType.toString());
|
48 | span.addAttribute("fieldName", info.fieldName);
|
49 | span.addAttribute("returnType", info.returnType.toString());
|
50 | }
|
51 |
|
52 | try {
|
53 | return await resolve(parent, args, context, info);
|
54 | } finally {
|
55 | if (span) span.end();
|
56 | }
|
57 | }
|