UNPKG

@splunk/otel

Version:

The Splunk distribution of OpenTelemetry Node Instrumentation provides a Node agent that automatically instruments your Node application to capture and report distributed traces to Splunk APM.

238 lines 10.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports._setDefaultOptions = _setDefaultOptions; exports.defaultSpanExporterFactory = defaultSpanExporterFactory; exports.otlpSpanExporterFactory = otlpSpanExporterFactory; exports.consoleSpanExporterFactory = consoleSpanExporterFactory; exports.defaultSpanProcessorFactory = defaultSpanProcessorFactory; exports.defaultPropagatorFactory = defaultPropagatorFactory; /* * Copyright Splunk Inc. * * 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 * * http://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. */ const util = require("util"); const sdk_trace_base_1 = require("@opentelemetry/sdk-trace-base"); const propagator_b3_1 = require("@opentelemetry/propagator-b3"); const propagator_aws_xray_1 = require("@opentelemetry/propagator-aws-xray"); const instrumentations_1 = require("../instrumentations"); const exporter_trace_otlp_proto_1 = require("@opentelemetry/exporter-trace-otlp-proto"); const resource_1 = require("../resource"); const utils_1 = require("../utils"); const semantic_conventions_1 = require("@opentelemetry/semantic-conventions"); const api_1 = require("@opentelemetry/api"); const core_1 = require("@opentelemetry/core"); const SplunkBatchSpanProcessor_1 = require("./SplunkBatchSpanProcessor"); const resources_1 = require("@opentelemetry/resources"); const NextJsSpanProcessor_1 = require("./NextJsSpanProcessor"); function defaultSampler(config) { if (config.sampler === undefined && (0, utils_1.getNonEmptyEnvVar)('OTEL_TRACES_SAMPLER') === undefined) { return new sdk_trace_base_1.AlwaysOnSampler(); } return undefined; } function _setDefaultOptions(options = {}) { var _a, _b; process.env.OTEL_SPAN_LINK_COUNT_LIMIT = (_a = (0, utils_1.getNonEmptyEnvVar)('OTEL_SPAN_LINK_COUNT_LIMIT')) !== null && _a !== void 0 ? _a : '1000'; process.env.OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT = (_b = (0, utils_1.getNonEmptyEnvVar)('OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT')) !== null && _b !== void 0 ? _b : '12000'; const accessToken = options.accessToken || (0, utils_1.getNonEmptyEnvVar)('SPLUNK_ACCESS_TOKEN') || ''; const realm = options.realm || (0, utils_1.getNonEmptyEnvVar)('SPLUNK_REALM'); if (realm) { if (!accessToken) { throw new Error('Splunk realm is set, but access token is unset. To send traces to the Observability Cloud, both need to be set'); } } const envResource = (0, resource_1.getDetectedResource)(); const resourceFactory = options.resourceFactory || ((r) => r); let resource = resourceFactory((0, resources_1.resourceFromAttributes)(envResource.attributes || {})); const serviceName = options.serviceName || (0, utils_1.getNonEmptyEnvVar)('OTEL_SERVICE_NAME') || resource.attributes[semantic_conventions_1.ATTR_SERVICE_NAME]; resource = resource.merge((0, resources_1.resourceFromAttributes)({ [semantic_conventions_1.ATTR_SERVICE_NAME]: serviceName || (0, utils_1.defaultServiceName)(), })); const extraTracerConfig = options.tracerConfig || {}; const sampler = defaultSampler(extraTracerConfig); const tracerConfig = Object.assign({ resource, sampler }, extraTracerConfig); const instrumentations = options.instrumentations || (0, instrumentations_1.getInstrumentations)(); if (instrumentations.length === 0) { api_1.diag.warn('No instrumentations set to be loaded. Install an instrumentation package to enable auto-instrumentation.'); } return { realm, endpoint: options.endpoint, serviceName: String(resource.attributes[semantic_conventions_1.ATTR_SERVICE_NAME]), accessToken, serverTimingEnabled: options.serverTimingEnabled || (0, utils_1.getEnvBoolean)('SPLUNK_TRACE_RESPONSE_HEADER_ENABLED', true), captureHttpRequestUriParams: options.captureHttpRequestUriParams || [], instrumentations, tracerConfig, spanExporterFactory: options.spanExporterFactory || defaultSpanExporterFactory(realm), spanProcessorFactory: options.spanProcessorFactory || defaultSpanProcessorFactory, propagatorFactory: options.propagatorFactory || defaultPropagatorFactory, }; } const SUPPORTED_EXPORTER_TYPES = ['console', 'otlp', 'none']; const SpanExporterMap = { console: consoleSpanExporterFactory, otlp: otlpSpanExporterFactory, none: () => [], }; function containsSupportedRealmExporter(exporterTypes) { return exporterTypes.includes('otlp'); } function areValidExporterTypes(types) { for (const t of types) { if (!SUPPORTED_EXPORTER_TYPES.includes(t)) { return false; } } return true; } function getExporterTypes(realm) { const traceExporters = (0, utils_1.getEnvArray)('OTEL_TRACES_EXPORTER', [ 'otlp', ]); if (realm) { if (!containsSupportedRealmExporter(traceExporters)) { throw new Error('Setting the Splunk realm with an explicit OTEL_TRACES_EXPORTER requires OTEL_TRACES_EXPORTER to be either otlp or be left undefined'); } } if (!areValidExporterTypes(traceExporters)) { throw new Error(`Invalid value for OTEL_TRACES_EXPORTER env variable: ${util.inspect(process.env.OTEL_TRACES_EXPORTER)}. Choose from ${util.inspect(SUPPORTED_EXPORTER_TYPES, { compact: true, })} or leave undefined.`); } return traceExporters; } function defaultSpanExporterFactory(realm) { const exporterTypes = getExporterTypes(realm); return (options) => { const factories = exporterTypes.map((t) => SpanExporterMap[t]); return factories.flatMap((factory) => factory(options)); }; } function otlpSpanExporterFactory(options) { let protocol = (0, utils_1.getEnvValueByPrecedence)([ 'OTEL_EXPORTER_OTLP_TRACES_PROTOCOL', 'OTEL_EXPORTER_OTLP_PROTOCOL', ]); let endpoint = options.endpoint; const accessToken = options.accessToken; if (options.realm !== undefined) { if (protocol !== undefined && protocol !== 'http/protobuf') { api_1.diag.warn(`OTLP span exporter factory: defaulting protocol to 'http/protobuf' instead of ${protocol} due to realm being defined.`); } const envEndpoint = (0, utils_1.getEnvValueByPrecedence)([ 'OTEL_EXPORTER_OTLP_TRACES_ENDPOINT', 'OTEL_EXPORTER_OTLP_ENDPOINT', ]); if (endpoint === undefined && envEndpoint === undefined) { endpoint = `https://ingest.${options.realm}.signalfx.com/v2/trace/otlp`; protocol = 'http/protobuf'; } else { api_1.diag.warn('OTLP span exporter factory: Realm value ignored (full endpoint URL has been specified).'); } } protocol = protocol !== null && protocol !== void 0 ? protocol : 'http/protobuf'; switch (protocol) { case 'grpc': { const grpcModule = require('@grpc/grpc-js'); const otlpGrpc = require('@opentelemetry/exporter-trace-otlp-grpc'); const metadata = new grpcModule.Metadata(); if (accessToken) { // for forward compatibility, is not currently supported metadata.set('X-SF-TOKEN', accessToken); } return new otlpGrpc.OTLPTraceExporter({ url: endpoint, metadata, }); } case 'http/protobuf': { const headers = accessToken ? { 'X-SF-TOKEN': accessToken, } : undefined; const url = (0, utils_1.ensureResourcePath)(endpoint, '/v1/traces'); return new exporter_trace_otlp_proto_1.OTLPTraceExporter({ url, headers, }); } default: throw new Error(`Expected OTLP protocol to be either grpc or http/protobuf, got ${protocol}.`); } } function consoleSpanExporterFactory() { return new sdk_trace_base_1.ConsoleSpanExporter(); } function defaultSpanProcessorFactory(options) { let exporters = []; const spanExporters = options.spanExporterFactory(options); if (!Array.isArray(spanExporters)) { exporters = [spanExporters]; } else { exporters = spanExporters; } const nextJsFixEnabled = (0, utils_1.getEnvBoolean)('SPLUNK_NEXTJS_FIX_ENABLED', false); const processors = []; if (nextJsFixEnabled) { processors.push(new NextJsSpanProcessor_1.NextJsSpanProcessor()); } for (const exporter of exporters) { processors.push(new SplunkBatchSpanProcessor_1.SplunkBatchSpanProcessor(exporter)); } return processors; } // eslint-disable-next-line @typescript-eslint/no-unused-vars function defaultPropagatorFactory(_options) { const envPropagators = (0, utils_1.getEnvArray)('OTEL_PROPAGATORS', [ 'tracecontext', 'baggage', ]); const propagators = []; for (const propagator of envPropagators) { switch (propagator) { case 'baggage': propagators.push(new core_1.W3CBaggagePropagator()); break; case 'tracecontext': propagators.push(new core_1.W3CTraceContextPropagator()); break; case 'b3multi': propagators.push(new propagator_b3_1.B3Propagator({ injectEncoding: propagator_b3_1.B3InjectEncoding.MULTI_HEADER })); break; case 'b3': propagators.push(new propagator_b3_1.B3Propagator()); break; case 'xray': propagators.push(new propagator_aws_xray_1.AWSXRayPropagator()); break; default: break; } } return new core_1.CompositePropagator({ propagators, }); } //# sourceMappingURL=options.js.map