🚀 Big News: Socket Acquires Coana to Bring Reachability Analysis to Every Appsec Team.Learn more
Socket
Book a DemoInstallSign in
Socket

dd-trace

Package Overview
Dependencies
Maintainers
3
Versions
640
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

dd-trace - npm Package Compare versions

Comparing version

to
0.1.2

CONTRIBUTING.md

22

package.json
{
"name": "dd-trace",
"version": "0.1.1",
"version": "0.1.2",
"description": "Datadog APM tracing client for JavaScript (experimental)",

@@ -8,5 +8,6 @@ "main": "index.js",

"bench": "node benchmark",
"lint": "eslint .",
"lint": "eslint . && node scripts/check_licenses.js",
"tdd": "mocha --watch",
"test": "nyc --reporter text --reporter lcov mocha"
"test": "nyc --reporter text --reporter lcov mocha",
"version": "genversion lib/version.js && git add lib/version.js"
},

@@ -24,3 +25,3 @@ "repository": {

],
"author": "Datadog, Inc.",
"author": "Datadog Inc. <info@datadoghq.com>",
"license": "BSD-3-Clause",

@@ -40,10 +41,17 @@ "bugs": {

"koalas": "^1.0.2",
"methods": "^1.1.2",
"msgpack-lite": "^0.1.26",
"opentracing": "^0.14.1",
"opentracing": "0.14.1",
"parent-module": "^0.1.0",
"performance-now": "^2.1.0",
"read-pkg-up": "^3.0.0",
"require-dir": "^1.0.0",
"require-in-the-middle": "^2.2.1",
"safe-buffer": "^5.1.1",
"semver": "^5.5.0",
"shimmer": "^1.2.0",
"url-parse": "^1.2.0"
},
"devDependencies": {
"axios": "^0.18.0",
"benchmark": "^2.1.4",

@@ -60,2 +68,3 @@ "bluebird": "^3.5.1",

"express": "^4.16.2",
"genversion": "^2.0.1",
"get-port": "^3.2.0",

@@ -65,4 +74,5 @@ "mocha": "^5.0.0",

"nyc": "^11.4.1",
"pg": "^6.4.2",
"proxyquire": "^1.8.0",
"semver": "^5.5.0",
"retry": "^0.10.1",
"sinon": "^4.2.1",

@@ -69,0 +79,0 @@ "sinon-chai": "^2.14.0"

# dd-trace-js
Experimental JavaScript tracer (APM)
[![npm](https://img.shields.io/npm/v/dd-trace.svg)](https://www.npmjs.com/package/dd-trace)
[![CircleCI](https://img.shields.io/circleci/project/github/DataDog/dd-trace-js.svg)](https://circleci.com/gh/DataDog/dd-trace-js/tree/master)
**Experimental JavaScript Tracer!**
This project is **experimental** and under active development. Use it at your own risk.
## Installation

@@ -16,31 +22,9 @@

### Example
Simply require and initialize the tracer and all supported
[libraries](#automatic-instrumentation) will automatically
be instrumented.
```js
const tracer = require('dd-trace').init({
service: 'example'
})
const express = require('express')
const app = express()
app.get('/hello/:name', (req, res) => {
const options = {
resource: '/hello/:name',
type: 'web',
tags: {
'span.kind': 'server',
'http.method': 'GET',
'http.url': req.url,
'http.status_code': '200'
}
}
tracer.trace('say_hello', options, span => {
res.send(`Hello, ${req.params.name}!`)
span.finish()
})
})
app.listen(3000)
// The tracer must be initialized before other libraries
const tracer = require('dd-trace').init()
```

@@ -60,4 +44,13 @@

| flushInterval | | 2000 | Interval in milliseconds at which the tracer will submit traces to the agent. |
| experimental | | {} | Experimental features can be enabled all at once using boolean `true` or individually using key/value pairs. Available experimental features: `asyncHooks`.
| experimental | | {} | Experimental features can be enabled all at once using boolean `true` or individually using key/value pairs. Available experimental features: `asyncHooks`. |
| plugins | | true | Whether or not to enable automatic instrumentation of external libraries using the built-in plugins. |
### Automatic Instrumentation
The following libraries are instrumented automatically by default:
* [http](https://nodejs.org/api/http.html)
* [express](https://expressjs.com/) (version 4)
* [pg](https://node-postgres.com/) (version 6)
### OpenTracing

@@ -80,4 +73,43 @@

**NOTE: When using OpenTracing, context propagation is not handled
automatically.**
## Advanced Usage
In some cases you may want to do manual instrumentation. For example
if there is no built-in plugin covering a library you are using or if you want more control on how instrumentation is done.
### Manual instrumentation
```js
const tracer = require('dd-trace').init()
const http = require('http')
const server = http.createServer((req, res) => {
const options = {
resource: '/hello/:name',
type: 'web',
tags: {
'span.kind': 'server',
'http.method': 'GET',
'http.url': req.url,
'http.status_code': '200'
}
}
tracer.trace('say_hello', options, span => {
res.write('Hello, World!')
span.finish()
})
res.end()
})
server.listen(8000)
```
## Development
Before contributing to this open source project, read our [CONTRIBUTING.md](https://github.com/DataDog/dd-trace-js/blob/master/CONTRIBUTING.md).
### Requirements

@@ -96,2 +128,10 @@

Before running the tests, the data stores need to be running.
The easiest way to start all of them is to use the provided
docker-compose configuration:
```sh
$ docker-compose up -d
```
To run the unit tests, use:

@@ -98,0 +138,0 @@

@@ -19,3 +19,3 @@ 'use strict'

this.debug = String(debug) === 'true'
this.service = coalesce(options.service, platform.env('DD_SERVICE_NAME'))
this.service = coalesce(options.service, platform.env('DD_SERVICE_NAME'), platform.service())
this.env = coalesce(options.env, platform.env('DD_ENV'))

@@ -28,2 +28,3 @@ this.url = new URL(`${protocol}://${hostname}:${port}`)

this.logger = options.logger
this.plugins = coalesce(options.plugins, true)
this.experimental = {

@@ -30,0 +31,0 @@ asyncHooks: isFlagEnabled(options.experimental, 'asyncHooks')

@@ -14,4 +14,4 @@ 'use strict'

extractError(formatted, span._error)
extractTags(formatted, span._tags)
extractError(formatted, span._error)

@@ -46,2 +46,8 @@ return formatted

break
case 'error.type':
case 'error.msg':
case 'error.stack':
trace.error = 1
trace.meta[tag] = tags[tag]
break
default:

@@ -55,3 +61,2 @@ trace.meta[tag] = tags[tag]

if (error) {
trace.error = 1
trace.meta['error.msg'] = error.message

@@ -58,0 +63,0 @@ trace.meta['error.type'] = error.name

'use strict'
const requireDir = require('require-dir')
const path = require('path')
const semver = require('semver')
const hook = require('require-in-the-middle')
class Instrumenter {
constructor (config) {
constructor (tracer, config) {
this._tracer = tracer
this._plugins = loadPlugins(config)
this._instrumented = new Map()
}
patch (tracer) {
this._plugins.forEach(plugin => {
plugin.patch(require(plugin.name), tracer)
})
patch () {
const instrumentedModules = this._plugins.map(plugin => plugin.name)
hook(instrumentedModules, this.hookModule.bind(this))
}
unpatch (tracer) {
this._plugins.forEach(plugin => {
plugin.unpatch(require(plugin.name), tracer)
unpatch () {
this._instrumented.forEach((instrumentation, moduleExports) => {
instrumentation.unpatch(moduleExports)
})
}
hookModule (moduleExports, moduleName, moduleBaseDir) {
const moduleVersion = getVersion(moduleBaseDir)
this._plugins
.filter(plugin => plugin.name === moduleName)
.filter(plugin => matchVersion(moduleVersion, plugin.versions))
.forEach(plugin => {
plugin.patch(moduleExports, this._tracer)
this._instrumented.set(moduleExports, plugin)
})
return moduleExports
}
}

@@ -38,2 +56,13 @@

function matchVersion (version, ranges) {
return !version || (ranges && ranges.some(range => semver.satisfies(version, range)))
}
function getVersion (moduleBaseDir) {
if (moduleBaseDir) {
const packageJSON = path.join(moduleBaseDir, 'package.json')
return require(packageJSON).version
}
}
module.exports = Instrumenter

@@ -20,2 +20,3 @@ 'use strict'

this._service = config.service
this._url = config.url
this._recorder = new Recorder(config.url, config.flushInterval, config.bufferSize)

@@ -22,0 +23,0 @@ this._recorder.init()

'use strict'
const cls = require('cls-hooked')
const clsBluebird = require('./cls_bluebird')
const namespace = cls.createNamespace('dd-trace')
clsBluebird(namespace)
module.exports = namespace
'use strict'
const cls = require('continuation-local-storage')
const clsBluebird = require('./cls_bluebird')
const namespace = cls.createNamespace('dd-trace')
clsBluebird(namespace)
module.exports = namespace
'use strict'
const clsBluebird = require('cls-bluebird')
module.exports = config => {

@@ -14,5 +12,3 @@ let namespace

clsBluebird(namespace)
return namespace
}

@@ -6,2 +6,4 @@ 'use strict'

const env = require('./env')
const load = require('./load')
const service = require('./service')
const request = require('./request')

@@ -12,5 +14,10 @@ const context = require('./context')

module.exports = {
name: () => 'nodejs',
version: () => process.version,
engine: () => process.jsEngine || 'v8',
id,
now,
env,
load,
service,
request,

@@ -17,0 +24,0 @@ context,

@@ -7,11 +7,18 @@ 'use strict'

const Config = require('./config')
const platform = require('./platform')
const noop = new NoopTracer()
let tracer = noop
class TracerProxy extends Tracer {
constructor () {
super()
this._tracer = noop
}
init (options) {
if (tracer === noop) {
if (this._tracer === noop) {
platform.load()
const config = new Config(options)
tracer = new DatadogTracer(config)
this._tracer = new DatadogTracer(config)
}

@@ -23,27 +30,27 @@

trace () {
return tracer.trace.apply(tracer, arguments)
return this._tracer.trace.apply(this._tracer, arguments)
}
startSpan () {
return tracer.startSpan.apply(tracer, arguments)
return this._tracer.startSpan.apply(this._tracer, arguments)
}
inject () {
return tracer.inject.apply(tracer, arguments)
return this._tracer.inject.apply(this._tracer, arguments)
}
extract () {
return tracer.extract.apply(tracer, arguments)
return this._tracer.extract.apply(this._tracer, arguments)
}
currentSpan () {
return tracer.currentSpan.apply(tracer, arguments)
return this._tracer.currentSpan.apply(this._tracer, arguments)
}
bind () {
return tracer.bind.apply(tracer, arguments)
return this._tracer.bind.apply(this._tracer, arguments)
}
bindEmitter () {
return tracer.bindEmitter.apply(tracer, arguments)
return this._tracer.bindEmitter.apply(this._tracer, arguments)
}

@@ -50,0 +57,0 @@ }

@@ -5,2 +5,3 @@ 'use strict'

const Tracer = require('./opentracing/tracer')
const Instrumenter = require('./instrumenter')

@@ -12,2 +13,4 @@ class DatadogTracer extends Tracer {

this._context = platform.context(config)
this._instrumenter = new Instrumenter(this, config)
this._instrumenter.patch()
}

@@ -22,3 +25,3 @@

this._context.run(() => {
const childOf = this._context.get('current')
const childOf = options.childOf || this._context.get('current')
const tags = Object.assign({

@@ -25,0 +28,0 @@ 'service.name': options.service || this._service,

@@ -7,2 +7,3 @@ 'use strict'

const encode = require('./encode')
const tracerVersion = require('../lib/version')

@@ -46,3 +47,8 @@ class Writer {

headers: {
'Content-Type': 'application/msgpack'
'Content-Type': 'application/msgpack',
'Datadog-Meta-Lang': platform.name(),
'Datadog-Meta-Lang-Version': platform.version(),
'Datadog-Meta-Lang-Interpreter': platform.engine(),
'Datadog-Meta-Tracer-Version': tracerVersion,
'X-Datadog-Trace-Count': String(this._queue.length)
},

@@ -49,0 +55,0 @@ data

@@ -5,16 +5,14 @@ 'use strict'

let Config
let platform
beforeEach(() => {
Config = require('../src/config')
})
platform = {
env: sinon.stub(),
service: sinon.stub()
}
platform.service.returns('test')
afterEach(() => {
delete process.env.DD_TRACE_AGENT_HOSTNAME
delete process.env.DD_TRACE_AGENT_PORT
delete process.env.DD_TRACE_ENABLED
delete process.env.DD_TRACE_DEBUG
delete process.env.DD_SERVICE_NAME
delete process.env.DD_ENV
Config = require('../src/config')
Config = proxyquire('../src/config', {
'./platform': platform
})
})

@@ -25,2 +23,3 @@

expect(config).to.have.property('service', 'test')
expect(config).to.have.property('enabled', true)

@@ -35,11 +34,12 @@ expect(config).to.have.property('debug', false)

expect(config).to.have.deep.property('tags', {})
expect(config).to.have.property('plugins', true)
})
it('should initialize from environment variables', () => {
process.env.DD_TRACE_AGENT_HOSTNAME = 'agent'
process.env.DD_TRACE_AGENT_PORT = '6218'
process.env.DD_TRACE_ENABLED = 'false'
process.env.DD_TRACE_DEBUG = 'true'
process.env.DD_SERVICE_NAME = 'service'
process.env.DD_ENV = 'test'
platform.env.withArgs('DD_TRACE_AGENT_HOSTNAME').returns('agent')
platform.env.withArgs('DD_TRACE_AGENT_PORT').returns('6218')
platform.env.withArgs('DD_TRACE_ENABLED').returns('false')
platform.env.withArgs('DD_TRACE_DEBUG').returns('true')
platform.env.withArgs('DD_SERVICE_NAME').returns('service')
platform.env.withArgs('DD_ENV').returns('test')

@@ -68,3 +68,4 @@ const config = new Config()

tags,
flushInterval: 5000
flushInterval: 5000,
plugins: false
})

@@ -80,12 +81,13 @@

expect(config).to.have.deep.property('tags', tags)
expect(config).to.have.deep.property('flushInterval', 5000)
expect(config).to.have.property('flushInterval', 5000)
expect(config).to.have.property('plugins', false)
})
it('should give priority to the options', () => {
process.env.DD_TRACE_AGENT_HOSTNAME = 'agent'
process.env.DD_TRACE_AGENT_PORT = '6218'
process.env.DD_TRACE_ENABLED = 'false'
process.env.DD_TRACE_DEBUG = 'true'
process.env.DD_SERVICE_NAME = 'service'
process.env.DD_ENV = 'test'
platform.env.withArgs('DD_TRACE_AGENT_HOSTNAME').returns('agent')
platform.env.withArgs('DD_TRACE_AGENT_PORT').returns('6218')
platform.env.withArgs('DD_TRACE_ENABLED').returns('false')
platform.env.withArgs('DD_TRACE_DEBUG').returns('true')
platform.env.withArgs('DD_SERVICE_NAME').returns('service')
platform.env.withArgs('DD_ENV').returns('test')

@@ -92,0 +94,0 @@ const config = new Config({

'use strict'
const tracer = require('../')
const express = require('express')

@@ -12,2 +11,3 @@ const bodyParser = require('body-parser')

describe('dd-trace', () => {
let tracer
let agent

@@ -17,10 +17,13 @@ let listener

beforeEach(() => {
tracer = require('../')
return getPort().then(port => {
agent = express()
listener = agent.listen(port, 'localhost')
listener = agent.listen()
tracer.init({
service: 'test',
port,
flushInterval: 10
port: listener.address().port,
flushInterval: 10,
plugins: false
})

@@ -32,2 +35,3 @@ })

listener.close()
delete require.cache[require.resolve('../')]
})

@@ -34,0 +38,0 @@

@@ -87,3 +87,13 @@ 'use strict'

})
it('should set the error flag when there is an error tag', () => {
span._tags['error.type'] = 'Error'
span._tags['error.msg'] = 'boom'
span._tags['error.stack'] = ''
trace = format(span)
expect(trace.error).to.equal(1)
})
})
})

@@ -9,19 +9,17 @@ 'use strict'

let integrations
let config
let tracer
let requireDir
let foo
let bar
beforeEach(() => {
foo = 'foo'
bar = 'bar'
tracer = 'tracer'
integrations = {
foo: {
name: 'foo',
http: {
name: 'http',
patch: sinon.spy(),
unpatch: sinon.spy()
},
bar: {
name: 'bar',
express: {
name: 'express',
versions: ['4.x'],
patch: sinon.spy(),

@@ -36,5 +34,3 @@ unpatch: sinon.spy()

Instrumenter = proxyquire('../src/instrumenter', {
'require-dir': requireDir,
'foo': foo,
'bar': bar
'require-dir': requireDir
})

@@ -45,25 +41,41 @@ })

beforeEach(() => {
config = { plugins: true }
instrumenter = new Instrumenter(config)
instrumenter = new Instrumenter(tracer, { plugins: true })
})
describe('patch', () => {
it('should patch all modules', () => {
const tracer = 'tracer'
it('should patch modules from node_modules when they are loaded', () => {
instrumenter.patch()
instrumenter.patch(tracer)
const express = require('express')
expect(integrations.foo.patch).to.have.been.calledWith(foo, tracer)
expect(integrations.bar.patch).to.have.been.calledWith(bar, tracer)
expect(integrations.express.patch).to.have.been.calledWith(express, tracer)
})
it('should only patch a module if its version is supported by the plugin ', () => {
integrations.express.versions = ['^3.0.0']
instrumenter.patch()
const express = require('express')
expect(integrations.express.patch).to.not.have.been.calledWith(express, tracer)
})
it('should patch native modules when they are loaded', () => {
instrumenter.patch()
const http = require('http')
expect(integrations.http.patch).to.have.been.calledWith(http, tracer)
})
})
describe('unpatch', () => {
it('should unpatch all modules', () => {
const tracer = 'tracer'
it('should unpatch patched modules', () => {
instrumenter.patch()
instrumenter.unpatch(tracer)
const express = require('express')
expect(integrations.foo.unpatch).to.have.been.calledWith(foo, tracer)
expect(integrations.bar.unpatch).to.have.been.calledWith(bar, tracer)
instrumenter.unpatch()
expect(integrations.express.unpatch).to.have.been.calledWith(express)
})

@@ -75,4 +87,3 @@ })

beforeEach(() => {
config = { plugins: false }
instrumenter = new Instrumenter(config)
instrumenter = new Instrumenter(tracer, { plugins: false })
})

@@ -82,22 +93,10 @@

it('should not patch any module', () => {
const tracer = 'tracer'
instrumenter.patch()
instrumenter.patch(tracer)
const express = require('express')
expect(integrations.foo.patch).to.not.have.been.called
expect(integrations.bar.patch).to.not.have.been.called
expect(integrations.express.patch).to.not.have.been.calledWith(express, tracer)
})
})
describe('unpatch', () => {
it('should not unpatch any module', () => {
const tracer = 'tracer'
instrumenter.unpatch(tracer)
expect(integrations.foo.unpatch).to.not.have.been.called
expect(integrations.bar.unpatch).to.not.have.been.called
})
})
})
})

@@ -9,2 +9,52 @@ 'use strict'

describe('Node', () => {
let platform
describe('name', () => {
beforeEach(() => {
platform = require('../../../src/platform/node')
})
it('should return nodejs', () => {
expect(platform.name()).to.equal('nodejs')
})
})
describe('version', () => {
beforeEach(() => {
platform = require('../../../src/platform/node')
})
it('should return the process version', () => {
const version = platform.version()
expect(version).to.be.a('string')
expect(semver.eq(version, semver.valid(version))).to.be.true
})
})
describe('engine', () => {
let realEngine
beforeEach(() => {
platform = require('../../../src/platform/node')
realEngine = process.jsEngine
})
afterEach(() => {
process.jsEngine = realEngine
})
it('should return the correct engine for Chakra', () => {
process.jsEngine = 'chakracore'
expect(platform.engine()).to.equal('chakracore')
})
it('should return the correct engine for V8', () => {
delete process.jsEngine
expect(platform.engine()).to.equal('v8')
})
})
describe('id', () => {

@@ -72,2 +122,27 @@ let id

describe('load', () => {
let service
beforeEach(() => {
platform = require('../../../src/platform/node')
service = platform._service
})
afterEach(() => {
platform._service = service
})
it('should load the service name from the user module', () => {
require('./load/direct')
expect(platform._service).to.equal('foo')
})
it('should work even in subfolders', () => {
require('./load/indirect')
expect(platform._service).to.have.equal('foo')
})
})
describe('request', () => {

@@ -232,4 +307,8 @@ let request

let cls
let clsBluebird
let config
beforeEach(() => {
clsBluebird = sinon.spy(require('cls-bluebird'))
require.cache[require.resolve('cls-bluebird')].exports = clsBluebird
context = require('../../../src/platform/node/context')

@@ -239,5 +318,3 @@ })

afterEach(() => {
delete require.cache[require.resolve('../../../src/platform/node/context')]
delete require.cache[require.resolve('bluebird')]
delete require.cache[require.resolve('cls-bluebird')]
cls.destroyNamespace('dd-trace')
})

@@ -247,39 +324,31 @@

beforeEach(() => {
cls = require('../../../src/platform/node/context/cls')
cls = require('continuation-local-storage')
config = { experimental: { asyncHooks: false } }
namespace = context(config)
})
afterEach(() => {
delete require.cache[require.resolve('../../../src/platform/node/context/cls')]
})
it('should use the correct implementation from the experimental flag', () => {
expect(context({ experimental: { asyncHooks: false } })).to.equal(cls)
})
testContext({ experimental: { asyncHooks: false } })
testContext('../../../src/platform/node/context/cls')
})
if (semver.gte(semver.valid(process.version), '8.2.0')) {
beforeEach(() => {
cls = require('../../../src/platform/node/context/cls_hooked')
})
afterEach(() => {
delete require.cache[require.resolve('../../../src/platform/node/context/cls_hooked')]
})
describe('cls-hooked', () => {
it('should use the correct implementation from the experimental flag', () => {
expect(context({ experimental: { asyncHooks: true } })).to.equal(cls)
beforeEach(() => {
cls = require('cls-hooked')
config = { experimental: { asyncHooks: true } }
namespace = context(config)
})
testContext({ experimental: { asyncHooks: true } })
testContext('../../../src/platform/node/context/cls_hooked')
})
}
function testContext (config) {
beforeEach(() => {
namespace = context(config)
function testContext (modulePath) {
afterEach(() => {
delete require.cache[require.resolve(modulePath)]
})
it('should use the correct implementation from the experimental flag', () => {
expect(namespace).to.equal(require(modulePath))
})
describe('get/set', () => {

@@ -378,2 +447,15 @@ it('should store a value', done => {

})
it('should only patch bluebird once', () => {
context(config)
expect(clsBluebird).to.not.have.been.called
})
it('should skip patching bluebird on error', () => {
clsBluebird = proxyquire('../src/platform/node/context/cls_bluebird', {
'cls-bluebird': () => { throw new Error() }
})
expect(() => clsBluebird(namespace)).to.not.throw()
})
}

@@ -380,0 +462,0 @@ })

@@ -12,2 +12,3 @@ 'use strict'

let config
let platform

@@ -41,6 +42,11 @@ beforeEach(() => {

platform = {
load: sinon.spy()
}
Proxy = proxyquire('../src/proxy', {
'./tracer': DatadogTracer,
'./noop': NoopTracer,
'./config': Config
'./config': Config,
'./platform': platform
})

@@ -66,2 +72,10 @@

it('should load the platform', () => {
const options = {}
proxy.init(options)
expect(platform.load).to.have.been.called
})
it('should not initialize twice', () => {

@@ -68,0 +82,0 @@ proxy.init()

@@ -8,5 +8,15 @@ 'use strict'

const nock = require('nock')
const retry = require('retry')
const pg = require('pg')
const platform = require('../src/platform')
const node = require('../src/platform/node')
const retryOptions = {
retries: 10,
factor: 1,
minTimeout: 1000,
maxTimeout: 1000,
randomize: false
}
chai.use(sinonChai)

@@ -20,1 +30,45 @@

platform.use(node)
waitForServices()
.then(run)
.catch(err => {
setImmediate(() => { throw err })
})
function waitForServices () {
return Promise.all([
waitForPostgres()
])
}
function waitForPostgres () {
return new Promise((resolve, reject) => {
const operation = retry.operation(retryOptions)
operation.attempt(currentAttempt => {
const client = new pg.Client({
user: 'postgres',
password: 'postgres',
database: 'postgres',
application_name: 'test'
})
client.connect((err) => {
if (operation.retry(err)) return
if (err) return reject(err)
client.query('SELECT version()', (err, result) => {
if (operation.retry(err)) return
if (err) return reject(err)
client.end((err) => {
if (operation.retry(err)) return
if (err) return reject(err)
resolve()
})
})
})
})
})
}
'use strict'
const Span = require('../src/opentracing/span')
const SpanContext = require('../src/opentracing/span_context')
const Config = require('../src/config')

@@ -12,2 +13,4 @@ const platform = require('../src/platform')

let config
let instrumenter
let Instrumenter

@@ -20,3 +23,10 @@ beforeEach(() => {

Tracer = require('../src/tracer')
instrumenter = {
patch: sinon.spy()
}
Instrumenter = sinon.stub().returns(instrumenter)
Tracer = proxyquire('../src/tracer', {
'./instrumenter': Instrumenter
})
})

@@ -29,2 +39,9 @@

it('should setup automatic instrumentation', () => {
tracer = new Tracer(config)
expect(Instrumenter).to.have.been.calledWith(tracer)
expect(instrumenter.patch).to.have.been.called
})
describe('trace', () => {

@@ -100,2 +117,17 @@ it('should run the callback with the new span', done => {

})
it('should support a custom parent span', done => {
const childOf = new SpanContext({
traceId: 1234,
spanId: 5678
})
tracer = new Tracer(config)
tracer.trace('name', { childOf }, current => {
expect(current.context().traceId).to.equal(childOf.traceId)
expect(current.context().parentId).to.equal(childOf.spanId)
done()
})
})
})

@@ -102,0 +134,0 @@

@@ -25,2 +25,5 @@ 'use strict'

platform = {
name: sinon.stub(),
version: sinon.stub(),
engine: sinon.stub(),
request: sinon.stub().returns(Promise.resolve()),

@@ -49,3 +52,4 @@ msgpack: {

'./format': format,
'./encode': encode
'./encode': encode,
'../lib/version': 'tracerVersion'
})

@@ -103,2 +107,5 @@ writer = new Writer(url, 3)

platform.msgpack.prefix.withArgs(['encoded', 'encoded']).returns('prefixed')
platform.name.returns('lang')
platform.version.returns('version')
platform.engine.returns('interpreter')

@@ -116,3 +123,8 @@ writer.append(span)

headers: {
'Content-Type': 'application/msgpack'
'Content-Type': 'application/msgpack',
'Datadog-Meta-Lang': 'lang',
'Datadog-Meta-Lang-Version': 'version',
'Datadog-Meta-Lang-Interpreter': 'interpreter',
'Datadog-Meta-Tracer-Version': 'tracerVersion',
'X-Datadog-Trace-Count': '2'
},

@@ -119,0 +131,0 @@ data: 'prefixed'

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet