UNPKG

@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
"use strict"; 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