From 15cf5b66e66b125bd9c0d23f4cdab5d8a97b2317 Mon Sep 17 00:00:00 2001 From: Naseem Ullah <24660299+naseemkullah@users.noreply.github.com> Date: Mon, 23 May 2022 20:25:29 -0400 Subject: [PATCH] feat(node-sdk): add serviceName config option --- experimental/CHANGELOG.md | 1 + .../packages/opentelemetry-sdk-node/README.md | 4 ++ .../opentelemetry-sdk-node/src/sdk.ts | 34 ++++++--- .../opentelemetry-sdk-node/src/types.ts | 9 +-- .../opentelemetry-sdk-node/test/sdk.test.ts | 72 +++++++++++++++++++ .../test/util/resource-assertions.ts | 2 +- 6 files changed, 109 insertions(+), 13 deletions(-) diff --git a/experimental/CHANGELOG.md b/experimental/CHANGELOG.md index f24fbe0ea0f..bdce8f2c2e7 100644 --- a/experimental/CHANGELOG.md +++ b/experimental/CHANGELOG.md @@ -33,6 +33,7 @@ All notable changes to experimental packages in this project will be documented * fix(sdk-metrics-base): misbehaving aggregation temporality selector tolerance #2958 @legendecas * feat(trace-otlp-grpc): configure security with env vars #2827 @svetlanabrennan * feat(sdk-metrics-base): async instruments callback timeout #2742 @legendecas +* feat(node-sdk): add serviceName config option #2867 @naseemkullah ### :bug: (Bug Fix) diff --git a/experimental/packages/opentelemetry-sdk-node/README.md b/experimental/packages/opentelemetry-sdk-node/README.md index 841bff28247..a21de3c7411 100644 --- a/experimental/packages/opentelemetry-sdk-node/README.md +++ b/experimental/packages/opentelemetry-sdk-node/README.md @@ -128,6 +128,10 @@ Configure a trace exporter. If an exporter OR span processor is not configured, Configure tracing parameters. These are the same trace parameters used to [configure a tracer](../../../packages/opentelemetry-sdk-trace-base/src/types.ts#L71). +### serviceName + +Configure the [service name](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/semantic_conventions/README.md#service). + ## Useful links - For more information on OpenTelemetry, visit: diff --git a/experimental/packages/opentelemetry-sdk-node/src/sdk.ts b/experimental/packages/opentelemetry-sdk-node/src/sdk.ts index aa3df3247c1..cce13f112c0 100644 --- a/experimental/packages/opentelemetry-sdk-node/src/sdk.ts +++ b/experimental/packages/opentelemetry-sdk-node/src/sdk.ts @@ -14,15 +14,12 @@ * limitations under the License. */ -import { TextMapPropagator } from '@opentelemetry/api'; +import { ContextManager, TextMapPropagator } from '@opentelemetry/api'; import { metrics } from '@opentelemetry/api-metrics'; -import { ContextManager } from '@opentelemetry/api'; -import { MeterProvider, MetricReader } from '@opentelemetry/sdk-metrics-base'; import { InstrumentationOption, - registerInstrumentations, + registerInstrumentations } from '@opentelemetry/instrumentation'; -import { NodeTracerConfig, NodeTracerProvider } from '@opentelemetry/sdk-trace-node'; import { awsEc2Detector } from '@opentelemetry/resource-detector-aws'; import { gcpDetector } from '@opentelemetry/resource-detector-gcp'; import { @@ -30,9 +27,18 @@ import { envDetector, processDetector, Resource, - ResourceDetectionConfig, + ResourceDetectionConfig } from '@opentelemetry/resources'; -import { BatchSpanProcessor, SpanProcessor } from '@opentelemetry/sdk-trace-base'; +import { MeterProvider, MetricReader } from '@opentelemetry/sdk-metrics-base'; +import { + BatchSpanProcessor, + SpanProcessor +} from '@opentelemetry/sdk-trace-base'; +import { + NodeTracerConfig, + NodeTracerProvider +} from '@opentelemetry/sdk-trace-node'; +import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'; import { NodeSDKConfiguration } from './types'; /** This class represents everything needed to register a fully configured OpenTelemetry Node.js SDK */ @@ -52,6 +58,7 @@ export class NodeSDK { private _tracerProvider?: NodeTracerProvider; private _meterProvider?: MeterProvider; + private _serviceName?: string; /** * Create a new NodeJS SDK instance @@ -59,6 +66,9 @@ export class NodeSDK { public constructor(configuration: Partial = {}) { this._resource = configuration.resource ?? new Resource({}); + + this._serviceName = configuration.serviceName; + this._autoDetectResources = configuration.autoDetectResources ?? true; if (configuration.spanProcessor || configuration.traceExporter) { @@ -115,7 +125,9 @@ export class NodeSDK { } /** Detect resource attributes */ - public async detectResources(config?: ResourceDetectionConfig): Promise { + public async detectResources( + config?: ResourceDetectionConfig + ): Promise { const internalConfig: ResourceDetectionConfig = { detectors: [awsEc2Detector, gcpDetector, envDetector, processDetector], ...config, @@ -137,6 +149,12 @@ export class NodeSDK { await this.detectResources(); } + this._resource = this._serviceName === undefined + ? this._resource + : this._resource.merge(new Resource( + {[SemanticResourceAttributes.SERVICE_NAME]: this._serviceName} + )); + if (this._tracerProviderConfig) { const tracerProvider = new NodeTracerProvider({ ...this._tracerProviderConfig.tracerConfig, diff --git a/experimental/packages/opentelemetry-sdk-node/src/types.ts b/experimental/packages/opentelemetry-sdk-node/src/types.ts index ea93ddae167..bb46bcaffb7 100644 --- a/experimental/packages/opentelemetry-sdk-node/src/types.ts +++ b/experimental/packages/opentelemetry-sdk-node/src/types.ts @@ -14,26 +14,27 @@ * limitations under the License. */ -import { SpanAttributes, TextMapPropagator, Sampler } from '@opentelemetry/api'; import type { ContextManager } from '@opentelemetry/api'; +import { Attributes, Sampler, TextMapPropagator } from '@opentelemetry/api'; import { InstrumentationOption } from '@opentelemetry/instrumentation'; -import { MetricReader } from '@opentelemetry/sdk-metrics-base'; import { Resource } from '@opentelemetry/resources'; +import { MetricReader } from '@opentelemetry/sdk-metrics-base'; import { SpanExporter, - SpanProcessor, SpanLimits, + SpanProcessor } from '@opentelemetry/sdk-trace-base'; export interface NodeSDKConfiguration { autoDetectResources: boolean; contextManager: ContextManager; - defaultAttributes: SpanAttributes; + defaultAttributes: Attributes; textMapPropagator: TextMapPropagator; metricReader: MetricReader; instrumentations: InstrumentationOption[]; resource: Resource; sampler: Sampler; + serviceName?: string; spanProcessor: SpanProcessor; traceExporter: SpanExporter; spanLimits: SpanLimits; diff --git a/experimental/packages/opentelemetry-sdk-node/test/sdk.test.ts b/experimental/packages/opentelemetry-sdk-node/test/sdk.test.ts index 2237828534f..d45d4a9812f 100644 --- a/experimental/packages/opentelemetry-sdk-node/test/sdk.test.ts +++ b/experimental/packages/opentelemetry-sdk-node/test/sdk.test.ts @@ -428,4 +428,76 @@ describe('Node SDK', () => { }); }); }); + + describe('configureServiceName', async () => { + it('should configure service name via config', async () => { + const sdk = new NodeSDK({ + serviceName: 'config-set-name', + }); + + await sdk.start(); + const resource = sdk['_resource']; + + assertServiceResource(resource, { + name: 'config-set-name', + }); + }); + + it('should configure service name via OTEL_SERVICE_NAME env var', async () => { + process.env.OTEL_SERVICE_NAME='env-set-name'; + const sdk = new NodeSDK(); + + await sdk.start(); + const resource = sdk['_resource']; + + assertServiceResource(resource, { + name: 'env-set-name', + }); + delete process.env.OTEL_SERVICE_NAME; + }); + + it('should favor config set service name over OTEL_SERVICE_NAME env set service name', async () => { + process.env.OTEL_SERVICE_NAME='env-set-name'; + const sdk = new NodeSDK({ + serviceName: 'config-set-name', + }); + + await sdk.start(); + const resource = sdk['_resource']; + + assertServiceResource(resource, { + name: 'config-set-name', + }); + delete process.env.OTEL_SERVICE_NAME; + }); + + + it('should configure service name via OTEL_RESOURCE_ATTRIBUTES env var', async () => { + process.env.OTEL_RESOURCE_ATTRIBUTES = 'service.name=resource-env-set-name'; + const sdk = new NodeSDK(); + + await sdk.start(); + const resource = sdk['_resource']; + + assertServiceResource(resource, { + name: 'resource-env-set-name', + }); + delete process.env.OTEL_RESOURCE_ATTRIBUTES; + }); + + 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'; + const sdk = new NodeSDK({ + serviceName: 'config-set-name', + }); + + await sdk.start(); + const resource = sdk['_resource']; + + assertServiceResource(resource, { + name: 'config-set-name', + }); + delete process.env.OTEL_RESOURCE_ATTRIBUTES; + }); + }); }); diff --git a/experimental/packages/opentelemetry-sdk-node/test/util/resource-assertions.ts b/experimental/packages/opentelemetry-sdk-node/test/util/resource-assertions.ts index 206c9bcf86a..331fed6e8ec 100644 --- a/experimental/packages/opentelemetry-sdk-node/test/util/resource-assertions.ts +++ b/experimental/packages/opentelemetry-sdk-node/test/util/resource-assertions.ts @@ -232,7 +232,7 @@ export const assertServiceResource = ( resource: Resource, validations: { name: string; - instanceId: string; + instanceId?: string; namespace?: string; version?: string; }