From 56c032ec71c0baa0120a5cc841c015a290fad654 Mon Sep 17 00:00:00 2001 From: Daniel Dyla Date: Tue, 1 Jun 2021 15:07:13 -0400 Subject: [PATCH] chore: set default service name (#2227) --- README.md | 2 + .../src/utils/environment.ts | 2 + .../README.md | 10 +- .../src/CollectorMetricExporter.ts | 5 - .../src/CollectorTraceExporter.ts | 5 - .../test/CollectorMetricExporter.test.ts | 3 - .../test/CollectorTraceExporter.test.ts | 3 - .../test/helper.ts | 36 +- .../README.md | 8 +- .../src/CollectorMetricExporter.ts | 5 - .../src/CollectorTraceExporter.ts | 5 - .../test/CollectorMetricExporter.test.ts | 1 - .../test/CollectorTraceExporter.test.ts | 1 - .../README.md | 8 +- .../src/CollectorExporterBase.ts | 3 - .../browser/CollectorMetricExporter.ts | 5 - .../browser/CollectorTraceExporter.ts | 5 - .../platform/node/CollectorMetricExporter.ts | 5 - .../platform/node/CollectorTraceExporter.ts | 5 - .../src/transform.ts | 5 +- .../src/transformMetrics.ts | 5 +- .../src/types.ts | 1 - .../browser/CollectorMetricExporter.test.ts | 2 - .../browser/CollectorTraceExporter.test.ts | 1 - .../common/CollectorMetricExporter.test.ts | 16 - .../common/CollectorTraceExporter.test.ts | 19 - .../test/helper.ts | 58 +- .../test/node/CollectorMetricExporter.test.ts | 1 - .../test/node/CollectorTraceExporter.test.ts | 1 - .../package.json | 1 + .../src/jaeger.ts | 59 +- .../src/types.ts | 1 - .../test/jaeger.test.ts | 139 +++-- .../package.json | 4 +- .../src/zipkin.ts | 12 +- .../test/common/transform.test.ts | 29 +- .../test/node/zipkin.test.ts | 548 ++++++------------ packages/opentelemetry-metrics/src/Meter.ts | 2 +- .../src/MeterProvider.ts | 4 +- .../opentelemetry-resources/src/Resource.ts | 6 +- .../platform/browser/default-service-name.ts | 19 + .../src/platform/browser/detect-resources.ts | 2 +- .../src/platform/browser/index.ts | 1 + .../src/platform/node/default-service-name.ts | 19 + .../src/platform/node/detect-resources.ts | 2 +- .../platform/node/detectors/EnvDetector.ts | 31 +- .../src/platform/node/index.ts | 1 + .../test/Resource.test.ts | 27 +- .../opentelemetry-sdk-node/test/sdk.test.ts | 30 +- .../src/BasicTracerProvider.ts | 4 +- 50 files changed, 503 insertions(+), 664 deletions(-) create mode 100644 packages/opentelemetry-resources/src/platform/browser/default-service-name.ts create mode 100644 packages/opentelemetry-resources/src/platform/node/default-service-name.ts diff --git a/README.md b/README.md index 8164207055..8232a4f5a5 100644 --- a/README.md +++ b/README.md @@ -232,6 +232,8 @@ To request automatic tracing support for a module not on this list, please [file - `JaegerHttpTracePropagator` renamed to `JaegerPropagator` +- `serviceName` configuration removed from Collector exporters. Use `service.name` Resource attribute instead. + ### 0.18.x to 0.19.0 - API is now a peer dependency. This means that users will need to include `@opentelemetry/api` as a dependency of their project in order to use the SDK. NPM version 7+ (Node 15+) should do this automatically. diff --git a/packages/opentelemetry-core/src/utils/environment.ts b/packages/opentelemetry-core/src/utils/environment.ts index 8e621a0d86..78b7f1f248 100644 --- a/packages/opentelemetry-core/src/utils/environment.ts +++ b/packages/opentelemetry-core/src/utils/environment.ts @@ -76,6 +76,7 @@ export type ENVIRONMENT = { OTEL_EXPORTER_ZIPKIN_ENDPOINT?: string; OTEL_LOG_LEVEL?: DiagLogLevel; OTEL_RESOURCE_ATTRIBUTES?: string; + OTEL_SERVICE_NAME?: string; OTEL_TRACES_EXPORTER?: string; OTEL_TRACES_SAMPLER_ARG?: string; OTEL_TRACES_SAMPLER?: string; @@ -115,6 +116,7 @@ export const DEFAULT_ENVIRONMENT: Required = { OTEL_NO_PATCH_MODULES: [], OTEL_PROPAGATORS: ['tracecontext', 'baggage'], OTEL_RESOURCE_ATTRIBUTES: '', + OTEL_SERVICE_NAME: '', OTEL_SPAN_ATTRIBUTE_COUNT_LIMIT: 128, OTEL_SPAN_EVENT_COUNT_LIMIT: 128, OTEL_SPAN_LINK_COUNT_LIMIT: 128, diff --git a/packages/opentelemetry-exporter-collector-grpc/README.md b/packages/opentelemetry-exporter-collector-grpc/README.md index 840afb7104..03a1bd41c4 100644 --- a/packages/opentelemetry-exporter-collector-grpc/README.md +++ b/packages/opentelemetry-exporter-collector-grpc/README.md @@ -13,6 +13,11 @@ This module provides exporter for web and node to be used with [opentelemetry-co npm install --save @opentelemetry/exporter-collector-grpc ``` +## Service Name + +The OpenTelemetry Collector Exporter does not have a service name configuration. +In order to set the service name, use the `service.name` resource attribute as prescribed in the [OpenTelemetry Resource Semantic Conventions][semconv-resource-service-name]. + ## Traces in Node - GRPC The CollectorTraceExporter in Node expects the URL to only be the hostname. It will not work with `/v1/traces`. @@ -22,7 +27,6 @@ const { BasicTracerProvider, SimpleSpanProcessor } = require('@opentelemetry/tra const { CollectorTraceExporter } = require('@opentelemetry/exporter-collector-grpc'); const collectorOptions = { - serviceName: 'basic-service', // url is optional and can be omitted - default is localhost:4317 url: ':', }; @@ -47,7 +51,6 @@ const { BasicTracerProvider, SimpleSpanProcessor } = require('@opentelemetry/tra const { CollectorTraceExporter } = require('@opentelemetry/exporter-collector-grpc'); const collectorOptions = { - serviceName: 'basic-service', // url is optional and can be omitted - default is localhost:4317 url: ':', credentials: grpc.credentials.createSsl(), @@ -88,7 +91,6 @@ const metadata = new grpc.Metadata(); metadata.set('k', 'v'); const collectorOptions = { - serviceName: 'basic-service', // url is optional and can be omitted - default is localhost:4317 url: ':', metadata, // // an optional grpc.Metadata object to be sent with each request @@ -114,7 +116,6 @@ The CollectorTraceExporter in Node expects the URL to only be the hostname. It w const { MeterProvider } = require('@opentelemetry/metrics'); const { CollectorMetricExporter } = require('@opentelemetry/exporter-collector-grpc'); const collectorOptions = { - serviceName: 'basic-service', // url is optional and can be omitted - default is localhost:4317 url: ':', }; @@ -161,3 +162,4 @@ Apache 2.0 - See [LICENSE][license-url] for more information. [npm-url]: https://www.npmjs.com/package/@opentelemetry/exporter-collector-grpc [npm-img]: https://badge.fury.io/js/%40opentelemetry%2Fexporter-collector-grpc.svg [opentelemetry-collector-url]: https://github.com/open-telemetry/opentelemetry-collector +[semconv-resource-service-name]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/semantic_conventions/README.md#service diff --git a/packages/opentelemetry-exporter-collector-grpc/src/CollectorMetricExporter.ts b/packages/opentelemetry-exporter-collector-grpc/src/CollectorMetricExporter.ts index a983474cf1..84a880c16d 100644 --- a/packages/opentelemetry-exporter-collector-grpc/src/CollectorMetricExporter.ts +++ b/packages/opentelemetry-exporter-collector-grpc/src/CollectorMetricExporter.ts @@ -24,7 +24,6 @@ import { CollectorExporterNodeBase } from './CollectorExporterNodeBase'; import { getEnv } from '@opentelemetry/core'; import { validateAndNormalizeUrl } from './util'; -const DEFAULT_SERVICE_NAME = 'collector-metric-exporter'; const DEFAULT_COLLECTOR_URL = 'localhost:4317'; /** @@ -59,10 +58,6 @@ export class CollectorMetricExporter : DEFAULT_COLLECTOR_URL; } - getDefaultServiceName(config: CollectorExporterConfigNode): string { - return config.serviceName || DEFAULT_SERVICE_NAME; - } - getServiceClientType() { return ServiceClientType.METRICS; } diff --git a/packages/opentelemetry-exporter-collector-grpc/src/CollectorTraceExporter.ts b/packages/opentelemetry-exporter-collector-grpc/src/CollectorTraceExporter.ts index 91163e3406..aae731d10c 100644 --- a/packages/opentelemetry-exporter-collector-grpc/src/CollectorTraceExporter.ts +++ b/packages/opentelemetry-exporter-collector-grpc/src/CollectorTraceExporter.ts @@ -24,7 +24,6 @@ import { CollectorExporterConfigNode, ServiceClientType } from './types'; import { getEnv } from '@opentelemetry/core'; import { validateAndNormalizeUrl } from './util'; -const DEFAULT_SERVICE_NAME = 'collector-trace-exporter'; const DEFAULT_COLLECTOR_URL = 'localhost:4317'; /** @@ -52,10 +51,6 @@ export class CollectorTraceExporter : DEFAULT_COLLECTOR_URL; } - getDefaultServiceName(config: CollectorExporterConfigNode): string { - return config.serviceName || DEFAULT_SERVICE_NAME; - } - getServiceClientType() { return ServiceClientType.SPANS; } diff --git a/packages/opentelemetry-exporter-collector-grpc/test/CollectorMetricExporter.test.ts b/packages/opentelemetry-exporter-collector-grpc/test/CollectorMetricExporter.test.ts index 989c4a10f2..a0cb218a7e 100644 --- a/packages/opentelemetry-exporter-collector-grpc/test/CollectorMetricExporter.test.ts +++ b/packages/opentelemetry-exporter-collector-grpc/test/CollectorMetricExporter.test.ts @@ -131,7 +131,6 @@ const testCollectorMetricExporter = (params: TestParams) => collectorExporter = new CollectorMetricExporter({ url: 'grpcs://' + address, credentials, - serviceName: 'basic-service', metadata: params.metadata, }); // Overwrites the start time to make tests consistent @@ -169,7 +168,6 @@ const testCollectorMetricExporter = (params: TestParams) => // Need to stub/spy on the underlying logger as the 'diag' instance is global const spyLoggerWarn = sinon.stub(diag, 'warn'); collectorExporter = new CollectorMetricExporter({ - serviceName: 'basic-service', url: `http://${address}`, headers: { foo: 'bar', @@ -181,7 +179,6 @@ const testCollectorMetricExporter = (params: TestParams) => it('should warn about path in url', () => { const spyLoggerWarn = sinon.stub(diag, 'warn'); collectorExporter = new CollectorMetricExporter({ - serviceName: 'basic-service', url: `http://${address}/v1/metrics` }); const args = spyLoggerWarn.args[0]; diff --git a/packages/opentelemetry-exporter-collector-grpc/test/CollectorTraceExporter.test.ts b/packages/opentelemetry-exporter-collector-grpc/test/CollectorTraceExporter.test.ts index 0bcca66ef7..1c91cae6a7 100644 --- a/packages/opentelemetry-exporter-collector-grpc/test/CollectorTraceExporter.test.ts +++ b/packages/opentelemetry-exporter-collector-grpc/test/CollectorTraceExporter.test.ts @@ -124,7 +124,6 @@ const testCollectorExporter = (params: TestParams) => ) : undefined; collectorExporter = new CollectorTraceExporter({ - serviceName: 'basic-service', url: 'grpcs://' + address, credentials, metadata: params.metadata, @@ -146,7 +145,6 @@ const testCollectorExporter = (params: TestParams) => // Need to stub/spy on the underlying logger as the 'diag' instance is global const spyLoggerWarn = sinon.stub(diag, 'warn'); collectorExporter = new CollectorTraceExporter({ - serviceName: 'basic-service', url: `http://${address}`, headers: { foo: 'bar', @@ -158,7 +156,6 @@ const testCollectorExporter = (params: TestParams) => it('should warn about path in url', () => { const spyLoggerWarn = sinon.stub(diag, 'warn'); collectorExporter = new CollectorTraceExporter({ - serviceName: 'basic-service', url: `http://${address}/v1/trace`, }); const args = spyLoggerWarn.args[0]; diff --git a/packages/opentelemetry-exporter-collector-grpc/test/helper.ts b/packages/opentelemetry-exporter-collector-grpc/test/helper.ts index 94591f5a2f..6e66e5a866 100644 --- a/packages/opentelemetry-exporter-collector-grpc/test/helper.ts +++ b/packages/opentelemetry-exporter-collector-grpc/test/helper.ts @@ -28,6 +28,7 @@ import { Resource } from '@opentelemetry/resources'; import { ReadableSpan } from '@opentelemetry/tracing'; import * as assert from 'assert'; import * as grpc from '@grpc/grpc-js'; +import { VERSION } from '@opentelemetry/core'; const meterProvider = new metrics.MeterProvider({ interval: 30000, @@ -157,11 +158,11 @@ export const mockedReadableSpan: ReadableSpan = { }, ], duration: [0, 8885000], - resource: new Resource({ + resource: Resource.default().merge(new Resource({ service: 'ui', version: 1, cost: 112.12, - }), + })), instrumentationLibrary: { name: 'default', version: '0.0.1' }, }; @@ -409,11 +410,32 @@ export function ensureResourceIsCorrect( assert.deepStrictEqual(resource, { attributes: [ { - key: 'service.name', - value: { - stringValue: 'basic-service', - value: 'stringValue', - }, + "key": "service.name", + "value": { + "stringValue": `unknown_service:${process.argv0}`, + "value": "stringValue" + } + }, + { + "key": "telemetry.sdk.language", + "value": { + "stringValue": "nodejs", + "value": "stringValue" + } + }, + { + "key": "telemetry.sdk.name", + "value": { + "stringValue": "opentelemetry", + "value": "stringValue" + } + }, + { + "key": "telemetry.sdk.version", + "value": { + "stringValue": VERSION, + "value": "stringValue" + } }, { key: 'service', diff --git a/packages/opentelemetry-exporter-collector-proto/README.md b/packages/opentelemetry-exporter-collector-proto/README.md index 4d8bee9f08..cd22a8769b 100644 --- a/packages/opentelemetry-exporter-collector-proto/README.md +++ b/packages/opentelemetry-exporter-collector-proto/README.md @@ -13,6 +13,11 @@ This module provides exporter for node to be used with [opentelemetry-collector] npm install --save @opentelemetry/exporter-collector-proto ``` +## Service Name + +The OpenTelemetry Collector Exporter does not have a service name configuration. +In order to set the service name, use the `service.name` resource attribute as prescribed in the [OpenTelemetry Resource Semantic Conventions][semconv-resource-service-name]. + ## Traces in Node - PROTO over http ```js @@ -20,7 +25,6 @@ const { BasicTracerProvider, SimpleSpanProcessor } = require('@opentelemetry/tra const { CollectorTraceExporter } = require('@opentelemetry/exporter-collector-proto'); const collectorOptions = { - serviceName: 'basic-service', url: '', // url is optional and can be omitted - default is http://localhost:55681/v1/traces headers: { foo: 'bar' @@ -41,7 +45,6 @@ provider.register(); const { MeterProvider } = require('@opentelemetry/metrics'); const { CollectorMetricExporter } = require('@opentelemetry/exporter-collector-proto'); const collectorOptions = { - serviceName: 'basic-service', url: '', // url is optional and can be omitted - default is http://localhost:55681/v1/metrics }; const exporter = new CollectorMetricExporter(collectorOptions); @@ -84,3 +87,4 @@ Apache 2.0 - See [LICENSE][license-url] for more information. [npm-url]: https://www.npmjs.com/package/@opentelemetry/exporter-collector-proto [npm-img]: https://badge.fury.io/js/%40opentelemetry%2Fexporter-collector-proto.svg [opentelemetry-collector-url]: https://github.com/open-telemetry/opentelemetry-collector +[semconv-resource-service-name]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/semantic_conventions/README.md#service diff --git a/packages/opentelemetry-exporter-collector-proto/src/CollectorMetricExporter.ts b/packages/opentelemetry-exporter-collector-proto/src/CollectorMetricExporter.ts index 73c4156d3b..76a93d98fe 100644 --- a/packages/opentelemetry-exporter-collector-proto/src/CollectorMetricExporter.ts +++ b/packages/opentelemetry-exporter-collector-proto/src/CollectorMetricExporter.ts @@ -24,7 +24,6 @@ import { ServiceClientType } from './types'; import { CollectorExporterNodeBase } from './CollectorExporterNodeBase'; import { getEnv, baggageUtils } from '@opentelemetry/core'; -const DEFAULT_SERVICE_NAME = 'collector-metric-exporter'; const DEFAULT_COLLECTOR_URL = 'http://localhost:4317/v1/metrics'; /** @@ -69,10 +68,6 @@ export class CollectorMetricExporter : DEFAULT_COLLECTOR_URL; } - getDefaultServiceName(config: CollectorExporterNodeConfigBase): string { - return config.serviceName || DEFAULT_SERVICE_NAME; - } - getServiceClientType() { return ServiceClientType.METRICS; } diff --git a/packages/opentelemetry-exporter-collector-proto/src/CollectorTraceExporter.ts b/packages/opentelemetry-exporter-collector-proto/src/CollectorTraceExporter.ts index 4c08ddb668..124eee5a2d 100644 --- a/packages/opentelemetry-exporter-collector-proto/src/CollectorTraceExporter.ts +++ b/packages/opentelemetry-exporter-collector-proto/src/CollectorTraceExporter.ts @@ -24,7 +24,6 @@ import { import { ServiceClientType } from './types'; import { getEnv, baggageUtils } from '@opentelemetry/core'; -const DEFAULT_SERVICE_NAME = 'collector-trace-exporter'; const DEFAULT_COLLECTOR_URL = 'http://localhost:4317/v1/traces'; /** @@ -62,10 +61,6 @@ export class CollectorTraceExporter : DEFAULT_COLLECTOR_URL; } - getDefaultServiceName(config: CollectorExporterNodeConfigBase): string { - return config.serviceName || DEFAULT_SERVICE_NAME; - } - getServiceClientType() { return ServiceClientType.SPANS; } diff --git a/packages/opentelemetry-exporter-collector-proto/test/CollectorMetricExporter.test.ts b/packages/opentelemetry-exporter-collector-proto/test/CollectorMetricExporter.test.ts index 5f4c4447a5..71f52a265b 100644 --- a/packages/opentelemetry-exporter-collector-proto/test/CollectorMetricExporter.test.ts +++ b/packages/opentelemetry-exporter-collector-proto/test/CollectorMetricExporter.test.ts @@ -99,7 +99,6 @@ describe('CollectorMetricExporter - node with proto over http', () => { foo: 'bar', }, hostname: 'foo', - serviceName: 'bar', attributes: {}, url: 'http://foo.bar.com', keepAlive: true, diff --git a/packages/opentelemetry-exporter-collector-proto/test/CollectorTraceExporter.test.ts b/packages/opentelemetry-exporter-collector-proto/test/CollectorTraceExporter.test.ts index fd812f7a4a..d33e8563b1 100644 --- a/packages/opentelemetry-exporter-collector-proto/test/CollectorTraceExporter.test.ts +++ b/packages/opentelemetry-exporter-collector-proto/test/CollectorTraceExporter.test.ts @@ -90,7 +90,6 @@ describe('CollectorTraceExporter - node with proto over http', () => { foo: 'bar', }, hostname: 'foo', - serviceName: 'bar', attributes: {}, url: 'http://foo.bar.com', keepAlive: true, diff --git a/packages/opentelemetry-exporter-collector/README.md b/packages/opentelemetry-exporter-collector/README.md index 33934ed95e..93902d9326 100644 --- a/packages/opentelemetry-exporter-collector/README.md +++ b/packages/opentelemetry-exporter-collector/README.md @@ -13,6 +13,11 @@ This module provides exporter for web and node to be used with [opentelemetry-co npm install --save @opentelemetry/exporter-collector ``` +## Service Name + +The OpenTelemetry Collector Exporter does not have a service name configuration. +In order to set the service name, use the `service.name` resource attribute as prescribed in the [OpenTelemetry Resource Semantic Conventions][semconv-resource-service-name]. + ## Traces in Web The CollectorTraceExporter in Web expects the endpoint to end in `/v1/traces`. @@ -78,7 +83,6 @@ const { BasicTracerProvider, BatchSpanProcessor } = require('@opentelemetry/trac const { CollectorTraceExporter } = require('@opentelemetry/exporter-collector'); const collectorOptions = { - serviceName: 'basic-service', url: '', // url is optional and can be omitted - default is http://localhost:55681/v1/trace headers: { foo: 'bar' @@ -105,7 +109,6 @@ provider.register(); const { MeterProvider } = require('@opentelemetry/metrics'); const { CollectorMetricExporter } = require('@opentelemetry/exporter-collector'); const collectorOptions = { - serviceName: 'basic-service', url: '', // url is optional and can be omitted - default is http://localhost:55681/v1/metrics concurrencyLimit: 1, // an optional limit on pending requests }; @@ -159,3 +162,4 @@ Apache 2.0 - See [LICENSE][license-url] for more information. [npm-url-proto]: https://www.npmjs.com/package/@opentelemetry/exporter-collector-proto [npm-img]: https://badge.fury.io/js/%40opentelemetry%2Fexporter-collector.svg [opentelemetry-collector-url]: https://github.com/open-telemetry/opentelemetry-collector +[semconv-resource-service-name]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/resource/semantic_conventions/README.md#service diff --git a/packages/opentelemetry-exporter-collector/src/CollectorExporterBase.ts b/packages/opentelemetry-exporter-collector/src/CollectorExporterBase.ts index c8a4d47637..f4705d9031 100644 --- a/packages/opentelemetry-exporter-collector/src/CollectorExporterBase.ts +++ b/packages/opentelemetry-exporter-collector/src/CollectorExporterBase.ts @@ -30,7 +30,6 @@ export abstract class CollectorExporterBase< ExportItem, ServiceRequest > { - public readonly serviceName: string; public readonly url: string; public readonly hostname: string | undefined; public readonly attributes?: SpanAttributes; @@ -43,7 +42,6 @@ export abstract class CollectorExporterBase< * @param config */ constructor(config: T = {} as T) { - this.serviceName = this.getDefaultServiceName(config); this.url = this.getDefaultUrl(config); if (typeof config.hostname === 'string') { this.hostname = config.hostname; @@ -140,6 +138,5 @@ export abstract class CollectorExporterBase< onError: (error: CollectorExporterError) => void ): void; abstract getDefaultUrl(config: T): string; - abstract getDefaultServiceName(config: T): string; abstract convert(objects: ExportItem[]): ServiceRequest; } diff --git a/packages/opentelemetry-exporter-collector/src/platform/browser/CollectorMetricExporter.ts b/packages/opentelemetry-exporter-collector/src/platform/browser/CollectorMetricExporter.ts index 4b8ce05b41..8d281e8c32 100644 --- a/packages/opentelemetry-exporter-collector/src/platform/browser/CollectorMetricExporter.ts +++ b/packages/opentelemetry-exporter-collector/src/platform/browser/CollectorMetricExporter.ts @@ -22,7 +22,6 @@ import { toCollectorExportMetricServiceRequest } from '../../transformMetrics'; import { getEnv, baggageUtils } from '@opentelemetry/core'; const DEFAULT_COLLECTOR_URL = 'http://localhost:55681/v1/metrics'; -const DEFAULT_SERVICE_NAME = 'collector-metric-exporter'; /** * Collector Metric Exporter for Web @@ -65,8 +64,4 @@ export class CollectorMetricExporter ? getEnv().OTEL_EXPORTER_OTLP_ENDPOINT : DEFAULT_COLLECTOR_URL; } - - getDefaultServiceName(config: CollectorExporterConfigBase): string { - return config.serviceName || DEFAULT_SERVICE_NAME; - } } diff --git a/packages/opentelemetry-exporter-collector/src/platform/browser/CollectorTraceExporter.ts b/packages/opentelemetry-exporter-collector/src/platform/browser/CollectorTraceExporter.ts index 8115e3a546..305875a088 100644 --- a/packages/opentelemetry-exporter-collector/src/platform/browser/CollectorTraceExporter.ts +++ b/packages/opentelemetry-exporter-collector/src/platform/browser/CollectorTraceExporter.ts @@ -21,7 +21,6 @@ import { toCollectorExportTraceServiceRequest } from '../../transform'; import * as collectorTypes from '../../types'; import { getEnv, baggageUtils } from '@opentelemetry/core'; -const DEFAULT_SERVICE_NAME = 'collector-trace-exporter'; const DEFAULT_COLLECTOR_URL = 'http://localhost:55681/v1/traces'; /** @@ -57,8 +56,4 @@ export class CollectorTraceExporter ? getEnv().OTEL_EXPORTER_OTLP_ENDPOINT : DEFAULT_COLLECTOR_URL; } - - getDefaultServiceName(config: CollectorExporterConfigBase): string { - return config.serviceName ?? DEFAULT_SERVICE_NAME; - } } diff --git a/packages/opentelemetry-exporter-collector/src/platform/node/CollectorMetricExporter.ts b/packages/opentelemetry-exporter-collector/src/platform/node/CollectorMetricExporter.ts index 90800cc250..dcffc1ac95 100644 --- a/packages/opentelemetry-exporter-collector/src/platform/node/CollectorMetricExporter.ts +++ b/packages/opentelemetry-exporter-collector/src/platform/node/CollectorMetricExporter.ts @@ -21,7 +21,6 @@ import { CollectorExporterNodeBase } from './CollectorExporterNodeBase'; import { toCollectorExportMetricServiceRequest } from '../../transformMetrics'; import { getEnv, baggageUtils } from '@opentelemetry/core'; -const DEFAULT_SERVICE_NAME = 'collector-metric-exporter'; const DEFAULT_COLLECTOR_URL = 'http://localhost:55681/v1/metrics'; /** @@ -65,8 +64,4 @@ export class CollectorMetricExporter ? getEnv().OTEL_EXPORTER_OTLP_ENDPOINT : DEFAULT_COLLECTOR_URL; } - - getDefaultServiceName(config: CollectorExporterNodeConfigBase): string { - return config.serviceName || DEFAULT_SERVICE_NAME; - } } diff --git a/packages/opentelemetry-exporter-collector/src/platform/node/CollectorTraceExporter.ts b/packages/opentelemetry-exporter-collector/src/platform/node/CollectorTraceExporter.ts index f33d90400d..7354491208 100644 --- a/packages/opentelemetry-exporter-collector/src/platform/node/CollectorTraceExporter.ts +++ b/packages/opentelemetry-exporter-collector/src/platform/node/CollectorTraceExporter.ts @@ -21,7 +21,6 @@ import * as collectorTypes from '../../types'; import { toCollectorExportTraceServiceRequest } from '../../transform'; import { getEnv, baggageUtils } from '@opentelemetry/core'; -const DEFAULT_SERVICE_NAME = 'collector-trace-exporter'; const DEFAULT_COLLECTOR_URL = 'http://localhost:55681/v1/traces'; /** @@ -58,8 +57,4 @@ export class CollectorTraceExporter ? getEnv().OTEL_EXPORTER_OTLP_ENDPOINT : DEFAULT_COLLECTOR_URL; } - - getDefaultServiceName(config: CollectorExporterNodeConfigBase): string { - return config.serviceName || DEFAULT_SERVICE_NAME; - } } diff --git a/packages/opentelemetry-exporter-collector/src/transform.ts b/packages/opentelemetry-exporter-collector/src/transform.ts index 37770ef759..0554f055f9 100644 --- a/packages/opentelemetry-exporter-collector/src/transform.ts +++ b/packages/opentelemetry-exporter-collector/src/transform.ts @@ -285,10 +285,7 @@ export function toCollectorExportTraceServiceRequest< const additionalAttributes = Object.assign( {}, - collectorTraceExporterBase.attributes, - { - 'service.name': collectorTraceExporterBase.serviceName, - } + collectorTraceExporterBase.attributes ); return { diff --git a/packages/opentelemetry-exporter-collector/src/transformMetrics.ts b/packages/opentelemetry-exporter-collector/src/transformMetrics.ts index b992a3b5ee..424bb77a43 100644 --- a/packages/opentelemetry-exporter-collector/src/transformMetrics.ts +++ b/packages/opentelemetry-exporter-collector/src/transformMetrics.ts @@ -177,10 +177,7 @@ export function toCollectorExportMetricServiceRequest< > = groupMetricsByResourceAndLibrary(metrics); const additionalAttributes = Object.assign( {}, - collectorExporterBase.attributes, - { - 'service.name': collectorExporterBase.serviceName, - } + collectorExporterBase.attributes ); return { resourceMetrics: toCollectorResourceMetrics( diff --git a/packages/opentelemetry-exporter-collector/src/types.ts b/packages/opentelemetry-exporter-collector/src/types.ts index f0b02825f3..d1de81259e 100644 --- a/packages/opentelemetry-exporter-collector/src/types.ts +++ b/packages/opentelemetry-exporter-collector/src/types.ts @@ -343,7 +343,6 @@ export interface ExportServiceError { export interface CollectorExporterConfigBase { headers?: Partial>; hostname?: string; - serviceName?: string; attributes?: SpanAttributes; url?: string; concurrencyLimit?: number; diff --git a/packages/opentelemetry-exporter-collector/test/browser/CollectorMetricExporter.test.ts b/packages/opentelemetry-exporter-collector/test/browser/CollectorMetricExporter.test.ts index 5f40d55c2e..d5208d20a0 100644 --- a/packages/opentelemetry-exporter-collector/test/browser/CollectorMetricExporter.test.ts +++ b/packages/opentelemetry-exporter-collector/test/browser/CollectorMetricExporter.test.ts @@ -84,7 +84,6 @@ describe('CollectorMetricExporter - web', () => { beforeEach(() => { collectorExporter = new CollectorMetricExporter({ url: 'http://foo.bar.com', - serviceName: 'bar', }); // Overwrites the start time to make tests consistent Object.defineProperty(collectorExporter, '_startTime', { @@ -193,7 +192,6 @@ describe('CollectorMetricExporter - web', () => { (window.navigator as any).sendBeacon = false; collectorExporter = new CollectorMetricExporter({ url: 'http://foo.bar.com', - serviceName: 'bar', }); // Overwrites the start time to make tests consistent Object.defineProperty(collectorExporter, '_startTime', { diff --git a/packages/opentelemetry-exporter-collector/test/browser/CollectorTraceExporter.test.ts b/packages/opentelemetry-exporter-collector/test/browser/CollectorTraceExporter.test.ts index f0950cb3f2..f0b8e6a1d2 100644 --- a/packages/opentelemetry-exporter-collector/test/browser/CollectorTraceExporter.test.ts +++ b/packages/opentelemetry-exporter-collector/test/browser/CollectorTraceExporter.test.ts @@ -54,7 +54,6 @@ describe('CollectorTraceExporter - web', () => { beforeEach(() => { collectorExporterConfig = { hostname: 'foo', - serviceName: 'bar', attributes: {}, url: 'http://foo.bar.com', }; diff --git a/packages/opentelemetry-exporter-collector/test/common/CollectorMetricExporter.test.ts b/packages/opentelemetry-exporter-collector/test/common/CollectorMetricExporter.test.ts index c455c0d1ad..63aea69a14 100644 --- a/packages/opentelemetry-exporter-collector/test/common/CollectorMetricExporter.test.ts +++ b/packages/opentelemetry-exporter-collector/test/common/CollectorMetricExporter.test.ts @@ -41,9 +41,6 @@ class CollectorMetricExporter extends CollectorExporterBase< getDefaultUrl(config: CollectorExporterConfig) { return config.url || ''; } - getDefaultServiceName(config: CollectorExporterConfig): string { - return config.serviceName || 'collector-metric-exporter'; - } convert( metrics: MetricRecord[] ): collectorTypes.opentelemetryProto.collector.metrics.v1.ExportMetricsServiceRequest { @@ -67,7 +64,6 @@ describe('CollectorMetricExporter - common', () => { onInitSpy = sinon.stub(CollectorMetricExporter.prototype, 'onInit'); collectorExporterConfig = { hostname: 'foo', - serviceName: 'bar', attributes: {}, url: 'http://foo.bar.com', }; @@ -100,10 +96,6 @@ describe('CollectorMetricExporter - common', () => { assert.strictEqual(collectorExporter.hostname, 'foo'); }); - it('should set serviceName', () => { - assert.strictEqual(collectorExporter.serviceName, 'bar'); - }); - it('should set url', () => { assert.strictEqual(collectorExporter.url, 'http://foo.bar.com'); }); @@ -113,13 +105,6 @@ describe('CollectorMetricExporter - common', () => { beforeEach(() => { collectorExporter = new CollectorMetricExporter(); }); - - it('should set default serviceName', () => { - assert.strictEqual( - collectorExporter.serviceName, - 'collector-metric-exporter' - ); - }); }); }); @@ -201,7 +186,6 @@ describe('CollectorMetricExporter - common', () => { ); collectorExporterConfig = { hostname: 'foo', - serviceName: 'bar', attributes: {}, url: 'http://foo.bar.com', }; diff --git a/packages/opentelemetry-exporter-collector/test/common/CollectorTraceExporter.test.ts b/packages/opentelemetry-exporter-collector/test/common/CollectorTraceExporter.test.ts index d104fd26c1..4d025ad191 100644 --- a/packages/opentelemetry-exporter-collector/test/common/CollectorTraceExporter.test.ts +++ b/packages/opentelemetry-exporter-collector/test/common/CollectorTraceExporter.test.ts @@ -46,9 +46,6 @@ class CollectorTraceExporter extends CollectorExporterBase< getDefaultUrl(config: CollectorExporterConfig): string { return config.url || ''; } - getDefaultServiceName(config: CollectorExporterConfig): string { - return config.serviceName || 'collector-exporter'; - } convert( spans: ReadableSpan[] @@ -72,7 +69,6 @@ describe('CollectorTraceExporter - common', () => { onInitSpy = sinon.stub(CollectorTraceExporter.prototype, 'onInit'); collectorExporterConfig = { hostname: 'foo', - serviceName: 'bar', attributes: {}, url: 'http://foo.bar.com', }; @@ -92,24 +88,10 @@ describe('CollectorTraceExporter - common', () => { assert.strictEqual(collectorExporter.hostname, 'foo'); }); - it('should set serviceName', () => { - assert.strictEqual(collectorExporter.serviceName, 'bar'); - }); - it('should set url', () => { assert.strictEqual(collectorExporter.url, 'http://foo.bar.com'); }); }); - - describe('when config is missing certain params', () => { - beforeEach(() => { - collectorExporter = new CollectorTraceExporter(); - }); - - it('should set default serviceName', () => { - assert.strictEqual(collectorExporter.serviceName, 'collector-exporter'); - }); - }); }); describe('export', () => { @@ -221,7 +203,6 @@ describe('CollectorTraceExporter - common', () => { ); collectorExporterConfig = { hostname: 'foo', - serviceName: 'bar', attributes: {}, url: 'http://foo.bar.com', }; diff --git a/packages/opentelemetry-exporter-collector/test/helper.ts b/packages/opentelemetry-exporter-collector/test/helper.ts index dde640298e..66a4a9ed5d 100644 --- a/packages/opentelemetry-exporter-collector/test/helper.ts +++ b/packages/opentelemetry-exporter-collector/test/helper.ts @@ -24,7 +24,7 @@ import { ValueRecorder, ValueType, } from '@opentelemetry/api-metrics'; -import { hexToBase64, InstrumentationLibrary } from '@opentelemetry/core'; +import { hexToBase64, InstrumentationLibrary, VERSION } from '@opentelemetry/core'; import * as metrics from '@opentelemetry/metrics'; import { Resource } from '@opentelemetry/resources'; import { ReadableSpan } from '@opentelemetry/tracing'; @@ -203,11 +203,12 @@ export const mockedReadableSpan: ReadableSpan = { }, ], duration: [0, 8885000], - resource: new Resource({ - service: 'ui', - version: 1, - cost: 112.12, - }), + resource: Resource.default() + .merge(new Resource({ + service: 'ui', + version: 1, + cost: 112.12, + })), instrumentationLibrary: { name: 'default', version: '0.0.1' }, }; @@ -532,35 +533,22 @@ export function ensureSpanIsCorrect( export function ensureWebResourceIsCorrect( resource: collectorTypes.opentelemetryProto.resource.v1.Resource ) { - assert.deepStrictEqual(resource, { - attributes: [ - { - key: 'service.name', - value: { - stringValue: 'bar', - }, - }, - { - key: 'service', - value: { - stringValue: 'ui', - }, - }, - { - key: 'version', - value: { - intValue: 1, - }, - }, - { - key: 'cost', - value: { - doubleValue: 112.12, - }, - }, - ], - droppedAttributesCount: 0, - }); + assert.strictEqual(resource.attributes.length, 7); + assert.strictEqual(resource.attributes[0].key, 'service.name'); + assert.strictEqual(resource.attributes[0].value.stringValue, 'unknown_service'); + assert.strictEqual(resource.attributes[1].key, 'telemetry.sdk.language'); + assert.strictEqual(resource.attributes[1].value.stringValue, 'webjs'); + assert.strictEqual(resource.attributes[2].key, 'telemetry.sdk.name'); + assert.strictEqual(resource.attributes[2].value.stringValue, 'opentelemetry'); + assert.strictEqual(resource.attributes[3].key, 'telemetry.sdk.version'); + assert.strictEqual(resource.attributes[3].value.stringValue, VERSION); + assert.strictEqual(resource.attributes[4].key, 'service'); + assert.strictEqual(resource.attributes[4].value.stringValue, 'ui'); + assert.strictEqual(resource.attributes[5].key, 'version'); + assert.strictEqual(resource.attributes[5].value.intValue, 1); + assert.strictEqual(resource.attributes[6].key, 'cost'); + assert.strictEqual(resource.attributes[6].value.doubleValue, 112.12); + assert.strictEqual(resource.droppedAttributesCount, 0); } export function ensureCounterIsCorrect( diff --git a/packages/opentelemetry-exporter-collector/test/node/CollectorMetricExporter.test.ts b/packages/opentelemetry-exporter-collector/test/node/CollectorMetricExporter.test.ts index dc3c0a98ff..750b196a2c 100644 --- a/packages/opentelemetry-exporter-collector/test/node/CollectorMetricExporter.test.ts +++ b/packages/opentelemetry-exporter-collector/test/node/CollectorMetricExporter.test.ts @@ -129,7 +129,6 @@ describe('CollectorMetricExporter - node with json over http', () => { foo: 'bar', }, hostname: 'foo', - serviceName: 'bar', attributes: {}, url: 'http://foo.bar.com', keepAlive: true, diff --git a/packages/opentelemetry-exporter-collector/test/node/CollectorTraceExporter.test.ts b/packages/opentelemetry-exporter-collector/test/node/CollectorTraceExporter.test.ts index ec9fac3653..d64ef15db1 100644 --- a/packages/opentelemetry-exporter-collector/test/node/CollectorTraceExporter.test.ts +++ b/packages/opentelemetry-exporter-collector/test/node/CollectorTraceExporter.test.ts @@ -115,7 +115,6 @@ describe('CollectorTraceExporter - node with json over http', () => { foo: 'bar', }, hostname: 'foo', - serviceName: 'bar', attributes: {}, url: 'http://foo.bar.com', keepAlive: true, diff --git a/packages/opentelemetry-exporter-jaeger/package.json b/packages/opentelemetry-exporter-jaeger/package.json index b0bfd07521..53314e2353 100644 --- a/packages/opentelemetry-exporter-jaeger/package.json +++ b/packages/opentelemetry-exporter-jaeger/package.json @@ -60,6 +60,7 @@ }, "dependencies": { "@opentelemetry/core": "0.19.0", + "@opentelemetry/semantic-conventions": "0.19.0", "@opentelemetry/tracing": "0.19.0", "jaeger-client": "^3.15.0" } diff --git a/packages/opentelemetry-exporter-jaeger/src/jaeger.ts b/packages/opentelemetry-exporter-jaeger/src/jaeger.ts index 7de46984e9..335767366d 100644 --- a/packages/opentelemetry-exporter-jaeger/src/jaeger.ts +++ b/packages/opentelemetry-exporter-jaeger/src/jaeger.ts @@ -18,6 +18,7 @@ import { diag } from '@opentelemetry/api'; import { ExportResult, ExportResultCode, getEnv } from '@opentelemetry/core'; import { ReadableSpan, SpanExporter } from '@opentelemetry/tracing'; import { Socket } from 'dgram'; +import { ResourceAttributes } from '@opentelemetry/semantic-conventions'; import { spanToThrift } from './transform'; import * as jaegerTypes from './types'; @@ -25,16 +26,16 @@ import * as jaegerTypes from './types'; * Format and sends span information to Jaeger Exporter. */ export class JaegerExporter implements SpanExporter { - private readonly _process: jaegerTypes.ThriftProcess; - private readonly _sender: typeof jaegerTypes.UDPSender; private readonly _onShutdownFlushTimeout: number; + private readonly _localConfig: jaegerTypes.ExporterConfig; private _isShutdown = false; private _shutdownFlushTimeout: NodeJS.Timeout | undefined; private _shuttingDownPromise: Promise = Promise.resolve(); - constructor(config: jaegerTypes.ExporterConfig) { + private _sender?: typeof jaegerTypes.UDPSender; + + constructor(config?: jaegerTypes.ExporterConfig) { const localConfig = Object.assign({}, config); - const tags: jaegerTypes.Tag[] = localConfig.tags || []; this._onShutdownFlushTimeout = typeof localConfig.flushTimeout === 'number' ? localConfig.flushTimeout @@ -54,24 +55,8 @@ export class JaegerExporter implements SpanExporter { localConfig.password = localConfig.password || env.OTEL_EXPORTER_JAEGER_PASSWORD; localConfig.host = localConfig.host || env.OTEL_EXPORTER_JAEGER_AGENT_HOST; - if (localConfig.endpoint) { - this._sender = new jaegerTypes.HTTPSender(localConfig); - } else { - this._sender = localConfig.endpoint = new jaegerTypes.UDPSender( - localConfig - ); - } - - if (this._sender._client instanceof Socket) { - // unref socket to prevent it from keeping the process running - this._sender._client.unref(); - } - this._process = { - serviceName: localConfig.serviceName, - tags: jaegerTypes.ThriftUtils.getThriftTags(tags), - }; - this._sender.setProcess(this._process); + this._localConfig = localConfig; } /** Exports a list of spans to Jaeger. */ @@ -144,12 +129,12 @@ export class JaegerExporter implements SpanExporter { // Flush all spans on each export. No-op if span buffer is empty await this._flush(); - if (done) return done({ code: ExportResultCode.SUCCESS }); + if (done) return process.nextTick(done, { code: ExportResultCode.SUCCESS }); } private async _append(span: jaegerTypes.ThriftSpan): Promise { return new Promise((resolve, reject) => { - this._sender.append(span, (count: number, err?: string) => { + this._getSender(span).append(span, (count: number, err?: string) => { if (err) { return reject(new Error(err)); } @@ -158,8 +143,36 @@ export class JaegerExporter implements SpanExporter { }); } + private _getSender(span: jaegerTypes.ThriftSpan): typeof jaegerTypes.UDPSender { + if (this._sender) { + return this._sender; + } + + const sender = this._localConfig.endpoint ? new jaegerTypes.HTTPSender(this._localConfig) : new jaegerTypes.UDPSender(this._localConfig); + + if (sender._client instanceof Socket) { + // unref socket to prevent it from keeping the process running + sender._client.unref(); + } + + const serviceNameTag = span.tags.find(t => t.key === ResourceAttributes.SERVICE_NAME) + const serviceName = serviceNameTag?.vStr || "unknown_service"; + + sender.setProcess({ + serviceName, + tags: jaegerTypes.ThriftUtils.getThriftTags(this._localConfig.tags || []), + }); + + this._sender = sender; + return sender; + } + private async _flush(): Promise { await new Promise((resolve, reject) => { + if (!this._sender) { + return resolve(); + } + this._sender.flush((_count: number, err?: string) => { if (err) { return reject(new Error(err)); diff --git a/packages/opentelemetry-exporter-jaeger/src/types.ts b/packages/opentelemetry-exporter-jaeger/src/types.ts index 9e5c3f0055..4a6ec67f12 100644 --- a/packages/opentelemetry-exporter-jaeger/src/types.ts +++ b/packages/opentelemetry-exporter-jaeger/src/types.ts @@ -18,7 +18,6 @@ * Options for Jaeger configuration */ export interface ExporterConfig { - serviceName: string; tags?: Tag[]; host?: string; // default: 'localhost' port?: number; // default: 6832 diff --git a/packages/opentelemetry-exporter-jaeger/test/jaeger.test.ts b/packages/opentelemetry-exporter-jaeger/test/jaeger.test.ts index afa0605497..0766e5a72a 100644 --- a/packages/opentelemetry-exporter-jaeger/test/jaeger.test.ts +++ b/packages/opentelemetry-exporter-jaeger/test/jaeger.test.ts @@ -23,25 +23,67 @@ import { ReadableSpan } from '@opentelemetry/tracing'; import { TraceFlags } from '@opentelemetry/api'; import { Resource } from '@opentelemetry/resources'; import * as nock from 'nock'; +import { ResourceAttributes } from '@opentelemetry/semantic-conventions'; describe('JaegerExporter', () => { + const readableSpan: ReadableSpan = { + name: 'my-span1', + kind: api.SpanKind.CLIENT, + spanContext: () => { + return { + traceId: 'd4cda95b652f4a1592b449d5929fda1b', + spanId: '6e0c63257de34c92', + traceFlags: TraceFlags.NONE, + }; + }, + startTime: [1566156729, 709], + endTime: [1566156731, 709], + ended: true, + status: { + code: api.SpanStatusCode.ERROR, + }, + attributes: {}, + links: [], + events: [], + duration: [32, 800000000], + resource: new Resource({ + [ResourceAttributes.SERVICE_NAME]: 'opentelemetry' + }), + instrumentationLibrary: { + name: 'default', + version: '0.0.1', + }, + }; describe('constructor', () => { afterEach(() => { delete process.env.OTEL_EXPORTER_JAEGER_AGENT_HOST; }); it('should construct an exporter', () => { - const exporter = new JaegerExporter({ serviceName: 'opentelemetry' }); + const exporter = new JaegerExporter(); assert.ok(typeof exporter.export === 'function'); assert.ok(typeof exporter.shutdown === 'function'); - const process: ThriftProcess = exporter['_sender']._process; - assert.strictEqual(process.serviceName, 'opentelemetry'); - assert.strictEqual(process.tags.length, 0); + }); + + it('should get service name from the the service name resource attribute of the first exported span', done => { + const mockedEndpoint = 'http://testendpoint'; + const scope =nock(mockedEndpoint) + .post('/') + .reply(202) + + const exporter = new JaegerExporter({ + endpoint: mockedEndpoint, + }); + exporter.export([readableSpan], result => { + assert.strictEqual(result.code, ExportResultCode.SUCCESS); + assert.strictEqual(exporter['_sender']._batch.process.serviceName, 'opentelemetry'); + scope.done(); + done(); + }); }); it('should construct an exporter with host, port, logger and tags', () => { const exporter = new JaegerExporter({ - serviceName: 'opentelemetry', host: 'remotehost', port: 8080, tags: [{ key: 'opentelemetry-exporter-jaeger', value: '0.1.0' }], @@ -49,7 +91,12 @@ describe('JaegerExporter', () => { assert.ok(typeof exporter.export === 'function'); assert.ok(typeof exporter.shutdown === 'function'); - const process: ThriftProcess = exporter['_sender']._process; + const process: ThriftProcess = exporter['_getSender']({ + tags: [{ + key: "service.name", + vStr: "opentelemetry" + }] + } as any)._process; assert.strictEqual(exporter['_sender']._host, 'remotehost'); assert.strictEqual(process.serviceName, 'opentelemetry'); assert.strictEqual(process.tags.length, 1); @@ -59,32 +106,44 @@ describe('JaegerExporter', () => { }); it('should default to localhost if no host is configured', () => { - const exporter = new JaegerExporter({ - serviceName: 'opentelemetry', - }); - assert.strictEqual(exporter['_sender']._host, 'localhost'); + const exporter = new JaegerExporter(); + const sender = exporter['_getSender']({ + tags: [{ + key: "service.name", + vStr: "opentelemetry" + }] + } as any); + assert.strictEqual(sender._host, 'localhost'); }); it('should respect jaeger host env variable', () => { process.env.OTEL_EXPORTER_JAEGER_AGENT_HOST = 'env-set-host'; - const exporter = new JaegerExporter({ - serviceName: 'test-service', - }); - assert.strictEqual(exporter['_sender']._host, 'env-set-host'); + const exporter = new JaegerExporter(); + const sender = exporter['_getSender']({ + tags: [{ + key: "service.name", + vStr: "opentelemetry" + }] + } as any); + assert.strictEqual(sender._host, 'env-set-host'); }); it('should prioritize host option over env variable', () => { process.env.OTEL_EXPORTER_JAEGER_AGENT_HOST = 'env-set-host'; const exporter = new JaegerExporter({ - serviceName: 'test-service', host: 'option-set-host', }); - assert.strictEqual(exporter['_sender']._host, 'option-set-host'); + const sender = exporter['_getSender']({ + tags: [{ + key: "service.name", + vStr: "opentelemetry" + }] + } as any); + assert.strictEqual(sender._host, 'option-set-host'); }); it('should construct an exporter with flushTimeout', () => { const exporter = new JaegerExporter({ - serviceName: 'opentelemetry', flushTimeout: 5000, }); assert.ok(typeof exporter.export === 'function'); @@ -94,9 +153,7 @@ describe('JaegerExporter', () => { }); it('should construct an exporter without flushTimeout', () => { - const exporter = new JaegerExporter({ - serviceName: 'opentelemetry', - }); + const exporter = new JaegerExporter(); assert.ok(typeof exporter.export === 'function'); assert.ok(typeof exporter.shutdown === 'function'); @@ -105,39 +162,10 @@ describe('JaegerExporter', () => { }); describe('export', () => { - const readableSpan: ReadableSpan = { - name: 'my-span1', - kind: api.SpanKind.CLIENT, - spanContext: () => { - return { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', - traceFlags: TraceFlags.NONE, - }; - }, - startTime: [1566156729, 709], - endTime: [1566156731, 709], - ended: true, - status: { - code: api.SpanStatusCode.ERROR, - }, - attributes: {}, - links: [], - events: [], - duration: [32, 800000000], - resource: Resource.empty(), - instrumentationLibrary: { - name: 'default', - version: '0.0.1', - }, - }; - let exporter: JaegerExporter; beforeEach(() => { - exporter = new JaegerExporter({ - serviceName: 'opentelemetry', - }); + exporter = new JaegerExporter(); }); afterEach(() => { @@ -156,7 +184,7 @@ describe('JaegerExporter', () => { }); }); - it('should use httpSender if config.endpoint is setten', done => { + it('should use httpSender if config.endpoint is set', done => { const mockedEndpoint = 'http://testendpoint'; nock(mockedEndpoint) .post('/') @@ -166,14 +194,14 @@ describe('JaegerExporter', () => { 'application/x-thrift' ); assert.strictEqual(this.req.headers.host, 'testendpoint'); - done(); }); const exporter = new JaegerExporter({ - serviceName: 'opentelemetry', endpoint: mockedEndpoint, }); - assert.strictEqual(exporter['_sender'].constructor.name, 'HTTPSender'); - exporter.export([readableSpan], () => {}); + exporter.export([readableSpan], () => { + assert.strictEqual(exporter['_sender'].constructor.name, 'HTTPSender'); + done(); + }); }); it('should return failed export result on error', () => { @@ -184,7 +212,6 @@ describe('JaegerExporter', () => { .post('/') .replyWithError(expectedError); const exporter = new JaegerExporter({ - serviceName: 'opentelemetry', endpoint: mockedEndpoint, }); diff --git a/packages/opentelemetry-exporter-zipkin/package.json b/packages/opentelemetry-exporter-zipkin/package.json index b59dea7e3e..03d06876ad 100644 --- a/packages/opentelemetry-exporter-zipkin/package.json +++ b/packages/opentelemetry-exporter-zipkin/package.json @@ -85,7 +85,7 @@ "dependencies": { "@opentelemetry/core": "0.19.0", "@opentelemetry/resources": "0.19.0", - "@opentelemetry/tracing": "0.19.0", - "@opentelemetry/semantic-conventions": "0.19.0" + "@opentelemetry/semantic-conventions": "0.19.0", + "@opentelemetry/tracing": "0.19.0" } } diff --git a/packages/opentelemetry-exporter-zipkin/src/zipkin.ts b/packages/opentelemetry-exporter-zipkin/src/zipkin.ts index c0cd5bbe35..cdf9df1980 100644 --- a/packages/opentelemetry-exporter-zipkin/src/zipkin.ts +++ b/packages/opentelemetry-exporter-zipkin/src/zipkin.ts @@ -64,12 +64,12 @@ export class ZipkinExporter implements SpanExporter { spans: ReadableSpan[], resultCallback: (result: ExportResult) => void ) { - if (typeof this._serviceName !== 'string') { - this._serviceName = String( + const serviceName = String( + this._serviceName || spans[0].resource.attributes[ResourceAttributes.SERVICE_NAME] || - this.DEFAULT_SERVICE_NAME - ); - } + this.DEFAULT_SERVICE_NAME + ); + diag.debug('Zipkin exporter export'); if (this._isShutdown) { setTimeout(() => @@ -81,7 +81,7 @@ export class ZipkinExporter implements SpanExporter { return; } const promise = new Promise(resolve => { - this._sendSpans(spans, this._serviceName!, result => { + this._sendSpans(spans, serviceName, result => { resolve(); resultCallback(result); const index = this._sendingPromises.indexOf(promise); diff --git a/packages/opentelemetry-exporter-zipkin/test/common/transform.test.ts b/packages/opentelemetry-exporter-zipkin/test/common/transform.test.ts index e1336ed151..46f3be7ca1 100644 --- a/packages/opentelemetry-exporter-zipkin/test/common/transform.test.ts +++ b/packages/opentelemetry-exporter-zipkin/test/common/transform.test.ts @@ -21,9 +21,9 @@ import { VERSION, } from '@opentelemetry/core'; import { Resource } from '@opentelemetry/resources'; -import { ResourceAttributes } from '@opentelemetry/semantic-conventions'; import { BasicTracerProvider, Span } from '@opentelemetry/tracing'; import * as assert from 'assert'; +import { ResourceAttributes } from '@opentelemetry/semantic-conventions'; import { statusCodeTagName, statusDescriptionTagName, @@ -32,7 +32,13 @@ import { _toZipkinTags, } from '../../src/transform'; import * as zipkinTypes from '../../src/types'; -const tracer = new BasicTracerProvider().getTracer('default'); +const tracer = new BasicTracerProvider({ + resource: Resource.default().merge( + new Resource({ + [ResourceAttributes.SERVICE_NAME]: 'zipkin-test', + }) + ), +}).getTracer('default'); const language = tracer.resource.attributes[ResourceAttributes.TELEMETRY_SDK_LANGUAGE]; @@ -48,6 +54,7 @@ const DUMMY_RESOURCE = new Resource({ service: 'ui', version: 1, cost: 112.12, + [ResourceAttributes.SERVICE_NAME]: 'zipkin-test', }); describe('transform', () => { @@ -95,6 +102,7 @@ describe('transform', () => { key1: 'value1', key2: 'value2', [statusCodeTagName]: 'UNSET', + [ResourceAttributes.SERVICE_NAME]: 'zipkin-test', 'telemetry.sdk.language': language, 'telemetry.sdk.name': 'opentelemetry', 'telemetry.sdk.version': VERSION, @@ -133,6 +141,7 @@ describe('transform', () => { parentId: undefined, tags: { [statusCodeTagName]: 'UNSET', + [ResourceAttributes.SERVICE_NAME]: 'zipkin-test', 'telemetry.sdk.language': language, 'telemetry.sdk.name': 'opentelemetry', 'telemetry.sdk.version': VERSION, @@ -181,6 +190,7 @@ describe('transform', () => { parentId: undefined, tags: { [statusCodeTagName]: 'UNSET', + [ResourceAttributes.SERVICE_NAME]: 'zipkin-test', 'telemetry.sdk.language': language, 'telemetry.sdk.name': 'opentelemetry', 'telemetry.sdk.version': VERSION, @@ -221,6 +231,7 @@ describe('transform', () => { cost: '112.12', service: 'ui', version: '1', + [ResourceAttributes.SERVICE_NAME]: 'zipkin-test', }); }); it('should map OpenTelemetry SpanStatus.code to a Zipkin tag', () => { @@ -245,13 +256,18 @@ describe('transform', () => { span.status, statusCodeTagName, statusDescriptionTagName, - Resource.empty() + Resource.empty().merge( + new Resource({ + [ResourceAttributes.SERVICE_NAME]: 'zipkin-test', + }) + ) ); assert.deepStrictEqual(tags, { key1: 'value1', key2: 'value2', [statusCodeTagName]: 'ERROR', + [ResourceAttributes.SERVICE_NAME]: 'zipkin-test', }); }); it('should map OpenTelemetry SpanStatus.message to a Zipkin tag', () => { @@ -277,7 +293,11 @@ describe('transform', () => { span.status, statusCodeTagName, statusDescriptionTagName, - Resource.empty() + Resource.empty().merge( + new Resource({ + [ResourceAttributes.SERVICE_NAME]: 'zipkin-test', + }) + ) ); assert.deepStrictEqual(tags, { @@ -285,6 +305,7 @@ describe('transform', () => { key2: 'value2', [statusCodeTagName]: 'ERROR', [statusDescriptionTagName]: status.message, + [ResourceAttributes.SERVICE_NAME]: 'zipkin-test', }); }); }); diff --git a/packages/opentelemetry-exporter-zipkin/test/node/zipkin.test.ts b/packages/opentelemetry-exporter-zipkin/test/node/zipkin.test.ts index 846e30ab06..31192fbd31 100644 --- a/packages/opentelemetry-exporter-zipkin/test/node/zipkin.test.ts +++ b/packages/opentelemetry-exporter-zipkin/test/node/zipkin.test.ts @@ -313,388 +313,220 @@ describe('Zipkin Exporter - node', () => { }); }); - it('should set serviceName to "Opentelemetry Service" by default', () => { - const scope = nock('http://localhost:9411') - .post('/api/v2/spans') - .replyWithError(new Error('My Socket Error')); - - const parentSpanId = '5c1c63257de34c67'; - const startTime = 1566156729709; - const duration = 2000; - - const span1: ReadableSpan = { - name: 'my-span', - kind: api.SpanKind.INTERNAL, - parentSpanId, - spanContext: () => { - return { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', - traceFlags: TraceFlags.NONE, - }; - }, - startTime: [startTime, 0], - endTime: [startTime + duration, 0], - ended: true, - duration: [duration, 0], - status: { - code: api.SpanStatusCode.OK, - }, - attributes: { - key1: 'value1', - key2: 'value2', - }, - links: [], - events: [ - { - name: 'my-event', - time: [startTime + 10, 0], - attributes: { key3: 'value3' }, - }, - ], - resource: Resource.empty(), - instrumentationLibrary: { name: 'default', version: '0.0.1' }, - }; - const span2: ReadableSpan = { - name: 'my-span', - kind: api.SpanKind.SERVER, - spanContext: () => { - return { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', - traceFlags: TraceFlags.NONE, - }; - }, - startTime: [startTime, 0], - endTime: [startTime + duration, 0], - ended: true, - duration: [duration, 0], - status: { - code: api.SpanStatusCode.OK, - }, - attributes: {}, - links: [], - events: [], - resource: Resource.empty(), - instrumentationLibrary: { name: 'default', version: '0.0.1' }, - }; - - const exporter = new ZipkinExporter({}); - - exporter.export([span1, span2], (result: ExportResult) => { - scope.done(); - assert.equal(exporter['_serviceName'], 'OpenTelemetry Service'); - }); - }); - - it('should set serviceName if resource has one', () => { - const resource_service_name = 'resource_service_name'; + it('should call globalErrorHandler on error', () => { + const expectedError = new Error('Whoops'); const scope = nock('http://localhost:9411') .post('/api/v2/spans') - .replyWithError(new Error('My Socket Error')); + .replyWithError(expectedError); - const parentSpanId = '5c1c63257de34c67'; - const startTime = 1566156729709; - const duration = 2000; - - const span1: ReadableSpan = { - name: 'my-span', - kind: api.SpanKind.INTERNAL, - parentSpanId, - spanContext: () => { - return { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', - traceFlags: TraceFlags.NONE, - }; - }, - startTime: [startTime, 0], - endTime: [startTime + duration, 0], - ended: true, - duration: [duration, 0], - status: { - code: api.SpanStatusCode.OK, - }, - attributes: { - key1: 'value1', - key2: 'value2', - }, - links: [], - events: [ - { - name: 'my-event', - time: [startTime + 10, 0], - attributes: { key3: 'value3' }, - }, - ], - resource: new Resource({ - [ResourceAttributes.SERVICE_NAME]: resource_service_name, - }), - instrumentationLibrary: { name: 'default', version: '0.0.1' }, - }; - const span2: ReadableSpan = { - name: 'my-span', - kind: api.SpanKind.SERVER, - spanContext: () => { - return { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', - traceFlags: TraceFlags.NONE, - }; - }, - startTime: [startTime, 0], - endTime: [startTime + duration, 0], - ended: true, - duration: [duration, 0], - status: { - code: api.SpanStatusCode.OK, - }, - attributes: {}, - links: [], - events: [], - resource: Resource.empty(), - instrumentationLibrary: { name: 'default', version: '0.0.1' }, - }; - - const exporter = new ZipkinExporter({}); - - exporter.export([span1, span2], (result: ExportResult) => { - scope.done(); - assert.equal(exporter['_serviceName'], resource_service_name); - - // checking if service name remains consistent in further exports - exporter.export([span2], (result: ExportResult) => { - scope.done(); - assert.equal(exporter['_serviceName'], resource_service_name); - }); + const exporter = new ZipkinExporter({ + serviceName: 'my-service', }); - it('should call globalErrorHandler on error', () => { - const expectedError = new Error('Whoops'); - const scope = nock('http://localhost:9411') - .post('/api/v2/spans') - .replyWithError(expectedError); - - const exporter = new ZipkinExporter({ - serviceName: 'my-service', - }); - - exporter.export([getReadableSpan()], (result: ExportResult) => { - assert.deepStrictEqual(result.code, ExportResultCode.FAILED); - assert.deepStrictEqual(result.error, expectedError); - scope.done(); - }); + exporter.export([getReadableSpan()], (result: ExportResult) => { + assert.deepStrictEqual(result.code, ExportResultCode.FAILED); + assert.deepStrictEqual(result.error, expectedError); + scope.done(); }); }); + }); - it('should set serviceName per-span if resource has one', () => { - const resource_service_name = 'resource_service_name'; - const resource_service_name_prime = 'resource_service_name_prime'; - - let requestBody: zipkinTypes.Span[]; - const scope = nock('http://localhost:9411') - .post('/api/v2/spans', body => { - requestBody = body; - return true; - }) - .replyWithError(new Error('My Socket Error')); - - const parentSpanId = '5c1c63257de34c67'; - const startTime = 1566156729709; - const duration = 2000; - - const span1: ReadableSpan = { - name: 'my-span', - kind: api.SpanKind.INTERNAL, - parentSpanId, - spanContext: () => { - return { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', - traceFlags: TraceFlags.NONE, - }; - }, - startTime: [startTime, 0], - endTime: [startTime + duration, 0], - ended: true, - duration: [duration, 0], - status: { - code: api.SpanStatusCode.OK, - }, - attributes: { - key1: 'value1', - key2: 'value2', - }, - links: [], - events: [ - { - name: 'my-event', - time: [startTime + 10, 0], - attributes: { key3: 'value3' }, - }, - ], - resource: new Resource({ - [ResourceAttributes.SERVICE_NAME]: resource_service_name, - }), - instrumentationLibrary: { name: 'default', version: '0.0.1' }, - }; - const span2: ReadableSpan = { - name: 'my-span', - kind: api.SpanKind.SERVER, - spanContext: () => { - return { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', - traceFlags: TraceFlags.NONE, - }; - }, - startTime: [startTime, 0], - endTime: [startTime + duration, 0], - ended: true, - duration: [duration, 0], - status: { - code: api.SpanStatusCode.OK, + it('should set serviceName per-span if resource has one', () => { + const resource_service_name = 'resource_service_name'; + const resource_service_name_prime = 'resource_service_name_prime'; + + let requestBody: zipkinTypes.Span[]; + const scope = nock('http://localhost:9411') + .post('/api/v2/spans', body => { + requestBody = body; + return true; + }) + .replyWithError(new Error('My Socket Error')); + + const parentSpanId = '5c1c63257de34c67'; + const startTime = 1566156729709; + const duration = 2000; + + const span1: ReadableSpan = { + name: 'my-span', + kind: api.SpanKind.INTERNAL, + parentSpanId, + spanContext: () => ({ + traceId: 'd4cda95b652f4a1592b449d5929fda1b', + spanId: '6e0c63257de34c92', + traceFlags: TraceFlags.NONE, + }), + startTime: [startTime, 0], + endTime: [startTime + duration, 0], + ended: true, + duration: [duration, 0], + status: { + code: api.SpanStatusCode.OK, + }, + attributes: { + key1: 'value1', + key2: 'value2', + }, + links: [], + events: [ + { + name: 'my-event', + time: [startTime + 10, 0], + attributes: { key3: 'value3' }, }, - attributes: {}, - links: [], - events: [], - resource: new Resource({ - [ResourceAttributes.SERVICE_NAME]: resource_service_name_prime, - }), - instrumentationLibrary: { name: 'default', version: '0.0.1' }, - }; - - const exporter = new ZipkinExporter({}); - - exporter.export([span1, span2], (result: ExportResult) => { - requestBody; - scope.done(); - assert.equal( - requestBody[0].localEndpoint.serviceName, - resource_service_name - ); - assert.equal( - requestBody[1].localEndpoint.serviceName, - resource_service_name_prime - ); - }); + ], + resource: new Resource({ + [ResourceAttributes.SERVICE_NAME]: resource_service_name, + }), + instrumentationLibrary: { name: 'default', version: '0.0.1' }, + }; + const span2: ReadableSpan = { + name: 'my-span', + kind: api.SpanKind.SERVER, + spanContext: () => ({ + traceId: 'd4cda95b652f4a1592b449d5929fda1b', + spanId: '6e0c63257de34c92', + traceFlags: TraceFlags.NONE, + }), + startTime: [startTime, 0], + endTime: [startTime + duration, 0], + ended: true, + duration: [duration, 0], + status: { + code: api.SpanStatusCode.OK, + }, + attributes: {}, + links: [], + events: [], + resource: new Resource({ + [ResourceAttributes.SERVICE_NAME]: resource_service_name_prime, + }), + instrumentationLibrary: { name: 'default', version: '0.0.1' }, + }; + + const exporter = new ZipkinExporter({}); + + exporter.export([span1, span2], (result: ExportResult) => { + requestBody; + scope.done(); + assert.equal( + requestBody[0].localEndpoint.serviceName, + resource_service_name + ); + assert.equal( + requestBody[1].localEndpoint.serviceName, + resource_service_name_prime + ); }); + }); - it('should set serviceName per-span if span has attribute', () => { - const span_service_name = 'span_service_name'; - const span_service_name_prime = 'span_service_name_prime'; - - let requestBody: any; - const scope = nock('http://localhost:9411') - .post('/api/v2/spans', body => { - requestBody = body; - return true; - }) - .replyWithError(new Error('My Socket Error')); - - const parentSpanId = '5c1c63257de34c67'; - const startTime = 1566156729709; - const duration = 2000; - - const span1: ReadableSpan = { - name: 'my-span', - kind: api.SpanKind.INTERNAL, - parentSpanId, - spanContext: () => { - return { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', - traceFlags: TraceFlags.NONE, - }; - }, - startTime: [startTime, 0], - endTime: [startTime + duration, 0], - ended: true, - duration: [duration, 0], - status: { - code: api.SpanStatusCode.OK, - }, - attributes: { - key1: 'value1', - key2: 'value2', - [ResourceAttributes.SERVICE_NAME]: span_service_name, - }, - links: [], - events: [ - { - name: 'my-event', - time: [startTime + 10, 0], - attributes: { key3: 'value3' }, - }, - ], - resource: Resource.empty(), - instrumentationLibrary: { name: 'default', version: '0.0.1' }, - }; - const span2: ReadableSpan = { - name: 'my-span', - kind: api.SpanKind.SERVER, - spanContext: () => { - return { - traceId: 'd4cda95b652f4a1592b449d5929fda1b', - spanId: '6e0c63257de34c92', - traceFlags: TraceFlags.NONE, - }; - }, - startTime: [startTime, 0], - endTime: [startTime + duration, 0], - ended: true, - duration: [duration, 0], - status: { - code: api.SpanStatusCode.OK, - }, - attributes: { - [ResourceAttributes.SERVICE_NAME]: span_service_name_prime, + it('should set serviceName per-span if span has attribute', () => { + const span_service_name = 'span_service_name'; + const span_service_name_prime = 'span_service_name_prime'; + + let requestBody: any; + const scope = nock('http://localhost:9411') + .post('/api/v2/spans', body => { + requestBody = body; + return true; + }) + .replyWithError(new Error('My Socket Error')); + + const parentSpanId = '5c1c63257de34c67'; + const startTime = 1566156729709; + const duration = 2000; + + const span1: ReadableSpan = { + name: 'my-span', + kind: api.SpanKind.INTERNAL, + parentSpanId, + spanContext: () => ({ + traceId: 'd4cda95b652f4a1592b449d5929fda1b', + spanId: '6e0c63257de34c92', + traceFlags: TraceFlags.NONE, + }), + startTime: [startTime, 0], + endTime: [startTime + duration, 0], + ended: true, + duration: [duration, 0], + status: { + code: api.SpanStatusCode.OK, + }, + attributes: { + key1: 'value1', + key2: 'value2', + [ResourceAttributes.SERVICE_NAME]: span_service_name, + }, + links: [], + events: [ + { + name: 'my-event', + time: [startTime + 10, 0], + attributes: { key3: 'value3' }, }, - links: [], - events: [], - resource: Resource.empty(), - instrumentationLibrary: { name: 'default', version: '0.0.1' }, - }; - - const exporter = new ZipkinExporter({}); - - exporter.export([span1, span2], (result: ExportResult) => { - requestBody; - scope.done(); - assert.equal( - requestBody[0].localEndpoint.serviceName, - span_service_name - ); - assert.equal( - requestBody[1].localEndpoint.serviceName, - span_service_name_prime - ); - }); + ], + resource: Resource.empty(), + instrumentationLibrary: { name: 'default', version: '0.0.1' }, + }; + const span2: ReadableSpan = { + name: 'my-span', + kind: api.SpanKind.SERVER, + spanContext: () => ({ + traceId: 'd4cda95b652f4a1592b449d5929fda1b', + spanId: '6e0c63257de34c92', + traceFlags: TraceFlags.NONE, + }), + startTime: [startTime, 0], + endTime: [startTime + duration, 0], + ended: true, + duration: [duration, 0], + status: { + code: api.SpanStatusCode.OK, + }, + attributes: { + [ResourceAttributes.SERVICE_NAME]: span_service_name_prime, + }, + links: [], + events: [], + resource: Resource.empty(), + instrumentationLibrary: { name: 'default', version: '0.0.1' }, + }; + + const exporter = new ZipkinExporter({}); + + exporter.export([span1, span2], (result: ExportResult) => { + requestBody; + scope.done(); + assert.equal( + requestBody[0].localEndpoint.serviceName, + span_service_name + ); + assert.equal( + requestBody[1].localEndpoint.serviceName, + span_service_name_prime + ); }); + }); - it('should support setting url via env', () => { + describe('when env.OTEL_EXPORTER_ZIPKIN_ENDPOINT is set', () => { + before(() => { process.env.OTEL_EXPORTER_ZIPKIN_ENDPOINT = 'http://localhost:9412'; + }) + after(() => { + delete process.env.OTEL_EXPORTER_ZIPKIN_ENDPOINT + }) + it('should use url from env', () => { const scope = nock('http://localhost:9412').post('/').reply(200); - + const exporter = new ZipkinExporter({ serviceName: 'my-service', }); - + exporter.export([getReadableSpan()], (result: ExportResult) => { scope.done(); assert.strictEqual(result.code, ExportResultCode.SUCCESS); }); }); }); - - describe('shutdown', () => { - before(() => { - nock.disableNetConnect(); - }); - - after(() => { - nock.enableNetConnect(); - }); - }); }); diff --git a/packages/opentelemetry-metrics/src/Meter.ts b/packages/opentelemetry-metrics/src/Meter.ts index 348c554dec..32f295694c 100644 --- a/packages/opentelemetry-metrics/src/Meter.ts +++ b/packages/opentelemetry-metrics/src/Meter.ts @@ -57,7 +57,7 @@ export class Meter implements api.Meter { const mergedConfig = merge({}, DEFAULT_CONFIG, config); this._processor = mergedConfig.processor ?? new UngroupedProcessor(); this._resource = - mergedConfig.resource || Resource.createTelemetrySDKResource(); + mergedConfig.resource || Resource.empty(); this._instrumentationLibrary = instrumentationLibrary; // start the push controller const exporter = mergedConfig.exporter || new NoopExporter(); diff --git a/packages/opentelemetry-metrics/src/MeterProvider.ts b/packages/opentelemetry-metrics/src/MeterProvider.ts index b38243ae13..1d0cf1f098 100644 --- a/packages/opentelemetry-metrics/src/MeterProvider.ts +++ b/packages/opentelemetry-metrics/src/MeterProvider.ts @@ -33,8 +33,8 @@ export class MeterProvider implements api.MeterProvider { constructor(config: MeterConfig = {}) { const mergedConfig = merge({}, DEFAULT_CONFIG, config); - this.resource = - mergedConfig.resource ?? Resource.createTelemetrySDKResource(); + this.resource = mergedConfig.resource || Resource.empty(); + this.resource = Resource.default().merge(this.resource); this._config = Object.assign({}, mergedConfig, { resource: this.resource, }); diff --git a/packages/opentelemetry-resources/src/Resource.ts b/packages/opentelemetry-resources/src/Resource.ts index ea5ed0ab37..161995ac0f 100644 --- a/packages/opentelemetry-resources/src/Resource.ts +++ b/packages/opentelemetry-resources/src/Resource.ts @@ -17,6 +17,7 @@ import { ResourceAttributes as SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'; import { SDK_INFO } from '@opentelemetry/core'; import { ResourceAttributes } from './types'; +import { defaultServiceName } from './platform'; /** * A Resource describes the entity for which a signals (metrics or trace) are @@ -35,15 +36,16 @@ export class Resource { /** * Returns a Resource that indentifies the SDK in use. */ - static createTelemetrySDKResource(): Resource { + static default(): Resource { return new Resource({ + [SemanticResourceAttributes.SERVICE_NAME]: defaultServiceName(), [SemanticResourceAttributes.TELEMETRY_SDK_LANGUAGE]: SDK_INFO[SemanticResourceAttributes.TELEMETRY_SDK_LANGUAGE], [SemanticResourceAttributes.TELEMETRY_SDK_NAME]: SDK_INFO[SemanticResourceAttributes.TELEMETRY_SDK_NAME], [SemanticResourceAttributes.TELEMETRY_SDK_VERSION]: SDK_INFO[SemanticResourceAttributes.TELEMETRY_SDK_VERSION], - }); + }) } constructor( diff --git a/packages/opentelemetry-resources/src/platform/browser/default-service-name.ts b/packages/opentelemetry-resources/src/platform/browser/default-service-name.ts new file mode 100644 index 0000000000..c31f3bedd9 --- /dev/null +++ b/packages/opentelemetry-resources/src/platform/browser/default-service-name.ts @@ -0,0 +1,19 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export function defaultServiceName() { + return 'unknown_service'; +} \ No newline at end of file diff --git a/packages/opentelemetry-resources/src/platform/browser/detect-resources.ts b/packages/opentelemetry-resources/src/platform/browser/detect-resources.ts index 7ea78b8d39..3a815e8825 100644 --- a/packages/opentelemetry-resources/src/platform/browser/detect-resources.ts +++ b/packages/opentelemetry-resources/src/platform/browser/detect-resources.ts @@ -22,5 +22,5 @@ import { Resource } from '../../Resource'; * is async to match the signature of corresponding method for node. */ export const detectResources = async (): Promise => { - return Resource.createTelemetrySDKResource(); + return Resource.empty(); }; diff --git a/packages/opentelemetry-resources/src/platform/browser/index.ts b/packages/opentelemetry-resources/src/platform/browser/index.ts index f90eb34a5f..742d36add7 100644 --- a/packages/opentelemetry-resources/src/platform/browser/index.ts +++ b/packages/opentelemetry-resources/src/platform/browser/index.ts @@ -14,4 +14,5 @@ * limitations under the License. */ +export * from './default-service-name'; export * from './detect-resources'; diff --git a/packages/opentelemetry-resources/src/platform/node/default-service-name.ts b/packages/opentelemetry-resources/src/platform/node/default-service-name.ts new file mode 100644 index 0000000000..0f5b870a63 --- /dev/null +++ b/packages/opentelemetry-resources/src/platform/node/default-service-name.ts @@ -0,0 +1,19 @@ +/* + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export function defaultServiceName() { + return `unknown_service:${process.argv0}`; +} \ No newline at end of file diff --git a/packages/opentelemetry-resources/src/platform/node/detect-resources.ts b/packages/opentelemetry-resources/src/platform/node/detect-resources.ts index a8e07ba42c..74a4d337b2 100644 --- a/packages/opentelemetry-resources/src/platform/node/detect-resources.ts +++ b/packages/opentelemetry-resources/src/platform/node/detect-resources.ts @@ -48,7 +48,7 @@ export const detectResources = async ( return resources.reduce( (acc, resource) => acc.merge(resource), - Resource.createTelemetrySDKResource() + Resource.empty() ); }; diff --git a/packages/opentelemetry-resources/src/platform/node/detectors/EnvDetector.ts b/packages/opentelemetry-resources/src/platform/node/detectors/EnvDetector.ts index bd2449921b..b496433b4d 100644 --- a/packages/opentelemetry-resources/src/platform/node/detectors/EnvDetector.ts +++ b/packages/opentelemetry-resources/src/platform/node/detectors/EnvDetector.ts @@ -16,6 +16,7 @@ import { diag } from '@opentelemetry/api'; import { getEnv } from '@opentelemetry/core'; +import { ResourceAttributes as SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'; import { Detector, Resource, @@ -55,20 +56,26 @@ class EnvDetector implements Detector { * @param config The resource detection config */ async detect(_config?: ResourceDetectionConfig): Promise { - try { - const rawAttributes = getEnv().OTEL_RESOURCE_ATTRIBUTES; - if (!rawAttributes) { - diag.debug( - 'EnvDetector failed: Environment variable "OTEL_RESOURCE_ATTRIBUTES" is missing.' - ); - return Resource.empty(); + const attributes: ResourceAttributes = {}; + const env = getEnv(); + + const rawAttributes = env.OTEL_RESOURCE_ATTRIBUTES; + const serviceName = env.OTEL_SERVICE_NAME; + + if (rawAttributes) { + try { + const parsedAttributes = this._parseResourceAttributes(rawAttributes); + Object.assign(attributes, parsedAttributes); + } catch (e) { + diag.debug(`EnvDetector failed: ${e.message}`); } - const attributes = this._parseResourceAttributes(rawAttributes); - return new Resource(attributes); - } catch (e) { - diag.debug(`EnvDetector failed: ${e.message}`); - return Resource.empty(); } + + if (serviceName) { + attributes[SemanticResourceAttributes.SERVICE_NAME] = serviceName; + } + + return new Resource(attributes); } /** diff --git a/packages/opentelemetry-resources/src/platform/node/index.ts b/packages/opentelemetry-resources/src/platform/node/index.ts index 7e82a09dd5..00426f781c 100644 --- a/packages/opentelemetry-resources/src/platform/node/index.ts +++ b/packages/opentelemetry-resources/src/platform/node/index.ts @@ -14,5 +14,6 @@ * limitations under the License. */ +export * from './default-service-name'; export * from './detect-resources'; export * from './detectors'; diff --git a/packages/opentelemetry-resources/test/Resource.test.ts b/packages/opentelemetry-resources/test/Resource.test.ts index 4e5962895c..d321a4422c 100644 --- a/packages/opentelemetry-resources/test/Resource.test.ts +++ b/packages/opentelemetry-resources/test/Resource.test.ts @@ -17,7 +17,7 @@ import * as assert from 'assert'; import { SDK_INFO } from '@opentelemetry/core'; import { Resource } from '../src'; -import { assertTelemetrySDKResource } from './util/resource-assertions'; +import { ResourceAttributes } from '@opentelemetry/semantic-conventions'; describe('Resource', () => { const resource1 = new Resource({ @@ -84,15 +84,15 @@ describe('Resource', () => { 'custom.number': 42, 'custom.boolean': true, }); - assert.equal(resource.attributes['custom.string'], 'strvalue'); - assert.equal(resource.attributes['custom.number'], 42); - assert.equal(resource.attributes['custom.boolean'], true); + assert.strictEqual(resource.attributes['custom.string'], 'strvalue'); + assert.strictEqual(resource.attributes['custom.number'], 42); + assert.strictEqual(resource.attributes['custom.boolean'], true); }); describe('.empty()', () => { - it('should return an empty resource', () => { + it('should return an empty resource (except required service name)', () => { const resource = Resource.empty(); - assert.equal(Object.entries(resource.attributes), 0); + assert.deepStrictEqual(Object.keys(resource.attributes), []); }); it('should return the same empty resource', () => { @@ -100,14 +100,13 @@ describe('Resource', () => { }); }); - describe('.createTelemetrySDKResource()', () => { - it('should return a telemetry SDK resource', () => { - const resource = Resource.createTelemetrySDKResource(); - assertTelemetrySDKResource(resource, { - language: SDK_INFO.LANGUAGE, - name: SDK_INFO.NAME, - version: SDK_INFO.VERSION, - }); + describe('.default()', () => { + it('should return a default resource', () => { + const resource = Resource.default(); + assert.strictEqual(resource.attributes[ResourceAttributes.TELEMETRY_SDK_NAME], SDK_INFO[ResourceAttributes.TELEMETRY_SDK_NAME]); + assert.strictEqual(resource.attributes[ResourceAttributes.TELEMETRY_SDK_LANGUAGE], SDK_INFO[ResourceAttributes.TELEMETRY_SDK_LANGUAGE]); + assert.strictEqual(resource.attributes[ResourceAttributes.TELEMETRY_SDK_VERSION], SDK_INFO[ResourceAttributes.TELEMETRY_SDK_VERSION]); + assert.strictEqual(resource.attributes[ResourceAttributes.SERVICE_NAME], `unknown_service:${process.argv0}`); }); }); }); diff --git a/packages/opentelemetry-sdk-node/test/sdk.test.ts b/packages/opentelemetry-sdk-node/test/sdk.test.ts index 920d29f6f2..3f80f61678 100644 --- a/packages/opentelemetry-sdk-node/test/sdk.test.ts +++ b/packages/opentelemetry-sdk-node/test/sdk.test.ts @@ -302,7 +302,7 @@ describe('Node SDK', () => { }); const resource: Resource = sdk['_resource']; assert.ok(resource); - assert.deepStrictEqual(resource, Resource.createTelemetrySDKResource()); + assert.deepStrictEqual(resource, Resource.empty()); scope.done(); }); @@ -392,34 +392,6 @@ describe('Node SDK', () => { ); }); - describe('with missing environment variable', () => { - beforeEach(() => { - delete process.env.OTEL_RESOURCE_ATTRIBUTES; - }); - - it('prints correct error messages when EnvDetector has no env variable', async () => { - const sdk = new NodeSDK({ - autoDetectResources: true, - }); - const mockedLoggerMethod = Sinon.fake(); - diag.setLogger( - { - debug: mockedLoggerMethod, - } as any, - DiagLogLevel.DEBUG - ); - - await sdk.detectResources(); - - assert.ok( - callArgsContains( - mockedLoggerMethod, - 'EnvDetector failed: Environment variable "OTEL_RESOURCE_ATTRIBUTES" is missing.' - ) - ); - }); - }); - describe('with a faulty environment variable', () => { beforeEach(() => { process.env.OTEL_RESOURCE_ATTRIBUTES = 'bad=~attribute'; diff --git a/packages/opentelemetry-tracing/src/BasicTracerProvider.ts b/packages/opentelemetry-tracing/src/BasicTracerProvider.ts index 4166d77394..d8ca406c1c 100644 --- a/packages/opentelemetry-tracing/src/BasicTracerProvider.ts +++ b/packages/opentelemetry-tracing/src/BasicTracerProvider.ts @@ -75,8 +75,8 @@ export class BasicTracerProvider implements TracerProvider { constructor(config: TracerConfig = {}) { const mergedConfig = merge({}, DEFAULT_CONFIG, config); - this.resource = - mergedConfig.resource ?? Resource.createTelemetrySDKResource(); + this.resource = mergedConfig.resource ?? Resource.empty(); + this.resource = Resource.default().merge(this.resource); this._config = Object.assign({}, mergedConfig, { resource: this.resource, });