@sentry/node
Version:
Sentry Node SDK using OpenTelemetry for performance instrumentation
138 lines (134 loc) • 4.95 kB
JavaScript
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const AttributeNames = require('./enums/AttributeNames.js');
const core = require('@sentry/core');
const setHttpServerSpanRouteAttribute = require('../../../../utils/setHttpServerSpanRouteAttribute.js');
const instrumentation = require('@opentelemetry/instrumentation');
const attributes = require('@sentry/conventions/attributes');
const utils = require('./utils.js');
const PACKAGE_NAME = "@sentry/instrumentation-connect";
const ANONYMOUS_NAME = "anonymous";
class ConnectInstrumentation extends instrumentation.InstrumentationBase {
constructor(config = {}) {
super(PACKAGE_NAME, core.SDK_VERSION, config);
}
init() {
return [
new instrumentation.InstrumentationNodeModuleDefinition("connect", [">=3.0.0 <4"], (moduleExports) => {
return this._patchConstructor(moduleExports);
})
];
}
_patchApp(patchedApp) {
if (!instrumentation.isWrapped(patchedApp.use)) {
this._wrap(patchedApp, "use", this._patchUse.bind(this));
}
if (!instrumentation.isWrapped(patchedApp.handle)) {
this._wrap(patchedApp, "handle", this._patchHandle.bind(this));
}
}
_patchConstructor(original) {
const patchApp = this._patchApp.bind(this);
return function(...args) {
const app = Reflect.apply(original, this, args);
patchApp(app);
return app;
};
}
_patchNext(next, span, finishSpan) {
return function nextFunction(err) {
if (core.isError(err)) {
span.setStatus({ code: core.SPAN_STATUS_ERROR, message: "internal_error" });
}
const result = next.apply(this, [err]);
finishSpan();
return result;
};
}
_startSpan(routeName, middleWare) {
const connectType = routeName ? AttributeNames.ConnectTypes.REQUEST_HANDLER : AttributeNames.ConnectTypes.MIDDLEWARE;
const connectName = routeName || middleWare.name || ANONYMOUS_NAME;
return core.startInactiveSpan({
name: connectName,
op: `${connectType}.connect`,
attributes: {
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.http.otel.connect",
[attributes.HTTP_ROUTE]: routeName.length > 0 ? routeName : "/",
[AttributeNames.AttributeNames.CONNECT_TYPE]: connectType,
[AttributeNames.AttributeNames.CONNECT_NAME]: connectName
}
});
}
_patchMiddleware(routeName, middleWare) {
const isEnabled = this.isEnabled.bind(this);
const startSpan = this._startSpan.bind(this);
const patchNext = this._patchNext.bind(this);
const isErrorMiddleware = middleWare.length === 4;
function patchedMiddleware() {
if (!isEnabled()) {
return Reflect.apply(middleWare, this, arguments);
}
const [reqArgIdx, resArgIdx, nextArgIdx] = isErrorMiddleware ? [1, 2, 3] : [0, 1, 2];
const req = arguments[reqArgIdx];
const res = arguments[resArgIdx];
const next = arguments[nextArgIdx];
utils.replaceCurrentStackRoute(req, routeName);
if (routeName) {
setHttpServerSpanRouteAttribute.setHttpServerSpanRouteAttribute(utils.generateRoute(req));
}
const span = startSpan(routeName, middleWare);
let spanFinished = false;
function finishSpan() {
if (!spanFinished) {
spanFinished = true;
span.end();
}
res.removeListener("close", finishSpan);
}
res.addListener("close", finishSpan);
arguments[nextArgIdx] = patchNext(next, span, finishSpan);
try {
return Reflect.apply(middleWare, this, arguments);
} catch (e) {
span.setStatus({ code: core.SPAN_STATUS_ERROR, message: "internal_error" });
finishSpan();
throw e;
}
}
Object.defineProperty(patchedMiddleware, "length", {
value: middleWare.length,
writable: false,
configurable: true
});
return patchedMiddleware;
}
_patchUse(original) {
const patchMiddleware = this._patchMiddleware.bind(this);
return function(...args) {
const middleWare = args[args.length - 1];
const routeName = args[args.length - 2] || "";
args[args.length - 1] = patchMiddleware(routeName, middleWare);
return original.apply(this, args);
};
}
_patchHandle(original) {
const patchOut = this._patchOut.bind(this);
return function() {
const [reqIdx, outIdx] = [0, 2];
const req = arguments[reqIdx];
const out = arguments[outIdx];
const completeStack = utils.addNewStackLayer(req);
if (typeof out === "function") {
arguments[outIdx] = patchOut(out, completeStack);
}
return Reflect.apply(original, this, arguments);
};
}
_patchOut(out, completeStack) {
return function nextFunction(...args) {
completeStack();
return Reflect.apply(out, this, args);
};
}
}
exports.ConnectInstrumentation = ConnectInstrumentation;
//# sourceMappingURL=instrumentation.js.map