UNPKG

dd-trace

Version:

Datadog APM tracing client for JavaScript

164 lines (135 loc) 4.41 kB
'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) } 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 = Object.assign({ 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 } ) } else { 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) }) } else { 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