elastic-apm-node
Version:
The official Elastic APM agent for Node.js
151 lines (119 loc) • 3.54 kB
JavaScript
/*
* Copyright Elasticsearch B.V. and other contributors where applicable.
* Licensed under the BSD 2-Clause License; you may not use this file except in
* compliance with the BSD 2-Clause License.
*/
'use strict';
const otel = require('@opentelemetry/api');
const agent = require('../..');
const { OUTCOME_UNKNOWN } = require('../constants');
const { traceparentStrFromOTelSpanContext } = require('./otelutils');
// This class is used to handle OTel's concept of a `NonRecordingSpan` -- a
// span that is never sent/exported, but can carry SpanContext (i.e. W3C
// trace-context) that should be propagated. For a use case, see:
// "test/opentelemetry-bridge/fixtures/nonrecordingspan-parent.js"
//
// This masquerades as a Transaction on the agent's internal run-context
// tracking. Therefore it needs to support enough of Transaction's interface
// for that to work.
//
// This also needs to support enough of OTel API's `interface Span` -- mostly
// mimicking the behavior of OTel's internal `NonRecordingSpan`:
// https://github.com/open-telemetry/opentelemetry-js-api/blob/main/src/trace/NonRecordingSpan.ts
class OTelBridgeNonRecordingSpan {
constructor(otelNonRecordingSpan) {
this._spanContext = otelNonRecordingSpan.spanContext();
this.name = '';
this.type = null;
this.subtype = null;
this.action = null;
this.outcome = OUTCOME_UNKNOWN;
this.ended = false;
this.result = '';
}
get id() {
return this._spanContext.spanId;
}
get traceparent() {
return traceparentStrFromOTelSpanContext(this._spanContext);
}
get ids() {
return {
'trace.id': this._spanContext.traceId,
'transaction.id': this._spanContext.spanId,
};
}
setType() {}
setLabel(_key, _value, _stringify) {
return false;
}
addLabels(_labels, _stringify) {
return false;
}
setOutcome(_outcome) {}
startSpan() {
return null;
}
ensureParentId() {
return '';
}
// ---- private class Transaction API
// Only the parts of that API that are used on instances of this class.
createSpan() {
return null;
}
// GenericSpan#propagateTraceContextHeaders()
//
// Implementation adapted from OTel's W3CTraceContextPropagator#inject().
propagateTraceContextHeaders(carrier, setter) {
if (!carrier || !setter) {
return;
}
if (!this._spanContext || !otel.isSpanContextValid(this._spanContext)) {
return;
}
const traceparentStr = traceparentStrFromOTelSpanContext(this._spanContext);
setter(carrier, 'traceparent', traceparentStr);
if (agent._conf.useElasticTraceparentHeader) {
setter(carrier, 'elastic-apm-traceparent', traceparentStr);
}
if (this._spanContext.traceState) {
setter(carrier, 'tracestate', this._spanContext.traceState.serialize());
}
}
// ---- OTel interface Span
// Implementation adapted from opentelemetry-js-api/src/trace/NonRecordingSpan.ts
spanContext() {
return this._spanContext;
}
setAttribute(_key, _value) {
return this;
}
setAttributes(_attributes) {
return this;
}
addEvent(_name, _attributes) {
return this;
}
setStatus(_status) {
return this;
}
updateName(_name) {
return this;
}
addLink(_link) {
return this;
}
addLinks(_links) {
return this;
}
end(_endTime) {}
// isRecording always returns false for NonRecordingSpan.
isRecording() {
return false;
}
recordException(_exception, _time) {}
}
module.exports = {
OTelBridgeNonRecordingSpan,
};