diff --git a/README.md b/README.md index b3f9350c..5a41d022 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ GitHub release (latest by date) - - Splunk GDI specification + + Splunk GDI specification npm node-current diff --git a/src/detectors/DistroDetector.ts b/src/detectors/DistroDetector.ts index 69180daf..3d6a798c 100644 --- a/src/detectors/DistroDetector.ts +++ b/src/detectors/DistroDetector.ts @@ -21,14 +21,11 @@ import { } from '@opentelemetry/resources'; import { VERSION } from '../version'; -/** - * DistroDetector will be used to detect `splunk.distro.version` and other - * distro-related resource information. - */ class DistroDetector { detect(_config?: ResourceDetectionConfig): Resource { const distroAttributes: ResourceAttributes = { - 'splunk.distro.version': VERSION, + 'telemetry.distro.name': 'splunk-nodejs', + 'telemetry.distro.version': VERSION, }; return new Resource(distroAttributes); } diff --git a/src/logging/index.ts b/src/logging/index.ts index c1d9173b..17bfe928 100644 --- a/src/logging/index.ts +++ b/src/logging/index.ts @@ -18,7 +18,6 @@ import * as util from 'util'; import * as logsAPI from '@opentelemetry/api-logs'; import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http'; import { Resource } from '@opentelemetry/resources'; -import { diag } from '@opentelemetry/api'; import { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions'; import { LoggerProvider, @@ -72,14 +71,6 @@ export function _setDefaultOptions( getNonEmptyEnvVar('OTEL_SERVICE_NAME') || envResource.attributes[ATTR_SERVICE_NAME]; - if (!serviceName) { - diag.warn( - 'service.name attribute for logging is not set, your service is unnamed and will be difficult to identify. ' + - 'Set your service name using the OTEL_RESOURCE_ATTRIBUTES environment variable. ' + - 'E.g. OTEL_RESOURCE_ATTRIBUTES="service.name="' - ); - } - const resourceFactory = options.resourceFactory || ((r: Resource) => r); const resource = resourceFactory(envResource).merge( new Resource({ diff --git a/src/metrics/index.ts b/src/metrics/index.ts index 7b212236..e1c84eb2 100644 --- a/src/metrics/index.ts +++ b/src/metrics/index.ts @@ -132,7 +132,12 @@ export function createOtlpExporter(options: MetricsOptions) { ); } - if (options.endpoint === undefined) { + const envEndpoint = getEnvValueByPrecedence([ + 'OTEL_EXPORTER_OTLP_METRICS_ENDPOINT', + 'OTEL_EXPORTER_OTLP_ENDPOINT', + ]); + + if (endpoint === undefined && envEndpoint === undefined) { endpoint = `https://ingest.${options.realm}.signalfx.com/v2/datapoint/otlp`; protocol = 'http/protobuf'; } else { @@ -366,9 +371,6 @@ export function _setDefaultOptions( const accessToken = options.accessToken || getNonEmptyEnvVar('SPLUNK_ACCESS_TOKEN') || ''; - const endpoint = - options.endpoint || getNonEmptyEnvVar('SPLUNK_METRICS_ENDPOINT'); - const realm = options.realm || getNonEmptyEnvVar('SPLUNK_REALM') || ''; if (realm) { @@ -408,7 +410,7 @@ export function _setDefaultOptions( accessToken, realm, resource, - endpoint, + endpoint: options.endpoint, views: options.views, metricReaderFactory: options.metricReaderFactory ?? defaultMetricReaderFactory, diff --git a/src/start.ts b/src/start.ts index 7f577ff6..f69bed84 100644 --- a/src/start.ts +++ b/src/start.ts @@ -38,8 +38,10 @@ import { MeterOptions, createNoopMeter, } from '@opentelemetry/api'; +import { ATTR_SERVICE_NAME } from '@opentelemetry/semantic-conventions'; import { StartLoggingOptions, startLogging } from './logging'; import { Resource } from '@opentelemetry/resources'; +import { getDetectedResource } from './resource'; export interface Options { accessToken: string; @@ -94,6 +96,21 @@ export const start = (options: Partial = {}) => { diag.setLogger(new DiagConsoleLogger(), logLevel); } + const envResource = getDetectedResource(); + + const serviceName = + options.serviceName || + getNonEmptyEnvVar('OTEL_SERVICE_NAME') || + envResource.attributes[ATTR_SERVICE_NAME]; + + if (!serviceName) { + diag.warn( + 'service.name attribute is not set, your service is unnamed and will be difficult to identify. ' + + 'Set your service name using the OTEL_RESOURCE_ATTRIBUTES environment variable. ' + + 'E.g. OTEL_RESOURCE_ATTRIBUTES="service.name="' + ); + } + const { tracingOptions, loggingOptions, profilingOptions, metricsOptions } = parseOptionsAndConfigureInstrumentations(options); diff --git a/src/tracing/options.ts b/src/tracing/options.ts index 33ec62f6..2b9f90be 100644 --- a/src/tracing/options.ts +++ b/src/tracing/options.ts @@ -81,14 +81,6 @@ export function _setDefaultOptions( getNonEmptyEnvVar('OTEL_SERVICE_NAME') || resource.attributes[ATTR_SERVICE_NAME]; - if (!serviceName) { - diag.warn( - 'service.name attribute is not set, your service is unnamed and will be difficult to identify. ' + - 'Set your service name using the OTEL_RESOURCE_ATTRIBUTES environment variable. ' + - 'E.g. OTEL_RESOURCE_ATTRIBUTES="service.name="' - ); - } - resource = resource.merge( new Resource({ [ATTR_SERVICE_NAME]: serviceName || defaultServiceName(), diff --git a/src/types.ts b/src/types.ts index 51af1d49..2d02123b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -27,6 +27,7 @@ export type EnvVarKey = | 'OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE' | 'OTEL_EXPORTER_OTLP_CLIENT_KEY' | 'OTEL_EXPORTER_OTLP_ENDPOINT' + | 'OTEL_EXPORTER_OTLP_METRICS_ENDPOINT' | 'OTEL_EXPORTER_OTLP_METRICS_PROTOCOL' | 'OTEL_EXPORTER_OTLP_PROTOCOL' | 'OTEL_EXPORTER_OTLP_TRACES_ENDPOINT' @@ -47,7 +48,6 @@ export type EnvVarKey = | 'SPLUNK_GRAPHQL_RESOLVE_SPANS_ENABLED' | 'SPLUNK_INSTRUMENTATION_METRICS_ENABLED' | 'SPLUNK_METRICS_ENABLED' - | 'SPLUNK_METRICS_ENDPOINT' | 'SPLUNK_NEXTJS_FIX_ENABLED' | 'SPLUNK_PROFILER_CALL_STACK_INTERVAL' | 'SPLUNK_PROFILER_ENABLED' diff --git a/src/utils.ts b/src/utils.ts index 7641d360..7913d9d6 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -427,15 +427,6 @@ export function listEnvVars() { type: 'boolean', category: 'metrics', }, - { - name: 'SPLUNK_METRICS_ENDPOINT', - property: 'metrics.endpoint', - description: - 'The metrics endpoint. Takes precedence over OTEL_EXPORTER_OTLP_METRICS_ENDPOINT. When SPLUNK_REALM is used, the default value is https://ingest..signalfx.com/v2/datapoint/otlp.', - default: '', - type: 'string', - category: 'metrics', - }, { name: 'SPLUNK_PROFILER_ENABLED', property: 'profilingEnabled', diff --git a/test/metrics.options.test.ts b/test/metrics.options.test.ts index 868f15e5..175033be 100644 --- a/test/metrics.options.test.ts +++ b/test/metrics.options.test.ts @@ -166,7 +166,7 @@ describe('metrics options', () => { it('warns when realm and endpoint are both set', () => { process.env.SPLUNK_REALM = 'us0'; process.env.SPLUNK_ACCESS_TOKEN = 'abc'; - process.env.SPLUNK_METRICS_ENDPOINT = 'http://localhost:4320'; + process.env.OTEL_EXPORTER_OTLP_ENDPOINT = 'http://localhost:4320'; const options = _setDefaultOptions(); const [reader] = options.metricReaderFactory(options); diff --git a/test/options.test.ts b/test/options.test.ts index d92dac24..f646dafd 100644 --- a/test/options.test.ts +++ b/test/options.test.ts @@ -68,12 +68,6 @@ const assertContainerId = (containerIdAttr) => { `${containerIdAttr} is not an hex string` ); }; -/* - service.name attribute is not set, your service is unnamed and will be difficult to identify. - Set your service name using the OTEL_RESOURCE_ATTRIBUTES environment variable. - E.g. OTEL_RESOURCE_ATTRIBUTES="service.name=" -*/ -const MATCH_SERVICE_NAME_WARNING = /service\.name.*not.*set/i; describe('options', () => { let logger; @@ -111,9 +105,12 @@ describe('options', () => { it('has expected defaults', () => { const options = _setDefaultOptions(); - assertVersion( - options.tracerConfig.resource?.attributes['splunk.distro.version'] - ); + const resAttrs = + options.tracerConfig.resource?.attributes || Resource.empty(); + + assertVersion(resAttrs['telemetry.distro.version']); + + assert.strictEqual(resAttrs['telemetry.distro.name'], 'splunk-nodejs'); const expectedAttributes = new Set([ ATTR_HOST_ARCH, @@ -124,27 +121,22 @@ describe('options', () => { ATTR_PROCESS_PID, ATTR_PROCESS_RUNTIME_NAME, ATTR_PROCESS_RUNTIME_VERSION, - 'splunk.distro.version', + 'telemetry.distro.version', + 'telemetry.distro.name', ]); expectedAttributes.forEach((processAttribute) => { - assert( - options.tracerConfig.resource?.attributes[processAttribute], - `${processAttribute} missing` - ); + assert(resAttrs[processAttribute], `${processAttribute} missing`); }); - assert.deepStrictEqual( - options.tracerConfig.resource?.attributes[ATTR_SERVICE_NAME], - '@splunk/otel' - ); + assert.deepStrictEqual(resAttrs[ATTR_SERVICE_NAME], '@splunk/otel'); // Container ID is checked in a different test, // this avoids collisions with stubbing fs methods. - delete options.tracerConfig.resource.attributes[ATTR_CONTAINER_ID]; + delete resAttrs[ATTR_CONTAINER_ID]; // resource attributes for process, host and os are different at each run, iterate through them, make sure they exist and then delete - Object.keys(options.tracerConfig.resource.attributes) + Object.keys(resAttrs) .filter((attribute) => { return expectedAttributes.has(attribute); }) @@ -184,9 +176,6 @@ describe('options', () => { const [exporter] = exporters; assert(exporter instanceof OTLPTraceExporter); - - const logMsg = logger.warn.mock.calls[0].arguments[0]; - assert(MATCH_SERVICE_NAME_WARNING.test(logMsg)); }); it('reads the container when setting default options', async () => { diff --git a/test/runner.js b/test/runner.js index 51e93baa..3e91b7b5 100644 --- a/test/runner.js +++ b/test/runner.js @@ -42,6 +42,8 @@ const args = [ '--require', 'ts-node/register/transpile-only', '--test', + '--test-reporter', + 'spec', ...testFiles, ]; diff --git a/test/start.test.ts b/test/start.test.ts index c92e9184..a09a39c0 100644 --- a/test/start.test.ts +++ b/test/start.test.ts @@ -269,18 +269,21 @@ describe('start', () => { describe('diagnostic logging', () => { let logSpy; let infoSpy; + let warnSpy; let debugSpy; beforeEach(() => { utils.cleanEnvironment(); logSpy = mock.method(console, 'log'); infoSpy = mock.method(console, 'info'); + warnSpy = mock.method(console, 'warn'); debugSpy = mock.method(console, 'debug'); }); afterEach(() => { logSpy.mock.resetCalls(); infoSpy.mock.resetCalls(); + warnSpy.mock.resetCalls(); debugSpy.mock.resetCalls(); }); @@ -315,5 +318,15 @@ describe('start', () => { diag.debug('42'); assert(debugSpy.mock.callCount() === 0); }); + + it('logs a warning when service name is not set', () => { + start({ logLevel: 'info' }); + utils.calledWithExactly( + warnSpy, + 'service.name attribute is not set, your service is unnamed and will be difficult to identify. ' + + 'Set your service name using the OTEL_RESOURCE_ATTRIBUTES environment variable. ' + + 'E.g. OTEL_RESOURCE_ATTRIBUTES="service.name="' + ); + }); }); });