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