Skip to content
Open
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
9 changes: 8 additions & 1 deletion packages/aws-lambda/src/wrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,14 @@ const { tracing, coreConfig } = instanaCore;
const { tracingHeaders, constants, spanBuffer } = tracing;

const lambdaConfigDefaults = {
tracing: { forceTransmissionStartingAt: 25, transmissionDelay: 100, initialTransmissionDelay: 100 }
// Preload OpenTelemetry deps to avoid lazy loading overhead
// See https://jsw.ibm.com/browse/INSTA-71262
preloadOpentelemetry: true,
tracing: {
forceTransmissionStartingAt: 25,
transmissionDelay: 100,
initialTransmissionDelay: 100
}
};

// Node.js 24+ removed support for callback-based handlers (3 parameters).
Expand Down
14 changes: 14 additions & 0 deletions packages/core/src/config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ const allowedSecretMatchers = ['equals', 'equals-ignore-case', 'contains', 'cont
* @property {InstanaTracingOption} [tracing]
* @property {InstanaSecretsOption} [secrets]
* @property {number} [timeBetweenHealthcheckCalls]
* @property {boolean} [preloadOpentelemetry]
*/

/** @type {import('../core').GenericLogger} */
Expand Down Expand Up @@ -122,6 +123,7 @@ let defaults = {
ignoreEndpointsDisableSuppression: false,
disableEOLEvents: false
},
preloadOpentelemetry: false,
secrets: {
matcherMode: 'contains-ignore-case',
keywords: ['key', 'pass', 'secret']
Expand Down Expand Up @@ -171,6 +173,7 @@ module.exports.normalize = (userConfig, defaultsOverride = {}) => {
normalizeMetricsConfig(targetConfig);
normalizeTracingConfig(targetConfig);
normalizeSecrets(targetConfig);
normalizePreloadOpentelemetry(targetConfig);
return targetConfig;
};

Expand Down Expand Up @@ -815,3 +818,14 @@ function normalizeDisableEOLEvents(config) {

config.tracing.disableEOLEvents = defaults.tracing.disableEOLEvents;
}

/**
* @param {InstanaConfig} config
*/
function normalizePreloadOpentelemetry(config) {
if (config.preloadOpentelemetry === true) {
return;
}

config.preloadOpentelemetry = defaults.preloadOpentelemetry;
}
3 changes: 2 additions & 1 deletion packages/core/src/tracing/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const tracingUtil = require('./tracingUtil');
const spanBuffer = require('./spanBuffer');
const shimmer = require('./shimmer');
const supportedVersion = require('./supportedVersion');
const { otelInstrumentations } = require('./opentelemetry-instrumentations');
const otelInstrumentations = require('./opentelemetry-instrumentations');
const cls = require('./cls');
const coreUtil = require('../util');

Expand Down Expand Up @@ -162,6 +162,7 @@ exports.preInit = function preInit(preliminaryConfig) {
* Another possible use case is, that its theoretically possible that the customer
* can already start using the SDK although we are not fully initialized.
*/
otelInstrumentations.preInit(preliminaryConfig);
spanHandle.init(preliminaryConfig);
shimmer.init(preliminaryConfig);
cls.init(preliminaryConfig);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,20 @@
const constants = require('../constants');
const W3cTraceContext = require('../w3c_trace_context/W3cTraceContext');

let ConfluentKafkaInstrumentation;

function initInstrumentation() {
ConfluentKafkaInstrumentation =
ConfluentKafkaInstrumentation ||
require('@instana/instrumentation-confluent-kafka-javascript').ConfluentKafkaInstrumentation;
}

module.exports.preInit = () => {
initInstrumentation();
};

module.exports.init = () => {
const { ConfluentKafkaInstrumentation } = require('@instana/instrumentation-confluent-kafka-javascript');
initInstrumentation();

const instrumentation = new ConfluentKafkaInstrumentation({});

Expand Down
12 changes: 11 additions & 1 deletion packages/core/src/tracing/opentelemetry-instrumentations/fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,21 @@

'use strict';

let FsInstrumentation;

function initInstrumentation() {
FsInstrumentation = FsInstrumentation || require('@opentelemetry/instrumentation-fs').FsInstrumentation;
}

module.exports.preInit = () => {
initInstrumentation();
};

// NOTE: otel fs instrumentation does not capture the file name currently
module.exports.init = ({ cls, api }) => {
initInstrumentation();
const constants = require('../constants');
const { NonRecordingSpan } = require('./files/NonRecordingSpan');
const { FsInstrumentation } = require('@opentelemetry/instrumentation-fs');

// eslint-disable-next-line max-len
// https://github.com/open-telemetry/opentelemetry-js-contrib/pull/1335/files#diff-9a2f445c78d964623d07987299501cbc3101cbe0f76f9e18d2d75787601539daR428
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
'use strict';

module.exports = {
get otelInstrumentations() {
return require('./wrap');
get init() {
return require('./wrap').init;
},
get preInit() {
return require('./wrap').preInit;
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,19 @@

const constants = require('../constants');

let OracleInstrumentation;

function initInstrumentation() {
OracleInstrumentation =
OracleInstrumentation || require('@opentelemetry/instrumentation-oracledb').OracleInstrumentation;
}

module.exports.preInit = () => {
initInstrumentation();
};

module.exports.init = () => {
const { OracleInstrumentation } = require('@opentelemetry/instrumentation-oracledb');
initInstrumentation();

const instrumentation = new OracleInstrumentation();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,20 @@

const constants = require('../constants');

let RestifyInstrumentation;

function initInstrumentation() {
if (!RestifyInstrumentation) {
RestifyInstrumentation = require('@opentelemetry/instrumentation-restify').RestifyInstrumentation;
}
}

module.exports.preInit = () => {
initInstrumentation();
};

module.exports.init = () => {
const { RestifyInstrumentation } = require('@opentelemetry/instrumentation-restify');
initInstrumentation();

const instrumentation = new RestifyInstrumentation();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,19 @@

const constants = require('../constants');

let SocketIoInstrumentation;

function initInstrumentation() {
SocketIoInstrumentation =
SocketIoInstrumentation || require('@opentelemetry/instrumentation-socket.io').SocketIoInstrumentation;
}

const isOnEvent = otelSpan => otelSpan.name.indexOf('receive') !== -1;

exports.preInit = () => {
initInstrumentation();
};

/**
* socket.io-client is not instrumented.
* We can easily instrument socket.io-client by instrumenting @socket.io/component-emitter
Expand All @@ -18,7 +30,7 @@ const isOnEvent = otelSpan => otelSpan.name.indexOf('receive') !== -1;
* headers or meta data, only payload!
*/
exports.init = () => {
const { SocketIoInstrumentation } = require('@opentelemetry/instrumentation-socket.io');
initInstrumentation();
const instrumentation = new SocketIoInstrumentation();

if (!instrumentation.getConfig().enabled) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,22 @@

const constants = require('../constants');

let TediousInstrumentation;

function initInstrumentation() {
TediousInstrumentation =
TediousInstrumentation || require('@opentelemetry/instrumentation-tedious').TediousInstrumentation;
}

module.exports.preInit = () => {
initInstrumentation();
};

module.exports.init = () => {
// Opentelemetry only supports tedious version >=1.11.0 and <=15, please refer the following link
// for more details: https://www.npmjs.com/package/@opentelemetry/instrumentation-tedious#supported-versions

const { TediousInstrumentation } = require('@opentelemetry/instrumentation-tedious');
initInstrumentation();

const instrumentation = new TediousInstrumentation();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@

'use strict';

const { AsyncHooksContextManager } = require('@opentelemetry/context-async-hooks');
const { W3CTraceContextPropagator, hrTimeDuration, hrTimeToMilliseconds } = require('@opentelemetry/core');
const api = require('@opentelemetry/api');
const { BasicTracerProvider } = require('@opentelemetry/sdk-trace-base');
const utils = require('./utils');
const constants = require('../constants');
const supportedVersion = require('../supportedVersion');
Expand All @@ -27,6 +23,48 @@ const instrumentations = {
'@instana/instrumentation-confluent-kafka-javascript': { name: 'confluent-kafka' }
};

let AsyncHooksContextManager;
let W3CTraceContextPropagator;
let hrTimeDuration;
let hrTimeToMilliseconds;
let api;
let BasicTracerProvider;
let coreModule;

function initOtelCoreDependencies() {
api = api || require('@opentelemetry/api');
coreModule = coreModule || require('@opentelemetry/core');
AsyncHooksContextManager =
AsyncHooksContextManager || require('@opentelemetry/context-async-hooks').AsyncHooksContextManager;
BasicTracerProvider = BasicTracerProvider || require('@opentelemetry/sdk-trace-base').BasicTracerProvider;

W3CTraceContextPropagator = coreModule.W3CTraceContextPropagator;
hrTimeDuration = coreModule.hrTimeDuration;
hrTimeToMilliseconds = coreModule.hrTimeToMilliseconds;
}

function initInstrumentations() {
Object.values(instrumentations).forEach(instr => {
const instrumentation = require(`./${instr.name}`);
if (instrumentation.preInit) {
instrumentation.preInit();
}
});
}

module.exports.preInit = config => {
if (!supportedVersion(process.versions.node)) {
return;
}

if (!config?.preloadOpentelemetry) {
return;
}

initOtelCoreDependencies();
initInstrumentations();
};

// NOTE: using a logger might create a recursive execution
// logger.debug -> creates fs call -> calls transformToInstanaSpan -> calls logger.debug
// use uninstrumented logger, but useless for production
Expand All @@ -35,6 +73,8 @@ module.exports.init = (_config, cls) => {
return;
}

initOtelCoreDependencies();

Object.keys(instrumentations).forEach(k => {
const value = instrumentations[k];
const instrumentation = require(`./${value.name}`);
Expand Down
26 changes: 26 additions & 0 deletions packages/core/test/config/normalizeConfig_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -943,6 +943,30 @@ describe('config.normalizeConfig', () => {
expect(config.tracing.ignoreEndpoints).to.deep.equal({});
});

it('preloadOpentelemetry should default to false', () => {
const config = coreConfig.normalize({});
expect(config.preloadOpentelemetry).to.be.false;
});

it('preloadOpentelemetry should accept true value', () => {
const config = coreConfig.normalize({
preloadOpentelemetry: true
});
expect(config.preloadOpentelemetry).to.be.true;
});

it('preloadOpentelemetry should work with custom defaults', () => {
const customDefaults = {
preloadOpentelemetry: true,
tracing: {
forceTransmissionStartingAt: 25
}
};
const config = coreConfig.normalize({}, customDefaults);
expect(config.preloadOpentelemetry).to.be.true;
expect(config.tracing.forceTransmissionStartingAt).to.equal(25);
});

describe('when testing ignore endpoints reading from INSTANA_IGNORE_ENDPOINTS_PATH env variable', () => {
let filePaths;

Expand Down Expand Up @@ -1048,6 +1072,8 @@ describe('config.normalizeConfig', () => {
expect(config.tracing.useOpentelemetry).to.equal(true);
expect(config.tracing.allowRootExitSpan).to.equal(false);

expect(config.preloadOpentelemetry).to.equal(false);

expect(config.secrets).to.be.an('object');
expect(config.secrets.matcherMode).to.equal('contains-ignore-case');
expect(config.secrets.keywords).to.deep.equal(['key', 'pass', 'secret']);
Expand Down