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(sdk-node): logs support added #3969

Merged
merged 7 commits into from
Jul 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions experimental/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ All notable changes to experimental packages in this project will be documented

### :rocket: (Enhancement)

* feat(sdk-node): logs support added [#3969](https://github.com/open-telemetry/opentelemetry-js/pull/3969) @psk001

### :bug: (Bug Fix)

### :books: (Refine Doc)
Expand Down
2 changes: 2 additions & 0 deletions experimental/packages/opentelemetry-sdk-node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"access": "public"
},
"dependencies": {
"@opentelemetry/api-logs":"0.41.0",
"@opentelemetry/core": "1.15.0",
"@opentelemetry/exporter-jaeger": "1.15.0",
"@opentelemetry/exporter-trace-otlp-grpc": "0.41.0",
Expand All @@ -52,6 +53,7 @@
"@opentelemetry/exporter-zipkin": "1.15.0",
"@opentelemetry/instrumentation": "0.41.0",
"@opentelemetry/resources": "1.15.0",
"@opentelemetry/sdk-logs":"0.41.0",
"@opentelemetry/sdk-metrics": "1.15.0",
"@opentelemetry/sdk-trace-base": "1.15.0",
"@opentelemetry/sdk-trace-node": "1.15.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
export * as api from '@opentelemetry/api';
export * as contextBase from '@opentelemetry/api';
export * as core from '@opentelemetry/core';
export * as logs from '@opentelemetry/sdk-logs';
export * as metrics from '@opentelemetry/sdk-metrics';
export * as node from '@opentelemetry/sdk-trace-node';
export * as resources from '@opentelemetry/resources';
Expand Down
58 changes: 58 additions & 0 deletions experimental/packages/opentelemetry-sdk-node/src/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
diag,
DiagConsoleLogger,
} from '@opentelemetry/api';
import { logs } from '@opentelemetry/api-logs';
import {
InstrumentationOption,
registerInstrumentations,
Expand All @@ -35,6 +36,7 @@ import {
Resource,
ResourceDetectionConfig,
} from '@opentelemetry/resources';
import { LogRecordProcessor, LoggerProvider } from '@opentelemetry/sdk-logs';
import { MeterProvider, MetricReader, View } from '@opentelemetry/sdk-metrics';
import {
BatchSpanProcessor,
Expand Down Expand Up @@ -63,13 +65,21 @@ export type MeterProviderConfig = {
views?: View[];
};

export type LoggerProviderConfig = {
/**
* Reference to the LoggerRecordProcessor instance by the NodeSDK
*/
logRecordProcessor: LogRecordProcessor;
};

export class NodeSDK {
private _tracerProviderConfig?: {
tracerConfig: NodeTracerConfig;
spanProcessor: SpanProcessor;
contextManager?: ContextManager;
textMapPropagator?: TextMapPropagator;
};
private _loggerProviderConfig?: LoggerProviderConfig;
private _meterProviderConfig?: MeterProviderConfig;
private _instrumentations: InstrumentationOption[];

Expand All @@ -79,6 +89,7 @@ export class NodeSDK {
private _autoDetectResources: boolean;

private _tracerProvider?: NodeTracerProvider | TracerProviderWithEnvExporters;
private _loggerProvider?: LoggerProvider;
private _meterProvider?: MeterProvider;
private _serviceName?: string;

Expand Down Expand Up @@ -140,6 +151,13 @@ export class NodeSDK {
);
}

if (configuration.logRecordProcessor) {
const loggerProviderConfig: LoggerProviderConfig = {
logRecordProcessor: configuration.logRecordProcessor,
};
this.configureLoggerProvider(loggerProviderConfig);
}

if (configuration.metricReader || configuration.views) {
const meterProviderConfig: MeterProviderConfig = {};
if (configuration.metricReader) {
Expand Down Expand Up @@ -175,6 +193,30 @@ export class NodeSDK {
};
}

/**Set configurations needed to register a LoggerProvider */
public configureLoggerProvider(config: LoggerProviderConfig): void {
// nothing is set yet, we can set config and then return
if (this._loggerProviderConfig == null) {
this._loggerProviderConfig = config;
return;
}

// make sure we do not override existing logRecordProcessor with other logRecordProcessors.
if (
this._loggerProviderConfig.logRecordProcessor != null &&
config.logRecordProcessor != null
) {
throw new Error(
'LogRecordProcessor passed but LogRecordProcessor has already been configured.'
);
}

// set logRecordProcessor, but make sure we do not override existing logRecordProcessors with null/undefined.
if (config.logRecordProcessor != null) {
this._loggerProviderConfig.logRecordProcessor = config.logRecordProcessor;
}
}

/** Set configurations needed to register a MeterProvider */
public configureMeterProvider(config: MeterProviderConfig): void {
// nothing is set yet, we can set config and return.
Expand Down Expand Up @@ -269,6 +311,19 @@ export class NodeSDK {
propagator: this._tracerProviderConfig?.textMapPropagator,
});

if (this._loggerProviderConfig) {
const loggerProvider = new LoggerProvider({
resource: this._resource,
});
loggerProvider.addLogRecordProcessor(
this._loggerProviderConfig.logRecordProcessor
);

this._loggerProvider = loggerProvider;

logs.setGlobalLoggerProvider(loggerProvider);
}

if (this._meterProviderConfig) {
const meterProvider = new MeterProvider({
resource: this._resource,
Expand Down Expand Up @@ -299,6 +354,9 @@ export class NodeSDK {
if (this._tracerProvider) {
promises.push(this._tracerProvider.shutdown());
}
if (this._loggerProvider) {
promises.push(this._loggerProvider.shutdown());
}
if (this._meterProvider) {
promises.push(this._meterProvider.shutdown());
}
Expand Down
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 @@ -18,6 +18,7 @@ import type { ContextManager } from '@opentelemetry/api';
import { TextMapPropagator } from '@opentelemetry/api';
import { InstrumentationOption } from '@opentelemetry/instrumentation';
import { Detector, DetectorSync, IResource } from '@opentelemetry/resources';
import { LogRecordProcessor } from '@opentelemetry/sdk-logs';
import { MetricReader, View } from '@opentelemetry/sdk-metrics';
import {
Sampler,
Expand All @@ -31,6 +32,7 @@ export interface NodeSDKConfiguration {
autoDetectResources: boolean;
contextManager: ContextManager;
textMapPropagator: TextMapPropagator;
logRecordProcessor: LogRecordProcessor;
metricReader: MetricReader;
views: View[];
instrumentations: InstrumentationOption[];
Expand Down
63 changes: 63 additions & 0 deletions experimental/packages/opentelemetry-sdk-node/test/sdk.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ import {
Resource,
} from '@opentelemetry/resources';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { logs } from '@opentelemetry/api-logs';
import {
SimpleLogRecordProcessor,
InMemoryLogRecordExporter,
LoggerProvider,
} from '@opentelemetry/sdk-logs';

const DefaultContextManager = semver.gte(process.version, '14.8.0')
? AsyncLocalStorageContextManager
Expand Down Expand Up @@ -112,6 +118,7 @@ describe('Node SDK', () => {
'tracer provider should not have changed'
);
assert.ok(!(metrics.getMeterProvider() instanceof MeterProvider));
assert.ok(!(logs.getLoggerProvider() instanceof LoggerProvider));
delete env.OTEL_TRACES_EXPORTER;
});

Expand Down Expand Up @@ -233,6 +240,40 @@ describe('Node SDK', () => {
await sdk.shutdown();
delete env.OTEL_TRACES_EXPORTER;
});

it('should register a logger provider if a log record processor is provided', async () => {
env.OTEL_TRACES_EXPORTER = 'none';
const logRecordExporter = new InMemoryLogRecordExporter();
const logRecordProcessor = new SimpleLogRecordProcessor(
logRecordExporter
);
const sdk = new NodeSDK({
logRecordProcessor: logRecordProcessor,
autoDetectResources: false,
});

sdk.start();

assert.strictEqual(
context['_getContextManager'](),
ctxManager,
'context manager should not change'
);
assert.strictEqual(
propagation['_getGlobalPropagator'](),
propagator,
'propagator should not change'
);
assert.strictEqual(
(trace.getTracerProvider() as ProxyTracerProvider).getDelegate(),
delegate,
'tracer provider should not have changed'
);

assert.ok(logs.getLoggerProvider() instanceof LoggerProvider);
await sdk.shutdown();
delete env.OTEL_TRACES_EXPORTER;
});
});

async function waitForNumberOfMetrics(
Expand Down Expand Up @@ -406,6 +447,28 @@ describe('Node SDK', () => {
);
});

it('should throw error when calling configureLoggerProvider when logRecordProcessor is already configured', () => {
const logRecordExporter = new InMemoryLogRecordExporter();
const logRecordProcessor = new SimpleLogRecordProcessor(logRecordExporter);
const sdk = new NodeSDK({
logRecordProcessor: logRecordProcessor,
autoDetectResources: false,
});

assert.throws(
() => {
sdk.configureLoggerProvider({
logRecordProcessor: logRecordProcessor,
});
},
(error: Error) => {
return error.message.includes(
'LogRecordProcessor passed but LogRecordProcessor has already been configured.'
);
}
);
});

describe('detectResources', async () => {
beforeEach(() => {
process.env.OTEL_RESOURCE_ATTRIBUTES =
Expand Down
6 changes: 6 additions & 0 deletions experimental/packages/opentelemetry-sdk-node/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
{
"path": "../../../api"
},
{
"path": "../../packages/api-logs"
},
{
"path": "../../../packages/opentelemetry-context-async-hooks"
},
Expand All @@ -36,6 +39,9 @@
{
"path": "../../../packages/opentelemetry-semantic-conventions"
},
{
"path": "../../packages/sdk-logs"
},
{
"path": "../../../packages/sdk-metrics"
},
Expand Down