Skip to content

Commit

Permalink
feat: added support for root exit spans (#1297)
Browse files Browse the repository at this point in the history
refs INSTA-793

---------

Co-authored-by: kirrg001 <[email protected]>
Co-authored-by: Arya <[email protected]>
  • Loading branch information
3 people committed Oct 23, 2024
1 parent 5647c3f commit f1e1f30
Show file tree
Hide file tree
Showing 35 changed files with 1,161 additions and 72 deletions.
108 changes: 108 additions & 0 deletions packages/collector/test/tracing/database/db2/allowRootExitSpanApp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
* (c) Copyright IBM Corp. 2024
*/

'use strict';

// NOTE: c8 bug https://github.com/bcoe/c8/issues/166
process.on('SIGTERM', () => {
process.disconnect();
process.exit(0);
});

require('../../../..')({
tracing: {
allowRootExitSpan: true
}
});

const { promisify } = require('util');
const ibmdb = require('ibm_db');
const { delay } = require('@instana/core/test/test_util');

const logPrefix = `DB2 Allow Root Exit Span App (${process.pid}):\t`;

const DB2_DATABASE_NAME = process.env.DB2_DATABASE_NAME || 'nodedb';
const connStr1 = process.env.DB2_CONN_STR || 'HOSTNAME=localhost;UID=node;PWD=nodepw;PORT=58885;PROTOCOL=TCPIP';
let connection;

const DB2_TABLE_NAME_1 = process.env.DB2_TABLE_NAME_1 || 'table1';

let tries = 0;
const MAX_TRIES = 10;
const CONNECT_TIMEOUT_IN_MS = 2000;

const db2OpenPromisified = promisify(ibmdb.open);

async function connect(connectionStr) {
log(`Trying to connect to DB2, attempt ${tries} of ${MAX_TRIES}`);

let conn;
try {
conn = await db2OpenPromisified(connectionStr);
} catch (err) {
log(err);
if (tries > MAX_TRIES) {
throw err;
}

tries += 1;
log(`Trying to connect to DB2 again in ${CONNECT_TIMEOUT_IN_MS} milliseconds.`);
await delay(CONNECT_TIMEOUT_IN_MS);
return connect(connectionStr);
}

log('A client has successfully connected.');
return conn;
}

(async function openConnections() {
await delay(1000 * 2);
connection = await connect(`${connStr1};DATABASE=${DB2_DATABASE_NAME}`);

connection.querySync(`drop table ${DB2_TABLE_NAME_1} if exists`);

const result = connection.querySync(
`create table ${DB2_TABLE_NAME_1} (COLINT INTEGER, COLDATETIME TIMESTAMP, COLTEXT VARCHAR(255))`
);

if (!(result instanceof Array)) {
throw new Error(result);
}

log('Clients is successfully connected.');

const prepareStmt = connection.prepareSync(`SELECT * FROM ${DB2_TABLE_NAME_1}`);
const executeResult = prepareStmt.executeSync();
executeResult.closeSync();

connection.beginTransaction(function (err) {
if (err) {
log(err);
return;
}

connection.query(`SELECT * FROM ${DB2_TABLE_NAME_1}`, function (err1) {
if (err1) {
log(err);
return;
}

connection.endTransaction(false, function (err2) {
if (err2) {
log(err);
return;
}

log('Transaction has been committed.');
});
});
});
})();

function log() {
/* eslint-disable no-console */
const args = Array.prototype.slice.call(arguments);
args[0] = logPrefix + args[0];
console.log.apply(console, args);
}
37 changes: 37 additions & 0 deletions packages/collector/test/tracing/database/db2/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
'use strict';

const dns = require('dns').promises;
const path = require('path');
const expect = require('chai').expect;
const semver = require('semver');

Expand Down Expand Up @@ -1245,6 +1246,42 @@ mochaSuiteFn('tracing/db2', function () {
});
});

describe('When allowRootExitSpan: true is set', function () {
before(async () => {
TABLE_NAME_1 = generateTableName();

controls = new ProcessControls({
useGlobalAgent: true,
appPath: path.join(__dirname, 'allowRootExitSpanApp'),
env: {
DB2_CONN_STR,
DB2_DATABASE_NAME,
DB2_TABLE_NAME_1: TABLE_NAME_1
}
});

await controls.start(retryTime, Date.now() + testTimeout - 5000, true);
});

beforeEach(async () => {
await agentControls.clearReceivedTraceData();
});

it('must trace', async function () {
await testUtils.retry(async () => {
const spans = await agentControls.getSpans();
expect(spans.length).to.be.eql(4);

// 4 spans, because we drop the table, create the table and do 2 x queries.
testUtils.expectExactlyNMatching(spans, 4, [
span => expect(span.n).to.equal('ibmdb2'),
span => expect(span.k).to.equal(2),
span => expect(span.data.db2.stmt).to.exist
]);
});
});
});

describe('tracing is disabled', function () {
before(async () => {
TABLE_NAME_1 = generateTableName();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* (c) Copyright IBM Corp. 2024
*/

'use strict';

// NOTE: c8 bug https://github.com/bcoe/c8/issues/166
process.on('SIGTERM', () => {
process.disconnect();
process.exit(0);
});

require('../../../..')({
tracing: {
allowRootExitSpan: true
}
});

const ioredis = require('ioredis');
const { delay } = require('@instana/core/test/test_util');

const logPrefix = `IORedis allowRootExitSpan App (${process.pid}):\t`;

log(logPrefix);

(async function connectRedis() {
await delay(1000);

try {
const client = new ioredis(`//${process.env.REDIS}`);

client.on('error', err => {
log('IORedis client error:', err);
});

client.on('ready', () => {
log(`Connected to client 1 (${process.env.REDIS}).`);
});

const multi = await client.multi().set('key', 'value').get('key').exec();
log('multi result: %s', multi);

await client.quit();
} catch (err) {
log('Failed to connect to IORedis:', err);
}
})();

function log() {
/* eslint-disable no-console */
const args = Array.prototype.slice.call(arguments);
args[0] = logPrefix + args[0];
console.log.apply(console, args);
}
58 changes: 57 additions & 1 deletion packages/collector/test/tracing/database/ioredis/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

const expect = require('chai').expect;
const semver = require('semver');
const path = require('path');

const constants = require('@instana/core').tracing.constants;
const supportedVersion = require('@instana/core').tracing.supportedVersion;
Expand Down Expand Up @@ -42,8 +43,57 @@ function checkConnection(span, setupType) {
// export AZURE_REDIS_CLUSTER=team-nodejs-redis-cluster-tekton.redis.cache.windows.net:6380
// export AZURE_REDIS_CLUSTER_PWD=
['default', 'cluster'].forEach(setupType => {
// TODO: Add test for cluster mode https://jsw.ibm.com/browse/INSTA-15876
if (setupType !== 'cluster') {
mochaSuiteFn('When allowRootExitSpan: true is set', function () {
this.timeout(config.getTestTimeout() * 4);

globalAgent.setUpCleanUpHooks();
const agentControls = globalAgent.instance;
let controls;

before(async () => {
controls = new ProcessControls({
useGlobalAgent: true,
appPath: path.join(__dirname, 'allowRootExitSpanApp'),
env: {
REDIS_CLUSTER: false
}
});

await controls.start(null, null, true);
});

beforeEach(async () => {
await agentControls.clearReceivedTraceData();
});

afterEach(async () => {
await controls.clearIpcMessages();
});

it('must trace exit span', async function () {
return retry(async () => {
const spans = await agentControls.getSpans();

// NO entry
// 1 x multi containing the sub commands
// 1 x exec span
// 2 x sub commands
expect(spans.length).to.be.eql(4);

expectAtLeastOneMatching(spans, [
span => expect(span.n).to.equal('redis'),
span => expect(span.k).to.equal(2),
span => expect(span.p).to.not.exist
]);
});
});
});
}

mochaSuiteFn(`tracing/ioredis ${setupType}`, function () {
this.timeout(config.getTestTimeout() + 4);
this.timeout(config.getTestTimeout() * 4);

globalAgent.setUpCleanUpHooks();
const agentControls = globalAgent.instance;
Expand Down Expand Up @@ -168,7 +218,9 @@ function checkConnection(span, setupType) {
span => expect(span.n).to.equal('node.http.server'),
span => expect(span.data.http.method).to.equal('POST')
]);

expect(spans).to.have.lengthOf(5);

expectAtLeastOneMatching(spans, [
span => expect(span.t).to.equal(writeEntrySpan.t),
span => expect(span.p).to.equal(writeEntrySpan.s),
Expand Down Expand Up @@ -248,7 +300,9 @@ function checkConnection(span, setupType) {
span => expect(span.n).to.equal('node.http.server'),
span => expect(span.data.http.method).to.equal('POST')
]);

expect(spans).to.have.lengthOf(5);

expectAtLeastOneMatching(spans, [
span => expect(span.t).to.equal(writeEntrySpan.t),
span => expect(span.p).to.equal(writeEntrySpan.s),
Expand Down Expand Up @@ -317,6 +371,8 @@ function checkConnection(span, setupType) {
span => expect(span.data.http.method).to.equal('GET')
]);

expect(spans.length).to.equal(2);

expectAtLeastOneMatching(spans, [
span => expect(span.t).to.equal(writeEntrySpan.t),
span => expect(span.p).to.equal(writeEntrySpan.s),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* (c) Copyright IBM Corp. 2024
*/

'use strict';

// NOTE: c8 bug https://github.com/bcoe/c8/issues/166
process.on('SIGTERM', () => {
process.disconnect();
process.exit(0);
});

require('../../../..')({
tracing: {
allowRootExitSpan: true
}
});

const redis = require(process.env.REDIS_PKG);
const { delay } = require('@instana/core/test/test_util');

const logPrefix = `Redis allowRootExitSpan App (version: ${process.env.REDIS_VERSION},
require: ${process.env.REDIS_PKG}):\t`;

log(logPrefix);

let client;

(async function connectRedis() {
await delay(1000);

try {
client = redis.createClient({ url: `redis://${process.env.REDIS}` });
client.on('error', err => {
log('Redis client error:', err);
});

await client.connect();
log('Redis connection established');

const result = await client.multi().set('key', 'value').get('key').exec();
log('value:', result);

await client.quit();
} catch (err) {
log('Failed to connect to Redis:', err);
}
})();

function log() {
/* eslint-disable no-console */
const args = Array.prototype.slice.call(arguments);
args[0] = logPrefix + args[0];
console.log.apply(console, args);
}
Loading

0 comments on commit f1e1f30

Please sign in to comment.