Skip to content
Draft
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
7a5da5a
chore: playground done
kirrg001 Apr 9, 2026
a046abc
chore: infra cor
kirrg001 Apr 9, 2026
378f117
chore: phase 1
abhilash-sivan May 4, 2026
c1ef77d
chore: phase 2
abhilash-sivan May 4, 2026
d261bc5
chore: phase 3
abhilash-sivan May 7, 2026
17710d0
chore: cleanup
abhilash-sivan May 7, 2026
0a6ec17
chore: rewrite
abhilash-sivan May 7, 2026
8a89eef
chore: test
abhilash-sivan May 7, 2026
c78331c
chore: a
abhilash-sivan May 7, 2026
bcb034e
chore: new fields
abhilash-sivan May 7, 2026
980a1c0
chore: test
abhilash-sivan May 7, 2026
5aebc15
test: fixed failing test
abhilash-sivan May 10, 2026
8c6cc88
chore: cleanup
abhilash-sivan May 10, 2026
c3179eb
chore: ui corrected
abhilash-sivan May 13, 2026
21c211d
chore: added kafka and pg, generalize
abhilash-sivan May 14, 2026
fcd7622
chore: update
abhilash-sivan May 14, 2026
c1253b0
chore: fix
abhilash-sivan May 15, 2026
d6c01a6
chore: clean
abhilash-sivan May 15, 2026
efd4103
chore: update
abhilash-sivan May 15, 2026
b85ae66
chore: added readme
abhilash-sivan May 18, 2026
b5a51c8
chore: added example
abhilash-sivan May 18, 2026
f79a641
chore: added example transformer
abhilash-sivan May 18, 2026
06835eb
chore: update readme to minimal
abhilash-sivan May 18, 2026
52be4b2
chore: update logic
abhilash-sivan May 19, 2026
b8a95a1
chore: spanBuffer uses temporary converter
abhilash-sivan May 19, 2026
402b4d3
chore: move files for using inside spanBuffer
abhilash-sivan May 19, 2026
3df77e8
chore: update
abhilash-sivan May 19, 2026
e8b37d9
chore: rearrange
abhilash-sivan May 19, 2026
059c844
chore: added separate transformer
abhilash-sivan May 20, 2026
c197345
chore: added example otel spans
abhilash-sivan May 20, 2026
0935eda
chore: make getSpanType dynamic
abhilash-sivan May 20, 2026
d805750
chore: fix status
abhilash-sivan May 20, 2026
0a099fd
chore: kafka systemName
abhilash-sivan May 20, 2026
3d4ae91
chore: v1 of multiple data key logic
abhilash-sivan May 21, 2026
90954b2
chore: refactor
abhilash-sivan May 21, 2026
d5575d7
chore: optimize additioanl attributes
abhilash-sivan May 22, 2026
4bdb790
chore: wip more dynamic
abhilash-sivan May 22, 2026
13eccd6
chore: refatcor transformers
abhilash-sivan May 26, 2026
891b4d8
chore: refactor main file
abhilash-sivan May 26, 2026
38b41de
chore: new otel span type file
abhilash-sivan May 26, 2026
94922bd
chore: cleanup otlp transformer
abhilash-sivan May 26, 2026
61a1afd
chore: minor refactor for pr comment
abhilash-sivan May 26, 2026
3b7331e
chore: udpate example app
abhilash-sivan Jun 2, 2026
c7c3e91
chore: refactor 1
abhilash-sivan Jun 4, 2026
37ae8af
chore: same format
abhilash-sivan Jun 4, 2026
f8636f7
chore: remove circular dependency
abhilash-sivan Jun 4, 2026
36e7492
chore: use fn instead of string
abhilash-sivan Jun 4, 2026
577fd32
chore: rearrange
abhilash-sivan Jun 4, 2026
018f831
chore: refactor clean
abhilash-sivan Jun 4, 2026
0d39a66
chore: refactor
abhilash-sivan Jun 4, 2026
6e5f7b6
chore: fix refactorig issues
abhilash-sivan Jun 4, 2026
f04608c
chore: rearrage
abhilash-sivan Jun 4, 2026
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: 1 addition & 1 deletion example-apps/collector/.env
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# All default settings defined here can be overridden by environment variables.

# MODE=npm
MODE=local
APP_PORT=2807
SENSOR_ENABLED=true
TRACING_ENABLED=true
Expand Down
3 changes: 3 additions & 0 deletions example-apps/collector/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ if (config.mode === 'npm') {
packageToRequire = '@instana/collector';
}

process.env.INSTANA_METRICS_TRANSMISSION_DELAY = 5000;
process.env.INSTANA_OTLP_FORMAT = 'true';

if (config.collectorEnabled) {
console.log(`enabling @instana/collector (requiring ${packageToRequire})`);
require(packageToRequire)({
Expand Down
181 changes: 152 additions & 29 deletions packages/collector/src/agentConnection.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const pathUtil = require('path');
const circularReferenceRemover = require('./util/removeCircular');
const agentOpts = require('./agent/opts');
const cmdline = require('./cmdline');

const otlpTransformer = require('@instana/core/src/tracing/otlpTransformer');
Comment thread
abhilash-sivan marked this conversation as resolved.
/** @typedef {import('@instana/core/src/core').InstanaBaseSpan} InstanaBaseSpan */

/** @type {import('@instana/core/src/core').GenericLogger} */
Expand Down Expand Up @@ -307,20 +307,55 @@ function checkWhetherResponseForPathIsOkay(path, cb) {
exports.sendMetrics = function sendMetrics(data, cb) {
cb = util.atMostOnce('callback for sendMetrics', cb);

sendData(`/com.instana.plugin.nodejs.${pidStore.pid}`, data, (err, body) => {
// Zeige nur die ersten 2 Keys für Debugging
const dataKeys = Object.keys(data);
const firstTwoKeys = {};
for (let i = 0; i < Math.min(2, dataKeys.length); i++) {
firstTwoKeys[dataKeys[i]] = data[dataKeys[i]];
}

// logger.debug(`sendMetrics called with data (first 2 keys): ${JSON.stringify(firstTwoKeys)}`);

// Transform Instana metrics to OTLP format
const otlpMetrics = otlpTransformer.transformMetrics(data);

// Zeige nur die ersten 2 Metriken für Debugging
let otlpPreview = otlpMetrics;
if (otlpMetrics.resourceMetrics && otlpMetrics.resourceMetrics.length > 0) {
const firstResource = otlpMetrics.resourceMetrics[0];
if (firstResource.scopeMetrics && firstResource.scopeMetrics.length > 0) {
const metrics = firstResource.scopeMetrics[0].metrics;
if (metrics && metrics.length > 2) {
otlpPreview = {
resourceMetrics: [
{
...firstResource,
scopeMetrics: [
{
...firstResource.scopeMetrics[0],
metrics: metrics.slice(0, 2)
}
]
}
],
totalMetrics: metrics.length
};
}
}
}

// logger.debug(`Transformed to OTLP (first 2 metrics) ${JSON.stringify(otlpPreview)}`);

// Send directly without using sendData (which would transform again)
sendOtlpData('/v1/metrics', otlpMetrics, err => {
if (err) {
logger.error('Error sending metrics:', err);
cb(err, null);
} else {
try {
// 2016-09-11
// Older sensor versions will not repond with a JSON
// structure. Support a smooth update path.
body = JSON.parse(body);
} catch (e) {
body = [];
}

cb(null, body);
// logger.debug('Metrics sent successfully');
// OTLP endpoints don't return requests like the old Instana endpoint
// Always return empty array for compatibility
cb(null, []);
}
});
};
Expand All @@ -335,16 +370,16 @@ exports.sendSpans = function sendSpans(spans, cb) {
if (err && !maxContentErrorHasBeenLogged && err instanceof PayloadTooLargeError) {
logLargeSpans(spans);
} else if (err) {
const spanInfo = getSpanLengthInfo(spans);
const spanInfo = spans;
logger.debug(`Failed to send: ${JSON.stringify(spanInfo)}`);
} else {
const spanInfo = getSpanLengthInfo(spans);
const spanInfo = spans;
logger.debug(`Successfully sent: ${JSON.stringify(spanInfo)}`);
}
cb(err);
});

sendData(`/com.instana.plugin.nodejs/traces.${pidStore.pid}`, spans, callback, true);
sendData('/v1/traces', spans, callback, true);
};

/**
Expand Down Expand Up @@ -425,7 +460,8 @@ exports.sendTracingMetricsToAgent = function sendTracingMetricsToAgent(tracingMe
cb(err);
});

sendData('/tracermetrics', tracingMetrics, callback);
// sendData('/tracermetrics', tracingMetrics, callback);
cb();
};

/**
Expand All @@ -437,6 +473,11 @@ exports.sendTracingMetricsToAgent = function sendTracingMetricsToAgent(tracingMe
*/
function sendData(path, data, cb, ignore404 = false) {
cb = util.atMostOnce(`callback for sendData: ${path}`, cb);
console.log(JSON.stringify(data));
// Transform Instana format to OTLP format
// const otlpFormat = otlpTransformer(data);

// console.log(JSON.stringify(otlpFormat));

const payloadAsString = JSON.stringify(data, circularReferenceRemover());
Comment thread
abhilash-sivan marked this conversation as resolved.
if (typeof logger.trace === 'function') {
Expand All @@ -455,7 +496,7 @@ function sendData(path, data, cb, ignore404 = false) {
const req = http.request(
{
host: agentOpts.host,
port: agentOpts.port,
port: 4318,
path,
method: 'POST',
agent: http.agent,
Expand All @@ -465,24 +506,26 @@ function sendData(path, data, cb, ignore404 = false) {
}
},
res => {
if (res.statusCode < 200 || res.statusCode >= 300) {
if (res.statusCode !== 404 || !ignore404) {
const statusCodeError = new Error(
`Failed to send data to agent via POST ${path}. Got status code ${res.statusCode}.`
);
// @ts-ignore
statusCodeError.statusCode = res.statusCode;
cb(statusCodeError);
return;
}
}

res.setEncoding('utf8');
let responseBody = '';
res.on('data', chunk => {
responseBody += chunk;
});
res.on('end', () => {
console.log(responseBody);

if (res.statusCode < 200 || res.statusCode >= 300) {
if (res.statusCode !== 404 || !ignore404) {
const statusCodeError = new Error(
`Failed to send data to agent via POST ${path}. Got status code ${res.statusCode}.`
);
// @ts-ignore
statusCodeError.statusCode = res.statusCode;
cb(statusCodeError);
return;
}
}

cb(null, responseBody);
});
}
Expand All @@ -509,6 +552,86 @@ function sendData(path, data, cb, ignore404 = false) {
req.end();
}

/**
* Sendet bereits transformierte OTLP-Daten an den Agent
* @param {string} path - API path
* @param {Object} otlpData - Already transformed OTLP data
* @param {(...args: *) => *} cb - Callback
* @param {boolean} [ignore404]
*/
function sendOtlpData(path, otlpData, cb, ignore404 = false) {
cb = util.atMostOnce(`callback for sendOtlpData: ${path}`, cb);

const payloadAsString = JSON.stringify(otlpData, circularReferenceRemover());
if (typeof logger.trace === 'function') {
logger.trace(`Sending OTLP data to ${path}.`);
} else {
logger.debug(`Sending OTLP data to ${path}, ${agentOpts}`);
}

// Convert payload to a buffer to correctly identify content-length ahead of time.
const payload = Buffer.from(payloadAsString, 'utf8');
if (payload.length > maxContentLength) {
const error = new PayloadTooLargeError(`Request payload is too large. Will not send data to agent. (POST ${path})`);
return setImmediate(cb.bind(null, error));
}

const req = http.request(
{
host: agentOpts.host,
port: 4318,
path,
method: 'POST',
agent: http.agent,
headers: {
'Content-Type': 'application/json; charset=UTF-8',
'Content-Length': payload.length
}
},
res => {
res.setEncoding('utf8');
let responseBody = '';
res.on('data', chunk => {
responseBody += chunk;
});
res.on('end', () => {
if (res.statusCode < 200 || res.statusCode >= 300) {
if (ignore404 && res.statusCode === 404) {
return cb(null, responseBody);
}
return cb(
new Error(
`Failed to send data to agent via POST ${path}. ` +
`Got status code ${res.statusCode}. Response: ${responseBody}`
),
responseBody
);
}
cb(null, responseBody);
});
}
);

req.setTimeout(agentOpts.requestTimeout, function onTimeout() {
if (req.destroyed) {
return;
}

req.destroy(new Error(`Sending data to agent via POST ${path}. Request timeout.`));
});

req.on('error', err => {
if (req.destroyed) {
return;
}

cb(new Error(`Send OTLP data to agent via POST ${path}. Request failed: ${err.message}`));
});

req.write(payload);
req.end();
}

exports.isConnected = function () {
return isConnected;
};
Expand Down
26 changes: 19 additions & 7 deletions packages/core/src/tracing/backend_mappers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,26 @@
'use strict';

const mapper = require('./mapper');
const otlpMapper = require('./otlpMapper');

/**
* @param {(span: import('../../core').InstanaBaseSpan) => import('../../core').InstanaBaseSpan} transformer
*/
function createSafeTransform(transformer) {
return (/** @type {import('../../core').InstanaBaseSpan} */ span) => {
try {
return transformer(span);
} catch (error) {
return span;
}
};
}

module.exports = {
get transform() {
return (/** @type {import('../../core').InstanaBaseSpan} */ span) => {
try {
return mapper.transform(span);
} catch (error) {
return span;
}
};
return createSafeTransform(mapper.transform);
},
get otlpTransform() {
Comment thread
abhilash-sivan marked this conversation as resolved.
Outdated
return createSafeTransform(otlpMapper.transform);
}
};
Loading