Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(opentelemetry-sdk-node): automatically configure metrics exporter based on environment variables #5168

2 changes: 2 additions & 0 deletions experimental/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ All notable changes to experimental packages in this project will be documented

### :rocket: (Enhancement)

* feat(opentelemetry-sdk-node): automatically configure metrics exporter based on environment variables [#5168](https://github.com/open-telemetry/opentelemetry-js/pull/5168) @bhaskarbanerjee

### :bug: (Bug Fix)

### :books: (Refine Doc)
Expand Down
3 changes: 3 additions & 0 deletions experimental/packages/opentelemetry-sdk-node/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,9 @@ This is an alternative to programmatically configuring an exporter or span proce
| OTEL_EXPORTER_OTLP_TRACES_PROTOCOL | The transport protocol to use on OTLP trace requests. Options include `grpc`, `http/protobuf`, and `http/json`. Default is `http/protobuf`. |
| OTEL_EXPORTER_OTLP_METRICS_PROTOCOL | The transport protocol to use on OTLP metric requests. Options include `grpc`, `http/protobuf`, and `http/json`. Default is `http/protobuf`. |
| OTEL_EXPORTER_OTLP_LOGS_PROTOCOL | The transport protocol to use on OTLP log requests. Options include `grpc`, `http/protobuf`, and `http/json`. Default is `http/protobuf`. |
| OTEL_METRICS_EXPORTER | Metrics exporter to be used. options are `otlp`, `prometheus`, `console` or `none`. |
| OTEL_METRIC_EXPORT_INTERVAL | The export interval when using a push Metric Reader. Default is `60000`. |
| OTEL_METRIC_EXPORT_TIMEOUT | The export timeout when using a push Metric Reader. Default is `30000`. |

Additionally, you can specify other applicable environment variables that apply to each exporter such as the following:

Expand Down
4 changes: 4 additions & 0 deletions experimental/packages/opentelemetry-sdk-node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@
"@opentelemetry/exporter-trace-otlp-proto": "0.56.0",
"@opentelemetry/exporter-zipkin": "1.29.0",
"@opentelemetry/instrumentation": "0.56.0",
"@opentelemetry/exporter-metrics-otlp-grpc": "0.56.0",
"@opentelemetry/exporter-metrics-otlp-proto": "0.56.0",
"@opentelemetry/exporter-metrics-otlp-http": "0.56.0",
"@opentelemetry/exporter-prometheus": "0.56.0",
"@opentelemetry/resources": "1.29.0",
"@opentelemetry/sdk-logs": "0.56.0",
"@opentelemetry/sdk-metrics": "1.29.0",
Expand Down
125 changes: 121 additions & 4 deletions experimental/packages/opentelemetry-sdk-node/src/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,17 @@
import { OTLPLogExporter as OTLPHttpLogExporter } from '@opentelemetry/exporter-logs-otlp-http';
import { OTLPLogExporter as OTLPGrpcLogExporter } from '@opentelemetry/exporter-logs-otlp-grpc';
import { OTLPLogExporter as OTLPProtoLogExporter } from '@opentelemetry/exporter-logs-otlp-proto';
import { MeterProvider, MetricReader, View } from '@opentelemetry/sdk-metrics';
import { OTLPMetricExporter as OTLPGrpcMetricExporter } from '@opentelemetry/exporter-metrics-otlp-grpc';
import { OTLPMetricExporter as OTLPProtoMetricExporter } from '@opentelemetry/exporter-metrics-otlp-proto';
import { OTLPMetricExporter as OTLPHttpMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http';
import { PrometheusExporter as PrometheusMetricExporter } from '@opentelemetry/exporter-prometheus';
import {
MeterProvider,
MetricReader,
View,
ConsoleMetricExporter,
PeriodicExportingMetricReader,
} from '@opentelemetry/sdk-metrics';
import {
BatchSpanProcessor,
SpanProcessor,
Expand Down Expand Up @@ -86,6 +96,107 @@
logRecordProcessors: LogRecordProcessor[];
};

/**
* @Returns param value, if set else returns the default value
*/
function getValueInMillis(envName: string, defaultValue: number): number {
return parseInt(process.env[envName] || '') || defaultValue;
}

/**
*
* @returns MetricReader[] if appropriate environment variables are configured
*/
function configureMetricProviderFromEnv(): MetricReader[] {
const metricReaders: MetricReader[] = [];
const metricsExporterList = process.env.OTEL_METRICS_EXPORTER?.trim();
if (!metricsExporterList) {
return metricReaders;
}
const enabledExporters = filterBlanksAndNulls(metricsExporterList.split(','));

if (enabledExporters.length === 0) {
diag.info('OTEL_METRICS_EXPORTER is empty. Using default otlp exporter.');

Check warning on line 119 in experimental/packages/opentelemetry-sdk-node/src/sdk.ts

View check run for this annotation

Codecov / codecov/patch

experimental/packages/opentelemetry-sdk-node/src/sdk.ts#L119

Added line #L119 was not covered by tests
}

if (enabledExporters.includes('none')) {
diag.info(
`OTEL_METRICS_EXPORTER contains "none". Metric provider will not be initialized.`
);
pichlermarc marked this conversation as resolved.
Show resolved Hide resolved
return metricReaders;
}
enabledExporters.forEach(exporter => {
if (exporter === 'otlp') {
const protocol =
process.env.OTEL_EXPORTER_OTLP_METRICS_PROTOCOL?.trim() ||
process.env.OTEL_EXPORTER_OTLP_PROTOCOL?.trim();

const exportIntervalMillis = getValueInMillis(
'OTEL_METRIC_EXPORT_INTERVAL',
60000
);
const exportTimeoutMillis = getValueInMillis(
'OTEL_METRIC_EXPORT_TIMEOUT',
30000
);

switch (protocol) {
case 'grpc':
metricReaders.push(
new PeriodicExportingMetricReader({
exporter: new OTLPGrpcMetricExporter(),
exportIntervalMillis: exportIntervalMillis,
exportTimeoutMillis: exportTimeoutMillis,
})
);
break;
case 'http/json':
metricReaders.push(
new PeriodicExportingMetricReader({
exporter: new OTLPHttpMetricExporter(),
exportIntervalMillis: exportIntervalMillis,
exportTimeoutMillis: exportTimeoutMillis,
})
);
break;
case 'http/protobuf':
metricReaders.push(
new PeriodicExportingMetricReader({
exporter: new OTLPProtoMetricExporter(),
exportIntervalMillis: exportIntervalMillis,
exportTimeoutMillis: exportTimeoutMillis,
})
);
break;
default:
diag.warn(
`Unsupported OTLP metrics protocol: "${protocol}". Using http/protobuf.`
);
metricReaders.push(
new PeriodicExportingMetricReader({
exporter: new OTLPProtoMetricExporter(),
exportIntervalMillis: exportIntervalMillis,
exportTimeoutMillis: exportTimeoutMillis,
})
);
}
} else if (exporter === 'console') {
metricReaders.push(
new PeriodicExportingMetricReader({
exporter: new ConsoleMetricExporter(),
})
);
} else if (exporter === 'prometheus') {
metricReaders.push(new PrometheusMetricExporter());
} else {
diag.warn(

Check warning on line 192 in experimental/packages/opentelemetry-sdk-node/src/sdk.ts

View check run for this annotation

Codecov / codecov/patch

experimental/packages/opentelemetry-sdk-node/src/sdk.ts#L192

Added line #L192 was not covered by tests
`Unsupported OTEL_METRICS_EXPORTER value: "${exporter}". Supported values are: otlp, console, prometheus, none.`
);
}
});

return metricReaders;
}
export class NodeSDK {
private _tracerProviderConfig?: {
tracerConfig: NodeTracerConfig;
Expand Down Expand Up @@ -290,11 +401,18 @@
logs.setGlobalLoggerProvider(loggerProvider);
}

if (this._meterProviderConfig) {
const metricReadersFromEnv: MetricReader[] =
configureMetricProviderFromEnv();
if (this._meterProviderConfig || metricReadersFromEnv.length > 0) {
const readers: MetricReader[] = [];
if (this._meterProviderConfig.reader) {
if (this._meterProviderConfig?.reader) {
readers.push(this._meterProviderConfig.reader);
}

if (readers.length === 0) {
metricReadersFromEnv.forEach((r: MetricReader) => readers.push(r));
}

const meterProvider = new MeterProvider({
resource: this._resource,
views: this._meterProviderConfig?.views ?? [],
Expand All @@ -303,7 +421,6 @@
});

this._meterProvider = meterProvider;

metrics.setGlobalMeterProvider(meterProvider);

// TODO: This is a workaround to fix https://github.com/open-telemetry/opentelemetry-js/issues/3609
Expand Down
Loading
Loading