Skip to content

Commit

Permalink
v0.8.0 (#430)
Browse files Browse the repository at this point in the history
* v0.8.0

* prefix span context properties with an underscore (#397)

* add log propagator and trace identifiers for log correlation (#396)

* fix baggage items at the span level instead of trace level (#398)

* add middleware and stack trace support for express (#399)

* add dns integration (#405)

* add net integration (#406)

* add trace search sampling configuration (#407)

* add more metadata to net.connect and update operation name (#409)

* add automatic log correlation of tracer identifiers for winston (#408)

* add automatic log correlation of trace identifiers for bunyan (#410)

* add noop span context with the correct API (#413)

* add automatic log correlation of tracer identifiers for pino (#414)

* add automatic log correlation of tracer identifiers for pino

* add missing plugins to the build

* Add protocol as a configuration option for the dd-trace-agent URL (#416)

* Add protocol as a configuration option for the dd-trace agent URL.

This is useful for scenarios where a SSL-terminating load balancer sits in front of the datadog-agent

* Fix lint errors

* Switching from protocol override to url override per CR

* Fixing missing comma from previous commit

* Fix tests

* overrideUrl -> url

* add support for latest module versions in all plugins (#417)

* fix using log correlation with a custom logger (#419)

* disable net and dns plugins (#421)

* fix http server response handlers not running in the request scope (#422)

* fix log injection with a null active span and update injection keys (#423)

* Revert "add trace search sampling configuration (#407)" (#425)

This reverts commit 4dac394.

* add documentation about enabling log correlation (#427)

* fix references to the old trace IDs (#426)

* fix noop span context trace IDs to match the backend expectation (#429)
  • Loading branch information
rochdev authored Feb 6, 2019
1 parent b2d587c commit c8c49dc
Show file tree
Hide file tree
Showing 77 changed files with 2,406 additions and 315 deletions.
30 changes: 30 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,14 @@ jobs:
- SERVICES=
- PLUGINS=bluebird

node-bunyan:
<<: *node-plugin-base
docker:
- image: node:8
environment:
- SERVICES=
- PLUGINS=bunyan

node-elasticsearch:
<<: *node-plugin-base
docker:
Expand Down Expand Up @@ -243,6 +251,14 @@ jobs:
- MONGODB_REPLICA_SET_MODE=primary
- MONGODB_ADVERTISED_HOSTNAME=localhost

node-pino:
<<: *node-plugin-base
docker:
- image: node:8
environment:
- SERVICES=
- PLUGINS=pino

node-postgres:
<<: *node-plugin-base
docker:
Expand Down Expand Up @@ -293,6 +309,14 @@ jobs:
- SERVICES=
- PLUGINS=when

node-winston:
<<: *node-plugin-base
docker:
- image: node:8
environment:
- SERVICES=
- PLUGINS=winston

workflows:
version: 2
build:
Expand All @@ -307,6 +331,7 @@ workflows:
- node-amqplib
- node-amqp10
- node-bluebird
- node-bunyan
- node-elasticsearch
- node-express
- node-graphql
Expand All @@ -316,11 +341,13 @@ workflows:
- node-memcached
- node-mongodb-core
- node-mysql
- node-pino
- node-postgres
- node-q
- node-redis
- node-restify
- node-when
- node-winston
nightly:
triggers:
- schedule:
Expand All @@ -338,6 +365,7 @@ workflows:
- node-amqplib
- node-amqp10
- node-bluebird
- node-bunyan
- node-elasticsearch
- node-express
- node-graphql
Expand All @@ -347,8 +375,10 @@ workflows:
- node-memcached
- node-mongodb-core
- node-mysql
- node-pino
- node-postgres
- node-q
- node-redis
- node-restify
- node-when
- node-winston
1 change: 1 addition & 0 deletions LICENSE-3rdparty.csv
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require,lodash.pick,MIT,Copyright JS Foundation and other contributors
require,lodash.truncate,MIT,Copyright JS Foundation and other contributors
require,lodash.uniq,MIT,Copyright JS Foundation and other contributors
require,methods,MIT,Copyright 2013-2014 TJ Holowaychuk 2013-2014 TJ Holowaychuk
require,module-details-from-path,MIT,Copyright 2016 Thomas Watson Steen
require,msgpack-lite,MIT,Copyright 2015 Yusuke Kawasaki
require,opentracing,MIT,Copyright 2016 Resonance Labs Inc
require,parent-module,MIT,Copyright Sindre Sorhus
Expand Down
2 changes: 2 additions & 0 deletions docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -387,9 +387,11 @@ Options can be configured as a parameter to the [init()](https://datadog.github.
| enabled | DD_TRACE_ENABLED | true | Whether to enable the tracer. |
| debug | DD_TRACE_DEBUG | false | Enable debug logging in the tracer. |
| service | DD_SERVICE_NAME | | The service name to be used for this program. |
| url | DD_TRACE_AGENT_URL | | The url of the trace agent that the tracer will submit to. Takes priority over hostname and port, if set. |
| hostname | DD_TRACE_AGENT_HOSTNAME | localhost | The address of the trace agent that the tracer will submit to. |
| port | DD_TRACE_AGENT_PORT | 8126 | The port of the trace agent that the tracer will submit to. |
| env | DD_ENV | | Set an application’s environment e.g. `prod`, `pre-prod`, `stage`. |
| logInjection | DD_LOGS_INJECTION | false | Enable automatic injection of trace IDs in logs for supported logging libraries.
| tags | | {} | Set global tags that should be applied to all spans. |
| sampleRate | | 1 | Percentage of spans to sample as a float between 0 and 1. |
| flushInterval | | 2000 | Interval in milliseconds at which the tracer will submit traces to the agent. |
Expand Down
10 changes: 10 additions & 0 deletions ext/formats.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
'use strict'

const opentracing = require('opentracing')

module.exports = {
TEXT_MAP: opentracing.FORMAT_TEXT_MAP,
HTTP_HEADERS: opentracing.FORMAT_HTTP_HEADERS,
BINARY: opentracing.FORMAT_BINARY,
LOG: 'log'
}
4 changes: 3 additions & 1 deletion ext/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

const priority = require('./priority')
const tags = require('./tags')
const formats = require('./formats')

module.exports = {
priority,
tags
tags,
formats
}
2 changes: 1 addition & 1 deletion lib/version.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
module.exports = '0.7.3'
module.exports = '0.8.0'
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "dd-trace",
"version": "0.7.3",
"version": "0.8.0",
"description": "Datadog APM tracing client for JavaScript",
"main": "index.js",
"scripts": {
Expand Down Expand Up @@ -46,6 +46,7 @@
"lodash.truncate": "^4.4.2",
"lodash.uniq": "^4.5.0",
"methods": "^1.1.2",
"module-details-from-path": "^1.0.3",
"msgpack-lite": "^0.1.26",
"opentracing": "0.14.1",
"parent-module": "^0.1.0",
Expand Down
5 changes: 4 additions & 1 deletion src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ class Config {

const enabled = coalesce(options.enabled, platform.env('DD_TRACE_ENABLED'), true)
const debug = coalesce(options.debug, platform.env('DD_TRACE_DEBUG'), false)
const logInjection = coalesce(options.logInjection, platform.env('DD_LOGS_INJECTION'), false)
const env = coalesce(options.env, platform.env('DD_ENV'))
const url = coalesce(options.url, platform.env('DD_TRACE_AGENT_URL'), null)
const protocol = 'http'
const hostname = coalesce(
options.hostname,
Expand All @@ -25,8 +27,9 @@ class Config {

this.enabled = String(enabled) === 'true'
this.debug = String(debug) === 'true'
this.logInjection = String(logInjection) === 'true'
this.env = env
this.url = new URL(`${protocol}://${hostname}:${port}`)
this.url = url ? new URL(url) : new URL(`${protocol}://${hostname}:${port}`)
this.tags = Object.assign({}, options.tags)
this.flushInterval = flushInterval
this.bufferSize = 100000
Expand Down
22 changes: 11 additions & 11 deletions src/format.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ function formatSpan (span) {
const spanContext = span.context()

return {
trace_id: spanContext.traceId,
span_id: spanContext.spanId,
parent_id: spanContext.parentId,
name: String(spanContext.name),
resource: String(spanContext.name),
trace_id: spanContext._traceId,
span_id: spanContext._spanId,
parent_id: spanContext._parentId,
name: String(spanContext._name),
resource: String(spanContext._name),
error: 0,
meta: {},
metrics: {},
Expand All @@ -39,7 +39,7 @@ function formatSpan (span) {
}

function extractTags (trace, span) {
const tags = span.context().tags
const tags = span.context()._tags

Object.keys(tags).forEach(tag => {
switch (tag) {
Expand Down Expand Up @@ -78,14 +78,14 @@ function extractError (trace, span) {
function extractMetrics (trace, span) {
const spanContext = span.context()

Object.keys(spanContext.metrics).forEach(metric => {
if (typeof spanContext.metrics[metric] === 'number') {
trace.metrics[metric] = spanContext.metrics[metric]
Object.keys(spanContext._metrics).forEach(metric => {
if (typeof spanContext._metrics[metric] === 'number') {
trace.metrics[metric] = spanContext._metrics[metric]
}
})

if (spanContext.sampling.priority !== undefined) {
trace.metrics[SAMPLING_PRIORITY_KEY] = spanContext.sampling.priority
if (spanContext._sampling.priority !== undefined) {
trace.metrics[SAMPLING_PRIORITY_KEY] = spanContext._sampling.priority
}
}

Expand Down
112 changes: 101 additions & 11 deletions src/instrumenter.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

const semver = require('semver')
const hook = require('require-in-the-middle')
const parse = require('module-details-from-path')
const path = require('path')
const shimmer = require('shimmer')
const uniq = require('lodash.uniq')
Expand Down Expand Up @@ -79,17 +80,28 @@ class Instrumenter {
if (typeof nodule[name] !== 'function') {
throw new Error(`Expected object ${nodule} to contain method ${name}.`)
}

Object.defineProperty(nodule[name], '_datadog_patched', {
value: true,
configurable: true
})
})
})

return shimmer.massWrap.call(this, nodules, names, wrapper)
shimmer.massWrap.call(this, nodules, names, wrapper)
}

unwrap (nodules, names, wrapper) {
nodules = [].concat(nodules)
names = [].concat(names)

return shimmer.massUnwrap.call(this, nodules, names, wrapper)
shimmer.massUnwrap.call(this, nodules, names, wrapper)

nodules.forEach(nodule => {
names.forEach(name => {
nodule[name] && delete nodule[name]._datadog_patched
})
})
}

hookModule (moduleExports, moduleName, moduleBaseDir) {
Expand All @@ -109,7 +121,7 @@ class Instrumenter {
.filter(plugin => [].concat(plugin).some(instrumentation =>
filename(instrumentation) === moduleName && matchVersion(moduleVersion, instrumentation.versions)
))
.forEach(plugin => this._validate(plugin, moduleBaseDir))
.forEach(plugin => this._validate(plugin, moduleBaseDir, moduleVersion))

this._plugins
.forEach((meta, plugin) => {
Expand All @@ -118,8 +130,7 @@ class Instrumenter {
.filter(instrumentation => moduleName === filename(instrumentation))
.filter(instrumentation => matchVersion(moduleVersion, instrumentation.versions))
.forEach(instrumentation => {
this._instrumented.set(instrumentation, moduleExports)
instrumentation.patch.call(this, moduleExports, this._tracer._tracer, this._plugins.get(plugin).config)
this._patch(instrumentation, moduleExports, this._plugins.get(plugin).config)
})
} catch (e) {
log.error(e)
Expand All @@ -136,14 +147,18 @@ class Instrumenter {
}

_set (plugin, meta) {
this._plugins.set(plugin, Object.assign({ config: {} }, meta))
meta = Object.assign({ config: {} }, meta)

this._plugins.set(plugin, meta)
this._load(plugin, meta)
}

_validate (plugin, moduleBaseDir) {
_validate (plugin, moduleBaseDir, moduleVersion) {
const meta = this._plugins.get(plugin)
const instrumentations = [].concat(plugin)

for (let i = 0; i < instrumentations.length; i++) {
if (instrumentations[i].versions && !matchVersion(moduleVersion, instrumentations[i].versions)) continue
if (instrumentations[i].file && !exists(moduleBaseDir, instrumentations[i].file)) {
this._fail(plugin)
log.debug([
Expand All @@ -165,15 +180,90 @@ class Instrumenter {
this._plugins.delete(plugin)
}

_patch (instrumentation, moduleExports, config) {
let instrumented = this._instrumented.get(instrumentation)

if (!instrumented) {
this._instrumented.set(instrumentation, instrumented = new Set())
}

if (!instrumented.has(moduleExports)) {
instrumented.add(moduleExports)
instrumentation.patch.call(this, moduleExports, this._tracer._tracer, config)
}
}

_unpatch (instrumentation) {
try {
instrumentation.unpatch.call(this, this._instrumented.get(instrumentation))
} catch (e) {
log.error(e)
const instrumented = this._instrumented.get(instrumentation)

if (instrumented) {
instrumented.forEach(moduleExports => {
try {
instrumentation.unpatch.call(this, moduleExports)
} catch (e) {
log.error(e)
}
})
}
}

_load (plugin, meta) {
if (this._enabled) {
const instrumentations = [].concat(plugin)

try {
instrumentations
.forEach(instrumentation => {
getModules(instrumentation).forEach(nodule => {
this._patch(instrumentation, nodule, meta.config)
})
})
} catch (e) {
log.error(e)
this._fail(plugin)
log.debug(`Error while trying to patch ${meta.name}. The plugin has been disabled.`)
}
}
}
}

function getModules (instrumentation) {
const modules = []
const ids = Object.keys(require.cache)

let pkg

for (let i = 0, l = ids.length; i < l; i++) {
const id = ids[i].replace(pathSepExpr, '/')

if (!id.includes(`/node_modules/${instrumentation.name}/`)) continue

if (instrumentation.file) {
if (!id.endsWith(`/node_modules/${filename(instrumentation)}`)) continue

const basedir = getBasedir(ids[i])

pkg = require(`${basedir}/package.json`)
} else {
const basedir = getBasedir(ids[i])

pkg = require(`${basedir}/package.json`)

if (!id.endsWith(`/node_modules/${instrumentation.name}/${pkg.main}`)) continue
}

if (!matchVersion(pkg.version, instrumentation.versions)) continue

modules.push(require.cache[ids[i]].exports)
}

return modules
}

function getBasedir (id) {
return parse(id).basedir.replace(pathSepExpr, '/')
}

function matchVersion (version, ranges) {
return !version || (ranges && ranges.some(range => semver.satisfies(version, range)))
}
Expand Down
Loading

0 comments on commit c8c49dc

Please sign in to comment.