UNPKG

@cap-js-community/event-queue

Version:

An event queue that enables secure transactional processing of asynchronous and periodic events, featuring instant event processing with Redis Pub/Sub and load distribution across all application instances.

114 lines (99 loc) 3.08 kB
"use strict"; const _resilientRequire = (module) => { try { return require(module); } catch { // ignore } }; const cds = require("@sap/cds"); const otel = _resilientRequire("@opentelemetry/api"); const config = require("../config"); const COMPONENT_NAME = "/shared/openTelemetry"; const trace = async (context, label, fn, { attributes = {}, newRootSpan = false, traceContext } = {}) => { if (!config.enableTelemetry || !otel) { return fn(); } const tracerProvider = otel.trace.getTracerProvider(); if ((!tracerProvider || tracerProvider === otel.trace.NOOP_TRACER_PROVIDER) && !process.env.DT_NODE_PRELOAD_OPTIONS) { return fn(); } const tracer = otel.trace.getTracer("@cap-js-community/event-queue"); const extractedContext = traceContext ? otel.propagation.extract(otel.context.active(), traceContext) : otel.context.active(); const span = tracer.startSpan( `eventqueue-${label}`, { kind: otel.SpanKind.INTERNAL, root: newRootSpan, }, extractedContext ); _setAttributes(context, span, attributes); const ctxWithSpan = otel.trace.setSpan(extractedContext, span); return await _startOtelTrace(ctxWithSpan, traceContext, span, fn); }; const _startOtelTrace = async (ctxWithSpan, traceContext, span, fn) => { return otel.context.with(ctxWithSpan, async () => { const onSuccess = (res) => { span.setStatus({ code: otel.SpanStatusCode.OK }); return res; }; const onFailure = (e) => { span.recordException(e); span.setStatus( Object.assign({ code: otel.SpanStatusCode.ERROR }, e.message ? { message: e.message } : undefined) ); throw e; }; const onDone = () => { try { if (span.status?.code !== otel.SpanStatusCode.UNSET && !span.ended) { span.end?.(); } } catch (err) { cds.log(COMPONENT_NAME).error("error in tracing", err, { span, }); } }; try { const res = fn(); if (res instanceof Promise) { return res.then(onSuccess).catch(onFailure).finally(onDone); } return onSuccess(res); } catch (e) { onFailure(e); } finally { onDone(); } }); }; const _setAttributes = (context, span, attributes) => { span.setAttribute("sap.tenancy.tenant_id", context.tenant); span.setAttribute("sap.correlation_id", context.id); _sanitizeAttributes(attributes); for (const attributeKey in attributes) { span.setAttribute(attributeKey, attributes[attributeKey]); } }; const _sanitizeAttributes = (attributes = {}) => { for (const attributeKey in attributes) { attributes[attributeKey] = typeof attributes[attributeKey] !== "string" ? JSON.stringify(attributes[attributeKey]) : attributes[attributeKey]; } return attributes; }; const getCurrentTraceContext = () => { if (!otel) { return null; } const carrier = {}; otel.propagation.inject(otel.context.active(), carrier); return carrier; }; module.exports = { trace, getCurrentTraceContext };