dd-trace
Version:
Datadog APM tracing client for JavaScript
151 lines (127 loc) • 4.56 kB
JavaScript
'use strict'
const os = require('os')
const SpanProcessor = require('../span_processor')
const PrioritySampler = require('../priority_sampler')
const formats = require('../../../../ext/formats')
const log = require('../log')
const runtimeMetrics = require('../runtime_metrics')
const getExporter = require('../exporter')
const Span = require('./span')
const TextMapPropagator = require('./propagation/text_map')
const DSMTextMapPropagator = require('./propagation/text_map_dsm')
const HttpPropagator = require('./propagation/http')
const BinaryPropagator = require('./propagation/binary')
const LogPropagator = require('./propagation/log')
const SpanContext = require('./span_context')
const REFERENCE_CHILD_OF = 'child_of'
const REFERENCE_FOLLOWS_FROM = 'follows_from'
class DatadogTracer {
constructor (config, prioritySampler, exporter) {
this._config = config
this._service = config.service
this._version = config.version
this._env = config.env
this._logInjection = config.logInjection
this._debug = config.debug
this._prioritySampler = prioritySampler ?? new PrioritySampler(config.env, config.sampler)
if (exporter) {
this._exporter = exporter
} else {
const Exporter = getExporter(config.experimental.exporter)
this._exporter = new Exporter(config, this._prioritySampler)
}
this._processor = new SpanProcessor(this._exporter, this._prioritySampler, config)
this._url = this._exporter._url
this._enableGetRumData = config.experimental.enableGetRumData
this._traceId128BitGenerationEnabled = config.traceId128BitGenerationEnabled
this._propagators = {
[formats.TEXT_MAP]: new TextMapPropagator(config),
[formats.HTTP_HEADERS]: new HttpPropagator(config),
[formats.BINARY]: new BinaryPropagator(config),
[formats.LOG]: new LogPropagator(config),
[formats.TEXT_MAP_DSM]: new DSMTextMapPropagator(config),
}
if (config.reportHostname) {
this._hostname = os.hostname()
}
}
startSpan (name, options = {}) {
const parent = options.childOf
? getContext(options.childOf)
: getParent(options.references)
// as per spec, allow the setting of service name through options
const tags = {
'service.name': options?.tags?.service ? String(options.tags.service) : this._service,
}
// As per unified service tagging spec if a span is created with a service name different from the global
// service name it will not inherit the global version value
if (options?.tags?.service && options.tags.service !== this._service) {
options.tags.version = undefined
}
const span = new Span(this, this._processor, this._prioritySampler, {
operationName: options.operationName || name,
parent,
tags,
startTime: options.startTime,
hostname: this._hostname,
traceId128BitGenerationEnabled: this._traceId128BitGenerationEnabled,
integrationName: options.integrationName,
links: options.links,
}, this._debug)
span.addTags(this._config.tags)
span.addTags(options.tags)
return span
}
inject (context, format, carrier) {
if (context instanceof Span) {
context = context.context()
}
try {
if (format !== 'text_map_dsm' && format !== formats.LOG) {
this._prioritySampler.sample(context)
}
this._propagators[format].inject(context, carrier)
} catch (e) {
log.error('Error injecting trace', e)
runtimeMetrics.increment('datadog.tracer.node.inject.errors', true)
}
}
extract (format, carrier) {
try {
return this._propagators[format].extract(carrier)
} catch (e) {
log.error('Error extracting trace', e)
runtimeMetrics.increment('datadog.tracer.node.extract.errors', true)
return null
}
}
}
/**
* Get the span context from a span or a span context.
*
* @param {Span|SpanContext} spanContext
* @returns {SpanContext}
*/
function getContext (spanContext) {
if (spanContext instanceof Span) {
spanContext = spanContext.context()
}
if (!(spanContext instanceof SpanContext)) {
spanContext = null
}
return spanContext
}
function getParent (references = []) {
let parent = null
for (const ref of references) {
const type = ref.type()
if (type === REFERENCE_CHILD_OF) {
parent = ref.referencedContext()
break
} else if (type === REFERENCE_FOLLOWS_FROM && !parent) {
parent = ref.referencedContext()
}
}
return parent
}
module.exports = DatadogTracer