Skip to content

Commit 172745b

Browse files
authored
Merge branch 'master' into nodejs-doc-restructure
2 parents 8e62cf9 + b9212b5 commit 172745b

17 files changed

+339
-26
lines changed

.ci/downstreamTests.groovy

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ it is need as field to store the results of the tests.
1111
@Field def nodeTasksGen
1212

1313
pipeline {
14-
agent any
14+
agent { label 'linux && immutable' }
1515
environment {
1616
REPO = 'apm-agent-nodejs'
1717
BASE_DIR="src/github.com/elastic/${REPO}"
@@ -40,7 +40,6 @@ pipeline {
4040
Checkout the code and stash it, to use it on other stages.
4141
*/
4242
stage('Checkout') {
43-
agent { label 'immutable' }
4443
options { skipDefaultCheckout() }
4544
steps {
4645
deleteDir()
@@ -57,7 +56,6 @@ pipeline {
5756
Run TAV tests.
5857
*/
5958
stage('TAV Test') {
60-
agent { label 'docker && immutable' }
6159
options { skipDefaultCheckout() }
6260
environment {
6361
HOME = "${env.WORKSPACE}"

.ci/linting.groovy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
@Library('apm@current') _
33

44
pipeline {
5-
agent { label 'docker && immutable' }
5+
agent { label 'linux && immutable' }
66
environment {
77
HOME = "${env.WORKSPACE}"
88
}

.tav.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ pg:
5555
mongodb-core:
5656
versions: '>=1.2.19 <4'
5757
commands: node test/instrumentation/modules/mongodb-core.js
58+
mongodb:
59+
versions: '>=3.3'
60+
commands: node test/instrumentation/modules/mongodb.js
5861
bluebird:
5962
versions: '>=2 <4'
6063
commands:

Jenkinsfile

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
@Library('apm@current') _
33

44
pipeline {
5-
agent any
5+
agent { label 'linux && immutable' }
66
environment {
77
REPO = 'apm-agent-nodejs'
88
BASE_DIR = "src/github.com/elastic/${env.REPO}"
@@ -38,7 +38,6 @@ pipeline {
3838
Checkout the code and stash it, to use it on other stages.
3939
*/
4040
stage('Checkout') {
41-
agent { label 'immutable' }
4241
options { skipDefaultCheckout() }
4342
steps {
4443
deleteDir()
@@ -59,7 +58,6 @@ pipeline {
5958
Run tests.
6059
*/
6160
stage('Test') {
62-
agent { label 'docker && immutable' }
6361
options { skipDefaultCheckout() }
6462
environment {
6563
HOME = "${env.WORKSPACE}"
@@ -98,7 +96,6 @@ pipeline {
9896
Run TAV tests.
9997
*/
10098
stage('TAV Test') {
101-
agent { label 'docker && immutable' }
10299
options { skipDefaultCheckout() }
103100
environment {
104101
HOME = "${env.WORKSPACE}"
@@ -157,7 +154,7 @@ pipeline {
157154
}
158155
parallel {
159156
stage('Nightly Test') {
160-
agent { label 'docker && immutable' }
157+
agent { label 'linux && immutable' }
161158
environment {
162159
NVM_NODEJS_ORG_MIRROR = "https://nodejs.org/download/nightly/"
163160
}
@@ -179,7 +176,7 @@ pipeline {
179176
}
180177
}
181178
stage('Nightly Test - No async hooks') {
182-
agent { label 'docker && immutable' }
179+
agent { label 'linux && immutable' }
183180
environment {
184181
NVM_NODEJS_ORG_MIRROR = "https://nodejs.org/download/nightly/"
185182
}
@@ -201,7 +198,7 @@ pipeline {
201198
}
202199
}
203200
stage('RC Test') {
204-
agent { label 'docker && immutable' }
201+
agent { label 'linux && immutablee' }
205202
environment {
206203
NVM_NODEJS_ORG_MIRROR = "https://nodejs.org/download/rc/"
207204
}
@@ -223,7 +220,7 @@ pipeline {
223220
}
224221
}
225222
stage('RC Test - No async hooks') {
226-
agent { label 'docker && immutable' }
223+
agent { label 'linux && immutable' }
227224
environment {
228225
NVM_NODEJS_ORG_MIRROR = "https://nodejs.org/download/rc/"
229226
}
@@ -328,7 +325,7 @@ def generateStep(Map params = [:]){
328325
def edge = params.containsKey('edge') ? params.edge : false
329326
def disableAsyncHooks = params.get('disableAsyncHooks', false)
330327
return {
331-
node('docker && linux && immutable'){
328+
node('linux && immutable'){
332329
try {
333330
env.HOME = "${WORKSPACE}"
334331
if (disableAsyncHooks) {
@@ -405,7 +402,7 @@ def getSmartTAVContext() {
405402

406403
def linting(){
407404
return {
408-
node('docker && linux && immutable') {
405+
node('linux && immutable') {
409406
catchError(stageResult: 'UNSTABLE', message: 'Linting failures') {
410407
withGithubNotify(context: 'Linting') {
411408
deleteDir()

docs/configuration.asciidoc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,16 @@ Note that if a custom logger is provided, the `logLevel` option will be ignored.
385385

386386
Whether or not the agent should monitor for uncaught exceptions and send them to the APM Server automatically.
387387

388+
[[log-uncaught-exceptions]]
389+
==== `logUncaughtExceptions`
390+
391+
* *Type:* Boolean
392+
* *Default:* `true`
393+
* *Env:* `ELASTIC_APM_LOG_UNCAUGHT_EXCEPTIONS`
394+
395+
By default the stack trace of uncaught exceptions is written to STDERR.
396+
Set this config option to `false` to turn this behaviour off.
397+
388398
[[capture-error-log-stack-traces]]
389399
==== `captureErrorLogStackTraces`
390400

docs/supported-technologies.asciidoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ The Node.js agent will automatically instrument the following modules to give yo
8484
A lot of higher level MongoDB modules use mongodb-core,
8585
so those should be supported as well
8686
|https://www.npmjs.com/package/mongodb[mongodb] |>=2.0.0 <3.3.0 |Supported via mongodb-core
87+
|https://www.npmjs.com/package/mongodb[mongodb] |^3.3.0 |Will instrument all queries
8788
|https://www.npmjs.com/package/mongojs[mongojs] |>=1.0.0 <2.7.0 |Supported via mongodb-core
8889
|https://www.npmjs.com/package/mongoose[mongoose] |>=4.0.0 <5.7.0 |Supported via mongodb-core
8990
|https://www.npmjs.com/package/mysql[mysql] |^2.0.0 |Will instrument all queries

lib/agent.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -337,9 +337,9 @@ Agent.prototype.captureError = function (err, opts, cb) {
337337
if (captureLocation) {
338338
// prepare to add a stack trace pointing to where captureError was called
339339
// from. This can make it easier to debug async stack traces.
340-
stackman.callsites(captureLocation, function (_err, callsites) {
341-
if (_err) {
342-
agent.logger.debug('error while getting capture location callsites: %s', _err.message)
340+
stackman.callsites(captureLocation, function (err, callsites) {
341+
if (err) {
342+
agent.logger.debug('error while getting capture location callsites: %s', err.message)
343343
}
344344

345345
var next = afterAll(function (_, frames) {
@@ -405,7 +405,13 @@ Agent.prototype.handleUncaughtExceptions = function (cb) {
405405
}
406406

407407
this._uncaughtExceptionListener = function (err) {
408+
// The stack trace of uncaught exceptions are normally written to STDERR.
409+
// The `uncaughtException` listener inhibits this behavor, and it's
410+
// therefore necessary to manually do this to not break expectations.
411+
if (agent._conf.logUncaughtExceptions === true) console.error(err)
412+
408413
agent.logger.debug('Elastic APM caught unhandled exception: %s', err.message)
414+
409415
agent.captureError(err, { handled: false }, function () {
410416
cb ? cb(err) : process.exit(1)
411417
})

lib/config.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ var DEFAULTS = {
4545
captureExceptions: true,
4646
captureHeaders: true,
4747
captureSpanStackTraces: true,
48+
centralConfig: true,
4849
containerId: undefined,
4950
disableInstrumentations: [],
5051
environment: process.env.NODE_ENV || 'development',
@@ -53,15 +54,15 @@ var DEFAULTS = {
5354
filterHttpHeaders: true,
5455
globalLabels: undefined,
5556
instrument: true,
57+
instrumentIncomingHTTPRequests: true,
5658
kubernetesNamespace: undefined,
5759
kubernetesNodeName: undefined,
5860
kubernetesPodName: undefined,
5961
kubernetesPodUID: undefined,
6062
logLevel: 'info',
63+
logUncaughtExceptions: true,
6164
metricsInterval: '30s',
6265
metricsLimit: 1000,
63-
instrumentIncomingHTTPRequests: true,
64-
centralConfig: true,
6566
serverTimeout: '30s',
6667
sourceLinesErrorAppFrames: 5,
6768
sourceLinesErrorLibraryFrames: 5,
@@ -87,6 +88,7 @@ var ENV_TABLE = {
8788
captureExceptions: 'ELASTIC_APM_CAPTURE_EXCEPTIONS',
8889
captureHeaders: 'ELASTIC_APM_CAPTURE_HEADERS',
8990
captureSpanStackTraces: 'ELASTIC_APM_CAPTURE_SPAN_STACK_TRACES',
91+
centralConfig: 'ELASTIC_APM_CENTRAL_CONFIG',
9092
containerId: 'ELASTIC_APM_CONTAINER_ID',
9193
disableInstrumentations: 'ELASTIC_APM_DISABLE_INSTRUMENTATIONS',
9294
environment: 'ELASTIC_APM_ENVIRONMENT',
@@ -104,10 +106,10 @@ var ENV_TABLE = {
104106
kubernetesPodName: ['ELASTIC_APM_KUBERNETES_POD_NAME', 'KUBERNETES_POD_NAME'],
105107
kubernetesPodUID: ['ELASTIC_APM_KUBERNETES_POD_UID', 'KUBERNETES_POD_UID'],
106108
logLevel: 'ELASTIC_APM_LOG_LEVEL',
109+
logUncaughtExceptions: 'ELASTIC_APM_LOG_UNCAUGHT_EXCEPTIONS',
107110
metricsInterval: 'ELASTIC_APM_METRICS_INTERVAL',
108111
metricsLimit: 'ELASTIC_APM_METRICS_LIMIT',
109112
payloadLogFile: 'ELASTIC_APM_PAYLOAD_LOG_FILE',
110-
centralConfig: 'ELASTIC_APM_CENTRAL_CONFIG',
111113
secretToken: 'ELASTIC_APM_SECRET_TOKEN',
112114
serverTimeout: 'ELASTIC_APM_SERVER_TIMEOUT',
113115
serverUrl: 'ELASTIC_APM_SERVER_URL',
@@ -144,6 +146,7 @@ var BOOL_OPTS = [
144146
'filterHttpHeaders',
145147
'instrument',
146148
'instrumentIncomingHTTPRequests',
149+
'logUncaughtExceptions',
147150
'usePathAsTransactionName',
148151
'verifyServerCert'
149152
]

lib/instrumentation/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ var MODULES = [
3535
'memcached',
3636
'mimic-response',
3737
'mongodb-core',
38+
'mongodb',
3839
'mysql',
3940
'mysql2',
4041
'pg',
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
'use strict'
2+
3+
const semver = require('semver')
4+
5+
module.exports = (mongodb, agent, { version, enabled }) => {
6+
if (!enabled) return mongodb
7+
if (!semver.satisfies(version, '>=3.3')) {
8+
agent.logger.debug('mongodb version %s not supported - aborting...', version)
9+
return mongodb
10+
}
11+
12+
const listener = mongodb.instrument()
13+
const activeSpans = new Map()
14+
15+
listener.on('started', onStart)
16+
listener.on('succeeded', onEnd)
17+
listener.on('failed', onEnd)
18+
19+
return mongodb
20+
21+
function onStart (event) {
22+
const name = [
23+
event.databaseName,
24+
collectionFor(event),
25+
event.commandName
26+
].join('.')
27+
28+
const span = agent.startSpan(name, 'db', 'mongodb', 'query')
29+
if (span) {
30+
activeSpans.set(event.requestId, span)
31+
}
32+
}
33+
34+
function onEnd (event) {
35+
if (!activeSpans.has(event.requestId)) return
36+
const span = activeSpans.get(event.requestId)
37+
activeSpans.delete(event.requestId)
38+
span.end((span._timer.start / 1000) + event.duration)
39+
}
40+
41+
function collectionFor (event) {
42+
const collection = event.command[event.commandName]
43+
return typeof collection === 'string' ? collection : '$cmd'
44+
}
45+
}

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@
150150
"memcached": "^2.2.2",
151151
"mimic-response": "^2.0.0",
152152
"mkdirp": "^0.5.1",
153+
"mongodb": "^3.3.2",
153154
"mongodb-core": "^3.2.7",
154155
"mysql": "^2.17.1",
155156
"mysql2": "^1.7.0",

test/_mock_http_client_states.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
'use strict'
2+
3+
module.exports = function (expectations = [], done) {
4+
return {
5+
_write (obj, cb) {
6+
cb = cb || (() => {})
7+
8+
const type = Object.keys(obj)[0]
9+
10+
for (let i = 0; i < expectations.length; i++) {
11+
const { find, test } = expectations[i]
12+
if (find(type, obj[type])) {
13+
expectations.splice(i, 1)
14+
if (!expectations.length) {
15+
done()
16+
}
17+
test(obj[type])
18+
break
19+
}
20+
}
21+
22+
process.nextTick(cb)
23+
},
24+
sendSpan (span, cb) {
25+
this._write({ span }, cb)
26+
},
27+
sendTransaction (transaction, cb) {
28+
this._write({ transaction }, cb)
29+
},
30+
sendError (error, cb) {
31+
this._write({ error }, cb)
32+
},
33+
sendMetricSet (metricset, cb) {
34+
this._write({ metricset }, cb)
35+
},
36+
flush (cb) {
37+
if (cb) process.nextTick(cb)
38+
}
39+
}
40+
}

test/config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ var optionFixtures = [
5353
['kubernetesPodName', 'KUBERNETES_POD_NAME'],
5454
['kubernetesPodUID', 'KUBERNETES_POD_UID'],
5555
['logLevel', 'LOG_LEVEL', 'info'],
56+
['logUncaughtExceptions', 'LOG_UNCAUGHT_EXCEPTIONS', true],
5657
['metricsInterval', 'METRICS_INTERVAL', 30],
5758
['metricsLimit', 'METRICS_LIMIT', 1000],
5859
['secretToken', 'SECRET_TOKEN'],

0 commit comments

Comments
 (0)