Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/proud-tips-invent.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@graphql-hive/plugin-opentelemetry': patch
---

Have a default endpoint for Hive Tracing
5 changes: 5 additions & 0 deletions .changeset/shaggy-seals-return.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@graphql-hive/plugin-opentelemetry': patch
---

Improved default resource service name and version to use Hive Gateway
24 changes: 19 additions & 5 deletions e2e/cloudflare-workers/cloudflare-workers.e2e.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import os from 'os';
import { createTenv, getAvailablePort, type Container } from '@internal/e2e';
import { getLocalhost, isDebug } from '@internal/testing';
import { getLocalhost } from '@internal/testing';
import { fetch } from '@whatwg-node/fetch';
import { ExecutionResult } from 'graphql';
import { beforeAll, describe, expect, it } from 'vitest';
Expand Down Expand Up @@ -35,7 +35,13 @@ describe.skipIf(gatewayRunner !== 'node' || process.version.startsWith('v1'))(
additionalContainerPorts: [16686],
healthcheck: ['CMD-SHELL', 'wget --spider http://0.0.0.0:14269'],
});
jaegerHostname = await getLocalhost(jaeger.port);
try {
jaegerHostname = await getLocalhost(jaeger.port);
} catch {
throw new Error(
`Jaeger unavailable\n${jaeger.getStd('both') || 'no output'}`,
);
}
});

type JaegerTracesApiResponse = {
Expand Down Expand Up @@ -83,7 +89,7 @@ describe.skipIf(gatewayRunner !== 'node' || process.version.startsWith('v1'))(
OTEL_SERVICE_NAME: string;
}) {
const port = await getAvailablePort();
await spawn([
const [proc] = await spawn([
'yarn',
'wrangler',
'dev',
Expand All @@ -95,9 +101,17 @@ describe.skipIf(gatewayRunner !== 'node' || process.version.startsWith('v1'))(
'OTEL_SERVICE_NAME:' + env.OTEL_SERVICE_NAME,
'--var',
'OTEL_LOG_LEVEL:debug',
...(isDebug() ? ['--var', 'DEBUG:1'] : []),
'--var',
'DEBUG:1',
]);
const hostname = await getLocalhost(port);
let hostname: string;
try {
hostname = await getLocalhost(port, undefined, 30_000);
} catch {
throw new Error(
`Wrangler unavailable\n${proc.getStd('both') || 'no output'}`,
);
}
return {
url: `${hostname}:${port}`,
async execute({
Expand Down
3 changes: 2 additions & 1 deletion internal/testing/src/getLocalhost.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ export const hostnames = ['0.0.0.0', '127.0.0.1', 'localhost'];
export async function getLocalhost(
port: number,
protocol = 'http',
timeout = 5000,
): Promise<string> {
const timeoutSignal = AbortSignal.timeout(5000);
const timeoutSignal = AbortSignal.timeout(timeout);
while (!timeoutSignal.aborted) {
for (const hostname of hostnames) {
const url = `${protocol}://${hostname}:${port}`;
Expand Down
94 changes: 46 additions & 48 deletions packages/plugins/opentelemetry/src/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ type BaseOptions = {
* The Resource that will be used to create the Trace Provider.
* Can be either a Resource instance, or an simple object with service name and version
*/
resource?: Resource | { serviceName: string; serviceVersion: string };
resource?: Resource | { serviceName: string; serviceVersion?: string };
/**
* The Context Manager to be used to track OTEL Context.
* If possible, use `AsyncLocalStorageContextManager` from `@opentelemetry/context-async-hooks`.
Expand Down Expand Up @@ -244,21 +244,7 @@ export function openTelemetrySetup(options: OpentelemetrySetupOptions) {
logAttributes['console'] = true;
}

const resource = createResource(
resourceFromAttributes({
[ATTR_SERVICE_NAME]:
getEnvStr('OTEL_SERVICE_NAME') ||
'@graphql-hive/plugin-opentelemetry',
[ATTR_SERVICE_VERSION]:
getEnvStr('OTEL_SERVICE_VERSION') ||
globalThis.__OTEL_PLUGIN_VERSION__ ||
'unknown',
['hive.gateway.version']: globalThis.__VERSION__,
['hive.otel.version']:
globalThis.__OTEL_PLUGIN_VERSION__ || 'unknown',
}),
options.resource,
);
const resource = createResource(options);

logAttributes['resource'] = resource.attributes;
logAttributes['sampling'] = options.sampler
Expand Down Expand Up @@ -311,6 +297,7 @@ export type HiveTracingOptions = { target?: string } & (
accessToken?: string;
batching?: BufferConfig;
processor?: never;
/** @default 'https://api.graphql-hive.com/otel/v1/traces' */
endpoint?: string;
}
| {
Expand Down Expand Up @@ -338,40 +325,48 @@ export function hiveTracingSetup(options: HiveTracingSetupOptions) {
target: options.target,
};

if (!options.processor) {
let processorOptions: HiveTracingSpanProcessorOptions;
if (options.processor) {
processorOptions = { processor: options.processor };
} else {
options.accessToken ??=
getEnvStr('HIVE_TRACING_ACCESS_TOKEN') ?? getEnvStr('HIVE_ACCESS_TOKEN');

if (!options.accessToken) {
throw new Error(
'You must specify the Hive Registry `accessToken`. Either provide `accessToken` option or `HIVE_ACCESS_TOKEN`/`HIVE_TRACE_ACCESS_TOKEN` environment variable.',
'You must specify the Hive Registry access token. Either provide the "accessToken" option or "HIVE_ACCESS_TOKEN"/"HIVE_TRACE_ACCESS_TOKEN" environment variable.',
);
}

options.endpoint ??=
getEnvStr('HIVE_TRACING_ENDPOINT') ??
'https://api.graphql-hive.com/otel/v1/traces';
if (!options.endpoint) {
throw new Error(
'You must specify the Hive Tracing endpoint. Either provide the "endpoint" option or the "HIVE_TRACING_ENDPOINT" environment variable.',
);
}

processorOptions = {
target: options.target,
accessToken: options.accessToken,
endpoint: options.endpoint,
batching: options.batching,
};

logAttributes['endpoint'] = options.endpoint;
logAttributes['batching'] = options.batching;
}

openTelemetrySetup({
...options,
log,
resource: createResource(
resource: createResource(options).merge(
resourceFromAttributes({
'hive.target_id': options.target,
[ATTR_SERVICE_NAME]: getEnvStr('OTEL_SERVICE_NAME') || 'hive-gateway',
[ATTR_SERVICE_VERSION]:
getEnvStr('OTEL_SERVICE_VERSION') ||
globalThis.__OTEL_PLUGIN_VERSION__ ||
'unknown',
}),
options.resource,
),
traces: {
processors: [
new HiveTracingSpanProcessor(
options as HiveTracingSpanProcessorOptions,
),
],
processors: [new HiveTracingSpanProcessor(processorOptions)],
spanLimits: options.spanLimits,
console: options.console,
},
Expand Down Expand Up @@ -400,24 +395,27 @@ function resolveBatchingConfig(
}
}

function createResource(
baseResource: Resource,
userResource?: OpentelemetrySetupOptions['resource'],
): Resource {
if (!userResource) {
return baseResource;
}

if ('serviceName' in userResource) {
return baseResource.merge(
resourceFromAttributes({
[ATTR_SERVICE_NAME]: userResource.serviceName,
[ATTR_SERVICE_VERSION]: userResource.serviceVersion,
}),
);
function createResource(opts: Pick<OpentelemetrySetupOptions, 'resource'>) {
const resourceObj =
opts.resource && 'serviceName' in opts.resource ? opts.resource : null;

let resource = resourceFromAttributes({
[ATTR_SERVICE_NAME]:
resourceObj?.serviceName ||
getEnvStr('OTEL_SERVICE_NAME') ||
'hive-gateway',
[ATTR_SERVICE_VERSION]:
resourceObj?.serviceVersion ||
getEnvStr('OTEL_SERVICE_VERSION') ||
globalThis.__VERSION__ ||
'unknown',
['hive.otel.version']: globalThis.__OTEL_PLUGIN_VERSION__ || 'unknown',
});
if (opts.resource && 'attributes' in opts.resource) {
// opts.resource is a Resource
resource = resource.merge(opts.resource);
}

return baseResource.merge(userResource);
return resource;
}

/**
Expand Down
6 changes: 3 additions & 3 deletions packages/plugins/opentelemetry/tests/useOpenTelemetry.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ describe('useOpenTelemetry', () => {

const resource = getResource();
expect(resource?.attributes).toMatchObject({
'service.name': '@graphql-hive/plugin-opentelemetry',
'service.name': 'hive-gateway',
});
});

Expand Down Expand Up @@ -398,7 +398,7 @@ describe('useOpenTelemetry', () => {
expect(exporter).toBeInstanceOf(OTLPTraceExporter);
// @ts-expect-error Access of private field
expect(exporter._delegate._transport._transport._parameters.url).toBe(
'http://localhost:4318/v1/traces',
'https://api.graphql-hive.com/otel/v1/traces',
);
});
});
Expand Down Expand Up @@ -562,7 +562,7 @@ describe('useOpenTelemetry', () => {
let attempts = 0;
await using gateway = await buildTestGatewayForCtx({
gatewayOptions: {
logging: true,
logging: false,
upstreamRetry: {
maxRetries: 2,
retryDelay: 1,
Expand Down
Loading