@graphql-hive/plugin-opentelemetry 1.0.0-alpha-2cea6e8a62aea3e45963d47c35cb6db588d78c54
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +215 -0
- package/dist/api.cjs +43 -0
- package/dist/api.d.cts +32 -0
- package/dist/api.d.ts +32 -0
- package/dist/api.js +36 -0
- package/dist/attributes-mikIPKnv.d.ts +10 -0
- package/dist/index.cjs +78 -0
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +12 -0
- package/dist/plugin-BT_oWPcx.cjs +1050 -0
- package/dist/plugin-Cn24wGGV.d.ts +184 -0
- package/dist/plugin-DUMSBw0j.js +1037 -0
- package/dist/setup.cjs +387 -0
- package/dist/setup.d.cts +128 -0
- package/dist/setup.d.ts +128 -0
- package/dist/setup.js +326 -0
- package/package.json +99 -0
|
@@ -0,0 +1,1037 @@
|
|
|
1
|
+
import { isRetryExecutionRequest as isRetryExecutionRequest$1, getRetryInfo as getRetryInfo$1, Logger } from '@graphql-hive/gateway-runtime';
|
|
2
|
+
import { getHeadersObj } from '@graphql-mesh/utils';
|
|
3
|
+
import { getOperationASTFromDocument, isAsyncIterable, fakePromise } from '@graphql-tools/utils';
|
|
4
|
+
import { setGlobalErrorHandler } from '@opentelemetry/core';
|
|
5
|
+
import { unfakePromise } from '@whatwg-node/promise-helpers';
|
|
6
|
+
import { hive } from './api.js';
|
|
7
|
+
import { trace, SpanStatusCode, context, ROOT_CONTEXT, SpanKind, DiagLogLevel, diag, propagation } from '@opentelemetry/api';
|
|
8
|
+
import { hashOperation } from '@graphql-hive/core';
|
|
9
|
+
import { defaultPrintFn } from '@graphql-mesh/transport-common';
|
|
10
|
+
import { SEMATTRS_EXCEPTION_STACKTRACE, SEMATTRS_EXCEPTION_MESSAGE, SEMATTRS_EXCEPTION_TYPE, SEMATTRS_HTTP_METHOD, SEMATTRS_HTTP_URL, SEMATTRS_NET_HOST_NAME, SEMATTRS_HTTP_HOST, SEMATTRS_HTTP_ROUTE, SEMATTRS_HTTP_SCHEME, SEMATTRS_HTTP_STATUS_CODE, SEMATTRS_HTTP_USER_AGENT, SEMATTRS_HTTP_CLIENT_IP } from '@opentelemetry/semantic-conventions';
|
|
11
|
+
import { printSchema, TypeInfo } from 'graphql';
|
|
12
|
+
|
|
13
|
+
class OtelContextStack {
|
|
14
|
+
#root;
|
|
15
|
+
#current;
|
|
16
|
+
constructor(root) {
|
|
17
|
+
this.#root = { ctx: root };
|
|
18
|
+
this.#current = this.#root;
|
|
19
|
+
}
|
|
20
|
+
get current() {
|
|
21
|
+
return this.#current.ctx;
|
|
22
|
+
}
|
|
23
|
+
get root() {
|
|
24
|
+
return this.#root.ctx;
|
|
25
|
+
}
|
|
26
|
+
push = (ctx) => {
|
|
27
|
+
this.#current = { ctx, previous: this.#current };
|
|
28
|
+
};
|
|
29
|
+
pop = () => {
|
|
30
|
+
this.#current = this.#current.previous ?? this.#root;
|
|
31
|
+
};
|
|
32
|
+
toString() {
|
|
33
|
+
let node = this.#current;
|
|
34
|
+
const names = [];
|
|
35
|
+
while (node != void 0) {
|
|
36
|
+
names.push(trace.getSpan(node.ctx).name);
|
|
37
|
+
node = node.previous;
|
|
38
|
+
}
|
|
39
|
+
return names.join(" -> ");
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function withState(pluginFactory) {
|
|
44
|
+
const states = {};
|
|
45
|
+
function getProp(scope, key) {
|
|
46
|
+
return {
|
|
47
|
+
get() {
|
|
48
|
+
if (!states[scope]) states[scope] = /* @__PURE__ */ new WeakMap();
|
|
49
|
+
let value = states[scope].get(key);
|
|
50
|
+
if (!value) states[scope].set(key, value = {});
|
|
51
|
+
return value;
|
|
52
|
+
},
|
|
53
|
+
enumerable: true
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function getState(payload) {
|
|
57
|
+
let { executionRequest, context, request } = payload;
|
|
58
|
+
const state = {};
|
|
59
|
+
const defineState = (scope, key) => Object.defineProperty(state, scope, getProp(scope, key));
|
|
60
|
+
if (executionRequest) {
|
|
61
|
+
defineState("forSubgraphExecution", executionRequest);
|
|
62
|
+
if (executionRequest.context?.params) context = executionRequest.context;
|
|
63
|
+
}
|
|
64
|
+
if (context) {
|
|
65
|
+
defineState("forOperation", context);
|
|
66
|
+
if (context.request) request = context.request;
|
|
67
|
+
}
|
|
68
|
+
if (request) {
|
|
69
|
+
defineState("forRequest", request);
|
|
70
|
+
}
|
|
71
|
+
return state;
|
|
72
|
+
}
|
|
73
|
+
function addStateGetters(src) {
|
|
74
|
+
const result = {};
|
|
75
|
+
const properties = Object.entries(Object.getOwnPropertyDescriptors(src));
|
|
76
|
+
for (const [hookName, descriptor] of properties) {
|
|
77
|
+
const hook = descriptor.value;
|
|
78
|
+
if (typeof hook !== "function") {
|
|
79
|
+
descriptor.get &&= () => src[hookName];
|
|
80
|
+
descriptor.set &&= (value) => {
|
|
81
|
+
src[hookName] = value;
|
|
82
|
+
};
|
|
83
|
+
Object.defineProperty(result, hookName, descriptor);
|
|
84
|
+
} else {
|
|
85
|
+
result[hookName] = {
|
|
86
|
+
[hook.name](payload, ...args) {
|
|
87
|
+
return hook(
|
|
88
|
+
{
|
|
89
|
+
...payload,
|
|
90
|
+
get state() {
|
|
91
|
+
return getState(payload);
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
...args
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
}[hook.name];
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
const plugin = pluginFactory(getState);
|
|
103
|
+
const pluginWithState = addStateGetters(plugin);
|
|
104
|
+
pluginWithState.instrumentation = addStateGetters(plugin.instrumentation);
|
|
105
|
+
return pluginWithState;
|
|
106
|
+
}
|
|
107
|
+
function getMostSpecificState(state = {}) {
|
|
108
|
+
const { forOperation, forRequest, forSubgraphExecution } = state;
|
|
109
|
+
return forSubgraphExecution ?? forOperation ?? forRequest;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const RETRY_SYMBOL = Symbol.for("@hive-gateway/runtime/upstreamRetry");
|
|
113
|
+
function isRetryExecutionRequest(executionRequest) {
|
|
114
|
+
return !!executionRequest?.[RETRY_SYMBOL];
|
|
115
|
+
}
|
|
116
|
+
function getRetryInfo(executionRequest) {
|
|
117
|
+
return executionRequest[RETRY_SYMBOL];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const SEMATTRS_GRAPHQL_DOCUMENT = "graphql.document";
|
|
121
|
+
const SEMATTRS_GRAPHQL_OPERATION_TYPE = "graphql.operation.type";
|
|
122
|
+
const SEMATTRS_GRAPHQL_OPERATION_NAME = "graphql.operation.name";
|
|
123
|
+
const SEMATTRS_HIVE_GRAPHQL_OPERATION_HASH = "hive.graphql.operation.hash";
|
|
124
|
+
const SEMATTRS_HIVE_GRAPHQL_ERROR_COUNT = "hive.graphql.error.count";
|
|
125
|
+
const SEMATTRS_HIVE_GRAPHQL_ERROR_CODES = "hive.graphql.error.codes";
|
|
126
|
+
const SEMATTRS_HIVE_GATEWAY_UPSTREAM_SUBGRAPH_NAME = "hive.gateway.upstream.subgraph.name";
|
|
127
|
+
const SEMATTRS_HIVE_GATEWAY_OPERATION_SUBGRAPH_NAMES = "hive.gateway.operation.subgraph.names";
|
|
128
|
+
|
|
129
|
+
function createHttpSpan(input) {
|
|
130
|
+
const { url, request, tracer } = input;
|
|
131
|
+
const span = tracer.startSpan(
|
|
132
|
+
`${request.method || "GET"} ${url.pathname}`,
|
|
133
|
+
{
|
|
134
|
+
attributes: {
|
|
135
|
+
[SEMATTRS_HTTP_METHOD]: request.method || "GET",
|
|
136
|
+
[SEMATTRS_HTTP_URL]: request.url,
|
|
137
|
+
[SEMATTRS_HTTP_ROUTE]: url.pathname,
|
|
138
|
+
[SEMATTRS_HTTP_SCHEME]: url.protocol,
|
|
139
|
+
[SEMATTRS_NET_HOST_NAME]: url.hostname || url.host || request.headers.get("host") || "localhost",
|
|
140
|
+
[SEMATTRS_HTTP_HOST]: url.host || request.headers.get("host") || void 0,
|
|
141
|
+
[SEMATTRS_HTTP_CLIENT_IP]: request.headers.get("x-forwarded-for")?.split(",")[0],
|
|
142
|
+
[SEMATTRS_HTTP_USER_AGENT]: request.headers.get("user-agent") || void 0,
|
|
143
|
+
"hive.client.name": request.headers.get("x-graphql-client-name") || void 0,
|
|
144
|
+
"hive.client.version": request.headers.get("x-graphql-client-version") || void 0
|
|
145
|
+
},
|
|
146
|
+
kind: SpanKind.SERVER
|
|
147
|
+
},
|
|
148
|
+
input.ctx
|
|
149
|
+
);
|
|
150
|
+
return {
|
|
151
|
+
ctx: trace.setSpan(input.ctx, span)
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
function setResponseAttributes(ctx, response) {
|
|
155
|
+
const span = trace.getSpan(ctx);
|
|
156
|
+
if (span) {
|
|
157
|
+
span.setAttribute(SEMATTRS_HTTP_STATUS_CODE, response.status);
|
|
158
|
+
span.setAttribute(
|
|
159
|
+
"gateway.cache.response_cache",
|
|
160
|
+
response.status === 304 && response.headers.get("ETag") ? "hit" : "miss"
|
|
161
|
+
);
|
|
162
|
+
span.setStatus({
|
|
163
|
+
code: response.ok ? SpanStatusCode.OK : SpanStatusCode.ERROR,
|
|
164
|
+
message: response.ok ? void 0 : response.statusText
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
function createGraphQLSpan(input) {
|
|
169
|
+
const span = input.tracer.startSpan(
|
|
170
|
+
`graphql.operation`,
|
|
171
|
+
{ kind: SpanKind.INTERNAL },
|
|
172
|
+
input.ctx
|
|
173
|
+
);
|
|
174
|
+
return trace.setSpan(input.ctx, span);
|
|
175
|
+
}
|
|
176
|
+
function setParamsAttributes(input) {
|
|
177
|
+
const { ctx, params } = input;
|
|
178
|
+
const span = trace.getSpan(ctx);
|
|
179
|
+
if (!span) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
span.setAttribute(SEMATTRS_GRAPHQL_DOCUMENT, params.query ?? "<undefined>");
|
|
183
|
+
if (params.operationName) {
|
|
184
|
+
span.setAttribute(SEMATTRS_GRAPHQL_OPERATION_NAME, params.operationName);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
const typeInfos = /* @__PURE__ */ new WeakMap();
|
|
188
|
+
const defaultOperationHashingFn = (input) => {
|
|
189
|
+
if (!typeInfos.has(input.schema)) {
|
|
190
|
+
typeInfos.set(input.schema, new TypeInfo(input.schema));
|
|
191
|
+
}
|
|
192
|
+
const typeInfo = typeInfos.get(input.schema);
|
|
193
|
+
return hashOperation({
|
|
194
|
+
documentNode: input.document,
|
|
195
|
+
operationName: input.operationName ?? null,
|
|
196
|
+
schema: input.schema,
|
|
197
|
+
variables: null,
|
|
198
|
+
// Unstable feature, not using it for now
|
|
199
|
+
typeInfo
|
|
200
|
+
});
|
|
201
|
+
};
|
|
202
|
+
function setExecutionAttributesOnOperationSpan(input) {
|
|
203
|
+
const { hashOperationFn = defaultOperationHashingFn, args, ctx } = input;
|
|
204
|
+
const span = trace.getSpan(ctx);
|
|
205
|
+
if (span) {
|
|
206
|
+
const operation = getOperationASTFromDocument(
|
|
207
|
+
args.document,
|
|
208
|
+
args.operationName || void 0
|
|
209
|
+
);
|
|
210
|
+
span.setAttribute(SEMATTRS_GRAPHQL_OPERATION_TYPE, operation.operation);
|
|
211
|
+
const document = defaultPrintFn(args.document);
|
|
212
|
+
span.setAttribute(SEMATTRS_GRAPHQL_DOCUMENT, document);
|
|
213
|
+
const hash = hashOperationFn?.({ ...args });
|
|
214
|
+
if (hash) {
|
|
215
|
+
span.setAttribute(SEMATTRS_HIVE_GRAPHQL_OPERATION_HASH, hash);
|
|
216
|
+
}
|
|
217
|
+
const operationName = operation.name?.value;
|
|
218
|
+
if (operationName) {
|
|
219
|
+
span.setAttribute(SEMATTRS_GRAPHQL_OPERATION_NAME, operationName);
|
|
220
|
+
span.updateName(`graphql.operation ${operationName}`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
function createGraphqlContextBuildingSpan(input) {
|
|
225
|
+
const span = input.tracer.startSpan(
|
|
226
|
+
"graphql.context",
|
|
227
|
+
{ kind: SpanKind.INTERNAL },
|
|
228
|
+
input.ctx
|
|
229
|
+
);
|
|
230
|
+
return trace.setSpan(input.ctx, span);
|
|
231
|
+
}
|
|
232
|
+
function createGraphQLParseSpan(input) {
|
|
233
|
+
const span = input.tracer.startSpan(
|
|
234
|
+
"graphql.parse",
|
|
235
|
+
{
|
|
236
|
+
kind: SpanKind.INTERNAL
|
|
237
|
+
},
|
|
238
|
+
input.ctx
|
|
239
|
+
);
|
|
240
|
+
return trace.setSpan(input.ctx, span);
|
|
241
|
+
}
|
|
242
|
+
function setGraphQLParseAttributes(input) {
|
|
243
|
+
const span = trace.getSpan(input.ctx);
|
|
244
|
+
if (!span) {
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
if (input.query) {
|
|
248
|
+
span.setAttribute(SEMATTRS_GRAPHQL_DOCUMENT, input.query);
|
|
249
|
+
}
|
|
250
|
+
if (input.operationName) {
|
|
251
|
+
span.setAttribute(SEMATTRS_GRAPHQL_OPERATION_NAME, input.operationName);
|
|
252
|
+
}
|
|
253
|
+
if (input.result instanceof Error) {
|
|
254
|
+
span.setAttribute(SEMATTRS_HIVE_GRAPHQL_ERROR_COUNT, 1);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
function createGraphQLValidateSpan(input) {
|
|
258
|
+
const span = input.tracer.startSpan(
|
|
259
|
+
"graphql.validate",
|
|
260
|
+
{
|
|
261
|
+
attributes: {
|
|
262
|
+
[SEMATTRS_GRAPHQL_DOCUMENT]: input.query,
|
|
263
|
+
[SEMATTRS_GRAPHQL_OPERATION_NAME]: input.operationName
|
|
264
|
+
},
|
|
265
|
+
kind: SpanKind.INTERNAL
|
|
266
|
+
},
|
|
267
|
+
input.ctx
|
|
268
|
+
);
|
|
269
|
+
return trace.setSpan(input.ctx, span);
|
|
270
|
+
}
|
|
271
|
+
function setGraphQLValidateAttributes(input) {
|
|
272
|
+
const { result, ctx } = input;
|
|
273
|
+
const span = trace.getSpan(ctx);
|
|
274
|
+
if (!span) {
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
if (result instanceof Error) {
|
|
278
|
+
span.setStatus({
|
|
279
|
+
code: SpanStatusCode.ERROR,
|
|
280
|
+
message: result.message
|
|
281
|
+
});
|
|
282
|
+
} else if (Array.isArray(result) && result.length > 0) {
|
|
283
|
+
span.setAttribute(SEMATTRS_HIVE_GRAPHQL_ERROR_COUNT, result.length);
|
|
284
|
+
span.setStatus({
|
|
285
|
+
code: SpanStatusCode.ERROR,
|
|
286
|
+
message: result.map((e) => e.message).join(", ")
|
|
287
|
+
});
|
|
288
|
+
for (const error in result) {
|
|
289
|
+
span.recordException(error);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
function createGraphQLExecuteSpan(input) {
|
|
294
|
+
const span = input.tracer.startSpan(
|
|
295
|
+
"graphql.execute",
|
|
296
|
+
{ kind: SpanKind.INTERNAL },
|
|
297
|
+
input.ctx
|
|
298
|
+
);
|
|
299
|
+
return trace.setSpan(input.ctx, span);
|
|
300
|
+
}
|
|
301
|
+
function setGraphQLExecutionAttributes(input) {
|
|
302
|
+
const { ctx, args } = input;
|
|
303
|
+
const span = trace.getSpan(ctx);
|
|
304
|
+
if (!span) {
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
const operation = getOperationASTFromDocument(
|
|
308
|
+
args.document,
|
|
309
|
+
args.operationName || void 0
|
|
310
|
+
);
|
|
311
|
+
span.setAttribute(SEMATTRS_GRAPHQL_OPERATION_TYPE, operation.operation);
|
|
312
|
+
const operationName = operation.name?.value;
|
|
313
|
+
if (operationName) {
|
|
314
|
+
span.setAttribute(SEMATTRS_GRAPHQL_OPERATION_NAME, operationName);
|
|
315
|
+
}
|
|
316
|
+
const document = defaultPrintFn(input.args.document);
|
|
317
|
+
span.setAttribute(SEMATTRS_GRAPHQL_DOCUMENT, document);
|
|
318
|
+
}
|
|
319
|
+
function setGraphQLExecutionResultAttributes(input) {
|
|
320
|
+
const { ctx, result } = input;
|
|
321
|
+
const span = trace.getSpan(ctx);
|
|
322
|
+
if (!span) {
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
if (input.subgraphNames?.length) {
|
|
326
|
+
span.setAttribute(
|
|
327
|
+
SEMATTRS_HIVE_GATEWAY_OPERATION_SUBGRAPH_NAMES,
|
|
328
|
+
input.subgraphNames
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
if (!isAsyncIterable(result) && // FIXME: Handle async iterable too
|
|
332
|
+
result.errors && result.errors.length > 0) {
|
|
333
|
+
span.setAttribute(SEMATTRS_HIVE_GRAPHQL_ERROR_COUNT, result.errors.length);
|
|
334
|
+
span.setStatus({
|
|
335
|
+
code: SpanStatusCode.ERROR,
|
|
336
|
+
message: result.errors.map((e) => e.message).join(", ")
|
|
337
|
+
});
|
|
338
|
+
const codes = [];
|
|
339
|
+
for (const error of result.errors) {
|
|
340
|
+
span.recordException(error);
|
|
341
|
+
if (error.extensions["code"]) {
|
|
342
|
+
codes.push(`${error.extensions["code"]}`);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
if (codes.length > 0) {
|
|
346
|
+
span.setAttribute(SEMATTRS_HIVE_GRAPHQL_ERROR_CODES, codes);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
function createSubgraphExecuteSpan(input) {
|
|
351
|
+
const operation = getOperationASTFromDocument(
|
|
352
|
+
input.executionRequest.document,
|
|
353
|
+
input.executionRequest.operationName
|
|
354
|
+
);
|
|
355
|
+
const span = input.tracer.startSpan(
|
|
356
|
+
`subgraph.execute (${input.subgraphName})`,
|
|
357
|
+
{
|
|
358
|
+
attributes: {
|
|
359
|
+
[SEMATTRS_GRAPHQL_OPERATION_NAME]: operation.name?.value,
|
|
360
|
+
[SEMATTRS_GRAPHQL_DOCUMENT]: defaultPrintFn(
|
|
361
|
+
input.executionRequest.document
|
|
362
|
+
),
|
|
363
|
+
[SEMATTRS_GRAPHQL_OPERATION_TYPE]: operation.operation,
|
|
364
|
+
[SEMATTRS_HIVE_GATEWAY_UPSTREAM_SUBGRAPH_NAME]: input.subgraphName
|
|
365
|
+
},
|
|
366
|
+
kind: SpanKind.CLIENT
|
|
367
|
+
},
|
|
368
|
+
input.ctx
|
|
369
|
+
);
|
|
370
|
+
return trace.setSpan(input.ctx, span);
|
|
371
|
+
}
|
|
372
|
+
function createUpstreamHttpFetchSpan(input) {
|
|
373
|
+
const span = input.tracer.startSpan(
|
|
374
|
+
"http.fetch",
|
|
375
|
+
{
|
|
376
|
+
attributes: {},
|
|
377
|
+
kind: SpanKind.CLIENT
|
|
378
|
+
},
|
|
379
|
+
input.ctx
|
|
380
|
+
);
|
|
381
|
+
return trace.setSpan(input.ctx, span);
|
|
382
|
+
}
|
|
383
|
+
function setUpstreamFetchAttributes(input) {
|
|
384
|
+
const { ctx, url, options: fetchOptions } = input;
|
|
385
|
+
const span = trace.getSpan(ctx);
|
|
386
|
+
if (!span) {
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
const urlObj = new URL(input.url);
|
|
390
|
+
span.setAttribute(SEMATTRS_HTTP_METHOD, fetchOptions.method ?? "GET");
|
|
391
|
+
span.setAttribute(SEMATTRS_HTTP_URL, url);
|
|
392
|
+
span.setAttribute(SEMATTRS_NET_HOST_NAME, urlObj.hostname);
|
|
393
|
+
span.setAttribute(SEMATTRS_HTTP_HOST, urlObj.host);
|
|
394
|
+
span.setAttribute(SEMATTRS_HTTP_ROUTE, urlObj.pathname);
|
|
395
|
+
span.setAttribute(SEMATTRS_HTTP_SCHEME, urlObj.protocol);
|
|
396
|
+
if (input.executionRequest && isRetryExecutionRequest(input.executionRequest)) {
|
|
397
|
+
const { attempt } = getRetryInfo(input.executionRequest);
|
|
398
|
+
if (attempt > 0) {
|
|
399
|
+
span.setAttribute("http.request.resend_count", attempt);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
function setUpstreamFetchResponseAttributes(input) {
|
|
404
|
+
const { ctx, response } = input;
|
|
405
|
+
const span = trace.getSpan(ctx);
|
|
406
|
+
if (!span) {
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
span.setAttribute(SEMATTRS_HTTP_STATUS_CODE, response.status);
|
|
410
|
+
span.setStatus({
|
|
411
|
+
code: response.ok ? SpanStatusCode.OK : SpanStatusCode.ERROR,
|
|
412
|
+
message: response.ok ? void 0 : response.statusText
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
function recordCacheEvent(event, payload) {
|
|
416
|
+
trace.getActiveSpan()?.addEvent("gateway.cache." + event, {
|
|
417
|
+
"gateway.cache.key": payload.key,
|
|
418
|
+
"gateway.cache.ttl": payload.ttl
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
function recordCacheError(action, error, payload) {
|
|
422
|
+
trace.getActiveSpan()?.addEvent("gateway.cache.error", {
|
|
423
|
+
"gateway.cache.key": payload.key,
|
|
424
|
+
"gateway.cache.ttl": payload.ttl,
|
|
425
|
+
"gateway.cache.action": action,
|
|
426
|
+
[SEMATTRS_EXCEPTION_TYPE]: "code" in error ? error.code : error.message,
|
|
427
|
+
[SEMATTRS_EXCEPTION_MESSAGE]: error.message,
|
|
428
|
+
[SEMATTRS_EXCEPTION_STACKTRACE]: error.stack
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
const responseCacheSymbol = Symbol.for("servedFromResponseCache");
|
|
432
|
+
function setExecutionResultAttributes(input) {
|
|
433
|
+
const span = trace.getSpan(input.ctx);
|
|
434
|
+
if (input.result && span) {
|
|
435
|
+
span.setAttribute(
|
|
436
|
+
"gateway.cache.response_cache",
|
|
437
|
+
input.result[responseCacheSymbol] ? "hit" : "miss"
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
function createSchemaLoadingSpan(inputs) {
|
|
442
|
+
const span = inputs.tracer.startSpan(
|
|
443
|
+
"gateway.schema",
|
|
444
|
+
{ attributes: { "gateway.schema.changed": false } },
|
|
445
|
+
inputs.ctx
|
|
446
|
+
);
|
|
447
|
+
const currentContext = context.active();
|
|
448
|
+
if (currentContext !== inputs.ctx) {
|
|
449
|
+
const currentSpan = trace.getActiveSpan();
|
|
450
|
+
currentSpan?.addLink({ context: span.spanContext() });
|
|
451
|
+
}
|
|
452
|
+
return trace.setSpan(ROOT_CONTEXT, span);
|
|
453
|
+
}
|
|
454
|
+
function setSchemaAttributes(inputs) {
|
|
455
|
+
const span = trace.getActiveSpan();
|
|
456
|
+
if (!span) {
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
span.setAttribute("gateway.schema.changed", true);
|
|
460
|
+
span.setAttribute("graphql.schema", printSchema(inputs.schema));
|
|
461
|
+
}
|
|
462
|
+
function registerException(ctx, error) {
|
|
463
|
+
const span = ctx && trace.getSpan(ctx);
|
|
464
|
+
if (!span) {
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
const message = error?.message?.toString() ?? error?.toString();
|
|
468
|
+
span.setStatus({ code: SpanStatusCode.ERROR, message });
|
|
469
|
+
span.recordException(error);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
function getEnvStr(key, opts = {}) {
|
|
473
|
+
const globalThat = opts.globalThis ?? globalThis;
|
|
474
|
+
let variable = globalThat.process?.env?.[key] || // @ts-expect-error can exist in wrangler and maybe other runtimes
|
|
475
|
+
globalThat.env?.[key] || // @ts-expect-error can exist in deno
|
|
476
|
+
globalThat.Deno?.env?.get(key) || // @ts-expect-error could be
|
|
477
|
+
globalThat[key];
|
|
478
|
+
if (variable != null) {
|
|
479
|
+
variable += "";
|
|
480
|
+
} else {
|
|
481
|
+
variable = void 0;
|
|
482
|
+
}
|
|
483
|
+
return variable?.trim();
|
|
484
|
+
}
|
|
485
|
+
function getEnvBool(key, opts = {}) {
|
|
486
|
+
return strToBool(getEnvStr(key, opts));
|
|
487
|
+
}
|
|
488
|
+
function strToBool(str) {
|
|
489
|
+
return ["1", "t", "true", "y", "yes", "on", "enabled"].includes(
|
|
490
|
+
(str || "").toLowerCase()
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
function isContextManagerCompatibleWithAsync() {
|
|
495
|
+
const symbol = Symbol();
|
|
496
|
+
const root = context.active();
|
|
497
|
+
return context.with(root.setValue(symbol, true), () => {
|
|
498
|
+
return new Promise((resolve) => {
|
|
499
|
+
setTimeout(() => {
|
|
500
|
+
resolve(context.active().getValue(symbol) || false);
|
|
501
|
+
});
|
|
502
|
+
});
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
const logLevelMap = {
|
|
506
|
+
ALL: DiagLogLevel.ALL,
|
|
507
|
+
VERBOSE: DiagLogLevel.VERBOSE,
|
|
508
|
+
DEBUG: DiagLogLevel.DEBUG,
|
|
509
|
+
INFO: DiagLogLevel.INFO,
|
|
510
|
+
WARN: DiagLogLevel.WARN,
|
|
511
|
+
ERROR: DiagLogLevel.ERROR,
|
|
512
|
+
NONE: DiagLogLevel.NONE
|
|
513
|
+
};
|
|
514
|
+
function diagLogLevelFromEnv() {
|
|
515
|
+
const value = getEnvStr("OTEL_LOG_LEVEL");
|
|
516
|
+
if (value == null) {
|
|
517
|
+
return void 0;
|
|
518
|
+
}
|
|
519
|
+
const resolvedLogLevel = logLevelMap[value.toUpperCase()];
|
|
520
|
+
if (resolvedLogLevel == null) {
|
|
521
|
+
diag.warn(
|
|
522
|
+
`Unknown log level "${value}", expected one of ${Object.keys(logLevelMap)}, using default`
|
|
523
|
+
);
|
|
524
|
+
return DiagLogLevel.INFO;
|
|
525
|
+
}
|
|
526
|
+
return resolvedLogLevel;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
const initializationTime = "performance" in globalThis ? performance.now() : void 0;
|
|
530
|
+
const otelCtxForRequestId = /* @__PURE__ */ new Map();
|
|
531
|
+
const HeadersTextMapGetter = {
|
|
532
|
+
keys(carrier) {
|
|
533
|
+
return [...carrier.keys()];
|
|
534
|
+
},
|
|
535
|
+
get(carrier, key) {
|
|
536
|
+
return carrier.get(key) || void 0;
|
|
537
|
+
}
|
|
538
|
+
};
|
|
539
|
+
function useOpenTelemetry(options) {
|
|
540
|
+
const inheritContext = options.inheritContext ?? true;
|
|
541
|
+
const propagateContext = options.propagateContext ?? true;
|
|
542
|
+
let useContextManager;
|
|
543
|
+
const traces = typeof options.traces === "object" ? options.traces : {};
|
|
544
|
+
let tracer;
|
|
545
|
+
let initSpan;
|
|
546
|
+
let pluginLogger = options.log && options.log.child("[OpenTelemetry] ");
|
|
547
|
+
function isParentEnabled(state) {
|
|
548
|
+
const parentState = getMostSpecificState(state);
|
|
549
|
+
return !parentState || !!parentState.otel;
|
|
550
|
+
}
|
|
551
|
+
function getContext(state) {
|
|
552
|
+
const specificState = getMostSpecificState(state)?.otel;
|
|
553
|
+
if (initSpan && !specificState) {
|
|
554
|
+
return initSpan;
|
|
555
|
+
}
|
|
556
|
+
if (useContextManager) {
|
|
557
|
+
return context.active();
|
|
558
|
+
}
|
|
559
|
+
return specificState?.current ?? ROOT_CONTEXT;
|
|
560
|
+
}
|
|
561
|
+
let preparation$ = init();
|
|
562
|
+
preparation$.then(() => {
|
|
563
|
+
preparation$ = fakePromise();
|
|
564
|
+
});
|
|
565
|
+
async function init() {
|
|
566
|
+
if (options.useContextManager !== false && !await isContextManagerCompatibleWithAsync()) {
|
|
567
|
+
useContextManager = false;
|
|
568
|
+
if (options.useContextManager === true) {
|
|
569
|
+
throw new Error(
|
|
570
|
+
"[OTEL] Context Manager usage is enabled, but the registered one is not compatible with async calls. Please use another context manager, such as `AsyncLocalStorageContextManager`."
|
|
571
|
+
);
|
|
572
|
+
}
|
|
573
|
+
} else {
|
|
574
|
+
useContextManager = options.useContextManager ?? true;
|
|
575
|
+
}
|
|
576
|
+
tracer = traces.tracer || trace.getTracer("gateway");
|
|
577
|
+
initSpan = trace.setSpan(
|
|
578
|
+
context.active(),
|
|
579
|
+
tracer.startSpan("gateway.initialization", {
|
|
580
|
+
startTime: initializationTime
|
|
581
|
+
})
|
|
582
|
+
);
|
|
583
|
+
if (!useContextManager) {
|
|
584
|
+
if (traces.spans?.schema) {
|
|
585
|
+
pluginLogger?.warn(
|
|
586
|
+
"Schema loading spans are disabled because no context manager is available"
|
|
587
|
+
);
|
|
588
|
+
}
|
|
589
|
+
traces.spans = traces.spans ?? {};
|
|
590
|
+
traces.spans.schema = false;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
const plugin = withState((getState) => ({
|
|
594
|
+
get tracer() {
|
|
595
|
+
return tracer;
|
|
596
|
+
},
|
|
597
|
+
getActiveContext: ({ state }) => getContext(state),
|
|
598
|
+
getHttpContext: (request) => {
|
|
599
|
+
return getState({ request }).forRequest.otel?.root;
|
|
600
|
+
},
|
|
601
|
+
getOperationContext: (context2) => {
|
|
602
|
+
return getState({ context: context2 }).forOperation.otel?.root;
|
|
603
|
+
},
|
|
604
|
+
getExecutionRequestContext: (executionRequest) => {
|
|
605
|
+
return getState({ executionRequest }).forSubgraphExecution.otel?.root;
|
|
606
|
+
},
|
|
607
|
+
instrumentation: {
|
|
608
|
+
request({ state: { forRequest }, request }, wrapped) {
|
|
609
|
+
if (!shouldTrace(traces.spans?.http, { request })) {
|
|
610
|
+
return wrapped();
|
|
611
|
+
}
|
|
612
|
+
const url = getURL(request);
|
|
613
|
+
return unfakePromise(
|
|
614
|
+
preparation$.then(() => {
|
|
615
|
+
const ctx = inheritContext ? propagation.extract(
|
|
616
|
+
context.active(),
|
|
617
|
+
request.headers,
|
|
618
|
+
HeadersTextMapGetter
|
|
619
|
+
) : context.active();
|
|
620
|
+
forRequest.otel = new OtelContextStack(
|
|
621
|
+
createHttpSpan({ ctx, request, tracer, url }).ctx
|
|
622
|
+
);
|
|
623
|
+
if (useContextManager) {
|
|
624
|
+
wrapped = context.bind(forRequest.otel.current, wrapped);
|
|
625
|
+
}
|
|
626
|
+
return wrapped();
|
|
627
|
+
}).catch((error) => {
|
|
628
|
+
registerException(forRequest.otel?.current, error);
|
|
629
|
+
throw error;
|
|
630
|
+
}).finally(() => {
|
|
631
|
+
const ctx = forRequest.otel?.root;
|
|
632
|
+
ctx && trace.getSpan(ctx)?.end();
|
|
633
|
+
})
|
|
634
|
+
);
|
|
635
|
+
},
|
|
636
|
+
operation({ context: gqlCtx, state: { forOperation, ...parentState } }, wrapped) {
|
|
637
|
+
if (!isParentEnabled(parentState) || !shouldTrace(traces.spans?.graphql, { context: gqlCtx })) {
|
|
638
|
+
return wrapped();
|
|
639
|
+
}
|
|
640
|
+
return unfakePromise(
|
|
641
|
+
preparation$.then(() => {
|
|
642
|
+
const ctx = getContext(parentState);
|
|
643
|
+
forOperation.otel = new OtelContextStack(
|
|
644
|
+
createGraphQLSpan({ tracer, ctx })
|
|
645
|
+
);
|
|
646
|
+
if (useContextManager) {
|
|
647
|
+
wrapped = context.bind(forOperation.otel.current, wrapped);
|
|
648
|
+
}
|
|
649
|
+
return fakePromise().then(wrapped).catch((err) => {
|
|
650
|
+
registerException(forOperation.otel?.current, err);
|
|
651
|
+
throw err;
|
|
652
|
+
}).finally(() => trace.getSpan(forOperation.otel.current)?.end());
|
|
653
|
+
})
|
|
654
|
+
);
|
|
655
|
+
},
|
|
656
|
+
context({ state, context: gqlCtx }, wrapped) {
|
|
657
|
+
if (!isParentEnabled(state) || !shouldTrace(traces.spans?.graphqlContextBuilding, {
|
|
658
|
+
context: gqlCtx
|
|
659
|
+
})) {
|
|
660
|
+
return wrapped();
|
|
661
|
+
}
|
|
662
|
+
const { forOperation } = state;
|
|
663
|
+
const ctx = getContext(state);
|
|
664
|
+
forOperation.otel.push(
|
|
665
|
+
createGraphqlContextBuildingSpan({ ctx, tracer })
|
|
666
|
+
);
|
|
667
|
+
if (useContextManager) {
|
|
668
|
+
wrapped = context.bind(forOperation.otel.current, wrapped);
|
|
669
|
+
}
|
|
670
|
+
try {
|
|
671
|
+
wrapped();
|
|
672
|
+
} catch (err) {
|
|
673
|
+
registerException(forOperation.otel?.current, err);
|
|
674
|
+
throw err;
|
|
675
|
+
} finally {
|
|
676
|
+
trace.getSpan(forOperation.otel.current)?.end();
|
|
677
|
+
forOperation.otel.pop();
|
|
678
|
+
}
|
|
679
|
+
},
|
|
680
|
+
parse({ state, context: gqlCtx }, wrapped) {
|
|
681
|
+
if (!isParentEnabled(state) || !shouldTrace(traces.spans?.graphqlParse, { context: gqlCtx })) {
|
|
682
|
+
return wrapped();
|
|
683
|
+
}
|
|
684
|
+
const ctx = getContext(state);
|
|
685
|
+
const { forOperation } = state;
|
|
686
|
+
forOperation.otel.push(createGraphQLParseSpan({ ctx, tracer }));
|
|
687
|
+
if (useContextManager) {
|
|
688
|
+
wrapped = context.bind(forOperation.otel.current, wrapped);
|
|
689
|
+
}
|
|
690
|
+
try {
|
|
691
|
+
wrapped();
|
|
692
|
+
} catch (err) {
|
|
693
|
+
registerException(forOperation.otel.current, err);
|
|
694
|
+
throw err;
|
|
695
|
+
} finally {
|
|
696
|
+
trace.getSpan(forOperation.otel.current)?.end();
|
|
697
|
+
forOperation.otel.pop();
|
|
698
|
+
}
|
|
699
|
+
},
|
|
700
|
+
validate({ state, context: gqlCtx }, wrapped) {
|
|
701
|
+
if (!isParentEnabled(state) || !shouldTrace(traces.spans?.graphqlValidate, { context: gqlCtx })) {
|
|
702
|
+
return wrapped();
|
|
703
|
+
}
|
|
704
|
+
const { forOperation } = state;
|
|
705
|
+
forOperation.otel.push(
|
|
706
|
+
createGraphQLValidateSpan({
|
|
707
|
+
ctx: getContext(state),
|
|
708
|
+
tracer,
|
|
709
|
+
query: gqlCtx.params.query?.trim(),
|
|
710
|
+
operationName: gqlCtx.params.operationName
|
|
711
|
+
})
|
|
712
|
+
);
|
|
713
|
+
if (useContextManager) {
|
|
714
|
+
wrapped = context.bind(forOperation.otel.current, wrapped);
|
|
715
|
+
}
|
|
716
|
+
try {
|
|
717
|
+
wrapped();
|
|
718
|
+
} catch (err) {
|
|
719
|
+
registerException(forOperation.otel?.current, err);
|
|
720
|
+
throw err;
|
|
721
|
+
} finally {
|
|
722
|
+
trace.getSpan(forOperation.otel.current)?.end();
|
|
723
|
+
forOperation.otel.pop();
|
|
724
|
+
}
|
|
725
|
+
},
|
|
726
|
+
execute({ state, context: gqlCtx }, wrapped) {
|
|
727
|
+
if (!isParentEnabled(state) || !shouldTrace(traces.spans?.graphqlExecute, { context: gqlCtx })) {
|
|
728
|
+
state.forOperation.skipExecuteSpan = true;
|
|
729
|
+
return wrapped();
|
|
730
|
+
}
|
|
731
|
+
const ctx = getContext(state);
|
|
732
|
+
const { forOperation } = state;
|
|
733
|
+
forOperation.otel?.push(createGraphQLExecuteSpan({ ctx, tracer }));
|
|
734
|
+
if (useContextManager) {
|
|
735
|
+
wrapped = context.bind(forOperation.otel.current, wrapped);
|
|
736
|
+
}
|
|
737
|
+
return unfakePromise(
|
|
738
|
+
fakePromise().then(wrapped).catch((err) => {
|
|
739
|
+
registerException(forOperation.otel.current, err);
|
|
740
|
+
throw err;
|
|
741
|
+
}).finally(() => {
|
|
742
|
+
trace.getSpan(forOperation.otel.current)?.end();
|
|
743
|
+
forOperation.otel.pop();
|
|
744
|
+
})
|
|
745
|
+
);
|
|
746
|
+
},
|
|
747
|
+
subgraphExecute({
|
|
748
|
+
state: { forSubgraphExecution, ...parentState },
|
|
749
|
+
executionRequest,
|
|
750
|
+
subgraphName
|
|
751
|
+
}, wrapped) {
|
|
752
|
+
const isIntrospection = !executionRequest.context.params;
|
|
753
|
+
if (!isParentEnabled(parentState) || parentState.forOperation?.skipExecuteSpan || !shouldTrace(
|
|
754
|
+
isIntrospection ? traces.spans?.schema : traces.spans?.subgraphExecute,
|
|
755
|
+
{
|
|
756
|
+
subgraphName,
|
|
757
|
+
executionRequest
|
|
758
|
+
}
|
|
759
|
+
)) {
|
|
760
|
+
return wrapped();
|
|
761
|
+
}
|
|
762
|
+
const parentContext = isIntrospection ? context.active() : getContext(parentState);
|
|
763
|
+
forSubgraphExecution.otel = new OtelContextStack(
|
|
764
|
+
createSubgraphExecuteSpan({
|
|
765
|
+
ctx: parentContext,
|
|
766
|
+
tracer,
|
|
767
|
+
executionRequest,
|
|
768
|
+
subgraphName
|
|
769
|
+
})
|
|
770
|
+
);
|
|
771
|
+
if (useContextManager) {
|
|
772
|
+
wrapped = context.bind(forSubgraphExecution.otel.current, wrapped);
|
|
773
|
+
}
|
|
774
|
+
return unfakePromise(
|
|
775
|
+
fakePromise().then(wrapped).catch((err) => {
|
|
776
|
+
registerException(forSubgraphExecution.otel.current, err);
|
|
777
|
+
throw err;
|
|
778
|
+
}).finally(() => {
|
|
779
|
+
trace.getSpan(forSubgraphExecution.otel.current)?.end();
|
|
780
|
+
forSubgraphExecution.otel.pop();
|
|
781
|
+
})
|
|
782
|
+
);
|
|
783
|
+
},
|
|
784
|
+
fetch({ state, executionRequest }, wrapped) {
|
|
785
|
+
if (isRetryExecutionRequest$1(executionRequest)) {
|
|
786
|
+
state = getState(getRetryInfo$1(executionRequest));
|
|
787
|
+
}
|
|
788
|
+
if (!isParentEnabled(state) || !shouldTrace(traces.spans?.upstreamFetch, { executionRequest })) {
|
|
789
|
+
return wrapped();
|
|
790
|
+
}
|
|
791
|
+
return unfakePromise(
|
|
792
|
+
preparation$.then(() => {
|
|
793
|
+
const { forSubgraphExecution } = state;
|
|
794
|
+
const ctx = createUpstreamHttpFetchSpan({
|
|
795
|
+
ctx: getContext(state),
|
|
796
|
+
tracer
|
|
797
|
+
});
|
|
798
|
+
forSubgraphExecution?.otel.push(ctx);
|
|
799
|
+
if (useContextManager) {
|
|
800
|
+
wrapped = context.bind(ctx, wrapped);
|
|
801
|
+
}
|
|
802
|
+
return fakePromise().then(wrapped).catch((err) => {
|
|
803
|
+
registerException(ctx, err);
|
|
804
|
+
throw err;
|
|
805
|
+
}).finally(() => {
|
|
806
|
+
trace.getSpan(ctx)?.end();
|
|
807
|
+
forSubgraphExecution?.otel.pop();
|
|
808
|
+
});
|
|
809
|
+
})
|
|
810
|
+
);
|
|
811
|
+
},
|
|
812
|
+
schema(_, wrapped) {
|
|
813
|
+
if (!shouldTrace(traces.spans?.schema, null)) {
|
|
814
|
+
return wrapped();
|
|
815
|
+
}
|
|
816
|
+
return unfakePromise(
|
|
817
|
+
preparation$.then(() => {
|
|
818
|
+
const ctx = createSchemaLoadingSpan({
|
|
819
|
+
ctx: initSpan ?? ROOT_CONTEXT,
|
|
820
|
+
tracer
|
|
821
|
+
});
|
|
822
|
+
return fakePromise().then(() => context.with(ctx, wrapped)).catch((err) => {
|
|
823
|
+
trace.getSpan(ctx)?.recordException(err);
|
|
824
|
+
}).finally(() => {
|
|
825
|
+
trace.getSpan(ctx)?.end();
|
|
826
|
+
});
|
|
827
|
+
})
|
|
828
|
+
);
|
|
829
|
+
}
|
|
830
|
+
},
|
|
831
|
+
onYogaInit({ yoga }) {
|
|
832
|
+
pluginLogger ??= new Logger({
|
|
833
|
+
writers: [
|
|
834
|
+
{
|
|
835
|
+
write(level, attrs, msg) {
|
|
836
|
+
level = level === "trace" ? "debug" : level;
|
|
837
|
+
yoga.logger[level](msg, attrs);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
]
|
|
841
|
+
}).child("[OpenTelemetry] ");
|
|
842
|
+
if (options.configureDiagLogger !== false) {
|
|
843
|
+
const logLevel = diagLogLevelFromEnv();
|
|
844
|
+
if (logLevel) {
|
|
845
|
+
const diagLog = pluginLogger.child("[diag] ");
|
|
846
|
+
diagLog.verbose = diagLog.trace;
|
|
847
|
+
diag.setLogger(diagLog, logLevel);
|
|
848
|
+
setGlobalErrorHandler((err) => diagLog.error(err));
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
pluginLogger.debug(
|
|
852
|
+
`context manager is ${useContextManager ? "enabled" : "disabled"}`
|
|
853
|
+
);
|
|
854
|
+
},
|
|
855
|
+
onRequest({ state, serverContext }) {
|
|
856
|
+
if (!useContextManager) {
|
|
857
|
+
const requestId = (
|
|
858
|
+
// TODO: serverContext.log will not be available in Yoga, this will be fixed when Hive Logger is integrated into Yoga
|
|
859
|
+
serverContext.log?.attrs?.[
|
|
860
|
+
// @ts-expect-error even if the attrs is an array this will work
|
|
861
|
+
"requestId"
|
|
862
|
+
]
|
|
863
|
+
);
|
|
864
|
+
if (typeof requestId === "string") {
|
|
865
|
+
otelCtxForRequestId.set(requestId, getContext(state));
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
},
|
|
869
|
+
onEnveloped({ state, extendContext }) {
|
|
870
|
+
extendContext({
|
|
871
|
+
openTelemetry: {
|
|
872
|
+
tracer,
|
|
873
|
+
getHttpContext: (request) => {
|
|
874
|
+
const { forRequest } = request ? getState({ request }) : state;
|
|
875
|
+
return forRequest.otel?.root;
|
|
876
|
+
},
|
|
877
|
+
getOperationContext: (context2) => {
|
|
878
|
+
const { forOperation } = context2 ? getState({ context: context2 }) : state;
|
|
879
|
+
return forOperation.otel?.root;
|
|
880
|
+
},
|
|
881
|
+
getExecutionRequestContext: (executionRequest) => {
|
|
882
|
+
return getState({ executionRequest }).forSubgraphExecution.otel?.root;
|
|
883
|
+
},
|
|
884
|
+
getActiveContext: (contextMatcher) => getContext(contextMatcher ? getState(contextMatcher) : state)
|
|
885
|
+
}
|
|
886
|
+
});
|
|
887
|
+
},
|
|
888
|
+
onCacheGet: (payload) => shouldTrace(traces.events?.cache, { key: payload.key, action: "read" }) ? {
|
|
889
|
+
onCacheMiss: () => recordCacheEvent("miss", payload),
|
|
890
|
+
onCacheHit: () => recordCacheEvent("hit", payload),
|
|
891
|
+
onCacheGetError: ({ error }) => recordCacheError("read", error, payload)
|
|
892
|
+
} : void 0,
|
|
893
|
+
onCacheSet: (payload) => shouldTrace(traces.events?.cache, { key: payload.key, action: "write" }) ? {
|
|
894
|
+
onCacheSetDone: () => recordCacheEvent("write", payload),
|
|
895
|
+
onCacheSetError: ({ error }) => recordCacheError("write", error, payload)
|
|
896
|
+
} : void 0,
|
|
897
|
+
onResponse({ response, state, serverContext }) {
|
|
898
|
+
state.forRequest.otel && setResponseAttributes(state.forRequest.otel.root, response);
|
|
899
|
+
if (!useContextManager) {
|
|
900
|
+
const requestId = (
|
|
901
|
+
// TODO: serverContext.log will not be available in Yoga, this will be fixed when Hive Logger is integrated into Yoga
|
|
902
|
+
serverContext.log?.attrs?.[
|
|
903
|
+
// @ts-expect-error even if the attrs is an array this will work
|
|
904
|
+
"requestId"
|
|
905
|
+
]
|
|
906
|
+
);
|
|
907
|
+
if (typeof requestId === "string") {
|
|
908
|
+
otelCtxForRequestId.delete(requestId);
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
},
|
|
912
|
+
onParams({ state, context: gqlCtx, params }) {
|
|
913
|
+
if (!isParentEnabled(state) || !shouldTrace(traces.spans?.graphql, { context: gqlCtx })) {
|
|
914
|
+
return;
|
|
915
|
+
}
|
|
916
|
+
const ctx = getContext(state);
|
|
917
|
+
setParamsAttributes({ ctx, params });
|
|
918
|
+
},
|
|
919
|
+
onExecutionResult({ result, context: gqlCtx, state }) {
|
|
920
|
+
if (!isParentEnabled(state) || !shouldTrace(traces.spans?.graphql, { context: gqlCtx })) {
|
|
921
|
+
return;
|
|
922
|
+
}
|
|
923
|
+
setExecutionResultAttributes({ ctx: getContext(state), result });
|
|
924
|
+
},
|
|
925
|
+
onParse({ state, context: gqlCtx }) {
|
|
926
|
+
if (!isParentEnabled(state) || !shouldTrace(traces.spans?.graphqlParse, { context: gqlCtx })) {
|
|
927
|
+
return;
|
|
928
|
+
}
|
|
929
|
+
return ({ result }) => {
|
|
930
|
+
setGraphQLParseAttributes({
|
|
931
|
+
ctx: getContext(state),
|
|
932
|
+
operationName: gqlCtx.params.operationName,
|
|
933
|
+
query: gqlCtx.params.query?.trim(),
|
|
934
|
+
result
|
|
935
|
+
});
|
|
936
|
+
};
|
|
937
|
+
},
|
|
938
|
+
onValidate({ state, context: gqlCtx }) {
|
|
939
|
+
if (!isParentEnabled(state) || !shouldTrace(traces.spans?.graphqlValidate, { context: gqlCtx })) {
|
|
940
|
+
return;
|
|
941
|
+
}
|
|
942
|
+
return ({ result }) => {
|
|
943
|
+
setGraphQLValidateAttributes({ ctx: getContext(state), result });
|
|
944
|
+
};
|
|
945
|
+
},
|
|
946
|
+
onExecute({ state, args }) {
|
|
947
|
+
if (!isParentEnabled(state)) {
|
|
948
|
+
return;
|
|
949
|
+
}
|
|
950
|
+
setExecutionAttributesOnOperationSpan({
|
|
951
|
+
ctx: state.forOperation.otel.root,
|
|
952
|
+
args,
|
|
953
|
+
hashOperationFn: options.hashOperation
|
|
954
|
+
});
|
|
955
|
+
if (state.forOperation.skipExecuteSpan) {
|
|
956
|
+
return;
|
|
957
|
+
}
|
|
958
|
+
const ctx = getContext(state);
|
|
959
|
+
setGraphQLExecutionAttributes({ ctx, args });
|
|
960
|
+
state.forOperation.subgraphNames = [];
|
|
961
|
+
return {
|
|
962
|
+
onExecuteDone({ result }) {
|
|
963
|
+
setGraphQLExecutionResultAttributes({
|
|
964
|
+
ctx,
|
|
965
|
+
result,
|
|
966
|
+
subgraphNames: state.forOperation.subgraphNames
|
|
967
|
+
});
|
|
968
|
+
}
|
|
969
|
+
};
|
|
970
|
+
},
|
|
971
|
+
onSubgraphExecute({ subgraphName, state }) {
|
|
972
|
+
state.forOperation?.subgraphNames?.push(subgraphName);
|
|
973
|
+
},
|
|
974
|
+
onFetch(payload) {
|
|
975
|
+
const { url, setFetchFn, fetchFn, executionRequest } = payload;
|
|
976
|
+
let { state } = payload;
|
|
977
|
+
if (executionRequest && isRetryExecutionRequest$1(executionRequest)) {
|
|
978
|
+
state = getState(getRetryInfo$1(executionRequest));
|
|
979
|
+
}
|
|
980
|
+
if (propagateContext) {
|
|
981
|
+
setFetchFn((url2, options2, ...args) => {
|
|
982
|
+
const reqHeaders = getHeadersObj(options2?.headers || {});
|
|
983
|
+
propagation.inject(getContext(state), reqHeaders);
|
|
984
|
+
return fetchFn(url2, { ...options2, headers: reqHeaders }, ...args);
|
|
985
|
+
});
|
|
986
|
+
}
|
|
987
|
+
if (!isParentEnabled(state) || !shouldTrace(traces.spans?.upstreamFetch, { executionRequest })) {
|
|
988
|
+
return;
|
|
989
|
+
}
|
|
990
|
+
const ctx = getContext(state);
|
|
991
|
+
setUpstreamFetchAttributes({
|
|
992
|
+
ctx,
|
|
993
|
+
url,
|
|
994
|
+
options: payload.options,
|
|
995
|
+
executionRequest
|
|
996
|
+
});
|
|
997
|
+
return ({ response }) => {
|
|
998
|
+
setUpstreamFetchResponseAttributes({ ctx, response });
|
|
999
|
+
};
|
|
1000
|
+
},
|
|
1001
|
+
onSchemaChange(payload) {
|
|
1002
|
+
setSchemaAttributes(payload);
|
|
1003
|
+
if (initSpan) {
|
|
1004
|
+
trace.getSpan(initSpan)?.end();
|
|
1005
|
+
initSpan = null;
|
|
1006
|
+
}
|
|
1007
|
+
},
|
|
1008
|
+
onDispose() {
|
|
1009
|
+
if (options.flushOnDispose !== false) {
|
|
1010
|
+
const flushMethod = options.flushOnDispose ?? "forceFlush";
|
|
1011
|
+
const provider = trace.getTracerProvider();
|
|
1012
|
+
if (flushMethod in provider && typeof provider[flushMethod] === "function") {
|
|
1013
|
+
return provider[flushMethod]();
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
}));
|
|
1018
|
+
hive.setPluginUtils(plugin);
|
|
1019
|
+
return plugin;
|
|
1020
|
+
}
|
|
1021
|
+
function shouldTrace(value, args) {
|
|
1022
|
+
if (value == null) {
|
|
1023
|
+
return true;
|
|
1024
|
+
}
|
|
1025
|
+
if (typeof value === "function") {
|
|
1026
|
+
return value(args);
|
|
1027
|
+
}
|
|
1028
|
+
return value;
|
|
1029
|
+
}
|
|
1030
|
+
function getURL(request) {
|
|
1031
|
+
if ("parsedUrl" in request) {
|
|
1032
|
+
return request.parsedUrl;
|
|
1033
|
+
}
|
|
1034
|
+
return new URL(request.url, "http://localhost");
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
export { SEMATTRS_GRAPHQL_DOCUMENT as S, SEMATTRS_GRAPHQL_OPERATION_TYPE as a, SEMATTRS_GRAPHQL_OPERATION_NAME as b, SEMATTRS_HIVE_GRAPHQL_OPERATION_HASH as c, SEMATTRS_HIVE_GRAPHQL_ERROR_COUNT as d, SEMATTRS_HIVE_GRAPHQL_ERROR_CODES as e, SEMATTRS_HIVE_GATEWAY_UPSTREAM_SUBGRAPH_NAME as f, SEMATTRS_HIVE_GATEWAY_OPERATION_SUBGRAPH_NAMES as g, getEnvBool as h, getEnvStr as i, otelCtxForRequestId as o, useOpenTelemetry as u };
|