@opentelemetry/propagator-ot-trace
Version:
The OpenTelemetry OTTracepropagator implements the propagation format used by the "basic tracer" implementations from the OpenTracing project
102 lines • 4.44 kB
JavaScript
/*
* 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.OTTracePropagator = exports.OT_BAGGAGE_PREFIX = exports.OT_SAMPLED_HEADER = exports.OT_SPAN_ID_HEADER = exports.OT_TRACE_ID_HEADER = void 0;
const api_1 = require("@opentelemetry/api");
/** OT header keys */
exports.OT_TRACE_ID_HEADER = 'ot-tracer-traceid';
exports.OT_SPAN_ID_HEADER = 'ot-tracer-spanid';
exports.OT_SAMPLED_HEADER = 'ot-tracer-sampled';
exports.OT_BAGGAGE_PREFIX = 'ot-baggage-';
const FIELDS = [exports.OT_TRACE_ID_HEADER, exports.OT_SPAN_ID_HEADER, exports.OT_SAMPLED_HEADER];
const PADDING = '0'.repeat(16);
function readHeader(carrier, getter, key) {
let header = getter.get(carrier, key);
if (Array.isArray(header))
[header] = header;
return header || '';
}
const VALID_HEADER_NAME_CHARS = /^[\^_`a-zA-Z\-0-9!#$%&'*+.|~]+$/;
function isValidHeaderName(name) {
return VALID_HEADER_NAME_CHARS.test(name);
}
const INVALID_HEADER_VALUE_CHARS = /[^\t\x20-\x7e\x80-\xff]/;
function isValidHeaderValue(value) {
return !INVALID_HEADER_VALUE_CHARS.test(value);
}
/**
* Propagator for the ot-trace HTTP format from OpenTracing.
*/
class OTTracePropagator {
inject(context, carrier, setter) {
const spanContext = api_1.trace.getSpan(context)?.spanContext();
if (!spanContext || !(0, api_1.isSpanContextValid)(spanContext))
return;
setter.set(carrier, exports.OT_TRACE_ID_HEADER, spanContext.traceId.substring(16));
setter.set(carrier, exports.OT_SPAN_ID_HEADER, spanContext.spanId);
setter.set(carrier, exports.OT_SAMPLED_HEADER, (spanContext.traceFlags & api_1.TraceFlags.SAMPLED) === api_1.TraceFlags.SAMPLED
? 'true'
: 'false');
const baggage = api_1.propagation.getBaggage(context);
if (!baggage)
return;
baggage.getAllEntries().forEach(([k, v]) => {
if (!isValidHeaderName(k) || !isValidHeaderValue(v.value))
return;
setter.set(carrier, `${exports.OT_BAGGAGE_PREFIX}${k}`, v.value);
});
}
extract(context, carrier, getter) {
let traceId = readHeader(carrier, getter, exports.OT_TRACE_ID_HEADER);
if (traceId.length === 16)
traceId = `${PADDING}${traceId}`;
const spanId = readHeader(carrier, getter, exports.OT_SPAN_ID_HEADER);
const sampled = readHeader(carrier, getter, exports.OT_SAMPLED_HEADER);
const traceFlags = sampled === 'true' ? 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,
}));
let baggage = api_1.propagation.getBaggage(context) || api_1.propagation.createBaggage();
getter.keys(carrier).forEach(k => {
if (!k.startsWith(exports.OT_BAGGAGE_PREFIX))
return;
const value = readHeader(carrier, getter, k);
baggage = baggage.setEntry(k.substring(exports.OT_BAGGAGE_PREFIX.length), {
value,
});
});
if (baggage.getAllEntries().length > 0) {
context = api_1.propagation.setBaggage(context, baggage);
}
}
return context;
}
/**
* Note: fields does not include baggage headers as they are dependent on
* carrier instance. Attempting to reuse a carrier by clearing fields could
* result in a memory leak.
*/
fields() {
return FIELDS.slice();
}
}
exports.OTTracePropagator = OTTracePropagator;
//# sourceMappingURL=OTTracePropagator.js.map
;