@opentelemetry/sdk-node
Version:
955 lines • 41.5 kB
JavaScript
"use strict";
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildSamplerFromConfig = exports.getSamplerFromConfiguration = exports.getInstanceID = exports.getMeterViewsFromConfiguration = exports.getAggregationType = exports.getInstrumentType = exports.getMeterReadersFromConfiguration = exports.getIdGeneratorFromConfiguration = exports.getSpanProcessorsFromConfiguration = exports.getSpanExporter = exports.getGrpcMetadataFromHeaders = exports.getGrpcCredentialsFromTls = exports.getHttpAgentOptionsFromTls = exports.validateExporterTimeout = exports.getHeadersFromConfiguration = exports.getBatchLogRecordProcessorFromEnv = exports.getBatchLogRecordProcessorConfigFromEnv = exports.getLoggerProviderConfigFromEnv = exports.getPeriodicMetricReaderFromConfiguration = exports.getMetricExporter = exports.getOtlpMetricExporterFromEnv = exports.getPeriodicExportingMetricReaderFromEnv = exports.getNonNegativeNumberFromEnv = exports.getKeyListFromObjectArray = exports.setupPropagator = exports.setupContextManager = exports.getPropagatorFromConfiguration = exports.getPropagatorFromEnv = exports.getSpanProcessorsFromEnv = exports.getOtlpProtocolFromEnv = exports.getResourceDetectorsFromConfiguration = exports.getResourceDetectorsFromEnv = exports.getResourceFromConfiguration = void 0;
const api_1 = require("@opentelemetry/api");
const core_1 = require("@opentelemetry/core");
const exporter_trace_otlp_proto_1 = require("@opentelemetry/exporter-trace-otlp-proto");
const exporter_trace_otlp_http_1 = require("@opentelemetry/exporter-trace-otlp-http");
const exporter_trace_otlp_grpc_1 = require("@opentelemetry/exporter-trace-otlp-grpc");
const exporter_zipkin_1 = require("@opentelemetry/exporter-zipkin");
const resources_1 = require("@opentelemetry/resources");
const sdk_trace_1 = require("@opentelemetry/sdk-trace");
const propagator_b3_1 = require("@opentelemetry/propagator-b3");
const propagator_jaeger_1 = require("@opentelemetry/propagator-jaeger");
const context_async_hooks_1 = require("@opentelemetry/context-async-hooks");
const otlp_exporter_base_1 = require("@opentelemetry/otlp-exporter-base");
const otlp_grpc_exporter_base_1 = require("@opentelemetry/otlp-grpc-exporter-base");
const configuration_1 = require("@opentelemetry/configuration");
const sdk_metrics_1 = require("@opentelemetry/sdk-metrics");
const exporter_metrics_otlp_grpc_1 = require("@opentelemetry/exporter-metrics-otlp-grpc");
const exporter_metrics_otlp_http_1 = require("@opentelemetry/exporter-metrics-otlp-http");
const exporter_metrics_otlp_http_2 = require("@opentelemetry/exporter-metrics-otlp-http");
const exporter_metrics_otlp_proto_1 = require("@opentelemetry/exporter-metrics-otlp-proto");
const sdk_logs_1 = require("@opentelemetry/sdk-logs");
const fs = require("fs");
const util_1 = require("util");
const create_from_env_1 = require("./create-from-env");
const RESOURCE_DETECTOR_ENVIRONMENT = 'env';
const RESOURCE_DETECTOR_HOST = 'host';
const RESOURCE_DETECTOR_OS = 'os';
const RESOURCE_DETECTOR_PROCESS = 'process';
const RESOURCE_DETECTOR_SERVICE_INSTANCE_ID = 'serviceinstance';
function getResourceFromConfiguration(config) {
if (!config.resource) {
return undefined;
}
const configAttrs = (0, configuration_1.mergeResourceAttributesConfig)(config.resource.attributes, config.resource.attributes_list);
if (!configAttrs) {
return undefined;
}
const attrs = {};
for (let i = 0; i < configAttrs.length; i++) {
const a = configAttrs[i];
if (a.value !== null) {
attrs[a.name] = a.value;
}
}
return (0, resources_1.resourceFromAttributes)(attrs, {
schemaUrl: config.resource.schema_url ?? undefined,
});
}
exports.getResourceFromConfiguration = getResourceFromConfiguration;
function getResourceDetectorsFromEnv() {
// When updating this list, make sure to also update the section `resourceDetectors` on README.
const resourceDetectors = new Map([
[RESOURCE_DETECTOR_HOST, resources_1.hostDetector],
[RESOURCE_DETECTOR_OS, resources_1.osDetector],
[RESOURCE_DETECTOR_SERVICE_INSTANCE_ID, resources_1.serviceInstanceIdDetector],
[RESOURCE_DETECTOR_PROCESS, resources_1.processDetector],
[RESOURCE_DETECTOR_ENVIRONMENT, resources_1.envDetector],
]);
const resourceDetectorsFromEnv = (0, core_1.getStringListFromEnv)('OTEL_NODE_RESOURCE_DETECTORS') ?? ['all'];
if (resourceDetectorsFromEnv.includes('all')) {
return [...resourceDetectors.values()].flat();
}
if (resourceDetectorsFromEnv.includes('none')) {
return [];
}
return resourceDetectorsFromEnv.flatMap(detector => {
const resourceDetector = resourceDetectors.get(detector);
if (!resourceDetector) {
api_1.diag.warn(`Invalid resource detector "${detector}" specified in the environment variable OTEL_NODE_RESOURCE_DETECTORS`);
}
return resourceDetector || [];
});
}
exports.getResourceDetectorsFromEnv = getResourceDetectorsFromEnv;
function getResourceDetectorsFromConfiguration(config) {
const detectors = config.resource?.['detection/development']?.detectors ?? [];
return detectors.flatMap(detector => {
const result = [];
if (detector.host !== undefined)
result.push(resources_1.hostDetector);
if (detector.os !== undefined)
result.push(resources_1.osDetector);
if (detector.process !== undefined)
result.push(resources_1.processDetector);
if (detector.service !== undefined)
result.push(resources_1.serviceInstanceIdDetector);
if (detector.env !== undefined)
result.push(resources_1.envDetector);
return result;
});
}
exports.getResourceDetectorsFromConfiguration = getResourceDetectorsFromConfiguration;
function getOtlpProtocolFromEnv() {
return ((0, core_1.getStringFromEnv)('OTEL_EXPORTER_OTLP_TRACES_PROTOCOL') ??
(0, core_1.getStringFromEnv)('OTEL_EXPORTER_OTLP_PROTOCOL') ??
'http/protobuf');
}
exports.getOtlpProtocolFromEnv = getOtlpProtocolFromEnv;
function getOtlpExporterFromEnv() {
const protocol = getOtlpProtocolFromEnv();
switch (protocol) {
case 'grpc':
return new exporter_trace_otlp_grpc_1.OTLPTraceExporter();
case 'http/json':
return new exporter_trace_otlp_http_1.OTLPTraceExporter();
case 'http/protobuf':
return new exporter_trace_otlp_proto_1.OTLPTraceExporter();
default:
api_1.diag.warn(`Unsupported OTLP traces protocol: ${protocol}. Using http/protobuf.`);
return new exporter_trace_otlp_proto_1.OTLPTraceExporter();
}
}
function getSpanProcessorsFromEnv(selfObsMeterProvider) {
const exportersMap = new Map([
['otlp', () => getOtlpExporterFromEnv()],
['zipkin', () => new exporter_zipkin_1.ZipkinExporter()],
['console', () => new sdk_trace_1.ConsoleSpanExporter()],
]);
const exporters = [];
const processors = [];
let traceExportersList = Array.from(new Set((0, core_1.getStringListFromEnv)('OTEL_TRACES_EXPORTER'))).filter(s => s !== 'null');
if (traceExportersList[0] === 'none') {
api_1.diag.warn('OTEL_TRACES_EXPORTER contains "none". SDK will not be initialized.');
return [];
}
if (traceExportersList.length === 0) {
api_1.diag.debug('OTEL_TRACES_EXPORTER is empty. Using default otlp exporter.');
traceExportersList = ['otlp'];
}
else if (traceExportersList.length > 1 &&
traceExportersList.includes('none')) {
api_1.diag.warn('OTEL_TRACES_EXPORTER contains "none" along with other exporters. Using default otlp exporter.');
traceExportersList = ['otlp'];
}
for (const name of traceExportersList) {
const exporter = exportersMap.get(name)?.();
if (exporter) {
exporters.push(exporter);
}
else {
api_1.diag.warn(`Unrecognized OTEL_TRACES_EXPORTER value: ${name}.`);
}
}
for (const exp of exporters) {
if (exp instanceof sdk_trace_1.ConsoleSpanExporter) {
processors.push(new sdk_trace_1.SimpleSpanProcessor({ exporter: exp, selfObsMeterProvider }));
}
else {
processors.push((0, create_from_env_1.createBatchSpanProcessorFromEnv)(exp, selfObsMeterProvider));
}
}
if (exporters.length === 0) {
api_1.diag.warn('Unable to set up trace exporter(s) due to invalid exporter and/or protocol values.');
}
return processors;
}
exports.getSpanProcessorsFromEnv = getSpanProcessorsFromEnv;
/**
* Get a propagator as defined by environment variables
*/
function getPropagatorFromEnv() {
// Empty and undefined MUST be treated equal.
const propagatorsEnvVarValue = (0, core_1.getStringListFromEnv)('OTEL_PROPAGATORS');
if (propagatorsEnvVarValue == null) {
// return undefined to fall back to default
return undefined;
}
if (propagatorsEnvVarValue.includes('none')) {
return null;
}
// Implementation note: this only contains specification required propagators that are actually hosted in this repo.
// Any other propagators (like aws, aws-lambda, should go into `@opentelemetry/auto-configuration-propagators` instead).
const propagatorsFactory = new Map([
['tracecontext', () => new core_1.W3CTraceContextPropagator()],
['baggage', () => new core_1.W3CBaggagePropagator()],
['b3', () => new propagator_b3_1.B3Propagator()],
[
'b3multi',
() => new propagator_b3_1.B3Propagator({ injectEncoding: propagator_b3_1.B3InjectEncoding.MULTI_HEADER }),
],
[
'jaeger',
() => {
api_1.diag.warn('The Jaeger propagator is deprecated and will be removed in a future release. Use the W3C TraceContext propagator ("tracecontext") instead.');
return new propagator_jaeger_1.JaegerPropagator();
},
],
]);
// Values MUST be deduplicated in order to register a Propagator only once.
const uniquePropagatorNames = Array.from(new Set(propagatorsEnvVarValue));
const validPropagators = [];
uniquePropagatorNames.forEach(name => {
const propagator = propagatorsFactory.get(name)?.();
if (!propagator) {
api_1.diag.warn(`Propagator "${name}" requested through environment variable is unavailable.`);
return;
}
validPropagators.push(propagator);
});
if (validPropagators.length === 0) {
// null to signal that the default should **not** be used in its place.
return null;
}
else if (uniquePropagatorNames.length === 1) {
return validPropagators[0];
}
else {
return new core_1.CompositePropagator({
propagators: validPropagators,
});
}
}
exports.getPropagatorFromEnv = getPropagatorFromEnv;
/**
* Get a propagator as defined by configuration model from configuration
*/
function getPropagatorFromConfiguration(config) {
if (!config.propagator) {
return undefined;
}
const configComposite = (0, configuration_1.mergePropagatorCompositeConfig)(config.propagator.composite, config.propagator.composite_list);
if (!configComposite) {
return undefined;
}
// TextMapPropagator config items are objects with a single key (the name).
// Transform this into a more convenient `(name, value)` 2-tuple.
//
// As well, guard against two cases where the TypeScript type
// `TextMapPropagatorConfigModel` does not exactly represent the JSON schema:
// 1. `"minProperties": 1, "maxProperties": 1,`
// 2. The type allows keys with an `undefined` value, but the JSON schema
// does not.
const kvFromItem = (item) => {
const keys = [];
let value = undefined;
for (const key of Object.keys(item)) {
value = item[key];
if (value === undefined) {
continue;
}
keys.push(key);
}
if (keys.length !== 1) {
throw new Error(`invalid "propagator" entry in configuration, there must be exactly one key (with a non-undefined value): ${(0, util_1.inspect)(item)}`);
}
return [keys[0], value];
};
// First pass: handle 'none', remove dupes.
const names = new Set();
const kvs = [];
for (const item of configComposite) {
const kv = kvFromItem(item);
const k = kv[0];
if (names.has(k)) {
continue;
}
names.add(k);
kvs.push(kv);
if (k === 'none') {
return undefined;
}
}
// Implementation note: this only contains specification required propagators that are actually hosted in this repo.
// Any other propagators (like aws, aws-lambda, should go into `@opentelemetry/auto-configuration-propagators` instead).
const propagatorsFactory = new Map([
['tracecontext', () => new core_1.W3CTraceContextPropagator()],
['baggage', () => new core_1.W3CBaggagePropagator()],
['b3', () => new propagator_b3_1.B3Propagator()],
[
'b3multi',
() => new propagator_b3_1.B3Propagator({ injectEncoding: propagator_b3_1.B3InjectEncoding.MULTI_HEADER }),
],
[
'jaeger',
() => {
api_1.diag.warn('The Jaeger propagator is deprecated and will be removed in a future release. Use the W3C TraceContext propagator ("tracecontext") instead.');
return new propagator_jaeger_1.JaegerPropagator();
},
],
]);
const validPropagators = [];
for (const [name] of kvs) {
const propagator = propagatorsFactory.get(name)?.();
if (!propagator) {
api_1.diag.warn(`Propagator "${name}" requested through configuration is unavailable.`);
continue;
}
validPropagators.push(propagator);
}
if (validPropagators.length === 0) {
return undefined;
}
else if (validPropagators.length === 1) {
return validPropagators[0];
}
else {
return new core_1.CompositePropagator({
propagators: validPropagators,
});
}
}
exports.getPropagatorFromConfiguration = getPropagatorFromConfiguration;
function setupContextManager(contextManager) {
// null means 'do not register'
if (contextManager === null) {
return;
}
// undefined means 'register default'
if (contextManager === undefined) {
const defaultContextManager = new context_async_hooks_1.AsyncLocalStorageContextManager();
defaultContextManager.enable();
api_1.context.setGlobalContextManager(defaultContextManager);
return;
}
contextManager.enable();
api_1.context.setGlobalContextManager(contextManager);
}
exports.setupContextManager = setupContextManager;
function setupPropagator(propagator) {
// null means 'do not register'
if (propagator === null) {
return;
}
// undefined means 'register default'
if (propagator === undefined) {
api_1.propagation.setGlobalPropagator(new core_1.CompositePropagator({
propagators: [
new core_1.W3CTraceContextPropagator(),
new core_1.W3CBaggagePropagator(),
],
}));
return;
}
api_1.propagation.setGlobalPropagator(propagator);
}
exports.setupPropagator = setupPropagator;
function getKeyListFromObjectArray(obj) {
if (!obj || obj.length === 0) {
return undefined;
}
const keys = [];
for (const item of obj) {
for (const key of Object.keys(item)) {
keys.push(key);
}
}
return keys;
}
exports.getKeyListFromObjectArray = getKeyListFromObjectArray;
function getNonNegativeNumberFromEnv(envVarName) {
const value = (0, core_1.getNumberFromEnv)(envVarName);
if (value != null && value <= 0) {
api_1.diag.warn(`${envVarName} (${value}) is invalid, expected number greater than 0, using default.`);
return undefined;
}
return value;
}
exports.getNonNegativeNumberFromEnv = getNonNegativeNumberFromEnv;
function getPeriodicExportingMetricReaderFromEnv(exporter) {
const defaultTimeoutMillis = 30000;
const defaultIntervalMillis = 60000;
const rawExportIntervalMillis = getNonNegativeNumberFromEnv('OTEL_METRIC_EXPORT_INTERVAL');
const rawExportTimeoutMillis = getNonNegativeNumberFromEnv('OTEL_METRIC_EXPORT_TIMEOUT');
// Apply defaults
const exportIntervalMillis = rawExportIntervalMillis ?? defaultIntervalMillis;
let exportTimeoutMillis = rawExportTimeoutMillis ?? defaultTimeoutMillis;
// Ensure timeout doesn't exceed interval
if (exportTimeoutMillis > exportIntervalMillis) {
// determine which env vars were set and which ones defaulted for logging purposes
const timeoutSource = rawExportTimeoutMillis != null
? rawExportTimeoutMillis.toString()
: `${defaultTimeoutMillis}, default`;
const intervalSource = rawExportIntervalMillis != null
? rawExportIntervalMillis.toString()
: `${defaultIntervalMillis}, default`;
const bothSetByUser = rawExportTimeoutMillis != null && rawExportIntervalMillis != null;
const logMessage = `OTEL_METRIC_EXPORT_TIMEOUT (${timeoutSource}) is greater than OTEL_METRIC_EXPORT_INTERVAL (${intervalSource}). Clamping timeout to interval value.`;
// only bother users if they explicitly set both values.
if (bothSetByUser) {
api_1.diag.warn(logMessage);
}
else {
api_1.diag.info(logMessage);
}
exportTimeoutMillis = exportIntervalMillis;
}
return new sdk_metrics_1.PeriodicExportingMetricReader({
exportTimeoutMillis,
exportIntervalMillis,
exporter,
});
}
exports.getPeriodicExportingMetricReaderFromEnv = getPeriodicExportingMetricReaderFromEnv;
function getOtlpMetricExporterFromEnv() {
const protocol = ((0, core_1.getStringFromEnv)('OTEL_EXPORTER_OTLP_METRICS_PROTOCOL') ??
(0, core_1.getStringFromEnv)('OTEL_EXPORTER_OTLP_PROTOCOL'))?.trim() || 'http/protobuf'; // Using || to also fall back on empty string
switch (protocol) {
case 'grpc':
return new exporter_metrics_otlp_grpc_1.OTLPMetricExporter();
case 'http/json':
return new exporter_metrics_otlp_http_1.OTLPMetricExporter();
case 'http/protobuf':
return new exporter_metrics_otlp_proto_1.OTLPMetricExporter();
}
api_1.diag.warn(`Unsupported OTLP metrics protocol: "${protocol}". Using http/protobuf.`);
return new exporter_metrics_otlp_proto_1.OTLPMetricExporter();
}
exports.getOtlpMetricExporterFromEnv = getOtlpMetricExporterFromEnv;
function getMetricProducersFromConfiguration(producers) {
if (!producers || producers.length === 0) {
return undefined;
}
const result = [];
for (const producer of producers) {
// Note: The "opencensus" MetricProducer is intentionally not supported.
// It is deprecated in OpenTelemetry Configuration v1.2.0.
api_1.diag.warn(`Unsupported metric producer in configuration: "${producer}". Skipping.`);
}
return result.length > 0 ? result : undefined;
}
/**
* Map a declarative-config `temporality_preference` value to the enum the OTLP
* metric exporters expect. Returns undefined for an unspecified preference so
* the exporter falls back to its own default (cumulative).
*/
function getMetricTemporalityPreference(preference) {
switch (preference) {
case 'delta':
return exporter_metrics_otlp_http_2.AggregationTemporalityPreference.DELTA;
case 'low_memory':
return exporter_metrics_otlp_http_2.AggregationTemporalityPreference.LOWMEMORY;
case 'cumulative':
return exporter_metrics_otlp_http_2.AggregationTemporalityPreference.CUMULATIVE;
default:
return undefined;
}
}
/**
* Map a declarative-config `default_histogram_aggregation` value to an
* AggregationSelector that applies the requested aggregation to histogram
* instruments and leaves all other instrument types at their default. Returns
* undefined for an unspecified value so the exporter uses its own default.
*/
function getMetricAggregationPreference(aggregation) {
let histogramAggregation;
switch (aggregation) {
case 'base2_exponential_bucket_histogram':
histogramAggregation = { type: sdk_metrics_1.AggregationType.EXPONENTIAL_HISTOGRAM };
break;
case 'explicit_bucket_histogram':
histogramAggregation = {
type: sdk_metrics_1.AggregationType.EXPLICIT_BUCKET_HISTOGRAM,
};
break;
default:
return undefined;
}
return (instrumentType) => instrumentType === sdk_metrics_1.InstrumentType.HISTOGRAM
? histogramAggregation
: { type: sdk_metrics_1.AggregationType.DEFAULT };
}
function getOtlpHttpMetricExporter(otlpHttp) {
const encoding = otlpHttp?.encoding ?? 'protobuf';
const options = {
compression: otlpHttp?.compression === 'gzip'
? otlp_exporter_base_1.CompressionAlgorithm.GZIP
: otlp_exporter_base_1.CompressionAlgorithm.NONE,
url: otlpHttp?.endpoint ?? undefined,
headers: getHeadersFromConfiguration(otlpHttp?.headers),
timeoutMillis: validateExporterTimeout(otlpHttp?.timeout),
httpAgentOptions: getHttpAgentOptionsFromTls(otlpHttp?.tls),
temporalityPreference: getMetricTemporalityPreference(otlpHttp?.temporality_preference),
aggregationPreference: getMetricAggregationPreference(otlpHttp?.default_histogram_aggregation),
};
if (encoding === 'json') {
return new exporter_metrics_otlp_http_1.OTLPMetricExporter(options);
}
else if (encoding === 'protobuf') {
return new exporter_metrics_otlp_proto_1.OTLPMetricExporter(options);
}
api_1.diag.warn(`Unsupported OTLP metrics encoding: ${encoding}.`);
return undefined;
}
function getOtlpGrpcMetricExporter(otlpGrpc) {
return new exporter_metrics_otlp_grpc_1.OTLPMetricExporter({
compression: otlpGrpc?.compression === 'gzip'
? otlp_exporter_base_1.CompressionAlgorithm.GZIP
: otlp_exporter_base_1.CompressionAlgorithm.NONE,
url: otlpGrpc?.endpoint ?? undefined,
timeoutMillis: validateExporterTimeout(otlpGrpc?.timeout),
credentials: getGrpcCredentialsFromTls(otlpGrpc?.tls),
metadata: getGrpcMetadataFromHeaders(otlpGrpc?.headers),
temporalityPreference: getMetricTemporalityPreference(otlpGrpc?.temporality_preference),
aggregationPreference: getMetricAggregationPreference(otlpGrpc?.default_histogram_aggregation),
});
}
function getMetricExporter(exporter) {
if (exporter.otlp_http !== undefined) {
return getOtlpHttpMetricExporter(exporter.otlp_http);
}
if (exporter.otlp_grpc !== undefined) {
return getOtlpGrpcMetricExporter(exporter.otlp_grpc);
}
if (exporter.console !== undefined) {
return new sdk_metrics_1.ConsoleMetricExporter();
}
api_1.diag.warn('Unsupported Metric Exporter.');
return undefined;
}
exports.getMetricExporter = getMetricExporter;
function getPeriodicMetricReaderFromConfiguration(periodic) {
if (!periodic.exporter) {
api_1.diag.warn('Unsupported Metric Exporter.');
return undefined;
}
const exporter = getMetricExporter(periodic.exporter);
if (!exporter) {
return undefined;
}
const metricProducers = getMetricProducersFromConfiguration(periodic.producers);
// TODO(6425): add cardinality_limits
return new sdk_metrics_1.PeriodicExportingMetricReader({
exportIntervalMillis: periodic.interval ?? 60000,
exportTimeoutMillis: periodic.timeout ?? 30000,
exporter,
metricProducers,
});
}
exports.getPeriodicMetricReaderFromConfiguration = getPeriodicMetricReaderFromConfiguration;
/**
* Get LoggerProviderConfig from environment variables.
*/
function getLoggerProviderConfigFromEnv() {
return {
logRecordLimits: {
attributeCountLimit: getNonNegativeNumberFromEnv('OTEL_LOGRECORD_ATTRIBUTE_COUNT_LIMIT') ??
getNonNegativeNumberFromEnv('OTEL_ATTRIBUTE_COUNT_LIMIT'),
attributeValueLengthLimit: getNonNegativeNumberFromEnv('OTEL_LOGRECORD_ATTRIBUTE_VALUE_LENGTH_LIMIT') ?? getNonNegativeNumberFromEnv('OTEL_ATTRIBUTE_VALUE_LENGTH_LIMIT'),
},
};
}
exports.getLoggerProviderConfigFromEnv = getLoggerProviderConfigFromEnv;
/**
* Get configuration for BatchLogRecordProcessor from environment variables.
*/
function getBatchLogRecordProcessorConfigFromEnv() {
return {
maxQueueSize: getNonNegativeNumberFromEnv('OTEL_BLRP_MAX_QUEUE_SIZE'),
scheduledDelayMillis: getNonNegativeNumberFromEnv('OTEL_BLRP_SCHEDULE_DELAY'),
exportTimeoutMillis: getNonNegativeNumberFromEnv('OTEL_BLRP_EXPORT_TIMEOUT'),
maxExportBatchSize: getNonNegativeNumberFromEnv('OTEL_BLRP_MAX_EXPORT_BATCH_SIZE'),
};
}
exports.getBatchLogRecordProcessorConfigFromEnv = getBatchLogRecordProcessorConfigFromEnv;
function getBatchLogRecordProcessorFromEnv(exporter, selfObsMeterProvider) {
return new sdk_logs_1.BatchLogRecordProcessor({
exporter,
selfObsMeterProvider,
...getBatchLogRecordProcessorConfigFromEnv(),
});
}
exports.getBatchLogRecordProcessorFromEnv = getBatchLogRecordProcessorFromEnv;
function getHeadersFromConfiguration(headers) {
if (!headers) {
return undefined;
}
const result = {};
headers.forEach(header => {
if (header.value !== null) {
result[header.name] = header.value;
}
});
return result;
}
exports.getHeadersFromConfiguration = getHeadersFromConfiguration;
/**
* Validate an exporter timeout value. The spec says 0 means "no limit
* (infinity)" but the JS exporters don't support that yet (see #6617).
* Warn and return undefined so the exporter falls back to its default.
*/
function validateExporterTimeout(timeout) {
if (timeout === null) {
return undefined;
}
else if (timeout === 0) {
api_1.diag.warn('Exporter timeout of 0 (infinite) is not supported. Using default timeout.');
return undefined;
}
return timeout;
}
exports.validateExporterTimeout = validateExporterTimeout;
function getHttpAgentOptionsFromTls(tls) {
if (tls && (tls.ca_file || tls.cert_file || tls.key_file)) {
return {
ca: readFileOrWarn(tls.ca_file, 'TLS CA'),
cert: readFileOrWarn(tls.cert_file, 'TLS cert'),
key: readFileOrWarn(tls.key_file, 'TLS key'),
};
}
return undefined;
}
exports.getHttpAgentOptionsFromTls = getHttpAgentOptionsFromTls;
function getGrpcCredentialsFromTls(tls) {
if (tls?.insecure) {
return (0, otlp_grpc_exporter_base_1.createInsecureCredentials)();
}
const rootCert = readFileOrWarn(tls?.ca_file, 'TLS CA');
const privateKey = readFileOrWarn(tls?.key_file, 'TLS key');
const certChain = readFileOrWarn(tls?.cert_file, 'TLS cert');
if (rootCert || privateKey || certChain) {
try {
return (0, otlp_grpc_exporter_base_1.createSslCredentials)(rootCert, privateKey, certChain);
}
catch (e) {
api_1.diag.warn(`Failed to create gRPC SSL credentials: ${e}`);
return undefined;
}
}
return undefined;
}
exports.getGrpcCredentialsFromTls = getGrpcCredentialsFromTls;
function getGrpcMetadataFromHeaders(headers) {
if (!headers || headers.length === 0) {
return undefined;
}
const metadata = (0, otlp_grpc_exporter_base_1.createEmptyMetadata)();
for (const header of headers) {
if (header.value !== null) {
metadata.set(header.name, header.value);
}
}
return metadata;
}
exports.getGrpcMetadataFromHeaders = getGrpcMetadataFromHeaders;
function readFileOrWarn(filePath, label) {
if (!filePath)
return undefined;
try {
return fs.readFileSync(filePath);
}
catch (e) {
api_1.diag.warn(`Failed to read ${label} file at ${filePath}: ${e}`);
return undefined;
}
}
function getSpanExporter(exporter) {
if (exporter.otlp_http !== undefined) {
const encoding = exporter.otlp_http?.encoding ?? 'protobuf';
if (encoding === 'json') {
return new exporter_trace_otlp_http_1.OTLPTraceExporter({
compression: exporter.otlp_http?.compression === 'gzip'
? otlp_exporter_base_1.CompressionAlgorithm.GZIP
: otlp_exporter_base_1.CompressionAlgorithm.NONE,
url: exporter.otlp_http?.endpoint ?? undefined,
headers: getHeadersFromConfiguration(exporter.otlp_http?.headers),
timeoutMillis: validateExporterTimeout(exporter.otlp_http?.timeout),
httpAgentOptions: getHttpAgentOptionsFromTls(exporter.otlp_http?.tls),
});
}
else {
return new exporter_trace_otlp_proto_1.OTLPTraceExporter({
compression: exporter.otlp_http?.compression === 'gzip'
? otlp_exporter_base_1.CompressionAlgorithm.GZIP
: otlp_exporter_base_1.CompressionAlgorithm.NONE,
url: exporter.otlp_http?.endpoint ?? undefined,
headers: getHeadersFromConfiguration(exporter.otlp_http?.headers),
timeoutMillis: validateExporterTimeout(exporter.otlp_http?.timeout),
httpAgentOptions: getHttpAgentOptionsFromTls(exporter.otlp_http?.tls),
});
}
}
else if (exporter.otlp_grpc !== undefined) {
return new exporter_trace_otlp_grpc_1.OTLPTraceExporter({
compression: exporter.otlp_grpc?.compression === 'gzip'
? otlp_exporter_base_1.CompressionAlgorithm.GZIP
: otlp_exporter_base_1.CompressionAlgorithm.NONE,
url: exporter.otlp_grpc?.endpoint ?? undefined,
timeoutMillis: validateExporterTimeout(exporter.otlp_grpc?.timeout),
credentials: getGrpcCredentialsFromTls(exporter.otlp_grpc?.tls),
metadata: getGrpcMetadataFromHeaders(exporter.otlp_grpc?.headers),
});
}
else if (exporter.console !== undefined) {
return new sdk_trace_1.ConsoleSpanExporter();
}
api_1.diag.warn('Unsupported Exporter value. No Span Exporter registered');
return undefined;
}
exports.getSpanExporter = getSpanExporter;
function getSpanProcessorsFromConfiguration(config) {
const spanProcessors = [];
config.tracer_provider?.processors?.forEach(processor => {
if (processor.batch) {
const exporter = getSpanExporter(processor.batch.exporter);
if (exporter) {
spanProcessors.push(new sdk_trace_1.BatchSpanProcessor({
exporter,
maxQueueSize: processor.batch.max_queue_size ?? undefined,
maxExportBatchSize: processor.batch.max_export_batch_size ?? undefined,
scheduledDelayMillis: processor.batch.schedule_delay ?? undefined,
exportTimeoutMillis: processor.batch.export_timeout ?? undefined,
}));
}
}
if (processor.simple) {
const exporter = getSpanExporter(processor.simple.exporter);
if (exporter) {
spanProcessors.push(new sdk_trace_1.SimpleSpanProcessor({ exporter }));
}
}
});
if (spanProcessors.length > 0) {
return spanProcessors;
}
return undefined;
}
exports.getSpanProcessorsFromConfiguration = getSpanProcessorsFromConfiguration;
function getIdGeneratorFromConfiguration(config) {
const idGenerator = config.tracer_provider?.id_generator;
if (!idGenerator) {
return undefined;
}
if (idGenerator.random !== undefined) {
return new sdk_trace_1.RandomIdGenerator();
}
// Any other key is a third-party / custom id_generator type which we
// don't currently support. Warn and fall back to SDK default.
const unknownKeys = Object.keys(idGenerator).filter(k => k !== 'random');
if (unknownKeys.length > 0) {
api_1.diag.warn(`Unsupported id_generator type(s): ${unknownKeys.join(', ')}. Using default.`);
}
return undefined;
}
exports.getIdGeneratorFromConfiguration = getIdGeneratorFromConfiguration;
function getMeterReadersFromConfiguration(config) {
const metricReaders = [];
config.meter_provider?.readers?.forEach(reader => {
if (reader.periodic) {
const periodicReader = getPeriodicMetricReaderFromConfiguration(reader.periodic);
if (periodicReader) {
metricReaders.push(periodicReader);
}
}
});
if (metricReaders.length > 0) {
return metricReaders;
}
return undefined;
}
exports.getMeterReadersFromConfiguration = getMeterReadersFromConfiguration;
function getInstrumentType(instrument) {
switch (instrument) {
case 'counter':
return sdk_metrics_1.InstrumentType.COUNTER;
case 'gauge':
return sdk_metrics_1.InstrumentType.GAUGE;
case 'histogram':
return sdk_metrics_1.InstrumentType.HISTOGRAM;
case 'observable_counter':
return sdk_metrics_1.InstrumentType.OBSERVABLE_COUNTER;
case 'observable_gauge':
return sdk_metrics_1.InstrumentType.OBSERVABLE_GAUGE;
case 'observable_up_down_counter':
return sdk_metrics_1.InstrumentType.OBSERVABLE_UP_DOWN_COUNTER;
case 'up_down_counter':
return sdk_metrics_1.InstrumentType.UP_DOWN_COUNTER;
default:
api_1.diag.warn(`Unsupported instrument type: ${instrument}`);
return undefined;
}
}
exports.getInstrumentType = getInstrumentType;
function getAggregationType(aggregation) {
if (aggregation.default) {
return {
type: sdk_metrics_1.AggregationType.DEFAULT,
};
}
if (aggregation.drop) {
return {
type: sdk_metrics_1.AggregationType.DROP,
};
}
if (aggregation.explicit_bucket_histogram) {
return {
type: sdk_metrics_1.AggregationType.EXPLICIT_BUCKET_HISTOGRAM,
options: {
recordMinMax: aggregation.explicit_bucket_histogram.record_min_max ?? true,
boundaries: aggregation.explicit_bucket_histogram.boundaries ?? [
0, 5, 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2500, 5000, 7500,
10000,
],
},
};
}
if (aggregation.base2_exponential_bucket_histogram) {
return {
type: sdk_metrics_1.AggregationType.EXPONENTIAL_HISTOGRAM,
options: {
recordMinMax: aggregation.base2_exponential_bucket_histogram.record_min_max ??
undefined,
maxSize: aggregation.base2_exponential_bucket_histogram.max_size ?? undefined,
},
};
}
if (aggregation.last_value) {
return {
type: sdk_metrics_1.AggregationType.LAST_VALUE,
};
}
if (aggregation.sum) {
return {
type: sdk_metrics_1.AggregationType.SUM,
};
}
api_1.diag.warn('Unsupported aggregation type');
return undefined;
}
exports.getAggregationType = getAggregationType;
function getMeterViewsFromConfiguration(config) {
const metricViews = [];
config.meter_provider?.views?.forEach(view => {
const viewOption = {};
if (view.selector) {
if (view.selector.instrument_name) {
viewOption.instrumentName = view.selector.instrument_name;
}
if (view.selector.instrument_type) {
const instrumentType = getInstrumentType(view.selector.instrument_type);
if (instrumentType) {
viewOption.instrumentType = instrumentType;
}
}
if (view.selector.unit) {
viewOption.instrumentUnit = view.selector.unit;
}
if (view.selector.meter_name) {
viewOption.meterName = view.selector.meter_name;
}
if (view.selector.meter_version) {
viewOption.meterVersion = view.selector.meter_version;
}
if (view.selector.meter_schema_url) {
viewOption.meterSchemaUrl = view.selector.meter_schema_url;
}
}
if (view.stream) {
if (view.stream.name) {
viewOption.name = view.stream.name;
}
viewOption.aggregationCardinalityLimit =
view.stream.aggregation_cardinality_limit ?? 2000;
if (view.stream.description) {
viewOption.description = view.stream.description;
}
if (view.stream.aggregation) {
const aggregationType = getAggregationType(view.stream.aggregation);
if (aggregationType) {
viewOption.aggregation = aggregationType;
}
}
if (view.stream.attribute_keys) {
const processors = [];
if (view.stream.attribute_keys.included &&
view.stream.attribute_keys.included.length > 0) {
processors.push((0, sdk_metrics_1.createAllowListAttributesProcessor)(view.stream.attribute_keys.included));
}
if (view.stream.attribute_keys.excluded &&
view.stream.attribute_keys.excluded.length > 0) {
processors.push((0, sdk_metrics_1.createDenyListAttributesProcessor)(view.stream.attribute_keys.excluded));
}
if (processors.length > 0) {
viewOption.attributesProcessors = processors;
}
}
}
if (Object.keys(viewOption).length > 0) {
metricViews.push(viewOption);
}
});
if (metricViews.length > 0) {
return metricViews;
}
return undefined;
}
exports.getMeterViewsFromConfiguration = getMeterViewsFromConfiguration;
function getInstanceID(config) {
if (config.resource?.attributes) {
for (let i = 0; i < config.resource.attributes.length; i++) {
const element = config.resource.attributes[i];
if (element.name === 'service.instance.id') {
return element.value?.toString();
}
}
}
return undefined;
}
exports.getInstanceID = getInstanceID;
const DEFAULT_RATIO = 1;
/**
* Returns the {@link Sampler} configured under `tracer_provider.sampler` in
* the declarative configuration, or `undefined` if none is set (in which case
* the SDK applies its default sampler).
*/
function getSamplerFromConfiguration(config) {
const samplerConfig = config.tracer_provider?.sampler;
if (!samplerConfig) {
return undefined;
}
return buildSamplerFromConfig(samplerConfig);
}
exports.getSamplerFromConfiguration = getSamplerFromConfiguration;
/**
* Builds a {@link Sampler} from a {@link SamplerConfigModel} data model.
* This allows sampler construction from declarative configuration.
*/
function buildSamplerFromConfig(samplerConfig) {
if (samplerConfig.always_on !== undefined) {
return new sdk_trace_1.AlwaysOnSampler();
}
if (samplerConfig.always_off !== undefined) {
return new sdk_trace_1.AlwaysOffSampler();
}
if (samplerConfig.trace_id_ratio_based !== undefined) {
return new sdk_trace_1.TraceIdRatioBasedSampler(samplerConfig.trace_id_ratio_based?.ratio ?? DEFAULT_RATIO);
}
if (samplerConfig.parent_based !== undefined) {
const pb = samplerConfig.parent_based ?? {};
return new sdk_trace_1.ParentBasedSampler({
root: pb.root ? buildSamplerFromConfig(pb.root) : new sdk_trace_1.AlwaysOnSampler(),
remoteParentSampled: pb.remote_parent_sampled
? buildSamplerFromConfig(pb.remote_parent_sampled)
: undefined,
remoteParentNotSampled: pb.remote_parent_not_sampled
? buildSamplerFromConfig(pb.remote_parent_not_sampled)
: undefined,
localParentSampled: pb.local_parent_sampled
? buildSamplerFromConfig(pb.local_parent_sampled)
: undefined,
localParentNotSampled: pb.local_parent_not_sampled
? buildSamplerFromConfig(pb.local_parent_not_sampled)
: undefined,
});
}
api_1.diag.warn('Unknown sampler config, defaulting to ParentBased(AlwaysOn).');
return new sdk_trace_1.ParentBasedSampler({ root: new sdk_trace_1.AlwaysOnSampler() });
}
exports.buildSamplerFromConfig = buildSamplerFromConfig;
//# sourceMappingURL=utils.js.map