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.

147 lines 7.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ElasticsearchInstrumentation = void 0; /* * Copyright Splunk Inc. * * 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 core_1 = require("@opentelemetry/core"); const instrumentation_1 = require("@opentelemetry/instrumentation"); const version_1 = require("../../../version"); const semantic_conventions_1 = require("@opentelemetry/semantic-conventions"); const utils_1 = require("./utils"); const helpers_1 = require("./helpers"); var AttributeNames; (function (AttributeNames) { AttributeNames["ELASTICSEARCH_INDICES"] = "elasticsearch.request.indices"; })(AttributeNames || (AttributeNames = {})); class ElasticsearchInstrumentation extends instrumentation_1.InstrumentationBase { constructor(config = {}) { super('splunk-opentelemetry-instrumentation-elasticsearch', version_1.VERSION, config); this._isEnabled = false; } init() { const apiModuleFiles = helpers_1.ELASTICSEARCH_API_FILES.map(({ path, operationClassName }) => new instrumentation_1.InstrumentationNodeModuleFile(`@elastic/elasticsearch/api/${path}`, ['>=5 <8'], (moduleExports, moduleVersion) => { api_1.diag.debug(`elasticsearch instrumentation: patch elasticsearch ${operationClassName}.`); this.moduleVersion = moduleVersion; this._isEnabled = true; const modulePrototypeKeys = Object.keys(moduleExports.prototype); if (modulePrototypeKeys.length > 0) { modulePrototypeKeys.forEach((functionName) => { this._wrap(moduleExports.prototype, functionName, this.wrappedApiRequest(operationClassName, functionName)); }); return moduleExports; } // For versions <= 7.9.0 const instrumentation = this; return function (opts) { const module = moduleExports(opts); instrumentation.patchObject(operationClassName, module); return module; }; }, (moduleExports) => { api_1.diag.debug(`elasticsearch instrumentation: unpatch elasticsearch.`); this._isEnabled = false; const modulePrototypeKeys = Object.keys(moduleExports.prototype); if (modulePrototypeKeys.length > 0) { modulePrototypeKeys.forEach((functionName) => { this._unwrap(moduleExports.prototype, functionName); }); } else { // Unable to unwrap function for versions <= 7.9.0. Using _isEnabled flag instead. } })); const module = new instrumentation_1.InstrumentationNodeModuleDefinition(ElasticsearchInstrumentation.component, ['*'], undefined, undefined, apiModuleFiles); return module; } // eslint-disable-next-line @typescript-eslint/no-explicit-any patchObject(operationClassName, object) { Object.keys(object).forEach((functionName) => { if (typeof object[functionName] === 'object') { this.patchObject(functionName, object[functionName]); } else { this._wrap(object, functionName, this.wrappedApiRequest(operationClassName, functionName)); } }); } wrappedApiRequest(apiClassName, functionName) { return (original) => { const instrumentation = this; return function (...args) { if (!instrumentation._isEnabled) { return original.apply(this, args); } const [params, options, originalCallback] = (0, utils_1.normalizeArguments)(args[0], args[1], args[2]); const operation = `${apiClassName}.${functionName}`; const span = (0, utils_1.startSpan)({ tracer: instrumentation.tracer, attributes: { [semantic_conventions_1.SemanticAttributes.DB_OPERATION]: operation, [AttributeNames.ELASTICSEARCH_INDICES]: (0, utils_1.getIndexName)(params), [semantic_conventions_1.SemanticAttributes.DB_STATEMENT]: (instrumentation._config.dbStatementSerializer || utils_1.defaultDbStatementSerializer)(operation, params, options), }, }); instrumentation._addModuleVersionIfNeeded(span); if (originalCallback) { const wrappedCallback = function (err, result) { if (err) { (0, utils_1.onError)(span, err); } else { (0, utils_1.onResponse)(span, result, instrumentation._config.responseHook); } return originalCallback.call(this, err, result); }; return instrumentation._callOriginalFunction(span, () => original.call(this, params, options, wrappedCallback)); } else { const promise = instrumentation._callOriginalFunction(span, () => original.apply(this, args)); promise.then((result) => { (0, utils_1.onResponse)(span, result, instrumentation._config.responseHook); return result; }, (err) => { (0, utils_1.onError)(span, err); return err; }); return promise; } }; }; } _callOriginalFunction(span, originalFunction) { var _a; if ((_a = this._config) === null || _a === void 0 ? void 0 : _a.suppressInternalInstrumentation) { return api_1.context.with((0, core_1.suppressTracing)(api_1.context.active()), originalFunction); } else { const activeContextWithSpan = api_1.trace.setSpan(api_1.context.active(), span); return api_1.context.with(activeContextWithSpan, originalFunction); } } _addModuleVersionIfNeeded(span) { if (this.moduleVersion === undefined) { return; } if (this._config.moduleVersionAttributeName) { span.setAttribute(this._config.moduleVersionAttributeName, this.moduleVersion); } } } exports.ElasticsearchInstrumentation = ElasticsearchInstrumentation; ElasticsearchInstrumentation.component = '@elastic/elasticsearch'; //# sourceMappingURL=elasticsearch.js.map