Skip to content

Commit

Permalink
Extract configureInstrumentations from tracing (#892)
Browse files Browse the repository at this point in the history
* Extract configureInstrumentations from tracing

* Increse debug metrics test timeout

* Extract setting default options also

* Increase jobs

* Fix example

* Cleanup
  • Loading branch information
mhennoch authored Apr 2, 2024
1 parent aa8c645 commit 0f8a6af
Show file tree
Hide file tree
Showing 26 changed files with 345 additions and 248 deletions.
2 changes: 1 addition & 1 deletion examples/express/tracer.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ if (process.env.OTEL_LOG_LEVEL) {
diag.setLogger(new DiagConsoleLogger(), DiagLogLevel[process.env.OTEL_LOG_LEVEL]);
}

const tracer = require('@splunk/otel').startTracing();
require('@splunk/otel').start();
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
"lint": "eslint . --ext .ts",
"lint:commits": "commitlint",
"test": "npm run test:unit && npm run test:debug-metrics && npm run test:instrumentations",
"test:unit": "cross-env TEST_ALLOW_DOUBLE_START=y nyc ts-mocha --exclude 'test/instrumentation/external/**/*.test.ts' --exclude 'test/separate_process/*' --timeout 60s --parallel --jobs 4 -p tsconfig.json 'test/**/*.test.ts'",
"test:debug-metrics": "nyc --no-clean ts-mocha -p tsconfig.json 'test/separate_process/debug_metrics.test.ts'",
"test:unit": "cross-env TEST_ALLOW_DOUBLE_START=y nyc ts-mocha --exclude 'test/instrumentation/external/**/*.test.ts' --exclude 'test/separate_process/*' --timeout 60s --parallel --jobs 8 -p tsconfig.json 'test/**/*.test.ts'",
"test:debug-metrics": "nyc --no-clean ts-mocha --timeout 10000 -p tsconfig.json 'test/separate_process/debug_metrics.test.ts'",
"test:instrumentations": "nyc ts-mocha --require test/instrumentation/external/setup.ts --jobs 1 'test/instrumentation/external/**/*.test.ts'",
"prebuild:current": "node scripts/prebuild-current.js",
"prebuild:os": "node scripts/prebuild-os.js",
Expand Down
12 changes: 8 additions & 4 deletions src/instrument.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { startMetrics } from './metrics';
import { startProfiling } from './profiling';
import { startTracing } from './tracing';
import { startLogging } from './logging';
import { parseOptionsAndConfigureInstrumentations } from './instrumentations';

function boot() {
const logLevel = parseLogLevel(getNonEmptyEnvVar('OTEL_LOG_LEVEL'));
Expand All @@ -46,21 +47,24 @@ function boot() {
}
}

const { tracingOptions, loggingOptions, profilingOptions, metricsOptions } =
parseOptionsAndConfigureInstrumentations();

if (getEnvBoolean('SPLUNK_PROFILER_ENABLED', false)) {
startProfiling();
startProfiling(profilingOptions);
}

startTracing();
startTracing(tracingOptions);

if (getEnvBoolean('SPLUNK_AUTOMATIC_LOG_COLLECTION', false)) {
startLogging();
startLogging(loggingOptions);
}

if (
getEnvBoolean('SPLUNK_METRICS_ENABLED', false) ||
getEnvBoolean('SPLUNK_PROFILER_MEMORY_ENABLED', false)
) {
startMetrics();
startMetrics(metricsOptions);
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/instrumentations/graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

import { Options } from '../tracing/options';
import { StartTracingOptions } from '../tracing';
import { getEnvBoolean } from '../utils';
import type {
GraphQLInstrumentation,
Expand All @@ -24,7 +24,7 @@ import type {
export function configureGraphQlInstrumentation(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
instrumentation: any,
_options: Options
_options: StartTracingOptions
) {
if (getEnvBoolean('SPLUNK_GRAPHQL_RESOLVE_SPANS_ENABLED', false)) {
return;
Expand Down
9 changes: 5 additions & 4 deletions src/instrumentations/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
* limitations under the License.
*/

import { Options, CaptureHttpUriParameters } from '../tracing/options';
import { CaptureHttpUriParameters } from '../tracing/options';
import { Options as TracingOptions } from '../tracing/options';
import { IncomingMessage, ServerResponse } from 'http';
import {
HttpInstrumentationConfig,
Expand All @@ -27,7 +28,7 @@ import * as Url from 'url';

type IncomingHttpRequestHook = (span: Span, request: IncomingMessage) => void;

function shouldAddRequestHook(options: Options): boolean {
function shouldAddRequestHook(options: TracingOptions): boolean {
if (
Array.isArray(options.captureHttpRequestUriParams) &&
options.captureHttpRequestUriParams.length === 0
Expand Down Expand Up @@ -86,7 +87,7 @@ function captureUriParamByFunction(
}

function createHttpRequestHook(
options: Options
options: TracingOptions
): HttpRequestCustomAttributeFunction {
const incomingRequestHooks: IncomingHttpRequestHook[] = [];

Expand Down Expand Up @@ -118,7 +119,7 @@ function createHttpRequestHook(
export function configureHttpInstrumentation(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
instrumentation: any,
options: Options
options: TracingOptions
) {
if (!options.serverTimingEnabled) {
return;
Expand Down
108 changes: 107 additions & 1 deletion src/instrumentations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,42 @@
*/

import { load } from './loader';
import { getEnvBoolean } from '../utils';
import { getEnvBoolean, assertNoExtraneousProperties, pick } from '../utils';
import type { EnvVarKey } from '../types';
import {
allowedTracingOptions,
Options as TracingOptions,
_setDefaultOptions as setDefaultTracingOptions,
} from '../tracing/options';

import type { StartLoggingOptions } from '../logging';
import {
allowedLoggingOptions,
_setDefaultOptions as setDefaultLoggingOptions,
} from '../logging';
import { allowedProfilingOptions } from '../profiling/types';
import { _setDefaultOptions as setDefaultProfilingOptions } from '../profiling';
import {
allowedMetricsOptions,
_setDefaultOptions as setDefaultMetricsOptions,
} from '../metrics';
import type { Options as StartOptions } from '../start';
import { configureGraphQlInstrumentation } from './graphql';
import { configureHttpInstrumentation } from './http';
import { configureLogInjection, disableLogSending } from './logging';
import { configureRedisInstrumentation } from './redis';

type InstrumentationInfo = {
module: string;
name: string;
shortName: string;
};

interface Options {
tracing: TracingOptions;
logging: StartLoggingOptions;
}

export const bundledInstrumentations: InstrumentationInfo[] = [
{
module: '@opentelemetry/instrumentation-amqplib',
Expand Down Expand Up @@ -233,3 +260,82 @@ export function getInstrumentations() {

return loaded;
}

export function configureInstrumentations(options: Options) {
const instrumentations = options.tracing.instrumentations || [];
for (const instrumentation of instrumentations) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const instr = instrumentation as any;

switch (instr['instrumentationName']) {
case '@opentelemetry/instrumentation-graphql':
configureGraphQlInstrumentation(instr, options.tracing);
break;
case '@opentelemetry/instrumentation-http':
configureHttpInstrumentation(instr, options.tracing);
break;
case '@opentelemetry/instrumentation-redis':
configureRedisInstrumentation(instr, options.tracing);
break;
case '@opentelemetry/instrumentation-bunyan':
disableLogSending(instr);
configureLogInjection(instr);
break;
case '@opentelemetry/instrumentation-pino':
case '@opentelemetry/instrumentation-winston':
configureLogInjection(instr);
break;
}
}
}

export function parseOptionsAndConfigureInstrumentations(
options: Partial<StartOptions> = {}
) {
const { metrics, profiling, tracing, logging, ...restOptions } = options;

assertNoExtraneousProperties(restOptions, [
'accessToken',
'endpoint',
'serviceName',
'logLevel',
]);

const startProfilingOptions = Object.assign(
pick(restOptions, allowedProfilingOptions),
profiling
);

assertNoExtraneousProperties(startProfilingOptions, allowedProfilingOptions);
const profilingOptions = setDefaultProfilingOptions(startProfilingOptions);

const startLoggingOptions = Object.assign(
pick(restOptions, allowedLoggingOptions),
logging
);

const loggingOptions = setDefaultLoggingOptions(startLoggingOptions);

const startTracingOptions = Object.assign(
pick(restOptions, allowedTracingOptions),
tracing
) as Partial<TracingOptions>;

assertNoExtraneousProperties(startTracingOptions, allowedTracingOptions);
const tracingOptions = setDefaultTracingOptions(startTracingOptions);

const startMetricsOptions = Object.assign(
pick(restOptions, allowedMetricsOptions),
metrics
);

assertNoExtraneousProperties(startMetricsOptions, allowedMetricsOptions);
const metricsOptions = setDefaultMetricsOptions(startMetricsOptions);

configureInstrumentations({
tracing: tracingOptions,
logging: loggingOptions,
});

return { tracingOptions, loggingOptions, profilingOptions, metricsOptions };
}
4 changes: 2 additions & 2 deletions src/instrumentations/redis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ import type {
RedisInstrumentationConfig,
} from '@opentelemetry/instrumentation-redis';
import { getEnvBoolean } from '../utils';
import { Options } from '../tracing/options';
import { StartTracingOptions } from '../tracing';

export function configureRedisInstrumentation(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
instrumentation: any,
_options: Options
_options: StartTracingOptions
) {
const redisInstrumentation = instrumentation as RedisInstrumentation;
if (getEnvBoolean('SPLUNK_REDIS_INCLUDE_COMMAND_ARGS', false)) {
Expand Down
17 changes: 7 additions & 10 deletions src/logging/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ import { getNonEmptyEnvVar, getEnvArray, defaultServiceName } from '../utils';
import { detect as detectResource } from '../resource';

type LogRecordProcessorFactory = (
options: LoggingOptions
options: Options
) => LogRecordProcessor | LogRecordProcessor[];

interface LoggingOptions {
export interface Options {
accessToken?: string;
realm?: string;
serviceName: string;
Expand All @@ -51,10 +51,9 @@ export const allowedLoggingOptions = [
'logRecordProcessorFactory',
];

export type StartLoggingOptions = Partial<Omit<LoggingOptions, 'resource'>>;
export type StartLoggingOptions = Partial<Omit<Options, 'resource'>>;

export function startLogging(opts: StartLoggingOptions = {}) {
const options = _setDefaultOptions(opts);
export function startLogging(options: Options) {
const loggerProvider = new LoggerProvider({
resource: options.resource,
});
Expand All @@ -78,9 +77,7 @@ export function startLogging(opts: StartLoggingOptions = {}) {
};
}

export function _setDefaultOptions(
options: StartLoggingOptions = {}
): LoggingOptions {
export function _setDefaultOptions(options: StartLoggingOptions = {}): Options {
let resource = detectResource();

const serviceName =
Expand Down Expand Up @@ -122,7 +119,7 @@ function areValidExporterTypes(types: string[]): boolean {
return types.every((t) => SUPPORTED_EXPORTER_TYPES.includes(t));
}

function createExporters(options: LoggingOptions) {
function createExporters(options: Options) {
const logExporters: string[] = getEnvArray('OTEL_LOGS_EXPORTER', ['otlp']);

if (!areValidExporterTypes(logExporters)) {
Expand Down Expand Up @@ -150,7 +147,7 @@ function createExporters(options: LoggingOptions) {
}

export function defaultlogRecordProcessorFactory(
options: LoggingOptions
options: Options
): LogRecordProcessor[] {
let exporters = createExporters(options);

Expand Down
9 changes: 2 additions & 7 deletions src/metrics/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import { OTLPMetricExporter as OTLPHttpProtoMetricExporter } from '@opentelemetr
import type * as grpc from '@grpc/grpc-js';
import type * as OtlpGrpc from '@opentelemetry/exporter-metrics-otlp-grpc';
import {
assertNoExtraneousProperties,
defaultServiceName,
getEnvArray,
getEnvBoolean,
Expand All @@ -43,7 +42,7 @@ import { ConsoleMetricExporter } from './ConsoleMetricExporter';
export type MetricReaderFactory = (options: MetricsOptions) => MetricReader[];
export type ResourceFactory = (resource: Resource) => Resource;

interface MetricsOptions {
export interface MetricsOptions {
accessToken: string;
realm?: string;
serviceName: string;
Expand Down Expand Up @@ -244,11 +243,7 @@ export const allowedMetricsOptions = [
'debugMetricsEnabled',
];

export function startMetrics(opts: StartMetricsOptions = {}) {
assertNoExtraneousProperties(opts, allowedMetricsOptions);

const options = _setDefaultOptions(opts);

export function startMetrics(options: MetricsOptions) {
const debugMetricsViews: View[] = options.debugMetricsEnabled
? getDebugMetricsViews()
: [];
Expand Down
8 changes: 1 addition & 7 deletions src/profiling/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import { context, diag } from '@opentelemetry/api';
import { Resource } from '@opentelemetry/resources';
import {
assertNoExtraneousProperties,
defaultServiceName,
getEnvBoolean,
getEnvNumber,
Expand All @@ -37,7 +36,6 @@ import {
ProfilingOptions,
StartProfilingOptions,
ProfilingStartOptions,
allowedProfilingOptions,
} from './types';
import { ProfilingContextManager } from './ProfilingContextManager';
import { OTLPProfilingExporter } from './OTLPProfilingExporter';
Expand Down Expand Up @@ -101,11 +99,7 @@ export function isProfilingContextManagerSet(): boolean {
return profilingContextManagerEnabled;
}

export function startProfiling(opts: StartProfilingOptions = {}) {
assertNoExtraneousProperties(opts, allowedProfilingOptions);

const options = _setDefaultOptions(opts);

export function startProfiling(options: ProfilingOptions) {
const extension = loadExtension();

if (extension === undefined) {
Expand Down
Loading

0 comments on commit 0f8a6af

Please sign in to comment.