dd-trace
Version:
Datadog APM tracing client for JavaScript
171 lines (141 loc) • 4.79 kB
JavaScript
'use strict'
const Tracer = require('./opentracing/tracer')
const tags = require('../../../ext/tags')
const Scope = require('./scope')
const { isError } = require('./util')
const { setStartupLogConfig } = require('./startup-log')
const { ERROR_MESSAGE, ERROR_TYPE, ERROR_STACK } = require('../../dd-trace/src/constants')
const { DataStreamsCheckpointer, DataStreamsManager, DataStreamsProcessor } = require('./datastreams')
const { flushStartupLogs } = require('../../datadog-instrumentations/src/helpers/check-require-cache')
const log = require('./log/writer')
const SPAN_TYPE = tags.SPAN_TYPE
const RESOURCE_NAME = tags.RESOURCE_NAME
const SERVICE_NAME = tags.SERVICE_NAME
const MEASURED = tags.MEASURED
class DatadogTracer extends Tracer {
constructor (config, prioritySampler) {
super(config, prioritySampler)
this._dataStreamsProcessor = new DataStreamsProcessor(config)
this._dataStreamsManager = new DataStreamsManager(this._dataStreamsProcessor)
this.dataStreamsCheckpointer = new DataStreamsCheckpointer(this)
this._scope = new Scope()
setStartupLogConfig(config)
flushStartupLogs(log)
if (!config._isInServerlessEnvironment()) {
const storeConfig = require('./tracer_metadata')
// Keep a reference to the handle, to keep the memfd alive in memory.
// It is read by the service discovery feature.
const metadata = storeConfig(config)
if (metadata === undefined) {
log.warn('Could not store tracer configuration for service discovery')
}
this._inmem_cfg = metadata
}
}
configure (config) {
const { env, sampler } = config
this._prioritySampler.configure(env, sampler, config)
}
// todo[piochelepiotr] These two methods are not related to the tracer, but to data streams monitoring.
// They should be moved outside of the tracer in the future.
setCheckpoint (edgeTags, span, payloadSize = 0) {
return this._dataStreamsManager.setCheckpoint(edgeTags, span, payloadSize)
}
decodeDataStreamsContext (carrier) {
return this._dataStreamsManager.decodeDataStreamsContext(carrier)
}
setOffset (offsetData) {
return this._dataStreamsProcessor.setOffset(offsetData)
}
trace (name, options, fn) {
options = { childOf: this.scope().active(), ...options }
const span = this.startSpan(name, options)
addTags(span, options)
try {
if (fn.length > 1) {
return this.scope().activate(span, () => fn(span, err => {
addError(span, err)
span.finish()
}))
}
const result = this.scope().activate(span, () => fn(span))
if (result && typeof result.then === 'function') {
return result.then(
value => {
span.finish()
return value
},
err => {
addError(span, err)
span.finish()
throw err
}
)
}
span.finish()
return result
} catch (e) {
addError(span, e)
span.finish()
throw e
}
}
wrap (name, options, fn) {
const tracer = this
return function () {
let optionsObj = options
if (typeof optionsObj === 'function' && typeof fn === 'function') {
optionsObj = optionsObj.apply(this, arguments)
}
const lastArgId = arguments.length - 1
const cb = arguments[lastArgId]
if (typeof cb === 'function') {
const scopeBoundCb = tracer.scope().bind(cb)
return tracer.trace(name, optionsObj, (span, done) => {
arguments[lastArgId] = function (err) {
done(err)
return scopeBoundCb.apply(this, arguments)
}
return fn.apply(this, arguments)
})
}
return tracer.trace(name, optionsObj, () => fn.apply(this, arguments))
}
}
setUrl (url) {
this._exporter.setUrl(url)
this._dataStreamsProcessor.setUrl(url)
}
scope () {
return this._scope
}
getRumData () {
if (!this._enableGetRumData) {
return ''
}
const span = this.scope().active().context()
const traceId = span.toTraceId()
const traceTime = Date.now()
return `\
<meta name="dd-trace-id" content="${traceId}" />\
<meta name="dd-trace-time" content="${traceTime}" />`
}
}
function addError (span, error) {
if (isError(error)) {
span.addTags({
[ERROR_TYPE]: error.name,
[ERROR_MESSAGE]: error.message,
[ERROR_STACK]: error.stack
})
}
}
function addTags (span, options) {
const tags = {}
if (options.type) tags[SPAN_TYPE] = options.type
if (options.service) tags[SERVICE_NAME] = options.service
if (options.resource) tags[RESOURCE_NAME] = options.resource
tags[MEASURED] = options.measured
span.addTags(tags)
}
module.exports = DatadogTracer