@sentry/node
Version:
Sentry Node SDK using OpenTelemetry for performance instrumentation
135 lines (131 loc) • 5.45 kB
JavaScript
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const attributes = require('@sentry/conventions/attributes');
const core = require('@sentry/core');
const DROPPED_ATTRIBUTES = /* @__PURE__ */ new Set([
// BullMQ sets these to `JSON.stringify()` output. They are left out until Sentry attributes support objects.
"bullmq.job.options",
"bullmq.job.progress",
"bullmq.queue.options",
"bullmq.worker.options",
// BullMQ deprecated this for `bullmq.job.attempt_finished_timestamp`, which it sets on the same spans.
"bullmq.job.finished.timestamp"
]);
const MESSAGING_BULLMQ_KEYS = /* @__PURE__ */ new Map([
["bullmq.flow.name", attributes.MESSAGING_BULLMQ_FLOW_NAME],
["bullmq.job.attempt_finished_timestamp", attributes.MESSAGING_BULLMQ_JOB_ATTEMPT_FINISHED_TIMESTAMP],
["bullmq.job.bulk.names", attributes.MESSAGING_BULLMQ_JOB_BULK_NAMES],
["bullmq.job.deduplication.key", attributes.MESSAGING_BULLMQ_JOB_DEDUPLICATION_KEY],
["bullmq.job.ids", attributes.MESSAGING_BULLMQ_JOB_IDS],
["bullmq.job.key", attributes.MESSAGING_BULLMQ_JOB_KEY],
["bullmq.job.name", attributes.MESSAGING_BULLMQ_JOB_NAME],
["bullmq.job.processed.timestamp", attributes.MESSAGING_BULLMQ_JOB_PROCESSED_TIMESTAMP],
["bullmq.job.scheduler.id", attributes.MESSAGING_BULLMQ_JOB_SCHEDULER_ID],
["bullmq.job.type", attributes.MESSAGING_BULLMQ_JOB_TYPE],
["bullmq.queue.clean.count", attributes.MESSAGING_BULLMQ_QUEUE_CLEAN_COUNT],
["bullmq.queue.clean.limit", attributes.MESSAGING_BULLMQ_QUEUE_CLEAN_LIMIT],
["bullmq.queue.drain.delay", attributes.MESSAGING_BULLMQ_QUEUE_DRAIN_DELAY],
["bullmq.queue.event.max.length", attributes.MESSAGING_BULLMQ_QUEUE_EVENT_MAX_LENGTH],
["bullmq.queue.grace", attributes.MESSAGING_BULLMQ_QUEUE_GRACE],
["bullmq.queue.jobs.state", attributes.MESSAGING_BULLMQ_QUEUE_JOBS_STATE],
["bullmq.queue.rate.limit", attributes.MESSAGING_BULLMQ_QUEUE_RATE_LIMIT],
["bullmq.worker.do.not.wait.active", attributes.MESSAGING_BULLMQ_WORKER_DO_NOT_WAIT_ACTIVE],
["bullmq.worker.force.close", attributes.MESSAGING_BULLMQ_WORKER_FORCE_CLOSE],
["bullmq.worker.jobs.to.extend.locks", attributes.MESSAGING_BULLMQ_WORKER_JOBS_TO_EXTEND_LOCKS],
["bullmq.worker.name", attributes.MESSAGING_BULLMQ_WORKER_NAME],
["bullmq.worker.rate.limit", attributes.MESSAGING_BULLMQ_WORKER_RATE_LIMIT],
["bullmq.worker.stalled.jobs", attributes.MESSAGING_BULLMQ_WORKER_STALLED_JOBS]
]);
function toMessagingKey(key) {
return MESSAGING_BULLMQ_KEYS.get(key) ?? (key.startsWith("bullmq.") ? `messaging.${key}` : key);
}
function toSentryAttributes(attributes$1) {
const {
"bullmq.queue.name": queueName,
"bullmq.queue.operation": operation,
"bullmq.job.id": jobId,
"bullmq.job.attempts.made": attemptsMade,
"bullmq.job.bulk.count": bulkCount,
"bullmq.worker.id": workerId,
"bullmq.job.state": jobState,
"bullmq.job.status": jobStatus,
...rest
} = attributes$1;
const result = {};
for (const [key, value] of Object.entries(rest)) {
if (!DROPPED_ATTRIBUTES.has(key)) {
result[toMessagingKey(key)] = value;
}
}
if (typeof queueName === "string") {
result[attributes.MESSAGING_DESTINATION_NAME] = queueName;
}
if (typeof operation === "string") {
result[attributes.MESSAGING_OPERATION_NAME] = operation;
}
if (jobId !== void 0) {
result[attributes.MESSAGING_MESSAGE_ID] = String(jobId);
}
if (typeof attemptsMade === "number") {
result[attributes.MESSAGING_MESSAGE_RETRY_COUNT] = Math.max(attemptsMade - 1, 0);
}
if (typeof bulkCount === "number") {
result[attributes.MESSAGING_BATCH_MESSAGE_COUNT] = bulkCount;
}
if (typeof workerId === "string") {
result[attributes.MESSAGING_CLIENT_ID] = workerId;
}
const state = jobState ?? jobStatus;
if (typeof state === "string") {
result[attributes.MESSAGING_BULLMQ_JOB_STATE] = state;
}
return result;
}
class SentryBullMQSpan {
constructor(span, scope) {
this._span = span;
this._scope = scope;
}
setAttribute(key, value) {
this.setAttributes({ [key]: value });
}
setAttributes(attributes) {
this._span.setAttributes(toSentryAttributes(attributes));
}
addEvent(name, attributes) {
this._span.addEvent(name, attributes);
if (name === "job failed") {
this._span.setStatus({ code: core.SPAN_STATUS_ERROR, message: "internal_error" });
const reason = attributes?.["bullmq.job.failed.reason"];
const error = new Error(String(reason || "Unknown error"));
error.stack = void 0;
core.captureException(error, {
mechanism: {
handled: false,
type: "auto.queue.bullmq"
}
});
}
}
/**
* Does not capture to Sentry. BullMQ calls this for Redis, lock and serialization errors that it
* retries itself, often several times for one fault. Job failures are captured in `addEvent`.
*/
recordException(exception) {
const error = exception instanceof Error ? exception : new Error(typeof exception === "string" ? exception : exception.message || "Unknown error");
this._span.recordException(error);
}
setSpanOnContext(context) {
return {
...context,
span: this._span,
scope: this._scope
};
}
end() {
this._span.end();
}
}
exports.SentryBullMQSpan = SentryBullMQSpan;
exports.toMessagingKey = toMessagingKey;
exports.toSentryAttributes = toSentryAttributes;
//# sourceMappingURL=span.js.map