Skip to content

Commit 14d086a

Browse files
authored
feat(sdk-node)!: Automatically configure logs exporter (#4740)
1 parent e1522f0 commit 14d086a

File tree

9 files changed

+311
-16
lines changed

9 files changed

+311
-16
lines changed

experimental/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ All notable changes to experimental packages in this project will be documented
1616
* allowing overrides of the `User-Agent` header was not specification compliant.
1717
* feat(exporter-*-otlp*)!: remove environment-variable specific code from browser exporters
1818
* (user-facing) removes the ability to configure browser exporters by using `process.env` polyfills
19+
* feat(sdk-node)!: Automatically configure logs exporter [#4740](https://github.com/open-telemetry/opentelemetry-js/pull/4740)
1920

2021
### :rocket: (Enhancement)
2122

experimental/packages/opentelemetry-sdk-node/README.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,14 @@ Use a custom context manager. Default: [AsyncHooksContextManager](../../../packa
9191

9292
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)
9393

94+
### logRecordProcessor
95+
96+
Deprecated, please use [logRecordProcessors](#logrecordprocessors) instead.
97+
98+
### logRecordProcessors
99+
100+
An array of log record processors to register to the logger provider.
101+
94102
### metricReader
95103

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

178186
The default level is `INFO`.
179187

180-
## Configure Trace Exporter from environment
188+
## Configure Exporters from environment
181189

182-
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.
190+
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.
183191

184192
### Exporters
185193

186194
| Environment variable | Description |
187195
|----------------------|-------------|
188196
| 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. |
197+
| 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. |
189198

190199
### OTLP Exporter
191200

@@ -194,6 +203,7 @@ This is an alternative to programmatically configuring an exporter or span proce
194203
| 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`. |
195204
| 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`. |
196205
| 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`. |
206+
| 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`. |
197207

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

experimental/packages/opentelemetry-sdk-node/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@
5050
"@opentelemetry/exporter-trace-otlp-grpc": "0.52.1",
5151
"@opentelemetry/exporter-trace-otlp-http": "0.52.1",
5252
"@opentelemetry/exporter-trace-otlp-proto": "0.52.1",
53+
"@opentelemetry/exporter-logs-otlp-grpc": "0.52.1",
54+
"@opentelemetry/exporter-logs-otlp-http": "0.52.1",
55+
"@opentelemetry/exporter-logs-otlp-proto": "0.52.1",
5356
"@opentelemetry/exporter-zipkin": "1.25.1",
5457
"@opentelemetry/instrumentation": "0.52.1",
5558
"@opentelemetry/resources": "1.25.1",

experimental/packages/opentelemetry-sdk-node/src/TracerProviderWithEnvExporter.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import { OTLPTraceExporter as OTLPProtoTraceExporter } from '@opentelemetry/expo
3232
import { OTLPTraceExporter as OTLPHttpTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
3333
import { OTLPTraceExporter as OTLPGrpcTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc';
3434
import { ZipkinExporter } from '@opentelemetry/exporter-zipkin';
35+
import { filterBlanksAndNulls } from './utils';
3536

3637
export class TracerProviderWithEnvExporters extends NodeTracerProvider {
3738
private _configuredExporters: SpanExporter[] = [];
@@ -94,7 +95,7 @@ export class TracerProviderWithEnvExporters extends NodeTracerProvider {
9495

9596
public constructor(config: NodeTracerConfig = {}) {
9697
super(config);
97-
let traceExportersList = this.filterBlanksAndNulls(
98+
let traceExportersList = filterBlanksAndNulls(
9899
Array.from(new Set(getEnv().OTEL_TRACES_EXPORTER.split(',')))
99100
);
100101

@@ -175,8 +176,4 @@ export class TracerProviderWithEnvExporters extends NodeTracerProvider {
175176
}
176177
});
177178
}
178-
179-
private filterBlanksAndNulls(list: string[]): string[] {
180-
return list.map(item => item.trim()).filter(s => s !== 'null' && s !== '');
181-
}
182179
}

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

Lines changed: 96 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,17 @@ import {
3737
Resource,
3838
ResourceDetectionConfig,
3939
} from '@opentelemetry/resources';
40-
import { LogRecordProcessor, LoggerProvider } from '@opentelemetry/sdk-logs';
40+
import {
41+
LogRecordProcessor,
42+
LoggerProvider,
43+
BatchLogRecordProcessor,
44+
ConsoleLogRecordExporter,
45+
LogRecordExporter,
46+
SimpleLogRecordProcessor,
47+
} from '@opentelemetry/sdk-logs';
48+
import { OTLPLogExporter as OTLPHttpLogExporter } from '@opentelemetry/exporter-logs-otlp-http';
49+
import { OTLPLogExporter as OTLPGrpcLogExporter } from '@opentelemetry/exporter-logs-otlp-grpc';
50+
import { OTLPLogExporter as OTLPProtoLogExporter } from '@opentelemetry/exporter-logs-otlp-proto';
4151
import { MeterProvider, MetricReader, View } from '@opentelemetry/sdk-metrics';
4252
import {
4353
BatchSpanProcessor,
@@ -51,7 +61,7 @@ import { SEMRESATTRS_SERVICE_NAME } from '@opentelemetry/semantic-conventions';
5161
import { NodeSDKConfiguration } from './types';
5262
import { TracerProviderWithEnvExporters } from './TracerProviderWithEnvExporter';
5363
import { getEnv, getEnvWithoutDefaults } from '@opentelemetry/core';
54-
import { getResourceDetectorsFromEnv } from './utils';
64+
import { getResourceDetectorsFromEnv, filterBlanksAndNulls } from './utils';
5565

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

@@ -70,7 +80,7 @@ export type LoggerProviderConfig = {
7080
/**
7181
* Reference to the LoggerRecordProcessor instance by the NodeSDK
7282
*/
73-
logRecordProcessor: LogRecordProcessor;
83+
logRecordProcessors: LogRecordProcessor[];
7484
};
7585

7686
export class NodeSDK {
@@ -173,10 +183,19 @@ export class NodeSDK {
173183
};
174184
}
175185

176-
if (configuration.logRecordProcessor) {
186+
if (configuration.logRecordProcessors) {
187+
this._loggerProviderConfig = {
188+
logRecordProcessors: configuration.logRecordProcessors,
189+
};
190+
} else if (configuration.logRecordProcessor) {
177191
this._loggerProviderConfig = {
178-
logRecordProcessor: configuration.logRecordProcessor,
192+
logRecordProcessors: [configuration.logRecordProcessor],
179193
};
194+
diag.warn(
195+
"The 'logRecordProcessor' option is deprecated. Please use 'logRecordProcessors' instead."
196+
);
197+
} else {
198+
this.configureLoggerProviderFromEnv();
180199
}
181200

182201
if (configuration.metricReader || configuration.views) {
@@ -257,9 +276,11 @@ export class NodeSDK {
257276
const loggerProvider = new LoggerProvider({
258277
resource: this._resource,
259278
});
260-
loggerProvider.addLogRecordProcessor(
261-
this._loggerProviderConfig.logRecordProcessor
262-
);
279+
280+
for (const logRecordProcessor of this._loggerProviderConfig
281+
.logRecordProcessors) {
282+
loggerProvider.addLogRecordProcessor(logRecordProcessor);
283+
}
263284

264285
this._loggerProvider = loggerProvider;
265286

@@ -308,4 +329,71 @@ export class NodeSDK {
308329
.then(() => {})
309330
);
310331
}
332+
333+
private configureLoggerProviderFromEnv(): void {
334+
const logExportersList = process.env.OTEL_LOGS_EXPORTER ?? '';
335+
const enabledExporters = filterBlanksAndNulls(logExportersList.split(','));
336+
337+
if (enabledExporters.length === 0) {
338+
diag.info('OTEL_LOGS_EXPORTER is empty. Using default otlp exporter.');
339+
enabledExporters.push('otlp');
340+
}
341+
342+
if (enabledExporters.includes('none')) {
343+
diag.info(
344+
`OTEL_LOGS_EXPORTER contains "none". Logger provider will not be initialized.`
345+
);
346+
return;
347+
}
348+
349+
const exporters: LogRecordExporter[] = [];
350+
351+
enabledExporters.forEach(exporter => {
352+
if (exporter === 'otlp') {
353+
const protocol = (
354+
process.env.OTEL_EXPORTER_OTLP_LOGS_PROTOCOL ??
355+
process.env.OTEL_EXPORTER_OTLP_PROTOCOL
356+
)?.trim();
357+
358+
switch (protocol) {
359+
case 'grpc':
360+
exporters.push(new OTLPGrpcLogExporter());
361+
break;
362+
case 'http/json':
363+
exporters.push(new OTLPHttpLogExporter());
364+
break;
365+
case 'http/protobuf':
366+
exporters.push(new OTLPProtoLogExporter());
367+
break;
368+
case undefined:
369+
case '':
370+
exporters.push(new OTLPProtoLogExporter());
371+
break;
372+
default:
373+
diag.warn(
374+
`Unsupported OTLP logs protocol: "${protocol}". Using http/protobuf.`
375+
);
376+
exporters.push(new OTLPProtoLogExporter());
377+
}
378+
} else if (exporter === 'console') {
379+
exporters.push(new ConsoleLogRecordExporter());
380+
} else {
381+
diag.warn(
382+
`Unsupported OTEL_LOGS_EXPORTER value: "${exporter}". Supported values are: otlp, console, none.`
383+
);
384+
}
385+
});
386+
387+
if (exporters.length > 0) {
388+
this._loggerProviderConfig = {
389+
logRecordProcessors: exporters.map(exporter => {
390+
if (exporter instanceof ConsoleLogRecordExporter) {
391+
return new SimpleLogRecordProcessor(exporter);
392+
} else {
393+
return new BatchLogRecordProcessor(exporter);
394+
}
395+
}),
396+
};
397+
}
398+
}
311399
}

experimental/packages/opentelemetry-sdk-node/src/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ export interface NodeSDKConfiguration {
3232
autoDetectResources: boolean;
3333
contextManager: ContextManager;
3434
textMapPropagator: TextMapPropagator;
35+
/** @deprecated use logRecordProcessors instead*/
3536
logRecordProcessor: LogRecordProcessor;
37+
logRecordProcessors?: LogRecordProcessor[];
3638
metricReader: MetricReader;
3739
views: View[];
3840
instrumentations: (Instrumentation | Instrumentation[])[];

experimental/packages/opentelemetry-sdk-node/src/utils.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,7 @@ export function getResourceDetectorsFromEnv(): Array<DetectorSync> {
6161
return resourceDetector || [];
6262
});
6363
}
64+
65+
export function filterBlanksAndNulls(list: string[]): string[] {
66+
return list.map(item => item.trim()).filter(s => s !== 'null' && s !== '');
67+
}

0 commit comments

Comments
 (0)