Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

dd-trace

Package Overview
Dependencies
Maintainers
3
Versions
583
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 0.3.1 to 0.3.2

benchmark/benchmark.js

217

benchmark/index.js
'use strict'
const Benchmark = require('benchmark')
const Buffer = require('safe-buffer').Buffer
const EventEmitter = require('events')
const proxyquire = require('proxyquire')
const semver = require('semver')
const Uint64BE = require('int64-buffer').Uint64BE
const platform = require('../src/platform')
const node = require('../src/platform/node')
const cls = require('../src/platform/node/context/cls')
const execSync = require('child_process').execSync
const exec = cmd => execSync(cmd, { stdio: [0, 1, 2] })
platform.use(node)
const Config = require('../src/config')
const DatadogTracer = require('../src/tracer')
const DatadogSpanContext = require('../src/opentracing/span_context')
const TextMapPropagator = require('../src/opentracing/propagation/text_map')
const Writer = proxyquire('../src/writer', {
'./platform': { request: () => Promise.resolve() }
})
const Sampler = require('../src/sampler')
const format = require('../src/format')
const encode = require('../src/encode')
const config = new Config({ service: 'benchmark' })
Benchmark.options.maxTime = 0
Benchmark.options.minSamples = 5
const suite = new Benchmark.Suite()
let tracer
let spanContext
let propagator
let carrier
let writer
let sampler
let emitter
let queue
let data
const traceStub = require('./stubs/trace')
const spanStub = require('./stubs/span')
suite
.add('DatadogTracer#trace', {
onStart () {
tracer = new DatadogTracer(config)
},
fn () {
tracer.trace('bench', () => {})
}
})
.add('DatadogTracer#startSpan', {
onStart () {
tracer = new DatadogTracer(config)
},
fn () {
tracer.startSpan()
}
})
.add('TextMapPropagator#inject', {
onStart () {
propagator = new TextMapPropagator()
carrier = {}
spanContext = new DatadogSpanContext({
traceId: new Uint64BE(0x12345678, 0x12345678),
spanId: new Uint64BE(0x12345678, 0x12345678),
baggageItems: { foo: 'bar' }
})
},
fn () {
propagator.inject(spanContext, carrier)
}
})
.add('TextMapPropagator#extract', {
onStart () {
propagator = new TextMapPropagator()
carrier = {
'x-datadog-trace-id': '1234567891234567',
'x-datadog-parent-id': '1234567891234567',
'ot-baggage-foo': 'bar'
}
},
fn () {
propagator.extract(carrier)
}
})
.add('Writer#append', {
onStart () {
writer = new Writer({}, 1000000)
},
fn () {
writer.append(spanStub)
}
})
.add('Writer#flush (1000 items)', {
onStart () {
writer = new Writer({}, 1001)
for (let i = 0; i < 1000; i++) {
writer.append(spanStub)
}
queue = writer._queue
},
fn () {
writer._queue = queue
writer.flush()
}
})
.add('Sampler#isSampled', {
onStart () {
sampler = new Sampler(0.5)
},
fn () {
sampler.isSampled()
}
})
.add('format', {
fn () {
format(spanStub)
}
})
.add('encode', {
fn () {
encode(traceStub)
}
})
.add('platform#id (Node)', {
fn () {
platform.id()
}
})
.add('platform#now (Node)', {
fn () {
platform.now()
}
})
.add('platform#request (Node)', {
onStart () {
data = Buffer.alloc(1000000)
},
fn () {
platform
.request({
protocol: 'http:',
hostname: 'test',
port: '8080',
path: '/v0.3/traces',
method: 'PUT',
headers: {
'Content-Type': 'application/msgpack'
},
data
})
.catch(() => {})
}
})
.add('cls#run (Node)', {
fn () {
cls.run(() => {})
}
})
.add('cls#bind (Node)', {
fn () {
cls.bind(() => {})
}
})
.add('cls#bindEmitter (Node)', {
onStart () {
emitter = new EventEmitter()
},
fn () {
cls.bindEmitter(emitter)
}
})
.add('msgpack#prefix (Node)', {
fn () {
platform.msgpack.prefix(traceStub)
}
})
if (semver.gte(semver.valid(process.version), '8.2.0')) {
const cls = require('../src/platform/node/context/cls_hooked')
suite
.add('clsHooked#run (Node)', {
fn () {
cls.run(() => {})
}
})
.add('clsHooked#bind (Node)', {
fn () {
cls.bind(() => {})
}
})
.add('clsHooked#bindEmitter (Node)', {
onStart () {
emitter = new EventEmitter()
},
fn () {
cls.bindEmitter(emitter)
}
})
}
suite
.on('cycle', event => {
console.log(String(event.target)) // eslint-disable-line no-console
})
.on('error', event => {
console.log(String(event.target.error)) // eslint-disable-line no-console
})
.run({ 'async': true })
exec('node benchmark/core')
exec('node benchmark/platform/node')
exec('node benchmark/dd-trace')

@@ -178,2 +178,3 @@ <h1 id="home">Datadog JavaScript Tracer API</h1>

| service | *Service name of the app* | The service name for this integration. |
| validateStatus | `code => code < 500` | Callback function to determine if there was an error. It should take a status code as its only parameter and return `true` for success or `false` for errors. |

@@ -180,0 +181,0 @@ <h3 id="graphql">graphql</h3>

@@ -1,1 +0,1 @@

module.exports = '0.3.1'
module.exports = '0.3.2'
{
"name": "dd-trace",
"version": "0.3.1",
"version": "0.3.2",
"description": "Datadog APM tracing client for JavaScript (experimental)",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -97,11 +97,2 @@ 'use strict'

.forEach(instrumentation => {
const modulePath = [moduleBaseDir, instrumentation.file].filter(val => val).join('/')
if (require.cache[modulePath]) {
log.debug([
`Instrumented module "${moduleName}" was imported before calling tracer.init().`,
`Please make sure to initialize the tracer before importing any instrumented module.`
].join(' '))
}
this._instrumented.set(instrumentation, moduleExports)

@@ -108,0 +99,0 @@ instrumentation.patch.call(this, moduleExports, this._tracer._tracer, this._plugins.get(plugin).config)

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

bind (callback) {}
bind (callback) {
return callback
}

@@ -17,0 +19,0 @@ bindEmitter (emitter) {}

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

_finish (finishTime) {
finishTime = parseInt(finishTime, 10) || platform.now()
finishTime = parseFloat(finishTime) || platform.now()

@@ -86,0 +86,0 @@ this._duration = finishTime - this._startTime

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

this._recorder.init()
this._sampler = new Sampler(1)
this._sampler = new Sampler(config.sampleRate)
this._propagators = {

@@ -31,0 +31,0 @@ [opentracing.FORMAT_TEXT_MAP]: new TextMapPropagator(),

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

function createWrapMethod (tracer, config) {
const validateStatus = typeof config.validateStatus === 'function'
? config.validateStatus
: code => code < 500
function middleware (req, res, next) {

@@ -33,2 +37,4 @@ const url = `${req.protocol}://${req.get('host')}${req.originalUrl}`

span.setTag('resource.name', `${req.method} ${paths.join('')}`)
} else {
span.setTag('resource.name', req.method)
}

@@ -40,2 +46,6 @@

if (!validateStatus(res.statusCode)) {
span.setTag(Tags.ERROR, true)
}
span.finish()

@@ -42,0 +52,0 @@

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

function createWrapExecute (tracer, config, defaultFieldResolver) {
function createWrapExecute (tracer, config, defaultFieldResolver, responsePathAsArray) {
return function wrapExecute (execute) {

@@ -14,22 +14,28 @@ return function executeWithTrace () {

const fieldResolver = args.fieldResolver || defaultFieldResolver
const operation = getOperation(document)
if (!schema || !document || typeof fieldResolver !== 'function') {
if (!schema || !operation || typeof fieldResolver !== 'function') {
return execute.apply(this, arguments)
}
args.fieldResolver = wrapResolve(fieldResolver, tracer, config)
args.fieldResolver = wrapFieldResolver(fieldResolver, tracer, config, responsePathAsArray)
args.contextValue = contextValue
Object.defineProperties(contextValue, {
_datadog_operation: { value: {} },
_datadog_fields: { value: {} },
_datadog_source: { value: document._datadog_source }
})
if (!schema._datadog_patched) {
wrapFields(schema._queryType, tracer, config, responsePathAsArray)
wrapFields(schema._mutationType, tracer, config, responsePathAsArray)
if (!schema._datadog_patched) {
wrapFields(schema._queryType._fields, tracer, config, [])
schema._datadog_patched = true
}
return call(execute, this, [args], defer(tracer), () => finishOperation(contextValue))
Object.defineProperties(contextValue, {
_datadog_operation: {
value: {
span: createOperationSpan(tracer, config, operation, document._datadog_source)
}
},
_datadog_fields: { value: {} }
})
return call(execute, this, [args], defer(tracer), err => finishOperation(contextValue, err))
}

@@ -45,3 +51,3 @@ }

Object.defineProperties(document, {
_datadog_source: { value: source }
_datadog_source: { value: source.body || source }
})

@@ -54,12 +60,22 @@

function wrapFields (fields, tracer, config) {
Object.keys(fields).forEach(key => {
const field = fields[key]
function wrapFields (type, tracer, config, responsePathAsArray) {
if (!type || type._datadog_patched) {
return
}
if (typeof field.resolve === 'function') {
field.resolve = wrapResolve(field.resolve, tracer, config)
type._datadog_patched = true
Object.keys(type._fields).forEach(key => {
const field = type._fields[key]
if (typeof field.resolve === 'function' && !field.resolve._datadog_patched) {
field.resolve = wrapResolve(field.resolve, tracer, config, responsePathAsArray)
}
if (field.type && field.type._fields) {
wrapFields(field.type._fields, tracer, config)
if (field.type) {
if (field.type._fields) {
wrapFields(field.type, tracer, config, responsePathAsArray)
} else if (field.type.ofType && field.type.ofType._fields) {
wrapFields(field.type.ofType, tracer, config, responsePathAsArray)
}
}

@@ -69,6 +85,11 @@ })

function wrapResolve (resolve, tracer, config) {
return function resolveWithTrace (source, args, contextValue, info) {
const path = getPath(info.path)
const fieldParent = getFieldParent(tracer, config, contextValue, info, path)
function wrapResolve (resolve, tracer, config, responsePathAsArray) {
function resolveWithTrace (source, args, contextValue, info) {
if (!contextValue || !contextValue._datadog_fields) {
return resolve.apply(arguments)
}
const path = responsePathAsArray(info.path)
const fieldParent = getFieldParent(contextValue, path)
const childOf = createSpan('graphql.field', tracer, config, fieldParent, path)

@@ -79,3 +100,3 @@ const deferred = defer(tracer)

contextValue._datadog_fields[path] = {
contextValue._datadog_fields[path.join('.')] = {
span: childOf,

@@ -93,4 +114,18 @@ parent: fieldParent

}
resolveWithTrace._datadog_patched = true
return resolveWithTrace
}
function wrapFieldResolver (fieldResolver, tracer, config, responsePathAsArray) {
return function fieldResolverWithTrace (source, args, contextValue, info) {
if (source && typeof source[info.fieldName] === 'function') {
return wrapResolve(fieldResolver, tracer, config, responsePathAsArray).apply(this, arguments)
}
return fieldResolver.apply(this, arguments)
}
}
function call (fn, thisContext, args, deferred, callback) {

@@ -134,12 +169,12 @@ try {

function getFieldParent (tracer, config, contextValue, info, path) {
if (!contextValue._datadog_operation.span) {
contextValue._datadog_operation.span = createOperationSpan(tracer, config, contextValue, info)
}
function getFieldParent (contextValue, path) {
for (let i = path.length - 1; i > 0; i--) {
const field = getField(contextValue, path.slice(0, i))
if (path.length === 1) {
return contextValue._datadog_operation.span
if (field) {
return field.span
}
}
return contextValue._datadog_fields[path.slice(0, -1).join('.')].span
return contextValue._datadog_operation.span
}

@@ -149,3 +184,3 @@

if (args.length === 1) {
return args
return args[0]
}

@@ -164,9 +199,9 @@

function createOperationSpan (tracer, config, contextValue, info) {
const type = info.operation.operation
const name = info.operation.name && info.operation.name.value
function createOperationSpan (tracer, config, operation, source) {
const type = operation.operation
const name = operation.name && operation.name.value
let span
tracer.trace(`graphql.${info.operation.operation}`, parent => {
tracer.trace(`graphql.${operation.operation}`, parent => {
span = parent

@@ -176,4 +211,3 @@ span.addTags({

'resource.name': [type, name].filter(val => val).join(' '),
'span.type': 'custom',
'graphql.document': contextValue._datadog_source
'graphql.document': source
})

@@ -199,4 +233,3 @@ })

'service.name': getService(tracer, config),
'resource.name': path.join('.'),
'span.type': 'custom'
'resource.name': path.join('.')
})

@@ -210,8 +243,12 @@ }

for (let i = path.length - 2; i >= 0; i--) {
contextValue._datadog_fields[path[i]].finishTime = platform.now()
for (let i = path.length; i > 0; i--) {
const field = getField(contextValue, path.slice(0, i))
if (field) {
field.finishTime = platform.now()
}
}
}
function finishOperation (contextValue) {
function finishOperation (contextValue, error) {
for (const key in contextValue._datadog_fields) {

@@ -221,5 +258,11 @@ contextValue._datadog_fields[key].span.finish(contextValue._datadog_fields[key].finishTime)

addError(contextValue._datadog_operation.span, error)
contextValue._datadog_operation.span.finish()
}
function getField (contextValue, path) {
return contextValue._datadog_fields[path.join('.')]
}
function getService (tracer, config) {

@@ -229,8 +272,11 @@ return config.service || `${tracer._service}-graphql`

function getPath (path) {
if (path.prev) {
return getPath(path.prev).concat(path.key)
} else {
return [path.key]
function getOperation (document) {
if (!document || !Array.isArray(document.definitions)) {
return
}
const types = ['query', 'mutation']
const definition = document.definitions.find(def => types.indexOf(def.operation) !== -1)
return definition
}

@@ -256,3 +302,8 @@

patch (execute, tracer, config) {
this.wrap(execute, 'execute', createWrapExecute(tracer, config, execute.defaultFieldResolver))
this.wrap(execute, 'execute', createWrapExecute(
tracer,
config,
execute.defaultFieldResolver,
execute.responsePathAsArray
))
},

@@ -259,0 +310,0 @@ unpatch (execute) {

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

span.setTag('out.port', String(this.config.port))
span.setTag('span.type', 'db')
span.setTag('span.type', 'sql')
span.setTag('db.user', this.config.user)

@@ -48,2 +48,14 @@

function createWrapEnqueue (tracer, config) {
return function wrapGetEnqueue (enqueue) {
return function enqueueWithTrace (sequence) {
if (sequence._callback) {
sequence._callback = tracer.bind(sequence._callback)
}
return enqueue.apply(this, arguments)
}
}
}
function wrapCallback (tracer, span, done) {

@@ -73,2 +85,10 @@ return tracer.bind((err, res) => {

function patchProtocol (Protocol, tracer, config) {
this.wrap(Protocol.prototype, '_enqueue', createWrapEnqueue(tracer, config))
}
function unpatchProtocol (Protocol) {
this.unwrap(Protocol.prototype, '_enqueue')
}
module.exports = [

@@ -81,3 +101,10 @@ {

unpatch: unpatchConnection
},
{
name: 'mysql',
file: 'lib/protocol/Protocol.js',
versions: ['2.x'],
patch: patchProtocol,
unpatch: unpatchProtocol
}
]

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

span.setTag('out.port', String(this.config.port))
span.setTag('span.type', 'db')
span.setTag('span.type', 'sql')
span.setTag('db.user', this.config.user)

@@ -28,0 +28,0 @@

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

span.setTag('resource.name', statement)
span.setTag('span.type', 'db')
span.setTag('span.type', 'sql')

@@ -27,0 +27,0 @@ if (params) {

@@ -33,2 +33,8 @@ 'use strict'

})
it('should return the callback', () => {
const callback = () => {}
expect(tracer.bind(callback)).to.equal(callback)
})
})

@@ -35,0 +41,0 @@

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

let recorder
let Sampler
let sampler
let SpanContext

@@ -39,2 +41,7 @@ let spanContext

sampler = {
isSampled: sinon.stub().returns(true)
}
Sampler = sinon.stub().returns(sampler)
spanContext = {}

@@ -56,2 +63,3 @@ carrier = {}

bufferSize: 1000,
sampleRate: 0.5,
logger: 'logger',

@@ -71,2 +79,3 @@ tags: {},

'../recorder': Recorder,
'../sampler': Sampler,
'./propagation/text_map': TextMapPropagator,

@@ -88,2 +97,8 @@ './propagation/http': HttpPropagator,

it('should support sampling', () => {
tracer = new Tracer(config)
expect(Sampler).to.have.been.calledWith(config.sampleRate)
})
it('should support logging', () => {

@@ -90,0 +105,0 @@ tracer = new Tracer(config)

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

it('should fallback to the default resource name if a path pattern could not be found', done => {
it('should fallback to the the verb if a path pattern could not be found', done => {
const app = express()

@@ -241,3 +241,3 @@

.use(traces => {
expect(traces[0][0]).to.have.property('resource', 'express.request')
expect(traces[0][0]).to.have.property('resource', 'GET')
})

@@ -427,2 +427,32 @@ .then(done)

})
it('should handle errors', done => {
const app = express()
app.use((req, res, next) => {
next()
})
app.get('/user', (req, res) => {
res.status(500).send()
})
getPort().then(port => {
agent.use(traces => {
expect(traces[0][0]).to.have.property('error', 1)
expect(traces[0][0]).to.have.property('resource', 'GET /user')
expect(traces[0][0].meta).to.have.property('http.status_code', '500')
done()
})
appListener = app.listen(port, 'localhost', () => {
axios
.get(`http://localhost:${port}/user`, {
validateStatus: status => status === 500
})
.catch(done)
})
})
})
})

@@ -435,3 +465,4 @@

config = {
service: 'custom'
service: 'custom',
validateStatus: code => code < 400
}

@@ -445,3 +476,3 @@

it('should be configured with the correct values', done => {
it('should be configured with the correct service name', done => {
const app = express()

@@ -468,4 +499,29 @@

})
it('should be configured with the correct status code validator', done => {
const app = express()
app.get('/user', (req, res) => {
res.status(400).send()
})
getPort().then(port => {
agent
.use(traces => {
expect(traces[0][0]).to.have.property('error', 1)
})
.then(done)
.catch(done)
appListener = app.listen(port, 'localhost', () => {
axios
.get(`http://localhost:${port}/user`, {
validateStatus: status => status === 400
})
.catch(done)
})
})
})
})
})
})

@@ -15,2 +15,68 @@ 'use strict'

function buildSchema () {
const Human = new graphql.GraphQLObjectType({
name: 'Human',
fields: {
name: {
type: graphql.GraphQLString,
resolve (obj, args) {
return 'test'
}
},
address: {
type: new graphql.GraphQLObjectType({
name: 'Address',
fields: {
civicNumber: {
type: graphql.GraphQLString,
resolve: () => 123
},
street: {
type: graphql.GraphQLString,
resolve: () => 'foo street'
}
}
}),
resolve (obj, args) {
return {}
}
},
pets: {
type: new graphql.GraphQLList(new graphql.GraphQLObjectType({
name: 'Pet',
fields: () => ({
type: {
type: graphql.GraphQLString,
resolve: () => 'dog'
},
name: {
type: graphql.GraphQLString,
resolve: () => 'foo bar'
},
owner: {
type: Human,
resolve: () => ({})
},
colours: {
type: new graphql.GraphQLList(new graphql.GraphQLObjectType({
name: 'Colour',
fields: {
code: {
type: graphql.GraphQLString,
resolve: () => '#ffffff'
}
}
})),
resolve (obj, args) {
return [{}, {}]
}
}
})
})),
resolve (obj, args) {
return [{}, {}, {}]
}
}
}
})
schema = new graphql.GraphQLSchema({

@@ -32,18 +98,38 @@ query: new graphql.GraphQLObjectType({

human: {
type: new graphql.GraphQLObjectType({
name: 'Human',
fields: {
name: {
type: graphql.GraphQLString,
resolve (obj, args) {
return obj
}
}
}
}),
type: Human,
resolve (obj, args) {
return Promise.resolve('test')
return Promise.resolve({})
}
},
friends: {
type: new graphql.GraphQLList(Human),
resolve () {
return [ { name: 'alice' }, { name: 'bob' } ]
}
}
}
}),
mutation: new graphql.GraphQLObjectType({
name: 'RootMutationType',
fields: {
human: {
type: Human,
resolve () {
return Promise.resolve({ name: 'human name' })
}
}
}
}),
subscription: new graphql.GraphQLObjectType({
name: 'RootSubscriptionType',
fields: {
human: {
type: Human,
resolve () {
return Promise.resolve({ name: 'human name' })
}
}
}
})

@@ -130,3 +216,13 @@ })

it('should instrument nested field resolvers', done => {
const source = `{ human { name } }`
const source = `
{
human {
name
address {
civicNumber
street
}
}
}
`

@@ -137,3 +233,3 @@ agent

expect(spans).to.have.length(5)
expect(spans).to.have.length(11)

@@ -145,2 +241,8 @@ const query = spans[0]

const humanNameResolve = spans[4]
const addressField = spans[5]
const addressResolve = spans[6]
const addressCivicNumberField = spans[7]
const addressCivicNumberResolve = spans[8]
const addressStreetField = spans[9]
const addressStreetResolve = spans[10]

@@ -153,2 +255,3 @@ expect(query).to.have.property('name', 'graphql.query')

expect(humanField.parent_id.toString()).to.equal(query.span_id.toString())
expect(humanField.duration.toNumber()).to.be.lte(query.duration.toNumber())

@@ -158,2 +261,3 @@ expect(humanResolve).to.have.property('name', 'graphql.resolve')

expect(humanResolve.parent_id.toString()).to.equal(humanField.span_id.toString())
expect(humanResolve.duration.toNumber()).to.be.lte(humanField.duration.toNumber())

@@ -167,2 +271,32 @@ expect(humanNameField).to.have.property('name', 'graphql.field')

expect(humanNameResolve.parent_id.toString()).to.equal(humanNameField.span_id.toString())
expect(addressField).to.have.property('name', 'graphql.field')
expect(addressField).to.have.property('resource', 'human.address')
expect(addressField.parent_id.toString()).to.equal(humanField.span_id.toString())
expect(addressField.duration.toNumber()).to.be.lte(humanField.duration.toNumber())
expect(addressResolve).to.have.property('name', 'graphql.resolve')
expect(addressResolve).to.have.property('resource', 'human.address')
expect(addressResolve.parent_id.toString()).to.equal(addressField.span_id.toString())
expect(addressResolve.duration.toNumber()).to.be.lte(addressField.duration.toNumber())
expect(addressCivicNumberField).to.have.property('name', 'graphql.field')
expect(addressCivicNumberField).to.have.property('resource', 'human.address.civicNumber')
expect(addressCivicNumberField.parent_id.toString()).to.equal(addressField.span_id.toString())
expect(addressCivicNumberField.duration.toNumber()).to.be.lte(addressField.duration.toNumber())
expect(addressCivicNumberResolve).to.have.property('name', 'graphql.resolve')
expect(addressCivicNumberResolve).to.have.property('resource', 'human.address.civicNumber')
expect(addressCivicNumberResolve.parent_id.toString()).to.equal(addressCivicNumberField.span_id.toString())
expect(addressCivicNumberResolve.duration.toNumber()).to.be.lte(addressCivicNumberField.duration.toNumber())
expect(addressStreetField).to.have.property('name', 'graphql.field')
expect(addressStreetField).to.have.property('resource', 'human.address.street')
expect(addressStreetField.parent_id.toString()).to.equal(addressField.span_id.toString())
expect(addressStreetField.duration.toNumber()).to.be.lte(addressField.duration.toNumber())
expect(addressStreetResolve).to.have.property('name', 'graphql.resolve')
expect(addressStreetResolve).to.have.property('resource', 'human.address.street')
expect(addressStreetResolve.parent_id.toString()).to.equal(addressStreetField.span_id.toString())
expect(addressStreetResolve.duration.toNumber()).to.be.lte(addressStreetField.duration.toNumber())
})

@@ -175,3 +309,81 @@ .then(done)

it('should instrument the default field resolver', done => {
it('should instrument list field resolvers', done => {
const source = `{ friends { name } }`
agent
.use(traces => {
const spans = sort(traces[0])
expect(spans).to.have.length(7)
const query = spans[0]
const friendsField = spans[1]
const friendsResolve = spans[2]
const friend0NameField = spans[3]
const friend0NameResolve = spans[4]
const friend1NameField = spans[5]
const friend1NameResolve = spans[6]
expect(query).to.have.property('name', 'graphql.query')
expect(query).to.have.property('resource', 'query')
expect(friendsField).to.have.property('name', 'graphql.field')
expect(friendsField).to.have.property('resource', 'friends')
expect(friendsField.parent_id.toString()).to.equal(query.span_id.toString())
expect(friendsResolve).to.have.property('name', 'graphql.resolve')
expect(friendsResolve).to.have.property('resource', 'friends')
expect(friendsResolve.parent_id.toString()).to.equal(friendsField.span_id.toString())
expect(friend0NameField).to.have.property('name', 'graphql.field')
expect(friend0NameField).to.have.property('resource', 'friends.0.name')
expect(friend0NameField.parent_id.toString()).to.equal(friendsField.span_id.toString())
expect(friend0NameResolve).to.have.property('name', 'graphql.resolve')
expect(friend0NameResolve).to.have.property('resource', 'friends.0.name')
expect(friend0NameResolve.parent_id.toString()).to.equal(friend0NameField.span_id.toString())
expect(friend1NameField).to.have.property('name', 'graphql.field')
expect(friend1NameField).to.have.property('resource', 'friends.1.name')
expect(friend1NameField.parent_id.toString()).to.equal(friendsField.span_id.toString())
expect(friend1NameResolve).to.have.property('name', 'graphql.resolve')
expect(friend1NameResolve).to.have.property('resource', 'friends.1.name')
expect(friend1NameResolve.parent_id.toString()).to.equal(friend1NameField.span_id.toString())
})
.then(done)
.catch(done)
graphql.graphql(schema, source).catch(done)
})
it('should instrument mutations', done => {
const source = `mutation { human { name } }`
agent
.use(traces => {
const spans = sort(traces[0])
expect(spans).to.have.length(5)
expect(spans[0]).to.have.property('name', 'graphql.mutation')
})
.then(done)
.catch(done)
graphql.graphql(schema, source).catch(done)
})
it('should handle a circular schema', done => {
const source = `{ human { pets { owner { name } } } }`
graphql.graphql(schema, source)
.then((result) => {
expect(result.data.human.pets[0].owner.name).to.equal('test')
done()
})
.catch(done)
})
it('should ignore the default field resolver', done => {
const schema = graphql.buildSchema(`

@@ -189,4 +401,4 @@ type Query {

expect(spans).to.have.length(3)
expect(spans[2]).to.have.property('resource', 'hello')
expect(spans).to.have.length(1)
expect(spans[0]).to.have.property('resource', 'query')
})

@@ -199,3 +411,3 @@ .then(done)

it('should instrument a custom field resolver', done => {
it('should ignore the execution field resolver without a rootValue resolver', done => {
const schema = graphql.buildSchema(`

@@ -219,4 +431,4 @@ type Query {

expect(spans).to.have.length(3)
expect(spans[2]).to.have.property('resource', 'hello')
expect(spans).to.have.length(1)
expect(spans[0]).to.have.property('resource', 'query')
})

@@ -248,3 +460,3 @@ .then(done)

it('should run the field resolver in the trace context', done => {
it('should run rootValue resolvers in the current context', done => {
const schema = graphql.buildSchema(`

@@ -258,22 +470,2 @@ type Query {

const rootValue = { hello: 'world' }
const fieldResolver = (source, args, contextValue, info) => {
expect(context.get('current')).to.not.be.undefined
done()
return source[info.fieldName]
}
graphql.graphql({ schema, source, rootValue, fieldResolver }).catch(done)
})
it('should run resolvers in the current context', done => {
const schema = graphql.buildSchema(`
type Query {
hello: String
}
`)
const source = `{ hello }`
const rootValue = {

@@ -311,2 +503,13 @@ hello () {

it('should handle unsupported operations', () => {
const query = `query MyQuery { hello(name: "world") }`
const subscription = `subscription { human { name } }`
return graphql.graphql(schema, query)
.then(() => graphql.graphql(schema, subscription))
.then(result => {
expect(result).to.not.have.property('errors')
})
})
it('should handle calling low level APIs directly', done => {

@@ -329,6 +532,65 @@ const source = `query MyQuery { hello(name: "world") }`

graphql.execute({ schema, document })
})
it('should handle Source objects', done => {
const source = `query MyQuery { hello(name: "world") }`
const document = graphql.parse(new graphql.Source(source))
agent
.use(traces => {
const spans = sort(traces[0])
expect(spans).to.have.length(3)
expect(spans[0]).to.have.property('service', 'test-graphql')
expect(spans[0]).to.have.property('name', 'graphql.query')
expect(spans[0]).to.have.property('resource', 'query MyQuery')
expect(spans[0].meta).to.have.property('graphql.document', source)
})
.then(done)
.catch(done)
graphql.execute(schema, document)
})
it('should handle exceptions', done => {
it('should handle executor exceptions', done => {
schema = new graphql.GraphQLSchema({
query: new graphql.GraphQLObjectType({
name: 'RootQueryType',
fields: {
hello: {}
}
})
})
const source = `{ hello }`
const document = graphql.parse(source)
let error
agent
.use(traces => {
const spans = sort(traces[0])
expect(spans).to.have.length(1)
expect(spans[0]).to.have.property('service', 'test-graphql')
expect(spans[0]).to.have.property('name', 'graphql.query')
expect(spans[0]).to.have.property('resource', 'query')
expect(spans[0].meta).to.have.property('graphql.document', source)
expect(spans[0]).to.have.property('error', 1)
expect(spans[0].meta).to.have.property('error.type', error.name)
expect(spans[0].meta).to.have.property('error.msg', error.message)
expect(spans[0].meta).to.have.property('error.stack', error.stack)
})
.then(done)
.catch(done)
try {
graphql.execute(schema, document)
} catch (e) {
error = e
}
})
it('should handle resolver exceptions', done => {
const error = new Error('test')

@@ -344,4 +606,6 @@

const fieldResolver = (source, args, contextValue, info) => {
throw error
const rootValue = {
hello: () => {
throw error
}
}

@@ -362,3 +626,3 @@

graphql.graphql({ schema, source, fieldResolver }).catch(done)
graphql.graphql({ schema, source, rootValue }).catch(done)
})

@@ -377,4 +641,6 @@

const fieldResolver = (source, args, contextValue, info) => {
return Promise.reject(error)
const rootValue = {
hello: () => {
return Promise.reject(error)
}
}

@@ -395,3 +661,3 @@

graphql.graphql({ schema, source, fieldResolver }).catch(done)
graphql.graphql({ schema, source, rootValue }).catch(done)
})

@@ -398,0 +664,0 @@ })

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

let mysql
let context
let tracer

@@ -16,3 +16,3 @@ describe('mysql', () => {

plugin = require('../../src/plugins/mysql')
context = require('../../src/platform').context()
tracer = require('../..')
})

@@ -48,11 +48,8 @@

it('should propagate context to callbacks', done => {
context.run(() => {
context.set('foo', 'bar')
connection.query('SELECT 1 + 1 AS solution', callback)
tracer.trace('test', span => {
connection.query('SELECT 1 + 1 AS solution', () => {
expect(tracer.currentSpan()).to.equal(span)
done()
})
})
function callback () {
expect(context.get('foo')).to.equal('bar')
done()
}
})

@@ -62,3 +59,3 @@

connection.query('SELECT 1 + 1 AS solution', () => {
expect(context.get('current')).to.be.undefined
expect(tracer.currentSpan()).to.be.null
done()

@@ -71,12 +68,9 @@ })

context.run(() => {
context.set('foo', 'bar')
tracer.trace('test', span => {
query = connection.query('SELECT 1 + 1 AS solution')
query.on('result', callback)
query.on('result', () => {
expect(tracer.currentSpan()).to.equal(span)
done()
})
})
function callback () {
expect(context.get('foo')).to.equal('bar')
done()
}
})

@@ -88,3 +82,3 @@

query.on('result', () => {
expect(context.get('current')).to.be.undefined
expect(tracer.currentSpan()).to.be.null
done()

@@ -98,3 +92,3 @@ })

expect(traces[0][0]).to.have.property('resource', 'SELECT 1 + 1 AS solution')
expect(traces[0][0]).to.have.property('type', 'db')
expect(traces[0][0]).to.have.property('type', 'sql')
expect(traces[0][0].meta).to.have.property('db.name', 'db')

@@ -201,3 +195,3 @@ expect(traces[0][0].meta).to.have.property('db.user', 'user')

expect(traces[0][0]).to.have.property('resource', 'SELECT 1 + 1 AS solution')
expect(traces[0][0]).to.have.property('type', 'db')
expect(traces[0][0]).to.have.property('type', 'sql')
expect(traces[0][0].meta).to.have.property('db.user', 'user')

@@ -214,11 +208,8 @@ expect(traces[0][0].meta).to.have.property('db.type', 'mysql')

it('should propagate context', done => {
context.run(() => {
context.set('foo', 'bar')
pool.query('SELECT 1 + 1 AS solution', callback)
tracer.trace('test', span => {
pool.query('SELECT 1 + 1 AS solution', () => {
expect(tracer.currentSpan()).to.equal(span)
done()
})
})
function callback () {
expect(context.get('foo')).to.equal('bar')
done()
}
})

@@ -228,3 +219,3 @@

pool.query('SELECT 1 + 1 AS solution', () => {
expect(context.get('current')).to.be.undefined
expect(tracer.currentSpan()).to.be.null
done()

@@ -231,0 +222,0 @@ })

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

expect(traces[0][0]).to.have.property('resource', 'SELECT 1 + 1 AS solution')
expect(traces[0][0]).to.have.property('type', 'db')
expect(traces[0][0]).to.have.property('type', 'sql')
expect(traces[0][0].meta).to.have.property('db.name', 'db')

@@ -201,3 +201,3 @@ expect(traces[0][0].meta).to.have.property('db.user', 'user')

expect(traces[0][0]).to.have.property('resource', 'SELECT 1 + 1 AS solution')
expect(traces[0][0]).to.have.property('type', 'db')
expect(traces[0][0]).to.have.property('type', 'sql')
expect(traces[0][0].meta).to.have.property('db.user', 'user')

@@ -204,0 +204,0 @@ expect(traces[0][0].meta).to.have.property('db.type', 'mysql')

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

expect(traces[0][0]).to.have.property('resource', 'SELECT $1::text as message')
expect(traces[0][0]).to.have.property('type', 'db')
expect(traces[0][0]).to.have.property('type', 'sql')
expect(traces[0][0].meta).to.have.property('db.name', 'postgres')

@@ -48,0 +48,0 @@ expect(traces[0][0].meta).to.have.property('db.user', 'postgres')

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc