UNPKG

@sentry/node

Version:

Sentry Node SDK using OpenTelemetry for performance instrumentation

238 lines (234 loc) 9.32 kB
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); const instrumentation = require('@opentelemetry/instrumentation'); const attributes = require('@sentry/conventions/attributes'); const core = require('@sentry/core'); const semconv = require('./semconv.js'); const utils = require('./utils.js'); const PACKAGE_NAME = "@sentry/instrumentation-kafkajs"; class KafkaJsInstrumentation extends instrumentation.InstrumentationBase { constructor(config = {}) { super(PACKAGE_NAME, core.SDK_VERSION, config); } init() { const unpatch = (moduleExports) => { if (instrumentation.isWrapped(moduleExports?.Kafka?.prototype.producer)) { this._unwrap(moduleExports.Kafka.prototype, "producer"); } if (instrumentation.isWrapped(moduleExports?.Kafka?.prototype.consumer)) { this._unwrap(moduleExports.Kafka.prototype, "consumer"); } }; const module = new instrumentation.InstrumentationNodeModuleDefinition( "kafkajs", [">=0.3.0 <3"], (moduleExports) => { unpatch(moduleExports); this._wrap(moduleExports?.Kafka?.prototype, "producer", this._getProducerPatch()); this._wrap(moduleExports?.Kafka?.prototype, "consumer", this._getConsumerPatch()); return moduleExports; }, unpatch ); return module; } _getConsumerPatch() { const instrumentation$1 = this; return (original) => { return function consumer(...args) { const newConsumer = original.apply(this, args); if (instrumentation.isWrapped(newConsumer.run)) { instrumentation$1._unwrap(newConsumer, "run"); } instrumentation$1._wrap(newConsumer, "run", instrumentation$1._getConsumerRunPatch()); return newConsumer; }; }; } _getProducerPatch() { const instrumentation$1 = this; return (original) => { return function consumer(...args) { const newProducer = original.apply(this, args); if (instrumentation.isWrapped(newProducer.sendBatch)) { instrumentation$1._unwrap(newProducer, "sendBatch"); } instrumentation$1._wrap(newProducer, "sendBatch", instrumentation$1._getSendBatchPatch()); if (instrumentation.isWrapped(newProducer.send)) { instrumentation$1._unwrap(newProducer, "send"); } instrumentation$1._wrap(newProducer, "send", instrumentation$1._getSendPatch()); if (instrumentation.isWrapped(newProducer.transaction)) { instrumentation$1._unwrap(newProducer, "transaction"); } instrumentation$1._wrap(newProducer, "transaction", instrumentation$1._getProducerTransactionPatch()); return newProducer; }; }; } _getConsumerRunPatch() { const instrumentation$1 = this; return (original) => { return function run(...args) { const config = args[0]; if (config?.eachMessage) { if (instrumentation.isWrapped(config.eachMessage)) { instrumentation$1._unwrap(config, "eachMessage"); } instrumentation$1._wrap(config, "eachMessage", instrumentation$1._getConsumerEachMessagePatch()); } if (config?.eachBatch) { if (instrumentation.isWrapped(config.eachBatch)) { instrumentation$1._unwrap(config, "eachBatch"); } instrumentation$1._wrap(config, "eachBatch", instrumentation$1._getConsumerEachBatchPatch()); } return original.call(this, config); }; }; } _getConsumerEachMessagePatch() { return (original) => { return function eachMessage(...args) { const payload = args[0]; const sentryTrace = utils.getHeaderAsString(payload.message.headers, "sentry-trace"); const baggage = utils.getHeaderAsString(payload.message.headers, "baggage"); return core.continueTrace({ sentryTrace, baggage }, () => { const span = utils.startConsumerSpan({ topic: payload.topic, message: payload.message, operationType: semconv.MESSAGING_OPERATION_TYPE_VALUE_PROCESS, attributes: { [semconv.ATTR_MESSAGING_DESTINATION_PARTITION_ID]: String(payload.partition) } }); const eachMessagePromise = core.withActiveSpan(span, () => { return original.apply(this, args); }); return utils.endSpansOnPromise([span], eachMessagePromise); }); }; }; } _getConsumerEachBatchPatch() { return (original) => { return function eachBatch(...args) { const payload = args[0]; const receivingSpan = core.startNewTrace( () => utils.startConsumerSpan({ topic: payload.batch.topic, message: void 0, operationType: semconv.MESSAGING_OPERATION_TYPE_VALUE_RECEIVE, attributes: { [attributes.MESSAGING_BATCH_MESSAGE_COUNT]: payload.batch.messages.length, [semconv.ATTR_MESSAGING_DESTINATION_PARTITION_ID]: String(payload.batch.partition) } }) ); return core.withActiveSpan(receivingSpan, () => { const spans = [receivingSpan]; payload.batch.messages.forEach((message) => { spans.push( utils.startConsumerSpan({ topic: payload.batch.topic, message, operationType: semconv.MESSAGING_OPERATION_TYPE_VALUE_PROCESS, links: utils.getLinksFromHeaders(message.headers), attributes: { [semconv.ATTR_MESSAGING_DESTINATION_PARTITION_ID]: String(payload.batch.partition) } }) ); }); const batchMessagePromise = original.apply(this, args); return utils.endSpansOnPromise(spans, batchMessagePromise); }); }; }; } _getProducerTransactionPatch() { const instrumentation = this; return (original) => { return function transaction(...args) { const transactionSpan = core.startInactiveSpan({ name: "transaction" }); const transactionPromise = original.apply(this, args); transactionPromise.then((transaction2) => { const originalSend = transaction2.send; transaction2.send = function send(...args2) { return core.withActiveSpan(transactionSpan, () => { const patched = instrumentation._getSendPatch()(originalSend); return patched.apply(this, args2).catch((err) => { transactionSpan.setStatus({ code: core.SPAN_STATUS_ERROR, message: err?.message }); throw err; }); }); }; const originalSendBatch = transaction2.sendBatch; transaction2.sendBatch = function sendBatch(...args2) { return core.withActiveSpan(transactionSpan, () => { const patched = instrumentation._getSendBatchPatch()(originalSendBatch); return patched.apply(this, args2).catch((err) => { transactionSpan.setStatus({ code: core.SPAN_STATUS_ERROR, message: err?.message }); throw err; }); }); }; const originalCommit = transaction2.commit; transaction2.commit = function commit(...args2) { const originCommitPromise = originalCommit.apply(this, args2).then(() => { transactionSpan.setStatus({ code: core.SPAN_STATUS_OK }); }); return utils.endSpansOnPromise([transactionSpan], originCommitPromise); }; const originalAbort = transaction2.abort; transaction2.abort = function abort(...args2) { const originAbortPromise = originalAbort.apply(this, args2); return utils.endSpansOnPromise([transactionSpan], originAbortPromise); }; }).catch((err) => { transactionSpan.setStatus({ code: core.SPAN_STATUS_ERROR, message: err?.message }); transactionSpan.end(); }); return transactionPromise; }; }; } _getSendBatchPatch() { return (original) => { return function sendBatch(...args) { const batch = args[0]; const messages = batch.topicMessages || []; const spans = []; messages.forEach((topicMessage) => { topicMessage.messages.forEach((message) => { spans.push(utils.startProducerSpan(topicMessage.topic, message)); }); }); const origSendResult = original.apply(this, args); return utils.endSpansOnPromise(spans, origSendResult); }; }; } _getSendPatch() { return (original) => { return function send(...args) { const record = args[0]; const spans = record.messages.map((message) => { return utils.startProducerSpan(record.topic, message); }); const origSendResult = original.apply(this, args); return utils.endSpansOnPromise(spans, origSendResult); }; }; } } exports.KafkaJsInstrumentation = KafkaJsInstrumentation; //# sourceMappingURL=instrumentation.js.map