dd-trace 2.0.0-beta.0 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MIGRATING.md +65 -0
- package/NOTICE +4 -0
- package/package.json +2 -2
- package/packages/datadog-instrumentations/index.js +1 -0
- package/packages/datadog-instrumentations/src/dns.js +2 -2
- package/packages/datadog-instrumentations/src/helpers/instrument.js +24 -25
- package/packages/datadog-instrumentations/src/memcached.js +3 -5
- package/packages/datadog-instrumentations/src/mysql.js +7 -9
- package/packages/datadog-instrumentations/src/mysql2.js +76 -0
- package/packages/datadog-instrumentations/src/q.js +9 -1
- package/packages/datadog-plugin-aws-sdk/src/helpers.js +4 -3
- package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +48 -0
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +56 -6
- package/packages/datadog-plugin-aws-sdk/src/services/sns.js +33 -6
- package/packages/datadog-plugin-mysql/src/index.js +4 -4
- package/packages/datadog-plugin-mysql2/src/index.js +5 -88
- package/packages/datadog-plugin-next/src/index.js +10 -6
- package/packages/datadog-plugin-pino/src/index.js +25 -1
- package/packages/datadog-plugin-winston/src/index.js +30 -12
- package/packages/dd-trace/lib/version.js +1 -1
- package/packages/dd-trace/src/appsec/index.js +13 -16
- package/packages/dd-trace/src/appsec/recommended.json +5708 -1
- package/packages/dd-trace/src/appsec/reporter.js +15 -3
- package/packages/dd-trace/src/config.js +7 -1
- package/packages/dd-trace/src/profiling/config.js +5 -1
- package/packages/dd-trace/src/profiling/profiler.js +15 -6
- package/packages/dd-trace/src/profiling/profilers/cpu.js +1 -1
- package/packages/dd-trace/src/profiling/profilers/heap.js +3 -2
- package/scripts/publish_docs.js +1 -1
- package/scripts/tracer-runner.js +13 -0
- package/packages/dd-trace/src/profiling/mapper.js +0 -91
package/MIGRATING.md
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Migrating
|
|
2
|
+
|
|
3
|
+
This guide describes the steps to upgrade dd-trace from a major version to the
|
|
4
|
+
next. If you are having any issues related to migrating, please feel free to
|
|
5
|
+
open an issue or contact our [support](https://www.datadoghq.com/support/) team.
|
|
6
|
+
|
|
7
|
+
## 1.0 to 2.0
|
|
8
|
+
|
|
9
|
+
### Configuration
|
|
10
|
+
|
|
11
|
+
The following configuraton options are no longer available programmatically and
|
|
12
|
+
must be configured using these environment variables:
|
|
13
|
+
|
|
14
|
+
* `enabled` -> `DD_TRACE_ENABLED=true|false`
|
|
15
|
+
* `debug` -> `DD_TRACE_DEBUG=true|false`
|
|
16
|
+
|
|
17
|
+
If environment variables were already used for these options, no action is
|
|
18
|
+
needed.
|
|
19
|
+
|
|
20
|
+
The following configuration options were completely removed and will no longer
|
|
21
|
+
have any effect:
|
|
22
|
+
|
|
23
|
+
* `scope`
|
|
24
|
+
|
|
25
|
+
Startup logs are now disabled by default and can be enabled if needed with
|
|
26
|
+
`DD_TRACE_STARTUP_LOGS=true`.
|
|
27
|
+
|
|
28
|
+
### Removed APIs
|
|
29
|
+
|
|
30
|
+
The original scope manager has been replaced several years ago and has now been
|
|
31
|
+
removed. Any code referencing `tracer.scopeManager()` should be removed or
|
|
32
|
+
replaced with `tracer.scope()` which is documented
|
|
33
|
+
[here](https://datadoghq.dev/dd-trace-js/#scope-manager).
|
|
34
|
+
|
|
35
|
+
### Nested objects as tags
|
|
36
|
+
|
|
37
|
+
Support for nested objects as tags as been removed. When adding an object as a
|
|
38
|
+
tag value, only properties that exist on that object directly will be added as
|
|
39
|
+
tags. If nested properties are also needed, these should be added by hand.
|
|
40
|
+
|
|
41
|
+
For example:
|
|
42
|
+
|
|
43
|
+
```js
|
|
44
|
+
const obj = {
|
|
45
|
+
a: 'foo',
|
|
46
|
+
b: {
|
|
47
|
+
c: 'bar'
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// 1.0
|
|
52
|
+
span.setTag('test', obj) // add test.a and test.b.c
|
|
53
|
+
|
|
54
|
+
// 2.0
|
|
55
|
+
span.setTag('test', obj) // add test.a
|
|
56
|
+
span.setTag('test.b', obj.b) // add test.b.c
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Arrays are no longer supported and must be converted to string manually.
|
|
60
|
+
|
|
61
|
+
### Outgoing request filtering
|
|
62
|
+
|
|
63
|
+
Outgoing request filtering is no longer supported and is now only available for
|
|
64
|
+
incoming requests. This means that the `blocklist` and `allowlist` options on
|
|
65
|
+
the `http` integration no longer have any effect.
|
package/NOTICE
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dd-trace",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "Datadog APM tracing client for JavaScript",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"typings": "index.d.ts",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"node": ">=12"
|
|
62
62
|
},
|
|
63
63
|
"dependencies": {
|
|
64
|
-
"@datadog/native-appsec": "^0.8.
|
|
64
|
+
"@datadog/native-appsec": "^0.8.1",
|
|
65
65
|
"@datadog/native-metrics": "^1.1.0",
|
|
66
66
|
"@datadog/pprof": "^0.3.0",
|
|
67
67
|
"@datadog/sketches-js": "^1.0.4",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { channel, addHook,
|
|
3
|
+
const { channel, addHook, AsyncResource } = require('./helpers/instrument')
|
|
4
4
|
const shimmer = require('../../datadog-shimmer')
|
|
5
5
|
|
|
6
6
|
const rrtypes = {
|
|
@@ -53,7 +53,7 @@ function wrap (prefix, fn, expectedArgs, rrtype) {
|
|
|
53
53
|
const errorCh = channel(prefix + ':error')
|
|
54
54
|
|
|
55
55
|
const wrapped = function () {
|
|
56
|
-
const cb = bind(arguments[arguments.length - 1])
|
|
56
|
+
const cb = AsyncResource.bind(arguments[arguments.length - 1])
|
|
57
57
|
if (
|
|
58
58
|
!startCh.hasSubscribers ||
|
|
59
59
|
arguments.length < expectedArgs ||
|
|
@@ -90,32 +90,31 @@ function getBasedir (id) {
|
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
if (semver.satisfies(process.versions.node, '>=16.0.0')) {
|
|
93
|
-
exports.
|
|
94
|
-
exports.bindAsyncResource = AsyncResource.prototype.bind
|
|
93
|
+
exports.AsyncResource = AsyncResource
|
|
95
94
|
} else {
|
|
96
|
-
exports.
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
configurable: true,
|
|
102
|
-
enumerable: false,
|
|
103
|
-
value: fn.length,
|
|
104
|
-
writable: false
|
|
105
|
-
},
|
|
106
|
-
'asyncResource': {
|
|
107
|
-
configurable: true,
|
|
108
|
-
enumerable: true,
|
|
109
|
-
value: this,
|
|
110
|
-
writable: true
|
|
111
|
-
}
|
|
112
|
-
})
|
|
113
|
-
return ret
|
|
114
|
-
}
|
|
95
|
+
exports.AsyncResource = class extends AsyncResource {
|
|
96
|
+
static bind (fn, type, thisArg) {
|
|
97
|
+
type = type || fn.name
|
|
98
|
+
return (new exports.AsyncResource(type || 'bound-anonymous-fn')).bind(fn, thisArg)
|
|
99
|
+
}
|
|
115
100
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
101
|
+
bind (fn, thisArg = this) {
|
|
102
|
+
const ret = this.runInAsyncScope.bind(this, fn, thisArg)
|
|
103
|
+
Object.defineProperties(ret, {
|
|
104
|
+
'length': {
|
|
105
|
+
configurable: true,
|
|
106
|
+
enumerable: false,
|
|
107
|
+
value: fn.length,
|
|
108
|
+
writable: false
|
|
109
|
+
},
|
|
110
|
+
'asyncResource': {
|
|
111
|
+
configurable: true,
|
|
112
|
+
enumerable: true,
|
|
113
|
+
value: this,
|
|
114
|
+
writable: true
|
|
115
|
+
}
|
|
116
|
+
})
|
|
117
|
+
return ret
|
|
118
|
+
}
|
|
120
119
|
}
|
|
121
120
|
}
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { AsyncResource } = require('async_hooks')
|
|
4
3
|
const {
|
|
5
4
|
channel,
|
|
6
5
|
addHook,
|
|
7
|
-
|
|
8
|
-
bindAsyncResource
|
|
6
|
+
AsyncResource
|
|
9
7
|
} = require('./helpers/instrument')
|
|
10
8
|
const shimmer = require('../../datadog-shimmer')
|
|
11
9
|
|
|
@@ -27,9 +25,9 @@ addHook({ name: 'memcached', versions: ['>=2.2'] }, Memcached => {
|
|
|
27
25
|
|
|
28
26
|
const wrappedQueryCompiler = function () {
|
|
29
27
|
const query = queryCompiler.apply(this, arguments)
|
|
30
|
-
const callback =
|
|
28
|
+
const callback = asyncResource.bind(query.callback)
|
|
31
29
|
|
|
32
|
-
query.callback = bind(function (err) {
|
|
30
|
+
query.callback = AsyncResource.bind(function (err) {
|
|
33
31
|
if (err) {
|
|
34
32
|
errorCh.publish(err)
|
|
35
33
|
}
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { AsyncResource } = require('async_hooks')
|
|
4
3
|
const {
|
|
5
4
|
channel,
|
|
6
5
|
addHook,
|
|
7
|
-
|
|
8
|
-
bindAsyncResource
|
|
6
|
+
AsyncResource
|
|
9
7
|
} = require('./helpers/instrument')
|
|
10
8
|
const shimmer = require('../../datadog-shimmer')
|
|
11
9
|
|
|
@@ -22,16 +20,16 @@ addHook({ name: 'mysql', file: 'lib/Connection.js', versions: ['>=2'] }, Connect
|
|
|
22
20
|
}
|
|
23
21
|
|
|
24
22
|
const sql = arguments[0].sql ? arguments[0].sql : arguments[0]
|
|
25
|
-
const
|
|
23
|
+
const conf = this.config
|
|
26
24
|
|
|
27
|
-
startCh.publish(
|
|
25
|
+
startCh.publish({ sql, conf })
|
|
28
26
|
|
|
29
27
|
try {
|
|
30
28
|
const res = query.apply(this, arguments)
|
|
31
29
|
|
|
32
30
|
if (res._callback) {
|
|
33
|
-
const cb =
|
|
34
|
-
res._callback = bind(function (error, result) {
|
|
31
|
+
const cb = asyncResource.bind(res._callback)
|
|
32
|
+
res._callback = AsyncResource.bind(function (error, result) {
|
|
35
33
|
if (error) {
|
|
36
34
|
errorCh.publish(error)
|
|
37
35
|
}
|
|
@@ -40,7 +38,7 @@ addHook({ name: 'mysql', file: 'lib/Connection.js', versions: ['>=2'] }, Connect
|
|
|
40
38
|
return cb.apply(this, arguments)
|
|
41
39
|
})
|
|
42
40
|
} else {
|
|
43
|
-
const cb = bind(function () {
|
|
41
|
+
const cb = AsyncResource.bind(function () {
|
|
44
42
|
asyncEndCh.publish(undefined)
|
|
45
43
|
})
|
|
46
44
|
res.on('end', cb)
|
|
@@ -62,7 +60,7 @@ addHook({ name: 'mysql', file: 'lib/Connection.js', versions: ['>=2'] }, Connect
|
|
|
62
60
|
|
|
63
61
|
addHook({ name: 'mysql', file: 'lib/Pool.js', versions: ['>=2'] }, Pool => {
|
|
64
62
|
shimmer.wrap(Pool.prototype, 'getConnection', getConnection => function (cb) {
|
|
65
|
-
arguments[0] = bind(cb)
|
|
63
|
+
arguments[0] = AsyncResource.bind(cb)
|
|
66
64
|
return getConnection.apply(this, arguments)
|
|
67
65
|
})
|
|
68
66
|
return Pool
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
channel,
|
|
5
|
+
addHook,
|
|
6
|
+
AsyncResource
|
|
7
|
+
} = require('./helpers/instrument')
|
|
8
|
+
const shimmer = require('../../datadog-shimmer')
|
|
9
|
+
|
|
10
|
+
addHook({ name: 'mysql2', file: 'lib/connection.js', versions: ['>=1'] }, Connection => {
|
|
11
|
+
const startCh = channel('apm:mysql2:query:start')
|
|
12
|
+
const asyncEndCh = channel('apm:mysql2:query:async-end')
|
|
13
|
+
const endCh = channel('apm:mysql2:query:end')
|
|
14
|
+
const errorCh = channel('apm:mysql2:query:error')
|
|
15
|
+
|
|
16
|
+
shimmer.wrap(Connection.prototype, 'addCommand', addCommand => function (cmd) {
|
|
17
|
+
if (!startCh.hasSubscribers) return addCommand.apply(this, arguments)
|
|
18
|
+
|
|
19
|
+
const asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
20
|
+
const name = cmd && cmd.constructor && cmd.constructor.name
|
|
21
|
+
const isCommand = typeof cmd.execute === 'function'
|
|
22
|
+
const isQuery = isCommand && (name === 'Execute' || name === 'Query')
|
|
23
|
+
|
|
24
|
+
// TODO: consider supporting all commands and not just queries
|
|
25
|
+
cmd.execute = isQuery
|
|
26
|
+
? wrapExecute(cmd, cmd.execute, asyncResource, this.config)
|
|
27
|
+
: bindExecute(cmd, cmd.execute, asyncResource)
|
|
28
|
+
|
|
29
|
+
return asyncResource.bind(addCommand, this).apply(this, arguments)
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
return Connection
|
|
33
|
+
|
|
34
|
+
function bindExecute (cmd, execute, asyncResource) {
|
|
35
|
+
return asyncResource.bind(function executeWithTrace (packet, connection) {
|
|
36
|
+
if (this.onResult) {
|
|
37
|
+
this.onResult = asyncResource.bind(this.onResult)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return execute.apply(this, arguments)
|
|
41
|
+
}, cmd)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function wrapExecute (cmd, execute, asyncResource, config) {
|
|
45
|
+
return asyncResource.bind(function executeWithTrace (packet, connection) {
|
|
46
|
+
const sql = cmd.statement ? cmd.statement.query : cmd.sql
|
|
47
|
+
|
|
48
|
+
startCh.publish({ sql, conf: config })
|
|
49
|
+
|
|
50
|
+
if (this.onResult) {
|
|
51
|
+
const onResult = asyncResource.bind(this.onResult)
|
|
52
|
+
|
|
53
|
+
this.onResult = AsyncResource.bind(function (error) {
|
|
54
|
+
if (error) {
|
|
55
|
+
errorCh.publish(error)
|
|
56
|
+
}
|
|
57
|
+
asyncEndCh.publish(undefined)
|
|
58
|
+
onResult.apply(this, arguments)
|
|
59
|
+
}, 'bound-anonymous-fn', this)
|
|
60
|
+
} else {
|
|
61
|
+
this.on('error', AsyncResource.bind(error => errorCh.publish(error)))
|
|
62
|
+
this.on('end', AsyncResource.bind(() => asyncEndCh.publish(undefined)))
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
this.execute = execute
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
return execute.apply(this, arguments)
|
|
69
|
+
} catch (err) {
|
|
70
|
+
errorCh.publish(err)
|
|
71
|
+
} finally {
|
|
72
|
+
endCh.publish(undefined)
|
|
73
|
+
}
|
|
74
|
+
}, cmd)
|
|
75
|
+
}
|
|
76
|
+
})
|
|
@@ -6,8 +6,16 @@ const shimmer = require('../../datadog-shimmer')
|
|
|
6
6
|
|
|
7
7
|
addHook({
|
|
8
8
|
name: 'q',
|
|
9
|
-
versions: ['
|
|
9
|
+
versions: ['1']
|
|
10
10
|
}, Q => {
|
|
11
11
|
shimmer.wrap(Q.makePromise.prototype, 'then', wrapThen)
|
|
12
12
|
return Q
|
|
13
13
|
})
|
|
14
|
+
|
|
15
|
+
addHook({
|
|
16
|
+
name: 'q',
|
|
17
|
+
versions: ['>=2']
|
|
18
|
+
}, Q => {
|
|
19
|
+
shimmer.wrap(Q.Promise.prototype, 'then', wrapThen)
|
|
20
|
+
return Q
|
|
21
|
+
})
|
|
@@ -10,7 +10,8 @@ const services = {
|
|
|
10
10
|
s3: getService(require('./services/s3')),
|
|
11
11
|
redshift: getService(require('./services/redshift')),
|
|
12
12
|
sns: getService(require('./services/sns')),
|
|
13
|
-
sqs: getService(require('./services/sqs'))
|
|
13
|
+
sqs: getService(require('./services/sqs')),
|
|
14
|
+
eventbridge: getService(require('./services/eventbridge'))
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
function getService (Service) {
|
|
@@ -78,8 +79,8 @@ const helpers = {
|
|
|
78
79
|
requestInject (span, request, serviceName, tracer) {
|
|
79
80
|
if (!span) return
|
|
80
81
|
|
|
81
|
-
const
|
|
82
|
-
if (
|
|
82
|
+
const service = services[serviceName] && services[serviceName]
|
|
83
|
+
if (service && service.requestInject) service.requestInject(span, request, tracer)
|
|
83
84
|
},
|
|
84
85
|
|
|
85
86
|
wrapCb (cb, serviceName, tags, request, tracer, childOf) {
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
const log = require('../../../dd-trace/src/log')
|
|
3
|
+
class EventBridge {
|
|
4
|
+
generateTags (params, operation, response) {
|
|
5
|
+
if (!params || !params.source) return {}
|
|
6
|
+
|
|
7
|
+
return {
|
|
8
|
+
'resource.name': `${operation} ${params.source}`,
|
|
9
|
+
'aws.eventbridge.source': params.source
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* requestInject
|
|
15
|
+
* @param {*} span
|
|
16
|
+
* @param {*} request
|
|
17
|
+
* @param {*} tracer
|
|
18
|
+
*
|
|
19
|
+
* Docs: https://docs.aws.amazon.com/eventbridge/latest/APIReference/API_PutEventsRequestEntry.html
|
|
20
|
+
* We cannot use the traceHeader field as that's reserved for X-Ray.
|
|
21
|
+
* Detail must be a valid JSON string
|
|
22
|
+
* Max size per event is 256kb (https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-putevent-size.html)
|
|
23
|
+
*/
|
|
24
|
+
requestInject (span, request, tracer) {
|
|
25
|
+
const operation = request.operation
|
|
26
|
+
if (operation === 'putEvents' &&
|
|
27
|
+
request.params &&
|
|
28
|
+
request.params.Entries &&
|
|
29
|
+
request.params.Entries.length > 0 &&
|
|
30
|
+
request.params.Entries[0].Detail) {
|
|
31
|
+
try {
|
|
32
|
+
const details = JSON.parse(request.params.Entries[0].Detail)
|
|
33
|
+
details._datadog = {}
|
|
34
|
+
tracer.inject(span, 'text_map', details._datadog)
|
|
35
|
+
const finalData = JSON.stringify(details)
|
|
36
|
+
const byteSize = Buffer.byteLength(finalData)
|
|
37
|
+
if (byteSize >= (1024 * 256)) {
|
|
38
|
+
log.info('Payload size too large to pass context')
|
|
39
|
+
return
|
|
40
|
+
}
|
|
41
|
+
request.params.Entries[0].Detail = finalData
|
|
42
|
+
} catch (e) {
|
|
43
|
+
log.error(e)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
module.exports = EventBridge
|
|
@@ -1,15 +1,65 @@
|
|
|
1
1
|
'use strict'
|
|
2
|
-
|
|
2
|
+
const log = require('../../../dd-trace/src/log')
|
|
3
3
|
class Kinesis {
|
|
4
4
|
generateTags (params, operation, response) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
if (!params || !params.StreamName) return tags
|
|
5
|
+
if (!params || !params.StreamName) return {}
|
|
8
6
|
|
|
9
|
-
return
|
|
7
|
+
return {
|
|
10
8
|
'resource.name': `${operation} ${params.StreamName}`,
|
|
11
9
|
'aws.kinesis.stream_name': params.StreamName
|
|
12
|
-
}
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// AWS-SDK will b64 kinesis payloads
|
|
14
|
+
// or will accept an already b64 encoded payload
|
|
15
|
+
// This method handles both
|
|
16
|
+
_tryParse (body) {
|
|
17
|
+
try {
|
|
18
|
+
return JSON.parse(body)
|
|
19
|
+
} catch (e) {
|
|
20
|
+
log.info('Not JSON string. Trying Base64 encoded JSON string')
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
return JSON.parse(Buffer.from(body, 'base64').toString('ascii'), true)
|
|
24
|
+
} catch (e) {
|
|
25
|
+
return null
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
requestInject (span, request, tracer) {
|
|
30
|
+
const operation = request.operation
|
|
31
|
+
if (operation === 'putRecord' || operation === 'putRecords') {
|
|
32
|
+
if (!request.params) {
|
|
33
|
+
return
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const traceData = {}
|
|
37
|
+
tracer.inject(span, 'text_map', traceData)
|
|
38
|
+
let injectPath
|
|
39
|
+
if (request.params.Records && request.params.Records.length > 0) {
|
|
40
|
+
injectPath = request.params.Records[0]
|
|
41
|
+
} else if (request.params.Data) {
|
|
42
|
+
injectPath = request.params
|
|
43
|
+
} else {
|
|
44
|
+
log.error('No valid payload passed, unable to pass trace context')
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
const parsedData = this._tryParse(injectPath.Data)
|
|
48
|
+
if (parsedData) {
|
|
49
|
+
parsedData._datadog = traceData
|
|
50
|
+
const finalData = JSON.stringify(parsedData)
|
|
51
|
+
const byteSize = Buffer.byteLength(finalData, 'ascii')
|
|
52
|
+
// Kinesis max payload size is 1MB
|
|
53
|
+
// So we must ensure adding DD context won't go over that (512b is an estimate)
|
|
54
|
+
if (byteSize >= 1048576) {
|
|
55
|
+
log.info('Payload size too large to pass context')
|
|
56
|
+
return
|
|
57
|
+
}
|
|
58
|
+
injectPath.Data = finalData
|
|
59
|
+
} else {
|
|
60
|
+
log.error('Unable to parse payload, unable to pass trace context')
|
|
61
|
+
}
|
|
62
|
+
}
|
|
13
63
|
}
|
|
14
64
|
}
|
|
15
65
|
|
|
@@ -1,21 +1,48 @@
|
|
|
1
1
|
'use strict'
|
|
2
|
+
const log = require('../../../dd-trace/src/log')
|
|
2
3
|
|
|
3
4
|
class Sns {
|
|
4
5
|
generateTags (params, operation, response) {
|
|
5
|
-
|
|
6
|
+
if (!params) return {}
|
|
6
7
|
|
|
7
|
-
if (!params) return
|
|
8
|
+
if (!params.TopicArn && !(response.data && response.data.TopicArn)) return {}
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
return Object.assign(tags, {
|
|
10
|
+
return {
|
|
12
11
|
'resource.name': `${operation} ${params.TopicArn || response.data.TopicArn}`,
|
|
13
12
|
'aws.sns.topic_arn': params.TopicArn || response.data.TopicArn
|
|
14
|
-
}
|
|
13
|
+
}
|
|
15
14
|
|
|
16
15
|
// TODO: should arn be sanitized or quantized in some way here,
|
|
17
16
|
// for example if it contains a phone number?
|
|
18
17
|
}
|
|
18
|
+
|
|
19
|
+
requestInject (span, request, tracer) {
|
|
20
|
+
const operation = request.operation
|
|
21
|
+
if (operation === 'publish' || operation === 'publishBatch') {
|
|
22
|
+
if (!request.params) {
|
|
23
|
+
request.params = {}
|
|
24
|
+
}
|
|
25
|
+
let injectPath
|
|
26
|
+
if (request.params.PublishBatchRequestEntries && request.params.PublishBatchRequestEntries.length > 0) {
|
|
27
|
+
injectPath = request.params.PublishBatchRequestEntries[0]
|
|
28
|
+
} else if (request.params.Message) {
|
|
29
|
+
injectPath = request.params
|
|
30
|
+
}
|
|
31
|
+
if (!injectPath.MessageAttributes) {
|
|
32
|
+
injectPath.MessageAttributes = {}
|
|
33
|
+
}
|
|
34
|
+
if (Object.keys(injectPath.MessageAttributes).length >= 10) { // SNS quota
|
|
35
|
+
log.info('Message attributes full, skipping trace context injection')
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
const ddInfo = {}
|
|
39
|
+
tracer.inject(span, 'text_map', ddInfo)
|
|
40
|
+
injectPath.MessageAttributes._datadog = {
|
|
41
|
+
DataType: 'String',
|
|
42
|
+
StringValue: JSON.stringify(ddInfo)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
19
46
|
}
|
|
20
47
|
|
|
21
48
|
module.exports = Sns
|
|
@@ -12,7 +12,7 @@ class MySQLPlugin extends Plugin {
|
|
|
12
12
|
constructor (...args) {
|
|
13
13
|
super(...args)
|
|
14
14
|
|
|
15
|
-
this.addSub(
|
|
15
|
+
this.addSub(`apm:${this.constructor.name}:query:start`, ({ sql, conf }) => {
|
|
16
16
|
const store = storage.getStore()
|
|
17
17
|
const childOf = store ? store.span : store
|
|
18
18
|
const span = this.tracer.startSpan('mysql.query', {
|
|
@@ -37,18 +37,18 @@ class MySQLPlugin extends Plugin {
|
|
|
37
37
|
this.enter(span, store)
|
|
38
38
|
})
|
|
39
39
|
|
|
40
|
-
this.addSub(
|
|
40
|
+
this.addSub(`apm:${this.constructor.name}:query:end`, () => {
|
|
41
41
|
this.exit()
|
|
42
42
|
})
|
|
43
43
|
|
|
44
|
-
this.addSub(
|
|
44
|
+
this.addSub(`apm:${this.constructor.name}:query:error`, err => {
|
|
45
45
|
if (err) {
|
|
46
46
|
const span = storage.getStore().span
|
|
47
47
|
span.setTag('error', err)
|
|
48
48
|
}
|
|
49
49
|
})
|
|
50
50
|
|
|
51
|
-
this.addSub(
|
|
51
|
+
this.addSub(`apm:${this.constructor.name}:query:async-end`, () => {
|
|
52
52
|
const span = storage.getStore().span
|
|
53
53
|
span.finish()
|
|
54
54
|
})
|
|
@@ -1,94 +1,11 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const analyticsSampler = require('../../dd-trace/src/analytics_sampler')
|
|
3
|
+
const MySQLPlugin = require('../../datadog-plugin-mysql/src')
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
return
|
|
9
|
-
const name = cmd && cmd.constructor && cmd.constructor.name
|
|
10
|
-
const isCommand = typeof cmd.execute === 'function'
|
|
11
|
-
const isSupported = name === 'Execute' || name === 'Query'
|
|
12
|
-
|
|
13
|
-
if (isCommand && isSupported) {
|
|
14
|
-
cmd.execute = wrapExecute(tracer, config, cmd.execute)
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
return addCommand.apply(this, arguments)
|
|
18
|
-
}
|
|
5
|
+
class MySQL2Plugin extends MySQLPlugin {
|
|
6
|
+
static get name () {
|
|
7
|
+
return 'mysql2'
|
|
19
8
|
}
|
|
20
9
|
}
|
|
21
10
|
|
|
22
|
-
|
|
23
|
-
const scope = tracer.scope()
|
|
24
|
-
const childOf = scope.active()
|
|
25
|
-
|
|
26
|
-
return function executeWithTrace (packet, connection) {
|
|
27
|
-
const connectionConfig = (connection && connection.config) || {}
|
|
28
|
-
const sql = this.statement ? this.statement.query : this.sql
|
|
29
|
-
const span = tracer.startSpan('mysql.query', {
|
|
30
|
-
childOf,
|
|
31
|
-
tags: {
|
|
32
|
-
[Tags.SPAN_KIND]: Tags.SPAN_KIND_RPC_CLIENT,
|
|
33
|
-
'service.name': config.service || `${tracer._service}-mysql`,
|
|
34
|
-
'resource.name': sql,
|
|
35
|
-
'span.type': 'sql',
|
|
36
|
-
'span.kind': 'client',
|
|
37
|
-
'db.type': 'mysql',
|
|
38
|
-
'db.user': connectionConfig.user,
|
|
39
|
-
'db.name': connectionConfig.database,
|
|
40
|
-
'out.host': connectionConfig.host,
|
|
41
|
-
'out.port': connectionConfig.port
|
|
42
|
-
}
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
analyticsSampler.sample(span, config.measured)
|
|
46
|
-
|
|
47
|
-
if (typeof this.onResult === 'function') {
|
|
48
|
-
this.onResult = wrapCallback(tracer, span, childOf, this.onResult)
|
|
49
|
-
} else {
|
|
50
|
-
this.on('error', error => span.addTags({ error }))
|
|
51
|
-
this.on('end', () => span.finish())
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
this.execute = execute
|
|
55
|
-
|
|
56
|
-
return scope.bind(execute, span).apply(this, arguments)
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function wrapCallback (tracer, span, parent, done) {
|
|
61
|
-
return tracer.scope().bind((...args) => {
|
|
62
|
-
const [ error ] = args
|
|
63
|
-
span.addTags({ error })
|
|
64
|
-
|
|
65
|
-
span.finish()
|
|
66
|
-
|
|
67
|
-
done(...args)
|
|
68
|
-
}, parent)
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
module.exports = [
|
|
72
|
-
{
|
|
73
|
-
name: 'mysql2',
|
|
74
|
-
file: 'lib/connection.js',
|
|
75
|
-
versions: ['>=1'],
|
|
76
|
-
patch (Connection, tracer, config) {
|
|
77
|
-
this.wrap(Connection.prototype, 'addCommand', createWrapAddCommand(tracer, config))
|
|
78
|
-
},
|
|
79
|
-
unpatch (Connection) {
|
|
80
|
-
this.unwrap(Connection.prototype, 'addCommand')
|
|
81
|
-
}
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
name: 'mysql2',
|
|
85
|
-
file: 'lib/commands/command.js',
|
|
86
|
-
versions: ['>=1'],
|
|
87
|
-
patch (Command, tracer, config) {
|
|
88
|
-
tracer.scope().bind(Command.prototype)
|
|
89
|
-
},
|
|
90
|
-
unpatch (Command, tracer) {
|
|
91
|
-
tracer.scope().unbind(Command.prototype)
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
]
|
|
11
|
+
module.exports = MySQL2Plugin
|