UNPKG

@opentelemetry/propagator-instana

Version:

The OpenTelemetry Instana Propagator implements the propagation format used by IBM Observability by Instana

98 lines 4.38 kB
"use strict"; /* * Copyright The OpenTelemetry Authors * * 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 * * https://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. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.InstanaPropagator = exports.INSTANA_LEVEL_HEADER = exports.INSTANA_SPAN_ID_HEADER = exports.INSTANA_TRACE_ID_HEADER = void 0; const api_1 = require("@opentelemetry/api"); /** Instana header names */ exports.INSTANA_TRACE_ID_HEADER = 'X-INSTANA-T'; exports.INSTANA_SPAN_ID_HEADER = 'X-INSTANA-S'; exports.INSTANA_LEVEL_HEADER = 'X-INSTANA-L'; const FIELDS = [ exports.INSTANA_TRACE_ID_HEADER, exports.INSTANA_SPAN_ID_HEADER, exports.INSTANA_LEVEL_HEADER, ]; function readHeader(carrier, getter, key) { // By convention, X-INSTANA-* headers are sent all-upper-case. For http and http/2, Node.js normalizes all headers to // all-lower-case, that's why we first read via the lower case variant of the header name. For other protocols, no // such normalization happens, so we also need to read via the original all-upper-case variant. let header = getter.get(carrier, key.toLowerCase()) || getter.get(carrier, key); if (Array.isArray(header)) [header] = header; return header || ''; } /** * Propagator for the Instana HTTP headers. */ class InstanaPropagator { /** * Injects the current span context into Instana's vendor specific trace correlation headers (X-INSTANA-T, X-INSTANA-S * and X-INSTANA-L). */ inject(context, carrier, setter) { const spanContext = api_1.trace.getSpan(context)?.spanContext(); if (!spanContext || !(0, api_1.isSpanContextValid)(spanContext)) { return; } setter.set(carrier, exports.INSTANA_TRACE_ID_HEADER, spanContext.traceId); setter.set(carrier, exports.INSTANA_SPAN_ID_HEADER, spanContext.spanId); const sampled = (spanContext.traceFlags & api_1.TraceFlags.SAMPLED) === api_1.TraceFlags.SAMPLED; setter.set(carrier, exports.INSTANA_LEVEL_HEADER, sampled ? '1' : '0'); } /** * Extracts the span context from Instana's vendor specific trace correlation headers (X-INSTANA-T, X-INSTANA-S * and X-INSTANA-L). */ extract(context, carrier, getter) { let traceId = readHeader(carrier, getter, exports.INSTANA_TRACE_ID_HEADER); if (traceId && traceId.length < 32) { traceId = traceId.padStart(32, '0'); } let spanId = readHeader(carrier, getter, exports.INSTANA_SPAN_ID_HEADER); if (spanId && spanId.length < 16) { spanId = spanId.padStart(16, '0'); } const level = readHeader(carrier, getter, exports.INSTANA_LEVEL_HEADER) || '1'; const sampled = level !== '0'; const traceFlags = sampled ? api_1.TraceFlags.SAMPLED : api_1.TraceFlags.NONE; if ((0, api_1.isValidTraceId)(traceId) && (0, api_1.isValidSpanId)(spanId)) { context = api_1.trace.setSpan(context, api_1.trace.wrapSpanContext({ traceId, spanId, isRemote: true, traceFlags, })); } else if (!sampled) { // Even if we do not receive a trace ID/span ID via X-INSTANA-T/X-INSTANA-S, if there is an explicit incoming // X-INSTANA-L=0, we want to capture that via trace flags. For Instana tracers, it is perfectly valid to send // X-INSTANA-L=0 without X-INSTANA-T/-S. context = api_1.trace.setSpan(context, api_1.trace.wrapSpanContext({ traceId: api_1.INVALID_TRACEID, spanId: api_1.INVALID_SPANID, isRemote: true, traceFlags, })); } return context; } fields() { return FIELDS.slice(); } } exports.InstanaPropagator = InstanaPropagator; //# sourceMappingURL=InstanaPropagator.js.map