Skip to content

Commit 6a64d1d

Browse files
feat(opentelemetry): allow more customization for hive tracing setup (#1611)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent ce83f35 commit 6a64d1d

File tree

5 files changed

+261
-170
lines changed

5 files changed

+261
-170
lines changed

.changeset/thirty-wasps-design.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@graphql-hive/plugin-opentelemetry': minor
3+
---
4+
5+
It is now possible to fully configure the OpenTelemetry setup when using `hiveTracingSetup`. You can now provide a `resource` and a `samplingRate` (among other options).

e2e/opentelemetry/opentelemetry.e2e.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ describe('OpenTelemetry', () => {
253253
const { execute } = await gateway({
254254
supergraph,
255255
env: {
256-
DISABLED_OPENTELEMETRY_SETUP: '1',
256+
DISABLE_OPENTELEMETRY_SETUP: '1',
257257
OTEL_SERVICE_NAME: serviceName,
258258
OTEL_SERVICE_VERSION: '1.0.0',
259259
},

packages/gateway/src/commands/handleOpenTelemetryCLIOpts.ts

Lines changed: 99 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { fakePromise } from '@graphql-tools/utils';
21
import {
32
BatchSpanProcessor,
43
SpanProcessor,
@@ -31,108 +30,119 @@ export async function handleOpenTelemetryCLIOpts(
3130
'Initializing OpenTelemetry SDK',
3231
);
3332

34-
return fakePromise().then(async () => {
35-
const { openTelemetrySetup, HiveTracingSpanProcessor } = await import(
36-
'@graphql-hive/plugin-opentelemetry/setup'
37-
);
38-
const processors: SpanProcessor[] = [];
39-
40-
const logAttributes = {
41-
traceEndpoints: [] as {
42-
url: string | null;
43-
type?: string;
44-
target?: string;
45-
}[],
46-
contextManager: false,
33+
const { openTelemetrySetup, HiveTracingSpanProcessor } = await import(
34+
'@graphql-hive/plugin-opentelemetry/setup'
35+
);
36+
const processors: SpanProcessor[] = [];
37+
38+
const logAttributes = {
39+
traceEndpoints: [] as {
40+
url: string | null;
41+
type?: string;
42+
target?: string;
43+
}[],
44+
contextManager: false,
45+
};
46+
47+
let integration: { name: string; source: { flag: string; env: string } };
48+
49+
if (openTelemetry) {
50+
const otelEndpoint =
51+
typeof openTelemetry === 'string'
52+
? openTelemetry
53+
: getEnvStr('OTEL_EXPORTER_OTLP_ENDPOINT');
54+
55+
log.debug({ exporterType, otelEndpoint }, 'Setting up OTLP Exporter');
56+
57+
integration = {
58+
name: 'OpenTelemetry',
59+
source: { flag: '--opentelemetry', env: 'OPENTELEMETRY' },
4760
};
4861

49-
let integrationName: string;
62+
logAttributes.traceEndpoints.push({
63+
url: otelEndpoint ?? null,
64+
type: exporterType,
65+
});
5066

51-
if (openTelemetry) {
52-
const otelEndpoint =
53-
typeof openTelemetry === 'string'
54-
? openTelemetry
55-
: getEnvStr('OTEL_EXPORTER_OTLP_ENDPOINT');
67+
log.debug({ type: exporterType }, 'Loading OpenTelemetry exporter');
5668

57-
log.debug({ exporterType, otelEndpoint }, 'Setting up OTLP Exporter');
69+
const { OTLPTraceExporter } = await import(
70+
`@opentelemetry/exporter-trace-${exporterType}`
71+
);
5872

59-
integrationName = 'OpenTelemetry';
60-
logAttributes.traceEndpoints.push({
61-
url: otelEndpoint ?? null,
62-
type: exporterType,
63-
});
73+
processors.push(
74+
new BatchSpanProcessor(new OTLPTraceExporter({ url: otelEndpoint })),
75+
);
76+
}
6477

65-
log.debug({ type: exporterType }, 'Loading OpenTelemetry exporter');
78+
if (accessToken) {
79+
log.debug({ target, traceEndpoint }, 'Setting up Hive Tracing');
6680

67-
const { OTLPTraceExporter } = await import(
68-
`@opentelemetry/exporter-trace-${exporterType}`
69-
);
70-
71-
processors.push(
72-
new BatchSpanProcessor(new OTLPTraceExporter({ url: otelEndpoint })),
81+
integration ??= {
82+
name: 'Hive Tracing',
83+
source: {
84+
flag: '--hive-trace-access-token',
85+
env: 'HIVE_TRACE_ACCESS_TOKEN',
86+
},
87+
};
88+
if (!target) {
89+
ctx.log.error(
90+
'Hive tracing needs a target. Please provide it through "--hive-target <target>"',
7391
);
92+
process.exit(1);
7493
}
7594

76-
if (accessToken) {
77-
log.debug({ target, traceEndpoint }, 'Setting up Hive Tracing');
78-
79-
integrationName ??= 'Hive Tracing';
80-
if (!target) {
81-
ctx.log.error(
82-
'Hive tracing needs a target. Please provide it through "--hive-target <target>"',
83-
);
84-
process.exit(1);
85-
}
95+
logAttributes.traceEndpoints.push({
96+
url: traceEndpoint,
97+
type: 'hive tracing',
98+
target,
99+
});
86100

87-
logAttributes.traceEndpoints.push({
88-
url: traceEndpoint,
89-
type: 'hive tracing',
101+
processors.push(
102+
new HiveTracingSpanProcessor({
103+
accessToken,
90104
target,
91-
});
92-
93-
processors.push(
94-
new HiveTracingSpanProcessor({
95-
accessToken,
96-
target,
97-
endpoint: traceEndpoint,
98-
}),
99-
);
100-
}
101-
102-
log.debug('Trying to load AsyncLocalStorage based Context Manager');
103-
104-
const contextManager = await import('@opentelemetry/context-async-hooks')
105-
.then((module) => {
106-
logAttributes.contextManager = true;
107-
return new module.AsyncLocalStorageContextManager();
108-
})
109-
.catch(() => null);
110-
111-
openTelemetrySetup({
112-
log,
113-
traces: { processors },
114-
resource: await detectResource().catch((err) => {
115-
if (
116-
err &&
117-
typeof err === 'object' &&
118-
'code' in err &&
119-
err.code === 'ERR_MODULE_NOT_FOUND'
120-
) {
121-
ctx.log.warn(
122-
err,
123-
`NodeJS modules necessary for environment detection is missing, please install it to auto-detect the environment`,
124-
);
125-
return undefined;
126-
}
127-
throw err;
105+
endpoint: traceEndpoint,
128106
}),
129-
contextManager,
130-
});
131-
132-
log.info(logAttributes, `${integrationName!} integration is enabled`);
133-
134-
return true;
107+
);
108+
}
109+
110+
log.debug('Trying to load AsyncLocalStorage based Context Manager');
111+
112+
const contextManager = await import('@opentelemetry/context-async-hooks')
113+
.then((module) => {
114+
logAttributes.contextManager = true;
115+
return new module.AsyncLocalStorageContextManager();
116+
})
117+
.catch(() => null);
118+
119+
openTelemetrySetup({
120+
log,
121+
traces: { processors },
122+
resource: await detectResource().catch((err) => {
123+
if (
124+
err &&
125+
typeof err === 'object' &&
126+
'code' in err &&
127+
err.code === 'ERR_MODULE_NOT_FOUND'
128+
) {
129+
ctx.log.warn(
130+
err,
131+
`NodeJS modules necessary for environment detection is missing, please install it to auto-detect the environment`,
132+
);
133+
return undefined;
134+
}
135+
throw err;
136+
}),
137+
contextManager,
138+
_initialization: {
139+
name: integration!.name,
140+
source: `cli flag (${integration!.source.flag}) or environment variables (${integration!.source.env})`,
141+
logAttributes,
142+
},
135143
});
144+
145+
return true;
136146
}
137147

138148
return false;

0 commit comments

Comments
 (0)