Skip to content

Commit 52c8f27

Browse files
authored
feat: Drop unsampled transactions when connected to APM Server 8.0+ (#2546)
This updates to an elastic-apm-http-client that calls the APM Server Information API on creation to get the APM Server version. Closes: #2455
1 parent ec9214c commit 52c8f27

27 files changed

+261
-93
lines changed

CHANGELOG.asciidoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ Notes:
3737
[float]
3838
===== Features
3939
40+
* Drop unsampled transactions when sending to APM Server v8.0+. ({issues}2455[#2455])
41+
4042
* The default <<service-name, `serviceName`>> string (when it is not configured
4143
and cannot be inferred from a "package.json" file) has been changed from
4244
"nodejs_service" to "unknown-nodejs-service". This is a standardized pattern

lib/config.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -925,9 +925,10 @@ function getBaseClientConfig (conf, agent) {
925925
time: conf.apiRequestTime * 1000,
926926
maxQueueSize: conf.maxQueueSize,
927927

928-
// Debugging
928+
// Debugging/testing options
929929
logger: clientLogger,
930930
payloadLogFile: conf.payloadLogFile,
931+
apmServerVersion: conf.apmServerVersion,
931932

932933
// Container conf
933934
containerId: conf.containerId,

lib/instrumentation/index.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,11 @@ Instrumentation.prototype.addEndedTransaction = function (transaction) {
281281
return
282282
}
283283

284+
// https://github.com/elastic/apm/blob/main/specs/agents/tracing-sampling.md#non-sampled-transactions
285+
if (!transaction.sampled && !agent._transport.supportsKeepingUnsampledTransaction()) {
286+
return
287+
}
288+
284289
var payload = agent._transactionFilters.process(transaction._encode())
285290
if (!payload) {
286291
agent.logger.debug('transaction ignored by filter %o', { trans: transaction.id, trace: transaction.traceId })

lib/noop-transport.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ class NoopTransport {
4343
}
4444
}
4545

46+
supportsKeepingUnsampledTransaction () {
47+
return true
48+
}
49+
4650
// Inherited from Writable, called in agent.js.
4751
destroy () {}
4852
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@
8686
"basic-auth": "^2.0.1",
8787
"cookie": "^0.4.0",
8888
"core-util-is": "^1.0.2",
89-
"elastic-apm-http-client": "^10.3.0",
89+
"elastic-apm-http-client": "^10.4.0",
9090
"end-of-stream": "^1.4.4",
9191
"error-callsites": "^2.0.4",
9292
"error-stack-parser": "^2.0.6",

test/_capturing_transport.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ class CapturingTransport {
7777
}
7878
}
7979

80+
supportsKeepingUnsampledTransaction () {
81+
return true
82+
}
83+
8084
// Inherited from Writable, called in agent.js.
8185
destroy () {}
8286
}

test/_mock_apm_server.js

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// A mock APM server to use in tests.
22
//
33
// Usage:
4-
// const server = new MockAPMServer()
4+
// const server = new MockAPMServer(opts)
55
// server.start(function (serverUrl) {
66
// // Test code using `serverUrl`...
77
// // - Events received on the intake API will be on `server.events`.
@@ -16,9 +16,14 @@ const { URL } = require('url')
1616
const zlib = require('zlib')
1717

1818
class MockAPMServer {
19-
constructor () {
19+
// - @param {Object} opts
20+
// - {String} opts.apmServerVersion - The version to report in the
21+
// "GET /" response body. Defaults to "8.0.0".
22+
constructor (opts) {
23+
opts = opts || {}
2024
this.clear()
2125
this.serverUrl = null // set in .start()
26+
this.apmServerVersion = opts.apmServerVersion || '8.0.0'
2227
this._http = http.createServer(this._onRequest.bind(this))
2328
}
2429

@@ -43,7 +48,15 @@ class MockAPMServer {
4348

4449
instream.on('end', () => {
4550
let resBody = ''
46-
if (parsedUrl.pathname === '/config/v1/agents') {
51+
if (req.method === 'GET' && parsedUrl.pathname === '/') {
52+
// https://www.elastic.co/guide/en/apm/server/current/server-info.html#server-info-endpoint
53+
res.writeHead(200)
54+
resBody = JSON.stringify({
55+
build_date: '2021-09-16T02:05:39Z',
56+
build_sha: 'a183f675ecd03fca4a897cbe85fda3511bc3ca43',
57+
version: this.apmServerVersion
58+
})
59+
} else if (parsedUrl.pathname === '/config/v1/agents') {
4760
// Central config mocking.
4861
res.writeHead(200)
4962
resBody = '{}'

test/_mock_http_client.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ module.exports = function (expected, done) {
5454
},
5555
flush (cb) {
5656
if (cb) process.nextTick(cb)
57+
},
58+
supportsKeepingUnsampledTransaction () {
59+
return true
5760
}
5861
}
5962

test/_mock_http_client_states.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ module.exports = function (expectations = [], done) {
3535
},
3636
flush (cb) {
3737
if (cb) process.nextTick(cb)
38+
},
39+
supportsKeepingUnsampledTransaction () {
40+
return true
3841
}
3942
}
4043
}

test/agent.test.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -553,7 +553,12 @@ test('filters', function (t) {
553553
filterAgentOpts = Object.assign(
554554
{},
555555
agentOpts,
556-
{ serverUrl }
556+
{
557+
serverUrl,
558+
// Ensure the APM client's `GET /` requests do not get in the way of
559+
// the test asserts below.
560+
apmServerVersion: '8.0.0'
561+
}
557562
)
558563
t.end()
559564
})

0 commit comments

Comments
 (0)