Skip to content

Commit

Permalink
feat(sdk-node)!: Automatically configure logs exporter (#4740)
Browse files Browse the repository at this point in the history
  • Loading branch information
mhennoch authored Aug 19, 2024
1 parent e1522f0 commit 14d086a
Show file tree
Hide file tree
Showing 9 changed files with 311 additions and 16 deletions.
1 change: 1 addition & 0 deletions experimental/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ All notable changes to experimental packages in this project will be documented
* allowing overrides of the `User-Agent` header was not specification compliant.
* feat(exporter-*-otlp*)!: remove environment-variable specific code from browser exporters
* (user-facing) removes the ability to configure browser exporters by using `process.env` polyfills
* feat(sdk-node)!: Automatically configure logs exporter [#4740](https://github.com/open-telemetry/opentelemetry-js/pull/4740)

### :rocket: (Enhancement)

Expand Down
14 changes: 12 additions & 2 deletions experimental/packages/opentelemetry-sdk-node/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,14 @@ Use a custom context manager. Default: [AsyncHooksContextManager](../../../packa

Use a custom propagator. Default: [CompositePropagator](../../../packages/opentelemetry-core/src/propagation/composite.ts) using [W3C Trace Context](../../../packages/opentelemetry-core/README.md#w3ctracecontextpropagator-propagator) and [Baggage](../../../packages/opentelemetry-core/README.md#baggage-propagator)

### logRecordProcessor

Deprecated, please use [logRecordProcessors](#logrecordprocessors) instead.

### logRecordProcessors

An array of log record processors to register to the logger provider.

### metricReader

Add a [MetricReader](../opentelemetry-sdk-metrics/src/export/MetricReader.ts)
Expand Down Expand Up @@ -177,15 +185,16 @@ Set the log level by setting the `OTEL_LOG_LEVEL` environment variable to enums:

The default level is `INFO`.

## Configure Trace Exporter from environment
## Configure Exporters from environment

This is an alternative to programmatically configuring an exporter or span processor. This package will auto setup the default `otlp` exporter with `http/protobuf` protocol if `traceExporter` or `spanProcessor` hasn't been passed into the `NodeSDK` constructor.
This is an alternative to programmatically configuring an exporter or span processor. For traces this package will auto setup the default `otlp` exporter with `http/protobuf` protocol if `traceExporter` or `spanProcessor` hasn't been passed into the `NodeSDK` constructor.

### Exporters

| Environment variable | Description |
|----------------------|-------------|
| OTEL_TRACES_EXPORTER | List of exporters to be used for tracing, separated by commas. Options include `otlp`, `jaeger`, `zipkin`, and `none`. Default is `otlp`. `none` means no autoconfigured exporter. |
| OTEL_LOGS_EXPORTER | List of exporters to be used for logging, separated by commas. Options include `otlp`, `console` and `none`. Default is `otlp`. `none` means no autoconfigured exporter. |

### OTLP Exporter

Expand All @@ -194,6 +203,7 @@ This is an alternative to programmatically configuring an exporter or span proce
| OTEL_EXPORTER_OTLP_PROTOCOL | The transport protocol to use on OTLP trace, metric, and log requests. Options include `grpc`, `http/protobuf`, and `http/json`. Default is `http/protobuf`. |
| 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`. |

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

Expand Down
3 changes: 3 additions & 0 deletions experimental/packages/opentelemetry-sdk-node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@
"@opentelemetry/exporter-trace-otlp-grpc": "0.52.1",
"@opentelemetry/exporter-trace-otlp-http": "0.52.1",
"@opentelemetry/exporter-trace-otlp-proto": "0.52.1",
"@opentelemetry/exporter-logs-otlp-grpc": "0.52.1",
"@opentelemetry/exporter-logs-otlp-http": "0.52.1",
"@opentelemetry/exporter-logs-otlp-proto": "0.52.1",
"@opentelemetry/exporter-zipkin": "1.25.1",
"@opentelemetry/instrumentation": "0.52.1",
"@opentelemetry/resources": "1.25.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { OTLPTraceExporter as OTLPProtoTraceExporter } from '@opentelemetry/expo
import { OTLPTraceExporter as OTLPHttpTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { OTLPTraceExporter as OTLPGrpcTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc';
import { ZipkinExporter } from '@opentelemetry/exporter-zipkin';
import { filterBlanksAndNulls } from './utils';

export class TracerProviderWithEnvExporters extends NodeTracerProvider {
private _configuredExporters: SpanExporter[] = [];
Expand Down Expand Up @@ -94,7 +95,7 @@ export class TracerProviderWithEnvExporters extends NodeTracerProvider {

public constructor(config: NodeTracerConfig = {}) {
super(config);
let traceExportersList = this.filterBlanksAndNulls(
let traceExportersList = filterBlanksAndNulls(
Array.from(new Set(getEnv().OTEL_TRACES_EXPORTER.split(',')))
);

Expand Down Expand Up @@ -175,8 +176,4 @@ export class TracerProviderWithEnvExporters extends NodeTracerProvider {
}
});
}

private filterBlanksAndNulls(list: string[]): string[] {
return list.map(item => item.trim()).filter(s => s !== 'null' && s !== '');
}
}
104 changes: 96 additions & 8 deletions experimental/packages/opentelemetry-sdk-node/src/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,17 @@ import {
Resource,
ResourceDetectionConfig,
} from '@opentelemetry/resources';
import { LogRecordProcessor, LoggerProvider } from '@opentelemetry/sdk-logs';
import {
LogRecordProcessor,
LoggerProvider,
BatchLogRecordProcessor,
ConsoleLogRecordExporter,
LogRecordExporter,
SimpleLogRecordProcessor,
} from '@opentelemetry/sdk-logs';
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 {
BatchSpanProcessor,
Expand All @@ -51,7 +61,7 @@ import { SEMRESATTRS_SERVICE_NAME } from '@opentelemetry/semantic-conventions';
import { NodeSDKConfiguration } from './types';
import { TracerProviderWithEnvExporters } from './TracerProviderWithEnvExporter';
import { getEnv, getEnvWithoutDefaults } from '@opentelemetry/core';
import { getResourceDetectorsFromEnv } from './utils';
import { getResourceDetectorsFromEnv, filterBlanksAndNulls } from './utils';

/** This class represents everything needed to register a fully configured OpenTelemetry Node.js SDK */

Expand All @@ -70,7 +80,7 @@ export type LoggerProviderConfig = {
/**
* Reference to the LoggerRecordProcessor instance by the NodeSDK
*/
logRecordProcessor: LogRecordProcessor;
logRecordProcessors: LogRecordProcessor[];
};

export class NodeSDK {
Expand Down Expand Up @@ -173,10 +183,19 @@ export class NodeSDK {
};
}

if (configuration.logRecordProcessor) {
if (configuration.logRecordProcessors) {
this._loggerProviderConfig = {
logRecordProcessors: configuration.logRecordProcessors,
};
} else if (configuration.logRecordProcessor) {
this._loggerProviderConfig = {
logRecordProcessor: configuration.logRecordProcessor,
logRecordProcessors: [configuration.logRecordProcessor],
};
diag.warn(
"The 'logRecordProcessor' option is deprecated. Please use 'logRecordProcessors' instead."
);
} else {
this.configureLoggerProviderFromEnv();
}

if (configuration.metricReader || configuration.views) {
Expand Down Expand Up @@ -257,9 +276,11 @@ export class NodeSDK {
const loggerProvider = new LoggerProvider({
resource: this._resource,
});
loggerProvider.addLogRecordProcessor(
this._loggerProviderConfig.logRecordProcessor
);

for (const logRecordProcessor of this._loggerProviderConfig
.logRecordProcessors) {
loggerProvider.addLogRecordProcessor(logRecordProcessor);
}

this._loggerProvider = loggerProvider;

Expand Down Expand Up @@ -308,4 +329,71 @@ export class NodeSDK {
.then(() => {})
);
}

private configureLoggerProviderFromEnv(): void {
const logExportersList = process.env.OTEL_LOGS_EXPORTER ?? '';
const enabledExporters = filterBlanksAndNulls(logExportersList.split(','));

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

if (enabledExporters.includes('none')) {
diag.info(
`OTEL_LOGS_EXPORTER contains "none". Logger provider will not be initialized.`
);
return;
}

const exporters: LogRecordExporter[] = [];

enabledExporters.forEach(exporter => {
if (exporter === 'otlp') {
const protocol = (
process.env.OTEL_EXPORTER_OTLP_LOGS_PROTOCOL ??
process.env.OTEL_EXPORTER_OTLP_PROTOCOL
)?.trim();

switch (protocol) {
case 'grpc':
exporters.push(new OTLPGrpcLogExporter());
break;
case 'http/json':
exporters.push(new OTLPHttpLogExporter());
break;
case 'http/protobuf':
exporters.push(new OTLPProtoLogExporter());
break;
case undefined:
case '':
exporters.push(new OTLPProtoLogExporter());
break;
default:
diag.warn(
`Unsupported OTLP logs protocol: "${protocol}". Using http/protobuf.`
);
exporters.push(new OTLPProtoLogExporter());
}
} else if (exporter === 'console') {
exporters.push(new ConsoleLogRecordExporter());
} else {
diag.warn(
`Unsupported OTEL_LOGS_EXPORTER value: "${exporter}". Supported values are: otlp, console, none.`
);
}
});

if (exporters.length > 0) {
this._loggerProviderConfig = {
logRecordProcessors: exporters.map(exporter => {
if (exporter instanceof ConsoleLogRecordExporter) {
return new SimpleLogRecordProcessor(exporter);
} else {
return new BatchLogRecordProcessor(exporter);
}
}),
};
}
}
}
2 changes: 2 additions & 0 deletions experimental/packages/opentelemetry-sdk-node/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ export interface NodeSDKConfiguration {
autoDetectResources: boolean;
contextManager: ContextManager;
textMapPropagator: TextMapPropagator;
/** @deprecated use logRecordProcessors instead*/
logRecordProcessor: LogRecordProcessor;
logRecordProcessors?: LogRecordProcessor[];
metricReader: MetricReader;
views: View[];
instrumentations: (Instrumentation | Instrumentation[])[];
Expand Down
4 changes: 4 additions & 0 deletions experimental/packages/opentelemetry-sdk-node/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,7 @@ export function getResourceDetectorsFromEnv(): Array<DetectorSync> {
return resourceDetector || [];
});
}

export function filterBlanksAndNulls(list: string[]): string[] {
return list.map(item => item.trim()).filter(s => s !== 'null' && s !== '');
}
Loading

0 comments on commit 14d086a

Please sign in to comment.