UNPKG

dd-trace

Version:

Datadog APM tracing client for JavaScript

218 lines (167 loc) 5.57 kB
'use strict' const web = require('../../dd-trace/src/plugins/util/web') const shimmer = require('../../datadog-shimmer') const analyticsSampler = require('../../dd-trace/src/analytics_sampler') const tags = require('../../../ext/tags') const types = require('../../../ext/types') const kinds = require('../../../ext/kinds') const WEB = types.WEB const SERVER = kinds.SERVER const RESOURCE_NAME = tags.RESOURCE_NAME const SERVICE_NAME = tags.SERVICE_NAME const SPAN_TYPE = tags.SPAN_TYPE const SPAN_KIND = tags.SPAN_KIND const HTTP_METHOD = tags.HTTP_METHOD const HTTP_URL = tags.HTTP_URL const HTTP_STATUS_CODE = tags.HTTP_STATUS_CODE const HTTP_ROUTE = tags.HTTP_ROUTE const HTTP_REQUEST_HEADERS = tags.HTTP_REQUEST_HEADERS const HTTP_RESPONSE_HEADERS = tags.HTTP_RESPONSE_HEADERS const MANUAL_DROP = tags.MANUAL_DROP const HTTP_STATUS_OK = 200 const HTTP2_HEADER_AUTHORITY = ':authority' const HTTP2_HEADER_SCHEME = ':scheme' const HTTP2_HEADER_METHOD = ':method' const HTTP2_HEADER_PATH = ':path' const HTTP2_HEADER_STATUS = ':status' function createWrapEmit (tracer, config) { return function wrapEmit (emit) { return function emitWithTrace (event, arg1, arg2) { if (event === 'stream') { const stream = arg1 const headers = arg2 return instrumentStream(tracer, config, stream, headers, 'http.request', () => { return emit.apply(this, arguments) }) } else if (event === 'request') { const req = arg1 const res = arg2 return web.instrument(tracer, config, req, res, 'http.request', () => { return emit.apply(this, arguments) }) } else { return emit.apply(this, arguments) } } } } function createWrapCreateServer (tracer, config) { config = web.normalizeConfig(config) return function wrapCreateServer (createServer) { return function createServerWithTrace (args) { const server = createServer.apply(this, arguments) shimmer.wrap(server, 'emit', createWrapEmit(tracer, config)) return server } } } function instrumentStream (tracer, config, stream, headers, name, callback) { if (!stream) return callback() headers = headers || {} web.patch(stream) const span = startStreamSpan(tracer, config, stream, headers, name) if (!config.filter(headers[HTTP2_HEADER_PATH])) { span.setTag(MANUAL_DROP, true) } if (config.service) { span.setTag(SERVICE_NAME, config.service) } analyticsSampler.sample(span, config.measured, true) wrapStreamEnd(stream) addRequestTags(stream, headers) addRequestHeaders(stream, headers) addResourceTags(stream, headers) return callback && tracer.scope().activate(span, () => callback(span)) } function startStreamSpan (tracer, config, stream, headers, name) { stream._datadog.config = config if (stream._datadog.span) { return stream._datadog.span } const span = web.startChildSpan(tracer, name, headers) stream._datadog.tracer = tracer stream._datadog.span = span return span } function wrapStreamEnd (stream) { function wrapEnd (end) { return function endWithTrace () { const returnValue = end.apply(this, arguments) finishStream(stream) return returnValue } } shimmer.wrap(stream, 'end', wrapEnd) } function finishStream (stream) { if (stream._datadog.finished) return addResponseTags(stream) addResponseHeaders(stream) stream._datadog.span.finish() stream._datadog.finished = true } function addRequestTags (stream, headers) { const span = stream._datadog.span const url = `${headers[HTTP2_HEADER_SCHEME]}://${headers[HTTP2_HEADER_AUTHORITY]}${headers[HTTP2_HEADER_PATH]}` span.addTags({ [HTTP_METHOD]: headers[HTTP2_HEADER_METHOD], [HTTP_URL]: url.split('?')[0], [SPAN_KIND]: SERVER, [SPAN_TYPE]: WEB }) } function addRequestHeaders (stream, headers) { if (!headers) return const span = stream._datadog.span stream._datadog.config.headers.forEach(key => { const reqHeader = headers[key] if (reqHeader) { span.setTag(`${HTTP_REQUEST_HEADERS}.${key}`, reqHeader) } }) } function addResponseTags (stream) { const span = stream._datadog.span const headers = stream.sentHeaders const statusCode = headers[HTTP2_HEADER_STATUS] span.addTags({ [HTTP_STATUS_CODE]: statusCode | 0 || HTTP_STATUS_OK }) web.addStatusError(stream, statusCode) } function addResponseHeaders (stream) { if (!stream.sentHeaders) return const span = stream._datadog.span stream._datadog.config.headers.forEach(key => { const resHeader = stream.sentHeaders && stream.sentHeaders[key] if (resHeader) { span.setTag(`${HTTP_RESPONSE_HEADERS}.${key}`, resHeader) } }) } function addResourceTags (stream, headers) { const span = stream._datadog.span const tags = span.context()._tags const method = headers[HTTP2_HEADER_METHOD] if (tags[RESOURCE_NAME]) return const resource = [method] .concat(tags[HTTP_ROUTE]) .filter(val => val) .join(' ') span.setTag(RESOURCE_NAME, resource) } module.exports = [ { name: 'http2', patch (http2, tracer, config) { if (config.server === false) return this.wrap(http2, 'createServer', createWrapCreateServer(tracer, config)) this.wrap(http2, 'createSecureServer', createWrapCreateServer(tracer, config)) }, unpatch (http2) { this.unwrap(http2, 'createServer') this.unwrap(http2, 'createSecureServer') } } ] module.exports = [] // temporarily disable HTTP2 server plugin