@instana/core
Advanced tools
Comparing version 1.119.2 to 1.119.3
{ | ||
"name": "@instana/core", | ||
"version": "1.119.2", | ||
"version": "1.119.3", | ||
"description": "Core library for Instana's Node.js packages", | ||
@@ -136,3 +136,3 @@ "main": "src/index.js", | ||
}, | ||
"gitHead": "d4ccbbe909316d9b32bdeddc71ee680d2d956509" | ||
"gitHead": "159bd562c2e9c6b41b1b9a30c53a59f0d6c6f331" | ||
} |
@@ -6,2 +6,4 @@ /* | ||
// @ts-nocheck | ||
'use strict'; | ||
@@ -15,2 +17,16 @@ | ||
/** | ||
* @typedef {{ | ||
h?: string, | ||
e?: string, | ||
hl?: boolean, | ||
cp?: string, | ||
}} PIDData | ||
*/ | ||
/** | ||
* @typedef {Object} ProcessIdentityProvider | ||
* @property {() => PIDData} getFrom | ||
*/ | ||
module.exports = exports = { | ||
@@ -17,0 +33,0 @@ logger: log, |
@@ -5,2 +5,3 @@ /* | ||
*/ | ||
// @ts-nocheck | ||
@@ -7,0 +8,0 @@ 'use strict'; |
@@ -13,2 +13,3 @@ /* | ||
const tracingMetrics = require('./metrics'); | ||
/** @type {import('../logger').GenericLogger} */ | ||
let logger; | ||
@@ -19,10 +20,12 @@ logger = require('../logger').getLogger('tracing/cls', newLogger => { | ||
const currentEntrySpanKey = (exports.currentEntrySpanKey = 'com.instana.entry'); | ||
const currentSpanKey = (exports.currentSpanKey = 'com.instana.span'); | ||
const reducedSpanKey = (exports.reducedSpanKey = 'com.instana.reduced'); | ||
const tracingLevelKey = (exports.tracingLevelKey = 'com.instana.tl'); | ||
const w3cTraceContextKey = (exports.w3cTraceContextKey = 'com.instana.w3ctc'); | ||
const currentEntrySpanKey = 'com.instana.entry'; | ||
const currentSpanKey = 'com.instana.span'; | ||
const reducedSpanKey = 'com.instana.reduced'; | ||
const tracingLevelKey = 'com.instana.tl'; | ||
const w3cTraceContextKey = 'com.instana.w3ctc'; | ||
// eslint-disable-next-line no-undef-init | ||
let serviceName = undefined; | ||
/** @type {String} */ | ||
let serviceName; | ||
/** @type {import('../index').ProcessIdentityProvider} */ | ||
let processIdentityProvider = null; | ||
@@ -38,5 +41,9 @@ | ||
*/ | ||
exports.ns = hooked.createNamespace('instana.collector'); | ||
const ns = hooked.createNamespace('instana.collector'); | ||
exports.init = function init(config, _processIdentityProvider) { | ||
/** | ||
* @param {import('../util/normalizeConfig').InstanaConfig} config | ||
* @param {import('../index').ProcessIdentityProvider} _processIdentityProvider | ||
*/ | ||
function init(config, _processIdentityProvider) { | ||
if (config && config.serviceName) { | ||
@@ -46,5 +53,34 @@ serviceName = config.serviceName; | ||
processIdentityProvider = _processIdentityProvider; | ||
}; | ||
} | ||
/** | ||
* This type is to be used across the code base, as we don't have a public explicit type for a span. | ||
* Also, it is often that we simply create a literal object and gradually throw few properties on it and | ||
* handle them as spans. This type has all span properties, but they are all optional, so we can safely | ||
* type these literal objects. | ||
* TODO: move InstanaSpan and InstanaPseudoSpan to their own file and make them publicly accessible? | ||
* @typedef {Object} InstanaBaseSpan | ||
* @property {string} [s] | ||
* @property {string} [t] | ||
* @property {number} [k] | ||
* @property {string} [p] | ||
* @property {number} [ec] | ||
* @property {number} [ts] | ||
* @property {number} [d] | ||
* @property {string} [n] | ||
* @property {*} [stack] | ||
* @property {Object.<string, *>} [data] | ||
* @property {{s?: number, d?: number}} [b] | ||
* @property {*} [f] | ||
* @property {*} [gqd] | ||
* @property {Function} [transmit] | ||
* @property {Function} [freezePathTemplate] | ||
* @property {Function} [disableAutoEnd] | ||
* @property {Function} [transmitManual] | ||
*/ | ||
class InstanaSpan { | ||
/** | ||
* @param {String} name | ||
*/ | ||
constructor(name) { | ||
@@ -63,3 +99,5 @@ // properties that part of our span model | ||
this.d = 0; | ||
/** @type {Array.<*>} */ | ||
this.stack = []; | ||
/** @type {Object.<string, *>} */ | ||
this.data = {}; | ||
@@ -92,3 +130,7 @@ | ||
/** | ||
* @param {Function} fn | ||
*/ | ||
addCleanup(fn) { | ||
// @ts-ignore | ||
this.cleanupFunctions.push(fn); | ||
@@ -124,3 +166,5 @@ } | ||
cleanup() { | ||
// @ts-ignore | ||
this.cleanupFunctions.forEach(call); | ||
// @ts-ignore | ||
this.cleanupFunctions.length = 0; | ||
@@ -165,6 +209,11 @@ } | ||
/* | ||
/** | ||
* Start a new span and set it as the current span. | ||
* @param {string} spanName | ||
* @param {number} kind | ||
* @param {string} traceId | ||
* @param {string} parentSpanId | ||
* @param {import('./w3c_trace_context/W3cTraceContext')} [w3cTraceContext] | ||
*/ | ||
exports.startSpan = function startSpan(spanName, kind, traceId, parentSpanId, w3cTraceContext) { | ||
function startSpan(spanName, kind, traceId, parentSpanId, w3cTraceContext) { | ||
tracingMetrics.incrementOpened(); | ||
@@ -178,4 +227,4 @@ if (!kind || (kind !== ENTRY && kind !== EXIT && kind !== INTERMEDIATE)) { | ||
const parentSpan = exports.getCurrentSpan(); | ||
const parentW3cTraceContext = exports.getW3cTraceContext(); | ||
const parentSpan = getCurrentSpan(); | ||
const parentW3cTraceContext = getW3cTraceContext(); | ||
@@ -214,3 +263,3 @@ if (serviceName != null && !parentSpan) { | ||
w3cTraceContext.updateParent(span.t, span.s); | ||
span.addCleanup(exports.ns.set(w3cTraceContextKey, w3cTraceContext)); | ||
span.addCleanup(ns.set(w3cTraceContextKey, w3cTraceContext)); | ||
} | ||
@@ -222,3 +271,3 @@ | ||
// and error messages to the entry span. | ||
span.addCleanup(exports.ns.set(currentEntrySpanKey, span)); | ||
span.addCleanup(ns.set(currentEntrySpanKey, span)); | ||
} | ||
@@ -228,11 +277,15 @@ | ||
// this span is transmitted. | ||
span.addCleanup(exports.ns.set(currentSpanKey, span)); | ||
span.addCleanup(ns.set(currentSpanKey, span)); | ||
return span; | ||
}; | ||
} | ||
/* | ||
/** | ||
* Puts a pseudo span in the CLS context that is simply a holder for a trace ID and span ID. This pseudo span will act | ||
* as the parent for other child span that are produced but will not be transmitted to the agent itself. | ||
* @param {string} spanName | ||
* @param {number} kind | ||
* @param {string} traceId | ||
* @param {string} spanId | ||
*/ | ||
exports.putPseudoSpan = function putPseudoSpan(spanName, kind, traceId, spanId) { | ||
function putPseudoSpan(spanName, kind, traceId, spanId) { | ||
if (!kind || (kind !== ENTRY && kind !== EXIT && kind !== INTERMEDIATE)) { | ||
@@ -261,3 +314,3 @@ logger.warn('Invalid pseudo span (%s) without kind/with invalid kind: %s, assuming EXIT.', spanName, kind); | ||
// and error messages to the entry span. | ||
span.addCleanup(exports.ns.set(currentEntrySpanKey, span)); | ||
span.addCleanup(ns.set(currentEntrySpanKey, span)); | ||
} | ||
@@ -267,5 +320,5 @@ | ||
// this span is transmitted. | ||
span.addCleanup(exports.ns.set(currentSpanKey, span)); | ||
span.addCleanup(ns.set(currentSpanKey, span)); | ||
return span; | ||
}; | ||
} | ||
@@ -275,19 +328,21 @@ /* | ||
*/ | ||
exports.getCurrentEntrySpan = function getCurrentEntrySpan() { | ||
return exports.ns.get(currentEntrySpanKey); | ||
}; | ||
function getCurrentEntrySpan() { | ||
return ns.get(currentEntrySpanKey); | ||
} | ||
/* | ||
/** | ||
* Set the currently active span. | ||
* @param {InstanaSpan} span | ||
*/ | ||
exports.setCurrentSpan = function setCurrentSpan(span) { | ||
exports.ns.set(currentSpanKey, span); | ||
}; | ||
function setCurrentSpan(span) { | ||
ns.set(currentSpanKey, span); | ||
} | ||
/* | ||
/** | ||
* Get the currently active span. | ||
* @returns {InstanaSpan} | ||
*/ | ||
exports.getCurrentSpan = function getCurrentSpan() { | ||
return exports.ns.get(currentSpanKey); | ||
}; | ||
function getCurrentSpan() { | ||
return ns.get(currentSpanKey); | ||
} | ||
@@ -297,12 +352,13 @@ /* | ||
*/ | ||
exports.getReducedSpan = function getReducedSpan() { | ||
return exports.ns.get(reducedSpanKey); | ||
}; | ||
function getReducedSpan() { | ||
return ns.get(reducedSpanKey); | ||
} | ||
/* | ||
/** | ||
* Stores the W3C trace context object. | ||
* @param {import('./w3c_trace_context/W3cTraceContext')} traceContext | ||
*/ | ||
exports.setW3cTraceContext = function setW3cTraceContext(traceContext) { | ||
exports.ns.set(w3cTraceContextKey, traceContext); | ||
}; | ||
function setW3cTraceContext(traceContext) { | ||
ns.set(w3cTraceContextKey, traceContext); | ||
} | ||
@@ -312,5 +368,5 @@ /* | ||
*/ | ||
exports.getW3cTraceContext = function getW3cTraceContext() { | ||
return exports.ns.get(w3cTraceContextKey); | ||
}; | ||
function getW3cTraceContext() { | ||
return ns.get(w3cTraceContextKey); | ||
} | ||
@@ -320,12 +376,13 @@ /* | ||
*/ | ||
exports.isTracing = function isTracing() { | ||
return !!exports.ns.get(currentSpanKey); | ||
}; | ||
function isTracing() { | ||
return !!ns.get(currentSpanKey); | ||
} | ||
/* | ||
/** | ||
* Set the tracing level | ||
* @param {string} level | ||
*/ | ||
exports.setTracingLevel = function setTracingLevel(level) { | ||
exports.ns.set(tracingLevelKey, level); | ||
}; | ||
function setTracingLevel(level) { | ||
ns.set(tracingLevelKey, level); | ||
} | ||
@@ -335,5 +392,5 @@ /* | ||
*/ | ||
exports.tracingLevel = function tracingLevel() { | ||
return exports.ns.get(tracingLevelKey); | ||
}; | ||
function tracingLevel() { | ||
return ns.get(tracingLevelKey); | ||
} | ||
@@ -343,13 +400,13 @@ /* | ||
*/ | ||
exports.tracingSuppressed = function tracingSuppressed() { | ||
const tl = exports.tracingLevel(); | ||
function tracingSuppressed() { | ||
const tl = tracingLevel(); | ||
return typeof tl === 'string' && tl.indexOf('0') === 0; | ||
}; | ||
} | ||
exports.getAsyncContext = function getAsyncContext() { | ||
if (!exports.ns) { | ||
function getAsyncContext() { | ||
if (!ns) { | ||
return null; | ||
} | ||
return exports.ns.active; | ||
}; | ||
return ns.active; | ||
} | ||
@@ -362,5 +419,6 @@ /** | ||
* async context is managed automatically for you with the runXxxInAsyncContext functions. | ||
* @param {import('./clsHooked/context').InstanaCLSContext} context | ||
*/ | ||
exports.enterAsyncContext = function enterAsyncContext(context) { | ||
if (!exports.ns) { | ||
function enterAsyncContext(context) { | ||
if (!ns) { | ||
return; | ||
@@ -372,10 +430,11 @@ } | ||
} | ||
exports.ns.enter(context); | ||
}; | ||
ns.enter(context); | ||
} | ||
/** | ||
* Needs to be called if and only if enterAsyncContext has been used earlier. | ||
* @param {import('./clsHooked/context').InstanaCLSContext} context | ||
*/ | ||
exports.leaveAsyncContext = function leaveAsyncContext(context) { | ||
if (!exports.ns) { | ||
function leaveAsyncContext(context) { | ||
if (!ns) { | ||
return; | ||
@@ -387,7 +446,11 @@ } | ||
} | ||
exports.ns.exit(context); | ||
}; | ||
ns.exit(context); | ||
} | ||
exports.runInAsyncContext = function runInAsyncContext(context, fn) { | ||
if (!exports.ns) { | ||
/** | ||
* @param {import('./clsHooked/context').InstanaCLSContext} context | ||
* @param {Function} fn | ||
*/ | ||
function runInAsyncContext(context, fn) { | ||
if (!ns) { | ||
return fn(); | ||
@@ -399,7 +462,12 @@ } | ||
} | ||
return exports.ns.runAndReturn(fn, context); | ||
}; | ||
return ns.runAndReturn(fn, context); | ||
} | ||
exports.runPromiseInAsyncContext = function runPromiseInAsyncContext(context, fn) { | ||
if (!exports.ns) { | ||
/** | ||
* @param {import('./clsHooked/context').InstanaCLSContext} context | ||
* @param {Function} fn | ||
* @returns {Function | *} | ||
*/ | ||
function runPromiseInAsyncContext(context, fn) { | ||
if (!ns) { | ||
return fn(); | ||
@@ -411,7 +479,37 @@ } | ||
} | ||
return exports.ns.runPromise(fn, context); | ||
}; | ||
return ns.runPromise(fn, context); | ||
} | ||
/** | ||
* @param {Function} fn | ||
*/ | ||
function call(fn) { | ||
fn(); | ||
} | ||
module.exports = { | ||
currentEntrySpanKey, | ||
currentSpanKey, | ||
reducedSpanKey, | ||
tracingLevelKey, | ||
w3cTraceContextKey, | ||
ns, | ||
init, | ||
startSpan, | ||
putPseudoSpan, | ||
getCurrentEntrySpan, | ||
setCurrentSpan, | ||
getCurrentSpan, | ||
getReducedSpan, | ||
setW3cTraceContext, | ||
getW3cTraceContext, | ||
isTracing, | ||
setTracingLevel, | ||
tracingLevel, | ||
tracingSuppressed, | ||
getAsyncContext, | ||
enterAsyncContext, | ||
leaveAsyncContext, | ||
runInAsyncContext, | ||
runPromiseInAsyncContext | ||
}; |
@@ -17,3 +17,5 @@ /* | ||
const assert = require('assert'); | ||
// @ts-ignore | ||
const wrapEmitter = require('emitter-listener'); | ||
// @ts-ignore | ||
const asyncHook = require('async-hook-jl'); | ||
@@ -38,2 +40,5 @@ const unset = require('./unset'); | ||
/** | ||
* @param {string} name | ||
*/ | ||
function Namespace(name) { | ||
@@ -43,2 +48,3 @@ this.name = name; | ||
this.active = null; | ||
/** @type {Array.<import('./context').InstanaCLSContext>} */ | ||
this._set = []; | ||
@@ -49,2 +55,7 @@ this.id = null; | ||
/** | ||
* @param {string} key | ||
* @param {*} value | ||
* @returns | ||
*/ | ||
Namespace.prototype.set = function set(key, value) { | ||
@@ -60,2 +71,6 @@ if (!this.active) { | ||
/** | ||
* @param {string} key | ||
* @returns {*} | ||
*/ | ||
Namespace.prototype.get = function get(key) { | ||
@@ -68,2 +83,6 @@ if (!this.active) { | ||
/** | ||
* | ||
* @returns {import('../clsHooked/context').InstanaCLSContext} | ||
*/ | ||
Namespace.prototype.createContext = function createContext() { | ||
@@ -77,2 +96,7 @@ let context = Object.create(this.active ? this.active : Object.prototype); | ||
/** | ||
* @param {Function} fn | ||
* @param {import('./context').InstanaCLSContext} ctx | ||
* @returns {import('./context').InstanaCLSContext} | ||
*/ | ||
Namespace.prototype.run = function run(fn, ctx) { | ||
@@ -89,5 +113,9 @@ let context = ctx || this.createContext(); | ||
/** | ||
* @param {Function} fn | ||
* @param {import('./context').InstanaCLSContext} ctx | ||
*/ | ||
Namespace.prototype.runAndReturn = function runAndReturn(fn, ctx) { | ||
let value; | ||
this.run(context => { | ||
this.run((/** @type {import('./context').InstanaCLSContext} */ context) => { | ||
value = fn(context); | ||
@@ -100,4 +128,5 @@ }, ctx); | ||
* Uses global Promise and assumes Promise is cls friendly or wrapped already. | ||
* @param {function} fn | ||
* @returns {*} | ||
* @param {Function} fn | ||
* @param {import('./context').InstanaCLSContext} ctx | ||
* @returns {void | Promise<*>} | ||
*/ | ||
@@ -114,7 +143,7 @@ Namespace.prototype.runPromise = function runPromise(fn, ctx) { | ||
return promise | ||
.then(result => { | ||
.then((/** @type {*} */ result) => { | ||
this.exit(context); | ||
return result; | ||
}) | ||
.catch(err => { | ||
.catch((/** @type {Error} */ err) => { | ||
this.exit(context); | ||
@@ -125,6 +154,14 @@ throw err; | ||
Namespace.prototype.runPromiseOrRunAndReturn = function runPromiseOrRunAndReturn(fn) { | ||
/** | ||
* @param {Function} _fn | ||
* @returns {Error} | ||
*/ | ||
Namespace.prototype.runPromiseOrRunAndReturn = function runPromiseOrRunAndReturn(_fn) { | ||
throw new Error('Namespace.prototype.runPromiseOrRunAndReturn is not supported in Node.js < 8.'); | ||
}; | ||
/** | ||
* @param {Function} fn | ||
* @param {import('./context').InstanaCLSContext} context | ||
*/ | ||
Namespace.prototype.bind = function bindFactory(fn, context) { | ||
@@ -150,2 +187,5 @@ if (!context) { | ||
/** | ||
* @param {import('./context').InstanaCLSContext} context | ||
*/ | ||
Namespace.prototype.enter = function enter(context) { | ||
@@ -157,2 +197,5 @@ assert.ok(context, 'context must be provided for entering'); | ||
/** | ||
* @param {import('./context').InstanaCLSContext} context | ||
*/ | ||
Namespace.prototype.exit = function exit(context) { | ||
@@ -182,2 +225,5 @@ assert.ok(context, 'context must be provided for exiting'); | ||
/** | ||
* @param {import('node:events').EventEmitter} emitter | ||
*/ | ||
Namespace.prototype.bindEmitter = function bindEmitter(emitter) { | ||
@@ -189,3 +235,6 @@ assert.ok(emitter.on && emitter.addListener && emitter.emit, 'can only bind real EEs'); | ||
// Capture the context active at the time the emitter is bound. | ||
/** | ||
* Capture the context active at the time the emitter is bound. | ||
* @param {*} listener | ||
*/ | ||
function attach(listener) { | ||
@@ -205,3 +254,6 @@ if (!listener) { | ||
// At emit time, bind the listener within the correct context. | ||
/** | ||
* At emit time, bind the listener within the correct context. | ||
* @param {*} unwrapped | ||
*/ | ||
function bind(unwrapped) { | ||
@@ -224,6 +276,13 @@ if (!(unwrapped && unwrapped[CONTEXTS_SYMBOL])) { | ||
/** | ||
* @param {string} name | ||
*/ | ||
function getNamespace(name) { | ||
// @ts-ignore | ||
return process.namespaces[name]; | ||
} | ||
/** | ||
* @param {string} name | ||
*/ | ||
function createNamespace(name) { | ||
@@ -236,3 +295,4 @@ assert.ok(name, 'namespace must be given a name.'); | ||
asyncHook.addHooks({ | ||
init(uid, handle, provider, parentUid, parentHandle) { | ||
// @ts-ignore | ||
init(uid, _handle, _provider, parentUid, _parentHandle) { | ||
//parentUid = parentUid || currentUid; // Suggested usage but appears to work better for tracing modules. | ||
@@ -248,3 +308,4 @@ currentUid = uid; | ||
}, | ||
pre(uid, handle) { | ||
// @ts-ignore | ||
pre(uid, _handle) { | ||
currentUid = uid; | ||
@@ -256,3 +317,4 @@ let context = namespace._contexts.get(uid); | ||
}, | ||
post(uid, handle) { | ||
// @ts-ignore | ||
post(uid, _handle) { | ||
currentUid = uid; | ||
@@ -264,2 +326,3 @@ let context = namespace._contexts.get(uid); | ||
}, | ||
// @ts-ignore | ||
destroy(uid) { | ||
@@ -271,2 +334,3 @@ currentUid = uid; | ||
// @ts-ignore | ||
process.namespaces[name] = namespace; | ||
@@ -276,2 +340,5 @@ return namespace; | ||
/** | ||
* @param {string} name | ||
*/ | ||
function destroyNamespace(name) { | ||
@@ -283,2 +350,3 @@ let namespace = getNamespace(name); | ||
// @ts-ignore | ||
process.namespaces[name] = null; | ||
@@ -289,3 +357,5 @@ } | ||
// must unregister async listeners | ||
// @ts-ignore | ||
if (process.namespaces) { | ||
// @ts-ignore | ||
Object.keys(process.namespaces).forEach(name => { | ||
@@ -295,5 +365,7 @@ destroyNamespace(name); | ||
} | ||
// @ts-ignore | ||
process.namespaces = Object.create(null); | ||
} | ||
// @ts-ignore | ||
process.namespaces = process.namespaces || {}; | ||
@@ -300,0 +372,0 @@ |
@@ -17,2 +17,3 @@ /* | ||
const assert = require('assert'); | ||
// @ts-ignore | ||
const wrapEmitter = require('emitter-listener'); | ||
@@ -34,4 +35,11 @@ const async_hooks = require('async_hooks'); | ||
/** | ||
* @typedef {Object.<string, *>} InstanaCLSContext | ||
*/ | ||
/** | ||
* Creates a new CLS namespace. | ||
*/ | ||
/** | ||
* @param {string} name | ||
*/ | ||
function Namespace(name) { | ||
@@ -41,2 +49,3 @@ this.name = name; | ||
this.active = null; | ||
/** @type {Array.<InstanaCLSContext>} */ | ||
this._set = []; | ||
@@ -51,2 +60,5 @@ this.id = null; | ||
* or a child context. | ||
* @param {string} key | ||
* @param {*} value | ||
* @returns | ||
*/ | ||
@@ -67,2 +79,3 @@ Namespace.prototype.set = function set(key, value) { | ||
* been set earlier in this context. | ||
* @param {string} key | ||
*/ | ||
@@ -92,2 +105,4 @@ Namespace.prototype.get = function get(key) { | ||
* use runAndReturn instead. | ||
* @param {Function} fn | ||
* @param {InstanaCLSContext} ctx | ||
*/ | ||
@@ -109,6 +124,8 @@ Namespace.prototype.run = function run(fn, ctx) { | ||
* terminates. Asynchronous work started in this function will happen in that new context. | ||
* @param {Function} fn | ||
* @param {InstanaCLSContext} ctx | ||
*/ | ||
Namespace.prototype.runAndReturn = function runAndReturn(fn, ctx) { | ||
let value; | ||
this.run(context => { | ||
this.run((/** @type {InstanaCLSContext} */ context) => { | ||
value = fn(context); | ||
@@ -127,2 +144,4 @@ }, ctx); | ||
* This function assumes that the returned promise is CLS-friendly or wrapped already. | ||
* @param {Function} fn | ||
* @param {InstanaCLSContext} ctx | ||
*/ | ||
@@ -139,7 +158,7 @@ Namespace.prototype.runPromise = function runPromise(fn, ctx) { | ||
return promise | ||
.then(result => { | ||
.then((/** @type {*} */ result) => { | ||
this.exit(context); | ||
return result; | ||
}) | ||
.catch(err => { | ||
.catch((/** @type {*} */ err) => { | ||
this.exit(context); | ||
@@ -156,2 +175,4 @@ throw err; | ||
* This function assumes that the returned promise (if any) is CLS-friendly or wrapped already. | ||
* @param {Function} fn | ||
* @param {InstanaCLSContext} ctx | ||
*/ | ||
@@ -170,7 +191,7 @@ Namespace.prototype.runPromiseOrRunAndReturn = function runPromiseOrRunAndReturn(fn, ctx) { | ||
return valueOrPromise | ||
.then(result => { | ||
.then((/** @type {*} */ result) => { | ||
this.exit(context); | ||
return result; | ||
}) | ||
.catch(err => { | ||
.catch((/** @type {*} */ err) => { | ||
this.exit(context); | ||
@@ -193,2 +214,4 @@ throw err; | ||
* and leave that context once the function terminates. If no context is active, a new context will be created. | ||
* @param {Function} fn | ||
* @param {InstanaCLSContext} context | ||
*/ | ||
@@ -218,2 +241,3 @@ Namespace.prototype.bind = function bind(fn, context) { | ||
* in that CLS context. | ||
* @param {import('node:events').EventEmitter} emitter | ||
*/ | ||
@@ -226,3 +250,6 @@ Namespace.prototype.bindEmitter = function bindEmitter(emitter) { | ||
// Capture the context active at the time the emitter is bound. | ||
/** | ||
* Capture the context active at the time the emitter is bound. | ||
* @param {*} listener | ||
*/ | ||
function attach(listener) { | ||
@@ -242,3 +269,6 @@ if (!listener) { | ||
// At emit time, bind the listener within the correct context. | ||
/** | ||
* At emit time, bind the listener within the correct context. | ||
* @param {*} unwrapped | ||
*/ | ||
function bind(unwrapped) { | ||
@@ -261,2 +291,5 @@ if (!(unwrapped && unwrapped[CONTEXTS_SYMBOL])) { | ||
/** | ||
* @param {InstanaCLSContext} context | ||
*/ | ||
Namespace.prototype.enter = function enter(context) { | ||
@@ -268,2 +301,5 @@ assert.ok(context, 'context must be provided for entering'); | ||
/** | ||
* @param {InstanaCLSContext} context | ||
*/ | ||
Namespace.prototype.exit = function exit(context) { | ||
@@ -293,6 +329,13 @@ assert.ok(context, 'context must be provided for exiting'); | ||
/** | ||
* @param {string} name | ||
*/ | ||
function getNamespace(name) { | ||
// @ts-ignore | ||
return process.namespaces[name]; | ||
} | ||
/** | ||
* @param {string} name | ||
*/ | ||
function createNamespace(name) { | ||
@@ -305,3 +348,3 @@ assert.ok(name, 'namespace must be given a name.'); | ||
const hook = async_hooks.createHook({ | ||
init(asyncId, type, triggerId, resource) { | ||
init(asyncId, _type, _triggerId, _resource) { | ||
currentUid = async_hooks.executionAsyncId(); | ||
@@ -350,2 +393,3 @@ if (namespace.active) { | ||
// @ts-ignore | ||
process.namespaces[name] = namespace; | ||
@@ -355,2 +399,5 @@ return namespace; | ||
/** | ||
* @param {string} name | ||
*/ | ||
function destroyNamespace(name) { | ||
@@ -362,2 +409,3 @@ let namespace = getNamespace(name); | ||
// @ts-ignore | ||
process.namespaces[name] = null; | ||
@@ -368,3 +416,5 @@ } | ||
// must unregister async listeners | ||
// @ts-ignore | ||
if (process.namespaces) { | ||
// @ts-ignore | ||
Object.keys(process.namespaces).forEach(name => { | ||
@@ -374,4 +424,6 @@ destroyNamespace(name); | ||
} | ||
// @ts-ignore | ||
process.namespaces = Object.create(null); | ||
} | ||
// @ts-ignore | ||
process.namespaces = process.namespaces || {}; |
@@ -11,3 +11,8 @@ /* | ||
module.exports = exports = function unset(context, key, value) { | ||
/** | ||
* @param {import('./context').InstanaCLSContext} context | ||
* @param {string} key | ||
* @param {*} value | ||
*/ | ||
module.exports = function unset(context, key, value) { | ||
if (context[key] === value) { | ||
@@ -23,2 +28,5 @@ storeReducedSpan(context, key, value); | ||
* like data, stackTrace, etc. are not stored. | ||
* @param {import('./context').InstanaCLSContext} context | ||
* @param {string} key | ||
* @param {import('../cls').InstanaBaseSpan} span | ||
*/ | ||
@@ -25,0 +33,0 @@ function storeReducedSpan(context, key, span) { |
@@ -45,4 +45,6 @@ /* | ||
/* | ||
/** | ||
* Determine if <span> is an entry span (server span). | ||
* @param {import('./cls').InstanaBaseSpan} span | ||
* @returns {boolean} | ||
*/ | ||
@@ -53,5 +55,6 @@ exports.isEntrySpan = function isEntrySpan(span) { | ||
/* | ||
/** | ||
* Determine if <span> is an exit span (client span). | ||
* | ||
* @param {import('./cls').InstanaBaseSpan} span | ||
* @returns {boolean} | ||
*/ | ||
@@ -62,4 +65,6 @@ exports.isExitSpan = function isExitSpan(span) { | ||
/* | ||
/** | ||
* Determine if <span> is an intermediate span (local span). | ||
* @param {import('./cls').InstanaBaseSpan} span | ||
* @returns {boolean} | ||
*/ | ||
@@ -66,0 +71,0 @@ exports.isIntermediateSpan = function isIntermediateSpan(span) { |
@@ -22,5 +22,9 @@ /* | ||
let automaticTracingEnabled = false; | ||
/** @type {import('./cls')} */ | ||
let cls = null; | ||
/** @type {import('../util/normalizeConfig').InstanaConfig} */ | ||
let config = null; | ||
/** @type {Array.<string>} */ | ||
let extraHeaders = []; | ||
/** @type {import('../index').ProcessIdentityProvider} */ | ||
let processIdentityProvider = null; | ||
@@ -73,3 +77,18 @@ | ||
/** | ||
* This is a temporary type definition for instrumented modules until we get to add types to these modules. | ||
* For now it is safe to say that these modules are objects with the following methods: | ||
* @typedef {Object} InstanaInstrumentedModule | ||
* @property {Function} init | ||
* @property {Function} activate | ||
* @property {Function} deactivate | ||
* @property {Function} [updateConfig] | ||
* @property {(extraHeaders: Array.<*>) => {}} [setExtraHttpHeadersToCapture] | ||
* @property {boolean} [batchable] | ||
* @property {string} [spanName] | ||
*/ | ||
/** @type {Array.<InstanaInstrumentedModule>} */ | ||
let additionalInstrumentationModules = []; | ||
/** @type {Object.<string, InstanaInstrumentedModule>} */ | ||
const instrumentationModules = {}; | ||
@@ -83,2 +102,5 @@ | ||
/** | ||
* @param {Array.<InstanaInstrumentedModule>} _additionalInstrumentationModules | ||
*/ | ||
exports.registerAdditionalInstrumentations = function registerAdditionalInstrumentations( | ||
@@ -90,2 +112,5 @@ _additionalInstrumentationModules | ||
/** | ||
* @param {import('../util/normalizeConfig').InstanaConfig} preliminaryConfig | ||
*/ | ||
exports.preInit = function preInit(preliminaryConfig) { | ||
@@ -95,2 +120,7 @@ initInstrumenations(preliminaryConfig); | ||
/** | ||
* @param {import('../util/normalizeConfig').InstanaConfig} _config | ||
* @param {import('./spanBuffer').TemporaryAgentConnection} downstreamConnection | ||
* @param {import('../index').ProcessIdentityProvider} _processIdentityProvider | ||
*/ | ||
exports.init = function init(_config, downstreamConnection, _processIdentityProvider) { | ||
@@ -122,2 +152,5 @@ config = _config; | ||
/** | ||
* @param {import('../util/normalizeConfig').InstanaConfig} _config | ||
*/ | ||
function initInstrumenations(_config) { | ||
@@ -192,2 +225,5 @@ // initialize all instrumentations | ||
/** | ||
* @param {Array.<string>} _extraHeaders | ||
*/ | ||
exports.setExtraHttpHeadersToCapture = function setExtraHttpHeadersToCapture(_extraHeaders) { | ||
@@ -213,4 +249,7 @@ extraHeaders = _extraHeaders; | ||
pid: | ||
// TODO: This is not typed yet -> /nodejs-sensor/packages/collector/src/pidStore/index.js | ||
// @ts-ignore | ||
processIdentityProvider && typeof processIdentityProvider.getEntityId === 'function' | ||
? processIdentityProvider.getEntityId() | ||
? // @ts-ignore | ||
processIdentityProvider.getEntityId() | ||
: undefined, | ||
@@ -221,2 +260,6 @@ metrics: tracingMetrics.getAndReset() | ||
/** | ||
* @param {string} name | ||
* @param {*} module_ | ||
*/ | ||
exports._instrument = function _instrument(name, module_) { | ||
@@ -223,0 +266,0 @@ if (name === 'superagent') { |
@@ -46,2 +46,3 @@ /* | ||
requireHook.onModuleLoad('aws-sdk', instrumentSQS); | ||
requireHook.onModuleLoad('sqs-consumer', instrumentSQSConsumer); | ||
}; | ||
@@ -51,4 +52,4 @@ | ||
// /aws-sdk/lib/service.js#defineMethods | ||
shimmer.wrap(AWS.Service, 'defineMethods', function(original) { | ||
return function(svc) { | ||
shimmer.wrap(AWS.Service, 'defineMethods', function (original) { | ||
return function (svc) { | ||
const patchedMethod = original.apply(this, arguments); | ||
@@ -73,3 +74,3 @@ | ||
function shimSendMessage(originalSendMessage) { | ||
return function() { | ||
return function () { | ||
if (isActive) { | ||
@@ -163,3 +164,3 @@ const originalArgs = new Array(arguments.length); | ||
if (typeof originalCallback === 'function') { | ||
originalArgs[1] = cls.ns.bind(function(err, data) { | ||
originalArgs[1] = cls.ns.bind(function (err, data) { | ||
finishSpan(err, data, span); | ||
@@ -224,3 +225,3 @@ originalCallback.apply(this, arguments); | ||
function shimReceiveMessage(originalReceiveMessage) { | ||
return function() { | ||
return function () { | ||
if (isActive) { | ||
@@ -260,6 +261,24 @@ const parentSpan = cls.getCurrentSpan(); | ||
/** | ||
* The MessageAttributeNames attribute is an option that you tell which message attributes you want to see. | ||
* As we use message attributes to store Instana headers, if the customer does not set this attribute to All, | ||
* we cannot see the Instana headers, so we need to explicitly add them. | ||
*/ | ||
const receveingParams = originalArgs[0]; | ||
if (!receveingParams.MessageAttributeNames) { | ||
receveingParams.MessageAttributeNames = []; | ||
} | ||
if ( | ||
!receveingParams.MessageAttributeNames.includes('X_INSTANA*') && | ||
!receveingParams.MessageAttributeNames.includes('All') | ||
) { | ||
receveingParams.MessageAttributeNames.push('X_INSTANA*'); | ||
} | ||
// callback use case | ||
const originalCallback = originalArgs[1]; | ||
if (typeof originalCallback === 'function') { | ||
originalArgs[1] = cls.ns.bind(function(err, data) { | ||
originalArgs[1] = cls.ns.bind(function (err, data) { | ||
if (err) { | ||
@@ -297,3 +316,3 @@ addErrorToSpan(err, span); | ||
const originalPromiseFn = awsRequest.promise; | ||
awsRequest.promise = cls.ns.bind(function() { | ||
awsRequest.promise = cls.ns.bind(function () { | ||
const promise = originalPromiseFn.apply(awsRequest, arguments); | ||
@@ -430,1 +449,70 @@ | ||
}; | ||
/* *********** SQS Consumer ************** */ | ||
function instrumentSQSConsumer(SQSConsumer) { | ||
shimmer.wrap(SQSConsumer.Consumer.prototype, 'receiveMessage', shimSQSConsumerReceiveMessage); | ||
shimmer.wrap(SQSConsumer.Consumer.prototype, 'executeHandler', shimSQSConsumerExecuteHandler); | ||
shimmer.wrap(SQSConsumer.Consumer.prototype, 'executeBatchHandler', shimSQSConsumerExecuteHandler); | ||
} | ||
function shimSQSConsumerExecuteHandler(original) { | ||
return function () { | ||
if (isActive) { | ||
const originalArgs = new Array(arguments.length); | ||
for (let i = 0; i < originalArgs.length; i++) { | ||
originalArgs[i] = arguments[i]; | ||
} | ||
return instrumentedSQSConsumerExecuteHandler(this, original, originalArgs); | ||
} | ||
return original.apply(this, arguments); | ||
}; | ||
} | ||
function instrumentedSQSConsumerExecuteHandler(ctx, original, originalArgs) { | ||
if (ctx.instanaAsyncContext) { | ||
return cls.runInAsyncContext(ctx.instanaAsyncContext, () => { | ||
const span = cls.getCurrentSpan(); | ||
span.disableAutoEnd(); | ||
const res = original.apply(ctx, originalArgs).then(data => { | ||
span.transmitManual(); | ||
return data; | ||
}); | ||
return res; | ||
}); | ||
} else { | ||
return original.apply(ctx, originalArgs); | ||
} | ||
} | ||
function shimSQSConsumerReceiveMessage(original) { | ||
return function () { | ||
if (isActive) { | ||
const originalArgs = new Array(arguments.length); | ||
for (let i = 0; i < originalArgs.length; i++) { | ||
originalArgs[i] = arguments[i]; | ||
} | ||
return instrumentedSQSConsumerReceiveMessage(this, original, originalArgs); | ||
} | ||
return original.apply(this, arguments); | ||
}; | ||
} | ||
function instrumentedSQSConsumerReceiveMessage(ctx, original, originalArgs) { | ||
const originalSQSReceiveMessage = ctx.sqs.receiveMessage; | ||
ctx.sqs.receiveMessage = function () { | ||
const res = originalSQSReceiveMessage.apply(this, arguments); | ||
const p = res.promise(); | ||
if (p.instanaAsyncContext) { | ||
ctx.instanaAsyncContext = p.instanaAsyncContext; | ||
} | ||
return res; | ||
}; | ||
return original.apply(ctx, originalArgs); | ||
} |
@@ -222,3 +222,3 @@ /* | ||
span.data.elasticsearch.id = params.id; | ||
if (action.indexOf('search') === 0) { | ||
if (action && action.indexOf('search') === 0) { | ||
span.data.elasticsearch.query = tracingUtil.shortenDatabaseStatement(JSON.stringify(params)); | ||
@@ -225,0 +225,0 @@ } |
@@ -10,2 +10,3 @@ /* | ||
/** @type {import('../../../logger').GenericLogger} */ | ||
let logger; | ||
@@ -19,3 +20,3 @@ logger = require('../../../logger').getLogger('tracing/grpc', newLogger => { | ||
exports.init = function() { | ||
exports.init = function () { | ||
requireHook.onModuleLoad('superagent', exports.instrument); | ||
@@ -35,4 +36,7 @@ }; | ||
// Request#then. | ||
/** | ||
* @param {import('superagent')} superagent | ||
*/ | ||
exports.instrument = function instrument(superagent) { | ||
// @ts-ignore | ||
const OriginalRequest = superagent.Request; | ||
@@ -50,2 +54,3 @@ if (!OriginalRequest || typeof OriginalRequest !== 'function') { | ||
// Instrument the superagent.Request constructor function to attach the async context to the request object. | ||
// @ts-ignore | ||
superagent.Request = function InstrumentedRequest() { | ||
@@ -63,8 +68,14 @@ const request = new (Function.prototype.bind.apply( | ||
// @ts-ignore | ||
superagent.Request.__in = true; | ||
// @ts-ignore | ||
superagent.Request.prototype = OriginalRequest.prototype; | ||
// @ts-ignore | ||
shimmer.wrap(superagent.Request.prototype, 'then', instrumentThen); | ||
}; | ||
/** | ||
* @param {*} originalThen | ||
*/ | ||
function instrumentThen(originalThen) { | ||
@@ -85,3 +96,3 @@ return function instrumentedThen() { | ||
exports.activate = function() { | ||
exports.activate = function () { | ||
// This instrumentation does not record spans on its own, it just helps propagating the async context. Thus the | ||
@@ -91,5 +102,5 @@ // instrumentation is always on and cannot be activted or deactivated. | ||
exports.deactivate = function() { | ||
exports.deactivate = function () { | ||
// This instrumentation does not record spans on its own, it just helps propagating the async context. Thus the | ||
// instrumentation is always on and cannot be activted or deactivated. | ||
}; |
@@ -52,3 +52,7 @@ /* | ||
]; | ||
/** | ||
* @param {string} str | ||
* @param {number} len | ||
* @returns {string} | ||
*/ | ||
function leftPad(str, len) { | ||
@@ -55,0 +59,0 @@ // use '0' as the padding char, always |
@@ -22,2 +22,5 @@ /* | ||
/** | ||
* @param {number} dropped | ||
*/ | ||
exports.incrementDropped = function incrementDropped(dropped) { | ||
@@ -24,0 +27,0 @@ if (dropped == null) { |
@@ -11,6 +11,13 @@ /* | ||
let isActive = false; | ||
/** @type {import('./Tracer')} */ | ||
let tracer; | ||
/** @type {import('../cls')} */ | ||
let cls; | ||
let automaticTracingEnabled = false; | ||
/** | ||
* @param {import('../../util/normalizeConfig').InstanaConfig} config | ||
* @param {boolean} _automaticTracingEnabled | ||
* @param {import('../../index').ProcessIdentityProvider} processIdentityProvider | ||
*/ | ||
exports.init = function init(config, _automaticTracingEnabled, processIdentityProvider) { | ||
@@ -65,7 +72,11 @@ automaticTracingEnabled = _automaticTracingEnabled; | ||
const spanContext = new opentracing.SpanContext(); | ||
// @ts-ignore | ||
spanContext.s = s; | ||
// @ts-ignore | ||
spanContext.t = t; | ||
// @ts-ignore | ||
spanContext.samplingPriority = cls.tracingLevel() === '0' ? 0 : 1; | ||
// @ts-ignore | ||
spanContext.baggage = {}; | ||
return spanContext; | ||
}; |
@@ -12,7 +12,62 @@ /* | ||
/** | ||
* @typedef {Object} OpenTracingSpanDataSdkCustom | ||
* @property {*} tags | ||
* @property {*} logs | ||
*/ | ||
/** | ||
* @typedef {Object} OpenTracingSpanDataSdk | ||
* @property {'local' | 'entry' | 'exit'} type | ||
* @property {string} name | ||
* @property {OpenTracingSpanDataSdkCustom} custom | ||
*/ | ||
/** | ||
* @typedef {Object} OpenTracingSpanData | ||
* @property {string} service | ||
* @property {OpenTracingSpanDataSdk} sdk | ||
*/ | ||
/** | ||
* @typedef {Object} OpenTracingSpan | ||
* @property {string} s | ||
* @property {string} t | ||
* @property {string} p | ||
* @property {number} ec | ||
* @property {number} ts | ||
* @property {number} d | ||
* @property {string} n | ||
* @property {*} stack | ||
* @property {OpenTracingSpanData} data | ||
* @property {*} [f] | ||
*/ | ||
/** | ||
* @typedef {Object} SpanFieldReference | ||
* @property {() => string} type | ||
* @property {() => *} referencedContext | ||
*/ | ||
/** | ||
* @typedef {Object} SpanFields | ||
* @property {Array.<SpanFieldReference>} references | ||
* @property {number} startTime | ||
* @property {string} operationName | ||
* @property {*} tags | ||
*/ | ||
// can be set via config | ||
/** @type {string} */ | ||
let serviceName; | ||
/** @type {import('../../index').ProcessIdentityProvider} */ | ||
let processIdentityProvider = null; | ||
/** | ||
* | ||
* @param {import('./Tracer')} tracer | ||
* @param {string} name | ||
* @param {SpanFields} fields | ||
*/ | ||
function Span(tracer, name, fields) { | ||
@@ -37,10 +92,16 @@ opentracing.Span.call(this); | ||
const spanId = tracingUtil.generateRandomSpanId(); | ||
/** @type {string} */ | ||
const traceId = (parentContext ? parentContext.t : null) || spanId; | ||
const parentId = (parentContext ? parentContext.s : null) || undefined; | ||
this._contextImpl = new opentracing.SpanContext(); | ||
// @ts-ignore | ||
this._contextImpl.s = spanId; | ||
// @ts-ignore | ||
this._contextImpl.t = traceId; | ||
// @ts-ignore | ||
this._contextImpl.baggage = copyBaggage(parentContext && parentContext.baggage); | ||
// @ts-ignore | ||
this._contextImpl.samplingPriority = parentContext ? parentContext.samplingPriority : 1; | ||
/** @type {OpenTracingSpan} */ | ||
this.span = { | ||
@@ -81,3 +142,3 @@ s: spanId, | ||
module.exports = exports = Span; | ||
module.exports = Span; | ||
@@ -94,2 +155,5 @@ Span.prototype = Object.create(opentracing.Span.prototype); | ||
/** | ||
* @param {string} name | ||
*/ | ||
Span.prototype._setOperationName = function _setOperationName(name) { | ||
@@ -99,10 +163,22 @@ this.span.data.sdk.name = name; | ||
/** | ||
* @param {string} key | ||
* @param {*} value | ||
*/ | ||
Span.prototype._setBaggageItem = function _setBaggageItem(key, value) { | ||
// @ts-ignore | ||
this._contextImpl.baggage[key] = value; | ||
}; | ||
/** | ||
* @param {string} key | ||
*/ | ||
Span.prototype._getBaggageItem = function _getBaggageItem(key) { | ||
// @ts-ignore | ||
return this._contextImpl.baggage[key]; | ||
}; | ||
/** | ||
* @param {Object.<string, *>} keyValuePairs | ||
*/ | ||
Span.prototype._addTags = function _addTags(keyValuePairs) { | ||
@@ -116,2 +192,6 @@ const keys = Object.keys(keyValuePairs); | ||
/** | ||
* @param {string} key | ||
* @param {*} value | ||
*/ | ||
Span.prototype._addTag = function _addTag(key, value) { | ||
@@ -129,2 +209,3 @@ if (key === opentracing.Tags.ERROR) { | ||
} else if (key === opentracing.Tags.SAMPLING_PRIORITY) { | ||
// @ts-ignore | ||
this._contextImpl.samplingPriority = value; | ||
@@ -136,2 +217,6 @@ } else { | ||
/** | ||
* @param {Object.<string, *>} keyValuePairs | ||
* @param {number} timestamp | ||
*/ | ||
Span.prototype._log = function _log(keyValuePairs, timestamp) { | ||
@@ -154,3 +239,7 @@ if (timestamp == null) { | ||
/** | ||
* @param {number} finishTime | ||
*/ | ||
Span.prototype._finish = function _finish(finishTime) { | ||
// @ts-ignore | ||
if (this._contextImpl.samplingPriority <= 0) { | ||
@@ -167,2 +256,5 @@ return; | ||
/** | ||
* @param {Object.<string, *>} baggage | ||
*/ | ||
function copyBaggage(baggage) { | ||
@@ -173,2 +265,3 @@ if (!baggage) { | ||
/** @type {Object.<string, *>} */ | ||
const copy = {}; | ||
@@ -185,3 +278,7 @@ | ||
exports.init = function init(config, _processIdentityProvider) { | ||
/** | ||
* @param {import('../../util/normalizeConfig').InstanaConfig} config | ||
* @param {import('../../index').ProcessIdentityProvider} _processIdentityProvider | ||
*/ | ||
Span.init = function init(config, _processIdentityProvider) { | ||
if (config.serviceName) { | ||
@@ -193,4 +290,7 @@ serviceName = config.serviceName; | ||
exports.setProcessIdentityProvider = function setProcessIdentityProvider(fn) { | ||
/** | ||
* @param {import('../../index').ProcessIdentityProvider} fn | ||
*/ | ||
Span.setProcessIdentityProvider = function setProcessIdentityProvider(fn) { | ||
processIdentityProvider = fn; | ||
}; |
@@ -14,2 +14,3 @@ /* | ||
/** @type {Object.<string, Function>} */ | ||
const valueEncoders = {}; | ||
@@ -19,2 +20,3 @@ valueEncoders[opentracing.FORMAT_TEXT_MAP] = identity; | ||
/** @type {Object.<string, Function>} */ | ||
const valueDecoders = {}; | ||
@@ -24,2 +26,5 @@ valueDecoders[opentracing.FORMAT_TEXT_MAP] = identity; | ||
/** | ||
* @param {boolean} isActive | ||
*/ | ||
function Tracer(isActive) { | ||
@@ -33,2 +38,7 @@ opentracing.Tracer.apply(this, arguments); | ||
/** | ||
* @param {string} name | ||
* @param {import('./Span').SpanFields} fields | ||
* @returns {Span} | ||
*/ | ||
Tracer.prototype._startSpan = function _startSpan(name, fields) { | ||
@@ -38,2 +48,9 @@ return new Span(this, name, fields); | ||
/** | ||
* | ||
* @param {opentracing.SpanContext} spanContext | ||
* @param {string} format | ||
* @param {Object.<string, *>} carrier | ||
* @returns | ||
*/ | ||
Tracer.prototype._inject = function _inject(spanContext, format, carrier) { | ||
@@ -50,8 +67,13 @@ if (format !== opentracing.FORMAT_TEXT_MAP && format !== opentracing.FORMAT_HTTP_HEADERS) { | ||
// @ts-ignore | ||
carrier[constants.spanIdHeaderNameLowerCase] = spanContext.s; | ||
// @ts-ignore | ||
carrier[constants.traceIdHeaderNameLowerCase] = spanContext.t; | ||
// @ts-ignore | ||
carrier[constants.traceLevelHeaderNameLowerCase] = String(spanContext.samplingPriority); | ||
const valueEncoder = valueEncoders[format]; | ||
// @ts-ignore | ||
Object.keys(spanContext.baggage).forEach(baggageKey => { | ||
// @ts-ignore | ||
carrier[baggageKeyPrefix + baggageKey] = valueEncoder(spanContext.baggage[baggageKey]); | ||
@@ -61,2 +83,7 @@ }); | ||
/** | ||
* @param {string} format | ||
* @param {*} carrier | ||
* @returns {opentracing.SpanContext} | ||
*/ | ||
Tracer.prototype._extract = function _extract(format, carrier) { | ||
@@ -76,9 +103,15 @@ if (format !== opentracing.FORMAT_TEXT_MAP && format !== opentracing.FORMAT_HTTP_HEADERS) { | ||
const spanContext = new opentracing.SpanContext(); | ||
// @ts-ignore | ||
spanContext.s = carrier[constants.spanIdHeaderNameLowerCase]; | ||
// @ts-ignore | ||
spanContext.t = carrier[constants.traceIdHeaderNameLowerCase]; | ||
// @ts-ignore | ||
spanContext.samplingPriority = Number(carrier[constants.traceLevelHeaderNameLowerCase]); | ||
// @ts-ignore | ||
if (isNaN(spanContext.samplingPriority)) { | ||
// @ts-ignore | ||
spanContext.samplingPriority = 0; | ||
} | ||
// @ts-ignore | ||
spanContext.baggage = {}; | ||
@@ -91,2 +124,3 @@ Object.keys(carrier).forEach(carrierKey => { | ||
const baggageKey = carrierKey.substring(baggageKeyPrefix.length); | ||
// @ts-ignore | ||
spanContext.baggage[baggageKey] = valueDecoder(carrier[carrierKey]); | ||
@@ -96,4 +130,7 @@ }); | ||
// ensure that both t and s aren't used when SpanContext data is incomplete | ||
// @ts-ignore | ||
if (spanContext.s == null || spanContext.t == null) { | ||
// @ts-ignore | ||
spanContext.s = null; | ||
// @ts-ignore | ||
spanContext.t = null; | ||
@@ -113,4 +150,8 @@ } | ||
/** | ||
* @param {*} v | ||
* @returns {*} | ||
*/ | ||
function identity(v) { | ||
return v; | ||
} |
@@ -10,4 +10,8 @@ /* | ||
const promise = require('./sdk')(false); | ||
/** @type {import('../cls')} */ | ||
let cls; | ||
/** | ||
* @param {import('../cls')} _cls | ||
*/ | ||
exports.init = function init(_cls) { | ||
@@ -51,2 +55,4 @@ cls = _cls; | ||
* This is the variant that you are probably looking for if you need to fix async_hook continuity issues. | ||
* @param {import('../clsHooked/context').InstanaCLSContext} context | ||
* @param {Function} fn | ||
*/ | ||
@@ -70,2 +76,4 @@ exports.runInAsyncContext = function runInAsyncContext(context, fn) { | ||
* based library. | ||
* @param {import('../clsHooked/context').InstanaCLSContext} context | ||
* @param {Function} fn | ||
*/ | ||
@@ -72,0 +80,0 @@ exports.runPromiseInAsyncContext = function runPromiseInAsyncContext(context, fn) { |
@@ -12,2 +12,3 @@ /* | ||
/** @type {import('../../logger').GenericLogger} */ | ||
let logger; | ||
@@ -20,6 +21,20 @@ logger = require('../../logger').getLogger('tracing/sdk', newLogger => { | ||
module.exports = exports = function(isCallbackApi) { | ||
/** | ||
* @type {Function} | ||
* @param {boolean} isCallbackApi | ||
*/ | ||
module.exports = exports = function (isCallbackApi) { | ||
/** @type {import('../cls')} */ | ||
let cls = null; | ||
/** @type {Function} */ | ||
let wrapper = null; | ||
/** | ||
* @param {string} name | ||
* @param {string} tags | ||
* @param {string} traceId | ||
* @param {string} parentSpanId | ||
* @param {Function | string} callback | ||
* @returns {Function | Promise<*>} | ||
*/ | ||
function startEntrySpan(name, tags, traceId, parentSpanId, callback) { | ||
@@ -35,3 +50,3 @@ if (isCallbackApi && arguments.length === 2 && typeof arguments[1] === 'function') { | ||
if (!isActive) { | ||
return callNext(callback); | ||
return callNext(/** @type {Function} */ (callback)); | ||
} | ||
@@ -47,3 +62,3 @@ | ||
); | ||
return callNext(callback); | ||
return callNext(/** @type {Function} */ (callback)); | ||
} | ||
@@ -59,6 +74,10 @@ | ||
parentSpanId, | ||
callback | ||
/** @type {Function} */ (callback) | ||
); | ||
} | ||
/** | ||
* @param {Error} error | ||
* @param {string} tags | ||
*/ | ||
function completeEntrySpan(error, tags) { | ||
@@ -91,2 +110,8 @@ if (!isActive) { | ||
/** | ||
* @param {string} name | ||
* @param {string} tags | ||
* @param {Function | string} callback | ||
* @returns {Function | Promise<*>} | ||
*/ | ||
function startIntermediateSpan(name, tags, callback) { | ||
@@ -99,3 +124,3 @@ if (isCallbackApi && arguments.length === 2 && typeof arguments[1] === 'function') { | ||
if (!isActive) { | ||
return callNext(callback); | ||
return callNext(/** @type {Function} */ (callback)); | ||
} | ||
@@ -110,3 +135,3 @@ | ||
); | ||
return callNext(callback); | ||
return callNext(/** @type {Function} */ (callback)); | ||
} | ||
@@ -120,3 +145,3 @@ if (constants.isExitSpan(parentSpan)) { | ||
); | ||
return callNext(callback); | ||
return callNext(/** @type {Function} */ (callback)); | ||
} | ||
@@ -132,6 +157,10 @@ | ||
null, | ||
callback | ||
/** @type {Function} */ (callback) | ||
); | ||
} | ||
/** | ||
* @param {Error} error | ||
* @param {string} tags | ||
*/ | ||
function completeIntermediateSpan(error, tags) { | ||
@@ -164,2 +193,8 @@ if (!isActive) { | ||
/** | ||
* @param {string} name | ||
* @param {string} tags | ||
* @param {Function | string} callback | ||
* @returns {Function | Promise<*>} | ||
*/ | ||
function startExitSpan(name, tags, callback) { | ||
@@ -172,3 +207,3 @@ if (isCallbackApi && arguments.length === 2 && typeof arguments[1] === 'function') { | ||
if (!isActive) { | ||
return callNext(callback); | ||
return callNext(/** @type {Function} */ (callback)); | ||
} | ||
@@ -183,3 +218,3 @@ | ||
); | ||
return callNext(callback); | ||
return callNext(/** @type {Function} */ (callback)); | ||
} | ||
@@ -193,8 +228,21 @@ if (constants.isExitSpan(parentSpan)) { | ||
); | ||
return callNext(callback); | ||
return callNext(/** @type {Function} */ (callback)); | ||
} | ||
return startSdkSpan(name, constants.EXIT, constants.SDK.EXIT, startExitSpan, tags, null, null, callback); | ||
return startSdkSpan( | ||
name, | ||
constants.EXIT, | ||
constants.SDK.EXIT, | ||
startExitSpan, | ||
tags, | ||
null, | ||
null, | ||
/** @type {Function} */ (callback) | ||
); | ||
} | ||
/** | ||
* @param {Error} error | ||
* @param {string} tags | ||
*/ | ||
function completeExitSpan(error, tags) { | ||
@@ -227,2 +275,13 @@ if (!isActive) { | ||
/** | ||
* @param {string} name | ||
* @param {number} kind | ||
* @param {string} sdkKind | ||
* @param {Function} stackTraceRef | ||
* @param {string} tags | ||
* @param {string} traceId | ||
* @param {string} parentSpanId | ||
* @param {Function} callback | ||
* @returns {Function | Promise<*>} | ||
*/ | ||
function startSdkSpan(name, kind, sdkKind, stackTraceRef, tags, traceId, parentSpanId, callback) { | ||
@@ -243,2 +302,7 @@ return wrapper(() => { | ||
/** | ||
* @param {Error} error | ||
* @param {import('../cls').InstanaBaseSpan} span | ||
* @param {string} tags | ||
*/ | ||
function completeSpan(error, span, tags) { | ||
@@ -280,2 +344,5 @@ if (!span.data.sdk) { | ||
/** | ||
* @param {import('node:events').EventEmitter} emitter | ||
*/ | ||
function bindEmitter(emitter) { | ||
@@ -287,2 +354,6 @@ if (isActive) { | ||
/** | ||
* @param {Function} callback | ||
* @returns {Function | Promise<*>} | ||
*/ | ||
function callNext(callback) { | ||
@@ -292,2 +363,5 @@ return isCallbackApi ? callback() : Promise.resolve(); | ||
/** | ||
* @param {import('../cls')} _cls | ||
*/ | ||
function init(_cls) { | ||
@@ -294,0 +368,0 @@ cls = _cls; |
@@ -10,2 +10,3 @@ /* | ||
/** @type {import('../logger').GenericLogger} */ | ||
let logger; | ||
@@ -16,5 +17,15 @@ logger = require('../logger').getLogger('tracing/spanBuffer', newLogger => { | ||
/** @type {Array.<string>} */ | ||
const batchableSpanNames = []; | ||
/** | ||
* This module will not be typed yet: /nodejs-sensor/packages/collector/src/agentConnection.js | ||
* @typedef {Object} TemporaryAgentConnection | ||
* @property {(spans: *, cb: Function) => void} sendSpans | ||
*/ | ||
/** @type {TemporaryAgentConnection} */ | ||
let downstreamConnection = null; | ||
let isActive = false; | ||
/** @type {number} */ | ||
let activatedAt = null; | ||
@@ -30,10 +41,16 @@ | ||
/** @type {number} */ | ||
let initialDelayBeforeSendingSpans; | ||
/** @type {number} */ | ||
let transmissionDelay; | ||
/** @type {number} */ | ||
let maxBufferedSpans; | ||
/** @type {number} */ | ||
let forceTransmissionStartingAt; | ||
/** @type {NodeJS.Timeout} */ | ||
let transmissionTimeoutHandle; | ||
/** @type {NodeJS.Timeout} */ | ||
let preActivationCleanupIntervalHandle; | ||
/** @type {Array.<import('./cls').InstanaBaseSpan>} */ | ||
let spans = []; | ||
@@ -68,4 +85,17 @@ | ||
// The batchingBuckets are cleared once the span buffer is flushed downstream. | ||
/** | ||
* @typedef {Map.<number, Array.<import('./cls').InstanaBaseSpan>>} BatchingBucket | ||
*/ | ||
/** | ||
* @typedef {Map.<string, BatchingBucket>} BatchingBucketMap | ||
*/ | ||
/** @type {BatchingBucketMap} */ | ||
const batchingBuckets = new Map(); | ||
/** | ||
* @param {import('../util/normalizeConfig').InstanaConfig} config | ||
* @param {TemporaryAgentConnection} _downstreamConnection | ||
*/ | ||
exports.init = function init(config, _downstreamConnection) { | ||
@@ -126,3 +156,6 @@ downstreamConnection = _downstreamConnection; | ||
exports.addBatchableSpanName = function(spanName) { | ||
/** | ||
* @param {string} spanName | ||
*/ | ||
exports.addBatchableSpanName = function (spanName) { | ||
if (!batchableSpanNames.includes(spanName)) { | ||
@@ -133,3 +166,6 @@ batchableSpanNames.push(spanName); | ||
exports.addSpan = function(span) { | ||
/** | ||
* @param {import('./cls').InstanaBaseSpan} span | ||
*/ | ||
exports.addSpan = function (span) { | ||
if (!isActive) { | ||
@@ -160,2 +196,6 @@ return; | ||
/** | ||
* @param {import('./cls').InstanaBaseSpan} span | ||
* @returns {boolean} | ||
*/ | ||
function addToBatch(span) { | ||
@@ -181,2 +221,9 @@ if (!batchingBuckets.has(span.t)) { | ||
/** | ||
* | ||
* @param {import('./cls').InstanaBaseSpan} newSpan | ||
* @param {BatchingBucket} bucketsForTrace | ||
* @param {number} bucketKey | ||
* @returns | ||
*/ | ||
function findBatchPartnerAndMerge(newSpan, bucketsForTrace, bucketKey) { | ||
@@ -213,2 +260,9 @@ const bucket = bucketsForTrace.get(bucketKey); | ||
/** | ||
* @param {import('./cls').InstanaBaseSpan} oldSpan | ||
* @param {import('./cls').InstanaBaseSpan} newSpan | ||
* @param {Array.<import('./cls').InstanaBaseSpan>} bucket | ||
* @param {number} bucketKey | ||
* @param {number} indexInBucket | ||
*/ | ||
function mergeSpansAsBatch(oldSpan, newSpan, bucket, bucketKey, indexInBucket) { | ||
@@ -244,5 +298,8 @@ // Determine, if the new span (about to be added to the buffer) is more significant than the old span that is already | ||
/* | ||
/** | ||
* Merges the source span into the target span. Assumes that target is already in the spanBuffer and source can be | ||
* discarded afterwards. | ||
* @param {import('./cls').InstanaBaseSpan} target | ||
* @param {import('./cls').InstanaBaseSpan} source | ||
* @param {number} originalBucketKey | ||
*/ | ||
@@ -285,2 +342,6 @@ function mergeIntoTargetSpan(target, source, originalBucketKey) { | ||
/** | ||
* @param {import('./cls').InstanaBaseSpan} target | ||
* @param {import('./cls').InstanaBaseSpan} source | ||
*/ | ||
function setBatchSize(target, source) { | ||
@@ -307,2 +368,6 @@ if (target.b && target.b.s && source.b && source.b.s) { | ||
/** | ||
* @param {import('./cls').InstanaBaseSpan} span | ||
* @param {number} [preComputedBucketKey] | ||
*/ | ||
function addToBucket(span, preComputedBucketKey) { | ||
@@ -318,8 +383,9 @@ // Put batcheable spans from the same trace into time-based buckets so we can find them for batching when more | ||
} | ||
batchingBuckets | ||
.get(span.t) | ||
.get(bucketKey) | ||
.push(span); | ||
batchingBuckets.get(span.t).get(bucketKey).push(span); | ||
} | ||
/** | ||
* @param {import('./cls').InstanaBaseSpan} span | ||
* @returns {number} | ||
*/ | ||
function batchingBucketKey(span) { | ||
@@ -330,2 +396,6 @@ const spanEnd = span.ts + span.d; | ||
/** | ||
* @param {import('./cls').InstanaBaseSpan} span | ||
* @returns {boolean} | ||
*/ | ||
function isBatchable(span) { | ||
@@ -358,3 +428,3 @@ return ( | ||
downstreamConnection.sendSpans(spansToSend, function sendSpans(error) { | ||
downstreamConnection.sendSpans(spansToSend, function sendSpans(/** @type {Error} */ error) { | ||
if (error) { | ||
@@ -361,0 +431,0 @@ logger.warn(`Failed to transmit spans, will retry in ${transmissionDelay} ms.`, error.message); |
@@ -12,2 +12,3 @@ /* | ||
* Provides very limited access from client code to the current active span. | ||
* @param {import('./cls').InstanaBaseSpan} _span | ||
*/ | ||
@@ -88,2 +89,6 @@ function SpanHandle(_span) { | ||
/** | ||
* @param {string} path | ||
* @param {*} value | ||
*/ | ||
SpanHandle.prototype.annotate = function annotate(path, value) { | ||
@@ -106,6 +111,12 @@ if (path == null) { | ||
/** | ||
* @param {Object.<string, *>} target | ||
* @param {string} path | ||
* @param {*} value | ||
*/ | ||
function _annotateWithString(target, path, value) { | ||
// remove trailing dots first | ||
if (path.charAt(path.length - 1) === '.') { | ||
return _annotateWithString(target, path.substring(0, path.length - 1), value); | ||
_annotateWithString(target, path.substring(0, path.length - 1), value); | ||
return; | ||
} | ||
@@ -129,2 +140,7 @@ const idx = path.indexOf('.'); | ||
/** | ||
* @param {Object.<string, *>} target | ||
* @param {string} path | ||
* @param {*} value | ||
*/ | ||
function _annotateWithArray(target, path, value) { | ||
@@ -157,2 +173,3 @@ if (path.length === 0) { | ||
* Finishes as span that has been switched to manual-end-mode before. | ||
* @param {boolean | number} errorCount | ||
*/ | ||
@@ -173,2 +190,3 @@ SpanHandle.prototype.end = function end(errorCount) { | ||
/** | ||
* TODO: make it as a class | ||
* Provides noop operation for the SpanHandle API when automatic tracing is not enabled or no span is currently active. | ||
@@ -178,2 +196,5 @@ */ | ||
/** | ||
* @returns {null} | ||
*/ | ||
NoopSpanHandle.prototype.getTraceId = function getTraceId() { | ||
@@ -183,2 +204,5 @@ return null; | ||
/** | ||
* @returns {null} | ||
*/ | ||
NoopSpanHandle.prototype.getSpanId = function getSpanId() { | ||
@@ -188,2 +212,5 @@ return null; | ||
/** | ||
* @returns {null} | ||
*/ | ||
NoopSpanHandle.prototype.getParentSpanId = function getParentSpanId() { | ||
@@ -193,2 +220,5 @@ return null; | ||
/** | ||
* @returns {null} | ||
*/ | ||
NoopSpanHandle.prototype.getName = function getName() { | ||
@@ -232,2 +262,6 @@ return null; | ||
/** | ||
* @param {import ('./cls')} cls | ||
* @returns {SpanHandle | NoopSpanHandle} | ||
*/ | ||
exports.getHandleForCurrentSpan = function getHandleForCurrentSpan(cls) { | ||
@@ -234,0 +268,0 @@ if (cls && cls.isTracing()) { |
@@ -14,3 +14,6 @@ /* | ||
exports.init = function(config) { | ||
/** | ||
* @param {import('../util/normalizeConfig').InstanaConfig} config | ||
*/ | ||
exports.init = function (config) { | ||
disableW3cTraceCorrelation = config.tracing.disableW3cTraceCorrelation; | ||
@@ -74,5 +77,7 @@ }; | ||
* context headers traceparent and tracestate. | ||
* @param {import('node:http').IncomingMessage} req | ||
*/ | ||
exports.fromHttpRequest = function fromHttpRequest(req) { | ||
if (!req || !req.headers) { | ||
// @ts-ignore | ||
req = { headers: {} }; | ||
@@ -86,2 +91,3 @@ } | ||
* context headers traceparent and tracestate. | ||
* @param {import('node:http').IncomingHttpHeaders} headers | ||
*/ | ||
@@ -117,4 +123,4 @@ exports.fromHeaders = function fromHeaders(headers) { | ||
const result = { | ||
traceId: xInstanaT, | ||
parentId: xInstanaS, | ||
traceId: /** @type {string} */ (xInstanaT), | ||
parentId: /** @type {string} */ (xInstanaS), | ||
usedTraceParent: false, | ||
@@ -132,4 +138,4 @@ level, | ||
return limitTraceId({ | ||
traceId: xInstanaT, | ||
parentId: xInstanaS, | ||
traceId: /** @type {string} */ (xInstanaT), | ||
parentId: /** @type {string} */ (xInstanaS), | ||
usedTraceParent: false, | ||
@@ -140,3 +146,7 @@ level, | ||
synthetic, | ||
w3cTraceContext: w3c.create(xInstanaT, xInstanaS, !isSuppressed(level)) | ||
w3cTraceContext: w3c.create( | ||
/** @type {string} */ (xInstanaT), | ||
/** @type {string} */ (xInstanaS), | ||
!isSuppressed(level) | ||
) | ||
}); | ||
@@ -229,2 +239,6 @@ } else if (w3cTraceContext && !disableW3cTraceCorrelation) { | ||
/** | ||
* @param {import('node:http').IncomingHttpHeaders} headers | ||
* @returns {string | Array.<string>} | ||
*/ | ||
function readInstanaTraceId(headers) { | ||
@@ -238,2 +252,6 @@ const xInstanaT = headers[constants.traceIdHeaderNameLowerCase]; | ||
/** | ||
* @param {import('node:http').IncomingHttpHeaders} headers | ||
* @returns {string | Array.<string>} | ||
*/ | ||
function readInstanaParentId(headers) { | ||
@@ -247,2 +265,5 @@ const xInstanaS = headers[constants.spanIdHeaderNameLowerCase]; | ||
/** | ||
* @param {import('node:http').IncomingHttpHeaders} headers | ||
*/ | ||
function readLevelAndCorrelation(headers) { | ||
@@ -269,3 +290,3 @@ const xInstanaL = headers[constants.traceLevelHeaderNameLowerCase]; | ||
const parts = xInstanaL.split(','); | ||
const parts = /** @type {string} */ (xInstanaL).split(','); | ||
if (parts.length > 1) { | ||
@@ -293,2 +314,6 @@ const idxType = parts[1].indexOf('correlationType='); | ||
/** | ||
* @param {string | undefined} level | ||
* @returns {boolean} | ||
*/ | ||
function isSuppressed(level) { | ||
@@ -298,2 +323,5 @@ return typeof level === 'string' && level.indexOf('0') === 0; | ||
/** | ||
* @param {import('node:http').IncomingHttpHeaders} headers | ||
*/ | ||
function readSyntheticMarker(headers) { | ||
@@ -303,11 +331,18 @@ return headers[constants.syntheticHeaderNameLowerCase] === '1'; | ||
/** | ||
* @param {import('./w3c_trace_context/W3cTraceContext')} w3cTraceContext | ||
* @returns {boolean} | ||
*/ | ||
function traceStateHasInstanaKeyValuePair(w3cTraceContext) { | ||
return w3cTraceContext.instanaTraceId && w3cTraceContext.instanaParentId; | ||
return !!(w3cTraceContext.instanaTraceId && w3cTraceContext.instanaParentId); | ||
} | ||
/** | ||
* @param {import('node:http').IncomingHttpHeaders} headers | ||
*/ | ||
function readW3cTraceContext(headers) { | ||
const traceParent = headers[constants.w3cTraceParent]; | ||
const traceParent = /** @type {string} */ (headers[constants.w3cTraceParent]); | ||
// The spec mandates that multiple tracestate headers should be treated by concatenating them. Node.js' http core | ||
// library takes care of that already. | ||
const traceState = headers[constants.w3cTraceState]; | ||
const traceState = /** @type {string} */ (headers[constants.w3cTraceState]); | ||
let traceContext; | ||
@@ -329,2 +364,26 @@ if (traceParent) { | ||
/** | ||
* @typedef {Object} InstanaAncestor | ||
* @property {string} t | ||
* @property {string} p | ||
*/ | ||
/** | ||
* @typedef {Object} TracingHeaders | ||
* @property {string} [traceId] | ||
* @property {string} [longTraceId] | ||
* @property {string} [parentId] | ||
* @property {boolean} usedTraceParent | ||
* @property {import('./w3c_trace_context/W3cTraceContext')} w3cTraceContext | ||
* @property {string} level | ||
* @property {string} [correlationType] | ||
* @property {string} [correlationId] | ||
* @property {boolean} synthetic | ||
* @property {InstanaAncestor} [instanaAncestor] | ||
*/ | ||
/** | ||
* @param {TracingHeaders} result | ||
* @returns {TracingHeaders} | ||
*/ | ||
function limitTraceId(result) { | ||
@@ -331,0 +390,0 @@ if (result.traceId && result.traceId.length >= 32) { |
@@ -16,6 +16,14 @@ /* | ||
exports.init = function(config) { | ||
/** | ||
* @param {import('../util/normalizeConfig').InstanaConfig} config | ||
*/ | ||
exports.init = function (config) { | ||
stackTraceLength = config.tracing.stackTraceLength; | ||
}; | ||
/** | ||
* @param {Function} referenceFunction | ||
* @param {number} [drop] | ||
* @returns {Array.<*>} | ||
*/ | ||
exports.getStackTrace = function getStackTrace(referenceFunction, drop) { | ||
@@ -38,3 +46,7 @@ return stackTrace.captureStackTrace(stackTraceLength, referenceFunction, drop); | ||
exports.generateRandomId = function(length) { | ||
/** | ||
* @param {number} length | ||
* @returns {string} | ||
*/ | ||
exports.generateRandomId = function (length) { | ||
return crypto | ||
@@ -46,2 +58,9 @@ .randomBytes(Math.ceil(length / 2)) | ||
/** | ||
* @param {Buffer} buffer | ||
* @returns {{ | ||
* t: string, | ||
* s: string | ||
* }} | ||
*/ | ||
exports.readTraceContextFromBuffer = function readTraceContextFromBuffer(buffer) { | ||
@@ -63,2 +82,8 @@ if (!Buffer.isBuffer(buffer)) { | ||
/** | ||
* @param {Buffer} buffer | ||
* @param {number} offset | ||
* @param {number} length | ||
* @returns {string} | ||
*/ | ||
function readHexFromBuffer(buffer, offset, length) { | ||
@@ -68,3 +93,10 @@ return hexDecoder.write(buffer.slice(offset, offset + length)); | ||
/** | ||
* @param {string} hexString | ||
* @param {Buffer} buffer | ||
* @param {number} offsetFromRight | ||
* @returns {Buffer} | ||
*/ | ||
exports.unsignedHexStringToBuffer = function unsignedHexStringToBuffer(hexString, buffer, offsetFromRight) { | ||
/** @type {number} */ | ||
let offset; | ||
@@ -88,2 +120,7 @@ if (buffer && offsetFromRight != null) { | ||
/** | ||
* @param {string} traceId | ||
* @param {string} spanId | ||
* @returns {Buffer} | ||
*/ | ||
exports.unsignedHexStringsToBuffer = function unsignedHexStringsToBuffer(traceId, spanId) { | ||
@@ -102,2 +139,5 @@ const buffer = Buffer.alloc(24); | ||
* The string hexString must only contain the characters [0-9a-f]. | ||
* @param {string} hexString | ||
* @param {Buffer} buffer | ||
* @param {number} offset | ||
*/ | ||
@@ -109,5 +149,10 @@ function writeHexToBuffer(hexString, buffer, offset) { | ||
// https://github.com/nodejs/node/blob/master/src/node_buffer.cc#L681 | ||
// @ts-ignore | ||
buffer.hexWrite(hexString, offset, hexString.length / 2); | ||
} | ||
/** | ||
* @param {import('./cls').InstanaBaseSpan} span | ||
* @returns {Buffer} | ||
*/ | ||
exports.renderTraceContextToBuffer = function renderTraceContextToBuffer(span) { | ||
@@ -117,2 +162,6 @@ return exports.unsignedHexStringsToBuffer(span.t, span.s); | ||
/** | ||
* @param {Error} err | ||
* @returns {string} | ||
*/ | ||
exports.getErrorDetails = function getErrorDetails(err) { | ||
@@ -125,2 +174,6 @@ if (err == null) { | ||
/** | ||
* @param {string} stmt | ||
* @returns {string} | ||
*/ | ||
exports.shortenDatabaseStatement = function shortenDatabaseStatement(stmt) { | ||
@@ -134,2 +187,7 @@ if (stmt == null || typeof stmt !== 'string') { | ||
/** | ||
* @param {*} object | ||
* @param {string} key | ||
* @returns {*} | ||
*/ | ||
exports.readAttribCaseInsensitive = function readAttribCaseInsensitive(object, key) { | ||
@@ -136,0 +194,0 @@ if (!object || typeof object !== 'object' || typeof key !== 'string') { |
@@ -10,4 +10,3 @@ /* | ||
module.exports = exports = W3cTraceContext.fromInstanaIds; | ||
exports.fromInstanaIds = W3cTraceContext.fromInstanaIds; | ||
exports.createEmptyUnsampled = W3cTraceContext.createEmptyUnsampled; |
@@ -8,6 +8,8 @@ /* | ||
module.exports = exports = { | ||
create: require('./create'), | ||
createEmptyUnsampled: require('./create').createEmptyUnsampled, | ||
const { createEmptyUnsampled, fromInstanaIds } = require('./create'); | ||
module.exports = { | ||
create: fromInstanaIds, | ||
createEmptyUnsampled: createEmptyUnsampled, | ||
parse: require('./parse') | ||
}; |
@@ -13,2 +13,3 @@ /* | ||
/** @type {import('../../logger').GenericLogger} */ | ||
let logger; | ||
@@ -24,3 +25,8 @@ logger = require('../../logger').getLogger('tracing/W3C trace context parser', newLogger => { | ||
module.exports = exports = function parse(traceParentRaw, traceStateRaw) { | ||
/** | ||
* @param {string} traceParentRaw | ||
* @param {string} traceStateRaw | ||
* @returns {W3cTraceContext} | ||
*/ | ||
module.exports = function parse(traceParentRaw, traceStateRaw) { | ||
const parsed = new W3cTraceContext(); | ||
@@ -35,2 +41,6 @@ parseTraceParent(traceParentRaw, parsed); | ||
/** | ||
* @param {string} traceParentRaw | ||
* @param {W3cTraceContext} parsed | ||
*/ | ||
function parseTraceParent(traceParentRaw, parsed) { | ||
@@ -60,2 +70,6 @@ if (typeof traceParentRaw !== 'string') { | ||
/** | ||
* @param {string} traceStateRaw | ||
* @param {W3cTraceContext} parsed | ||
*/ | ||
function parseTraceState(traceStateRaw, parsed) { | ||
@@ -101,2 +115,6 @@ if (typeof traceStateRaw !== 'string') { | ||
/** | ||
* @param {W3cTraceContext} parsed | ||
* @param {string} instanaKeyValuePair | ||
*/ | ||
function parseInstanaTraceStateKeyValuePair(parsed, instanaKeyValuePair) { | ||
@@ -108,2 +126,7 @@ const fields = instanaKeyValuePair.substring(instanaVendorKeyOffset).split(';'); | ||
/** | ||
* @param {string} id | ||
* @param {boolean} isTraceId | ||
* @returns {string | null} | ||
*/ | ||
function normalizeId(id, isTraceId) { | ||
@@ -110,0 +133,0 @@ if (!id || typeof id !== 'string' || id.trim() === '') { |
@@ -39,9 +39,12 @@ /* | ||
/** | ||
* @param {string} instanaTraceId | ||
* @param {string} instanaParentId | ||
* @param {boolean | *} sampled | ||
* @returns {W3cTraceContext} | ||
*/ | ||
W3cTraceContext.fromInstanaIds = function fromInstanaIds(instanaTraceId, instanaParentId, sampled) { | ||
const paddedTraceId = instanaTraceId.length === 16 ? LEFT_PAD_16 + instanaTraceId : instanaTraceId; | ||
sampled = typeof sampled === 'boolean' ? sampled : true; | ||
const traceContext = new W3cTraceContext( | ||
`${VERSION00}-${paddedTraceId}-${instanaParentId}-${sampled ? '01' : '00'}`, | ||
`${constants.w3cInstanaEquals + instanaTraceId};${instanaParentId}` | ||
); | ||
const traceContext = new W3cTraceContext(); | ||
traceContext.traceParentValid = true; | ||
@@ -60,5 +63,10 @@ traceContext.version = VERSION00; | ||
/** | ||
* @param {string} traceId | ||
* @param {string} parentId | ||
* @returns | ||
*/ | ||
W3cTraceContext.createEmptyUnsampled = function createEmptyUnsampled(traceId, parentId) { | ||
const paddedTraceId = traceId.length === 16 ? LEFT_PAD_16 + traceId : traceId; | ||
const traceContext = new W3cTraceContext(`${VERSION00}-${paddedTraceId}-${parentId}-00`); | ||
const traceContext = new W3cTraceContext(); | ||
traceContext.traceParentValid = true; | ||
@@ -73,2 +81,5 @@ traceContext.version = VERSION00; | ||
/** | ||
* @returns {string} | ||
*/ | ||
W3cTraceContext.prototype.renderTraceParent = function renderTraceParent() { | ||
@@ -82,2 +93,5 @@ if (!this.traceParentValid) { | ||
/** | ||
* @returns {'01' | '00'} | ||
*/ | ||
W3cTraceContext.prototype.renderFlags = function renderFlags() { | ||
@@ -87,2 +101,5 @@ return this.sampled ? '01' : '00'; | ||
/** | ||
* @returns {boolean} | ||
*/ | ||
W3cTraceContext.prototype.hasTraceState = function hasTraceState() { | ||
@@ -92,2 +109,5 @@ return ((this.instanaTraceId && this.instanaParentId) || this.traceStateHead || this.traceStateTail) != null; | ||
/** | ||
* @returns {string} | ||
*/ | ||
W3cTraceContext.prototype.renderTraceState = function renderTraceState() { | ||
@@ -97,2 +117,3 @@ if (!this.traceStateValid) { | ||
} | ||
/** @type {Array.<*>} */ | ||
let allKeyValuePairs = []; | ||
@@ -134,2 +155,4 @@ const instanaKeyValuePair = this.renderInstanaTraceStateValue(); | ||
* - upserts the in key-value pair in tracestate to the given trace ID and span ID, and moved to the leftmost position. | ||
* @param {string} instanaTraceId | ||
* @param {string} instanaParentId | ||
*/ | ||
@@ -154,2 +177,5 @@ W3cTraceContext.prototype.updateParent = function updateParent(instanaTraceId, instanaParentId) { | ||
/** | ||
* @param {string} longTraceId | ||
*/ | ||
W3cTraceContext.prototype.restartTrace = function restartTrace(longTraceId) { | ||
@@ -190,4 +216,5 @@ this.traceParentValid = true; | ||
module.exports = exports = W3cTraceContext; | ||
exports.VERSION00 = VERSION00; | ||
exports.SAMPLED_BITMASK = SAMPLED_BITMASK; | ||
W3cTraceContext.VERSION00 = VERSION00; | ||
W3cTraceContext.SAMPLED_BITMASK = SAMPLED_BITMASK; | ||
module.exports = W3cTraceContext; |
@@ -5,2 +5,3 @@ /* | ||
*/ | ||
// @ts-nocheck | ||
@@ -7,0 +8,0 @@ 'use strict'; |
@@ -15,3 +15,3 @@ /* | ||
* @param {number} [drop] | ||
* @returns {object} | ||
* @returns {Array.<*>} | ||
*/ | ||
@@ -65,3 +65,3 @@ exports.captureStackTrace = function captureStackTrace(length, referenceFunction, drop = 0) { | ||
const jsonStackTrace = /** @type {*} */ (error)._jsonStackTrace; | ||
delete /** @type {*} */ (error)._jsonStackTrace; | ||
delete (/** @type {*} */ (error)._jsonStackTrace); | ||
return jsonStackTrace; | ||
@@ -68,0 +68,0 @@ }; |
494719
14051