Skip to content

feat(resources): implements service.instance.id #4608

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Apr 15, 2024
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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ For experimental package changes, see the [experimental CHANGELOG](experimental/

### :rocket: (Enhancement)

feat(sdk-trace-base): log resource attributes in ConsoleSpanExporter [#4605](https://github.com/open-telemetry/opentelemetry-js/pull/4605) @pichlermarc
* feat(sdk-trace-base): log resource attributes in ConsoleSpanExporter [#4605](https://github.com/open-telemetry/opentelemetry-js/pull/4605) @pichlermarc
* feat(resources): new experimental detector ServiceInstanceIdDetectorSync that sets the value for `service.instance.id` as random UUID.

### :bug: (Bug Fix)

Expand Down
91 changes: 86 additions & 5 deletions experimental/packages/opentelemetry-sdk-node/test/sdk.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ import {
processDetector,
hostDetector,
Resource,
serviceInstanceIdDetectorSync,
} from '@opentelemetry/resources';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { logs } from '@opentelemetry/api-logs';
Expand All @@ -70,6 +71,7 @@ import {
import {
SEMRESATTRS_HOST_NAME,
SEMRESATTRS_PROCESS_PID,
SEMRESATTRS_SERVICE_INSTANCE_ID,
} from '@opentelemetry/semantic-conventions';

const DefaultContextManager = semver.gte(process.version, '14.8.0')
Expand Down Expand Up @@ -126,6 +128,7 @@ describe('Node SDK', () => {
assert.ok(!(metrics.getMeterProvider() instanceof MeterProvider));
assert.ok(!(logs.getLoggerProvider() instanceof LoggerProvider));
delete env.OTEL_TRACES_EXPORTER;
await sdk.shutdown();
});

it('should register a diag logger with OTEL_LOG_LEVEL', () => {
Expand All @@ -145,6 +148,7 @@ describe('Node SDK', () => {
});

delete env.OTEL_LOG_LEVEL;
sdk.shutdown();
});

it('should not register a diag logger with OTEL_LOG_LEVEL unset', () => {
Expand All @@ -158,6 +162,7 @@ describe('Node SDK', () => {
sdk.start();

assert.strictEqual(spy.callCount, 0);
sdk.shutdown();
});

it('should register a tracer provider if an exporter is provided', async () => {
Expand All @@ -180,6 +185,7 @@ describe('Node SDK', () => {
const apiTracerProvider =
trace.getTracerProvider() as ProxyTracerProvider;
assert.ok(apiTracerProvider.getDelegate() instanceof NodeTracerProvider);
await sdk.shutdown();
});

it('should register a tracer provider if an exporter is provided via env', async () => {
Expand All @@ -203,6 +209,7 @@ describe('Node SDK', () => {
trace.getTracerProvider() as ProxyTracerProvider;
assert.ok(apiTracerProvider.getDelegate() instanceof NodeTracerProvider);
delete env.OTEL_TRACES_EXPORTER;
await sdk.shutdown();
});

it('should register a tracer provider if span processors are provided', async () => {
Expand Down Expand Up @@ -240,6 +247,7 @@ describe('Node SDK', () => {
assert(listOfProcessors[0] instanceof NoopSpanProcessor);
assert(listOfProcessors[1] instanceof SimpleSpanProcessor);
assert(listOfProcessors[2] instanceof BatchSpanProcessor);
await sdk.shutdown();
});

it('should register a meter provider if a reader is provided', async () => {
Expand Down Expand Up @@ -446,6 +454,7 @@ describe('Node SDK', () => {
namespace: 'default',
version: '0.0.1',
});
await sdk.shutdown();
});
});

Expand Down Expand Up @@ -497,6 +506,7 @@ describe('Node SDK', () => {
namespace: 'default',
version: '0.0.1',
});
await sdk.shutdown();
});
});

Expand Down Expand Up @@ -551,6 +561,7 @@ describe('Node SDK', () => {
/{\s+"service\.instance\.id":\s+"627cc493",\s+"service\.name":\s+"my-service",\s+"service\.namespace":\s+"default",\s+"service\.version":\s+"0.0.1"\s+}\s*/gm
)
);
await sdk.shutdown();
});

describe('with a faulty environment variable', () => {
Expand Down Expand Up @@ -578,6 +589,7 @@ describe('Node SDK', () => {
'EnvDetector failed: Attribute value should be a ASCII string with a length not exceed 255 characters.'
)
);
await sdk.shutdown();
});
});
});
Expand All @@ -595,6 +607,7 @@ describe('Node SDK', () => {
assertServiceResource(resource, {
name: 'config-set-name',
});
await sdk.shutdown();
});

it('should configure service name via OTEL_SERVICE_NAME env var', async () => {
Expand All @@ -609,6 +622,7 @@ describe('Node SDK', () => {
name: 'env-set-name',
});
delete process.env.OTEL_SERVICE_NAME;
await sdk.shutdown();
});

it('should favor config set service name over OTEL_SERVICE_NAME env set service name', async () => {
Expand All @@ -625,11 +639,12 @@ describe('Node SDK', () => {
name: 'config-set-name',
});
delete process.env.OTEL_SERVICE_NAME;
await sdk.shutdown();
});

it('should configure service name via OTEL_RESOURCE_ATTRIBUTES env var', async () => {
process.env.OTEL_RESOURCE_ATTRIBUTES =
'service.name=resource-env-set-name';
'service.name=resource-env-set-name,service.instance.id=my-instance-id';
const sdk = new NodeSDK();

sdk.start();
Expand All @@ -638,13 +653,15 @@ describe('Node SDK', () => {

assertServiceResource(resource, {
name: 'resource-env-set-name',
instanceId: 'my-instance-id',
});
delete process.env.OTEL_RESOURCE_ATTRIBUTES;
await sdk.shutdown();
});

it('should favor config set service name over OTEL_RESOURCE_ATTRIBUTES env set service name', async () => {
process.env.OTEL_RESOURCE_ATTRIBUTES =
'service.name=resource-env-set-name';
'service.name=resource-env-set-name,service.instance.id=my-instance-id';
const sdk = new NodeSDK({
serviceName: 'config-set-name',
});
Expand All @@ -655,8 +672,55 @@ describe('Node SDK', () => {

assertServiceResource(resource, {
name: 'config-set-name',
instanceId: 'my-instance-id',
});
delete process.env.OTEL_RESOURCE_ATTRIBUTES;
await sdk.shutdown();
});
});

describe('configureServiceInstanceId', async () => {
it('should configure service instance id via OTEL_RESOURCE_ATTRIBUTES env var', async () => {
process.env.OTEL_RESOURCE_ATTRIBUTES =
'service.instance.id=627cc493,service.name=my-service';
const sdk = new NodeSDK();

sdk.start();
const resource = sdk['_resource'];
await resource.waitForAsyncAttributes?.();

assertServiceResource(resource, {
name: 'my-service',
instanceId: '627cc493',
});
delete process.env.OTEL_RESOURCE_ATTRIBUTES;
sdk.shutdown();
});

it('should configure service instance id with random UUID', async () => {
const sdk = new NodeSDK({
autoDetectResources: true,
resourceDetectors: [
processDetector,
envDetector,
hostDetector,
serviceInstanceIdDetectorSync,
],
});

sdk.start();
const resource = sdk['_resource'];
await resource.waitForAsyncAttributes?.();

const UUID_REGEX =
/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
assert.equal(
UUID_REGEX.test(
resource.attributes[SEMRESATTRS_SERVICE_INSTANCE_ID]?.toString() || ''
),
true
);
await sdk.shutdown();
});
});

Expand All @@ -671,7 +735,7 @@ describe('Node SDK', () => {

it('should not register a trace provider', async () => {
const sdk = new NodeSDK({});
await sdk.start();
sdk.start();

assert.strictEqual(
(trace.getTracerProvider() as ProxyTracerProvider).getDelegate(),
Expand All @@ -694,7 +758,7 @@ describe('Node SDK', () => {
metricReader: metricReader,
autoDetectResources: false,
});
await sdk.start();
sdk.start();

assert.ok(!(metrics.getMeterProvider() instanceof MeterProvider));

Expand Down Expand Up @@ -730,6 +794,7 @@ describe('Node SDK', () => {
await resource.waitForAsyncAttributes?.();

assert.deepStrictEqual(resource, Resource.empty());
await sdk.shutdown();
});
});
});
Expand Down Expand Up @@ -758,6 +823,7 @@ describe('Node SDK', () => {

assert.strictEqual(span.spanContext().spanId, 'constant-test-span-id');
assert.strictEqual(span.spanContext().traceId, 'constant-test-trace-id');
await sdk.shutdown();
});
});
});
Expand Down Expand Up @@ -786,6 +852,7 @@ describe('setup exporter from env', () => {
assert(sdk['_tracerProvider'] instanceof TracerProviderWithEnvExporters);
assert(listOfProcessors.length === 1);
assert(listOfProcessors[0] instanceof BatchSpanProcessor);
await sdk.shutdown();
});
it('ignore env exporter when user provides exporter to sdk config', async () => {
const traceExporter = new ConsoleSpanExporter();
Expand All @@ -802,6 +869,7 @@ describe('setup exporter from env', () => {
assert(listOfProcessors.length === 1);
assert(listOfProcessors[0] instanceof SimpleSpanProcessor === false);
assert(listOfProcessors[0] instanceof BatchSpanProcessor);
await sdk.shutdown();
});
it('ignores default env exporter when user provides span processor to sdk config', async () => {
const traceExporter = new ConsoleSpanExporter();
Expand All @@ -819,6 +887,7 @@ describe('setup exporter from env', () => {
assert(listOfProcessors.length === 1);
assert(listOfProcessors[0] instanceof SimpleSpanProcessor);
assert(listOfProcessors[0] instanceof BatchSpanProcessor === false);
await sdk.shutdown();
});
it('ignores env exporter when user provides tracer exporter to sdk config and sets exporter via env', async () => {
env.OTEL_TRACES_EXPORTER = 'console';
Expand All @@ -837,6 +906,7 @@ describe('setup exporter from env', () => {
assert(listOfProcessors[0] instanceof SimpleSpanProcessor === false);
assert(listOfProcessors[0] instanceof BatchSpanProcessor);
delete env.OTEL_TRACES_EXPORTER;
await sdk.shutdown();
});
it('should only create one span processor when configured using env vars and config', async () => {
env.OTEL_TRACES_EXPORTER = 'console';
Expand All @@ -852,6 +922,7 @@ describe('setup exporter from env', () => {
);
assert.strictEqual(listOfProcessors.length, 1);
delete env.OTEL_TRACES_EXPORTER;
await sdk.shutdown();
});
it('use otlp exporter and defined exporter protocol env value', async () => {
env.OTEL_TRACES_EXPORTER = 'otlp';
Expand All @@ -866,6 +937,7 @@ describe('setup exporter from env', () => {
assert(listOfProcessors[0] instanceof BatchSpanProcessor);
delete env.OTEL_TRACES_EXPORTER;
delete env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL;
await sdk.shutdown();
});
it('use noop span processor when user sets env exporter to none', async () => {
env.OTEL_TRACES_EXPORTER = 'none';
Expand All @@ -879,6 +951,7 @@ describe('setup exporter from env', () => {
assert(listOfProcessors.length === 0);
assert(activeProcessor instanceof NoopSpanProcessor);
delete env.OTEL_TRACES_EXPORTER;
await sdk.shutdown();
});
it('log warning that sdk will not be initialized when exporter is set to none', async () => {
env.OTEL_TRACES_EXPORTER = 'none';
Expand All @@ -890,16 +963,18 @@ describe('setup exporter from env', () => {
'OTEL_TRACES_EXPORTER contains "none". SDK will not be initialized.'
);
delete env.OTEL_TRACES_EXPORTER;
await sdk.shutdown();
});
it('use default otlp exporter when user does not set exporter via env or config', async () => {
const sdk = new NodeSDK();
await sdk.start();
sdk.start();

const listOfProcessors =
sdk['_tracerProvider']!['_registeredSpanProcessors']!;
assert(sdk['_tracerProvider'] instanceof TracerProviderWithEnvExporters);
assert(listOfProcessors.length === 1);
assert(listOfProcessors[0] instanceof BatchSpanProcessor);
await sdk.shutdown();
});
it('use default otlp exporter when empty value is provided for exporter via env', async () => {
env.OTEL_TRACES_EXPORTER = '';
Expand All @@ -912,6 +987,7 @@ describe('setup exporter from env', () => {
assert(listOfProcessors.length === 1);
assert(listOfProcessors[0] instanceof BatchSpanProcessor);
env.OTEL_TRACES_EXPORTER = '';
await sdk.shutdown();
});

it('use only default exporter when none value is provided with other exporters', async () => {
Expand All @@ -926,6 +1002,7 @@ describe('setup exporter from env', () => {
assert(listOfProcessors[0] instanceof BatchSpanProcessor);

delete env.OTEL_TRACES_EXPORTER;
await sdk.shutdown();
});
it('log warning that only default exporter will be used since exporter list contains none with other exports ', async () => {
env.OTEL_TRACES_EXPORTER = 'otlp,zipkin,none';
Expand All @@ -937,6 +1014,7 @@ describe('setup exporter from env', () => {
'OTEL_TRACES_EXPORTER contains "none" along with other exporters. Using default otlp exporter.'
);
delete env.OTEL_TRACES_EXPORTER;
await sdk.shutdown();
});
it('should warn that provided exporter value is unrecognized and not able to be set up', async () => {
env.OTEL_TRACES_EXPORTER = 'invalid';
Expand All @@ -954,6 +1032,7 @@ describe('setup exporter from env', () => {
);

delete env.OTEL_TRACES_EXPORTER;
await sdk.shutdown();
});
it('setup zipkin, jaeger and otlp exporters', async () => {
env.OTEL_TRACES_EXPORTER = 'zipkin, otlp, jaeger';
Expand All @@ -971,6 +1050,7 @@ describe('setup exporter from env', () => {

delete env.OTEL_TRACES_EXPORTER;
delete env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL;
await sdk.shutdown();
});
it('use the console exporter', async () => {
env.OTEL_TRACES_EXPORTER = 'console, otlp';
Expand All @@ -983,5 +1063,6 @@ describe('setup exporter from env', () => {
assert(listOfProcessors[0] instanceof SimpleSpanProcessor);
assert(listOfProcessors[1] instanceof BatchSpanProcessor);
delete env.OTEL_TRACES_EXPORTER;
await sdk.shutdown();
});
});
15 changes: 0 additions & 15 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading