@splunk/otel
Version:
The Splunk distribution of OpenTelemetry Node Instrumentation provides a Node agent that automatically instruments your Node application to capture and report distributed traces to Splunk APM.
134 lines • 6.69 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Neo4jInstrumentation = void 0;
/*
* Copyright Splunk Inc., Aspecto
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const api_1 = require("@opentelemetry/api");
const semconv_1 = require("./semconv");
const version_1 = require("../../../version");
const instrumentation_1 = require("@opentelemetry/instrumentation");
const utils_1 = require("./utils");
class Neo4jInstrumentation extends instrumentation_1.InstrumentationBase {
constructor(config = {}) {
super('splunk-opentelemetry-instrumentation-neo4j', version_1.VERSION, config);
}
init() {
return [
this.getModuleDefinition('neo4j-driver-core', ['>=4.3.0 <6']),
this.getModuleDefinition('neo4j-driver', ['>=4.0.0 <4.3.0']),
];
}
getModuleDefinition(name, supportedVersions) {
const apiModuleFiles = ['session', 'transaction'].map((file) => new instrumentation_1.InstrumentationNodeModuleFile(`${name}/lib/${file}.js`, supportedVersions, (moduleExports) => {
if ((0, instrumentation_1.isWrapped)(moduleExports.default.prototype.run)) {
this._unwrap(moduleExports.default.prototype, 'run');
}
this.patchSessionOrTransaction(moduleExports);
return moduleExports;
}, (moduleExports) => {
if ((0, instrumentation_1.isWrapped)(moduleExports.default.prototype.run)) {
this._unwrap(moduleExports.default.prototype, 'run');
}
}));
const module = new instrumentation_1.InstrumentationNodeModuleDefinition(name, supportedVersions, undefined, undefined, apiModuleFiles);
return module;
}
patchSessionOrTransaction(fileExport) {
const self = this;
this._wrap(fileExport.default.prototype, 'run', (originalRun) => {
return function (...args) {
if (self.getConfig().ignoreOrphanedSpans) {
if (!api_1.trace.getSpan(api_1.context.active())) {
return originalRun.apply(this, args);
}
}
const connectionAttributes = (0, utils_1.getAttributesFromNeo4jSession)(this);
const query = args[0];
const operation = query.trim().split(/\s+/)[0];
const span = self.tracer.startSpan(`${operation} ${connectionAttributes[semconv_1.ATTR_DB_NAME]}`, {
attributes: Object.assign(Object.assign({}, connectionAttributes), { [semconv_1.ATTR_DB_SYSTEM]: 'neo4j', [semconv_1.ATTR_DB_OPERATION]: operation, [semconv_1.ATTR_DB_STATEMENT]: query }),
kind: api_1.SpanKind.CLIENT,
});
let spanEnded = false;
const endSpan = () => {
if (spanEnded)
return;
span.end();
spanEnded = true;
};
const patchObserver = (observer) => {
const records = [];
return Object.assign(Object.assign({}, observer), { onKeys: function (...args) {
if (!observer.onKeys)
return;
if (!observer.onCompleted) {
endSpan();
}
return observer.onKeys.apply(this, args);
}, onNext: function (...args) {
if (self.getConfig().responseHook) {
records.push(args[0]);
}
if (observer.onNext)
return observer.onNext.apply(this, args);
}, onCompleted: function patchedOnCompleted(...args) {
const responseHook = self.getConfig().responseHook;
if (responseHook) {
(0, instrumentation_1.safeExecuteInTheMiddle)(() => responseHook(span, {
records: records,
summary: args[0],
}), (e) => {
if (e) {
api_1.diag.error('responseHook error', e);
}
}, true);
}
endSpan();
if (observer.onCompleted)
return observer.onCompleted.apply(this, args);
}, onError: function (...args) {
const err = args[0];
span.recordException(err);
span.setStatus({
code: api_1.SpanStatusCode.ERROR,
message: err.message,
});
endSpan();
if (observer.onError)
return observer.onError.apply(this, args);
} });
};
const response = originalRun.apply(this, args);
// Necessary for neo4j 5.x
if (typeof response._decorateObserver === 'function') {
const originalDecorate = response._decorateObserver;
response._decorateObserver = function patchedDecorate(originalObserver) {
const observer = originalDecorate.call(response, originalObserver);
return patchObserver(observer);
};
}
const originalSubscribe = response.subscribe;
response.subscribe = function (observer) {
return originalSubscribe.call(this, patchObserver(observer));
};
return response;
};
});
return fileExport;
}
}
exports.Neo4jInstrumentation = Neo4jInstrumentation;
//# sourceMappingURL=neo4j.js.map