Skip to content

Commit e017768

Browse files
authored
fix: Dropped support for ElasticSearch < 7.16.0 (#1940)
1 parent d3e393d commit e017768

File tree

3 files changed

+180
-10
lines changed

3 files changed

+180
-10
lines changed

lib/instrumentation/@elastic/elasticsearch.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ const { isNotEmpty } = require('../../util/objects')
2020
*/
2121
module.exports = function initialize(_agent, elastic, _moduleName, shim) {
2222
const pkgVersion = shim.pkgVersion
23-
if (semver.lt(pkgVersion, '7.13.0')) {
23+
if (semver.lt(pkgVersion, '7.16.0')) {
2424
shim &&
2525
shim.logger.debug(
26-
`ElasticSearch support is for versions 7.13.0 and above. Not instrumenting ${pkgVersion}.`
26+
`ElasticSearch support is for versions 7.16.0 and above. Not instrumenting ${pkgVersion}.`
2727
)
2828
return
2929
}
@@ -70,6 +70,7 @@ function queryParser(params) {
7070
} else if (Array.isArray(params.bulkBody) && params.bulkBody.length) {
7171
queryParam = params.bulkBody
7272
}
73+
// The helper interface provides a simpler API:
7374

7475
const query = JSON.stringify(queryParam)
7576

test/versioned/elastic/elasticsearch.tap.js

Lines changed: 175 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ const { readFile } = require('fs/promises')
1515
const semver = require('semver')
1616
const DB_INDEX = `test-${randomString()}`
1717
const DB_INDEX_2 = `test2-${randomString()}`
18+
const DB_INDEX_3 = `test3-${randomString()}`
19+
const SEARCHTERM_1 = randomString()
1820

1921
function randomString() {
2022
return crypto.randomBytes(5).toString('hex')
@@ -130,7 +132,10 @@ test('Elasticsearch instrumentation', (t) => {
130132
{ index: { _index: DB_INDEX_2 } },
131133
{ title: 'Fifth Bulk Doc', body: 'Content of fifth bulk document' },
132134
{ index: { _index: DB_INDEX_2 } },
133-
{ title: 'Sixth Bulk Doc', body: 'Content of sixth bulk document.' },
135+
{
136+
title: 'Sixth Bulk Doc',
137+
body: `Content of sixth bulk document. Has search term: ${SEARCHTERM_1}`
138+
},
134139
{ index: { _index: DB_INDEX_2 } },
135140
{ title: 'Seventh Bulk Doc', body: 'Content of seventh bulk document.' },
136141
{ index: { _index: DB_INDEX_2 } },
@@ -150,13 +155,54 @@ test('Elasticsearch instrumentation', (t) => {
150155
})
151156
})
152157

158+
t.test('should record bulk operations triggered by client helpers', async (t) => {
159+
await helper.runInTransaction(agent, async function transactionInScope(transaction) {
160+
const operations = [
161+
{ title: 'Ninth Bulk Doc from helpers', body: 'Content of ninth bulk document' },
162+
{ title: 'Tenth Bulk Doc from helpers', body: 'Content of tenth bulk document.' },
163+
{ title: 'Eleventh Bulk Doc from helpers', body: 'Content of eleventh bulk document.' },
164+
{ title: 'Twelfth Bulk Doc from helpers', body: 'Content of twelfth bulk document.' },
165+
{
166+
title: 'Thirteenth Bulk Doc from helpers',
167+
body: 'Content of thirteenth bulk document'
168+
},
169+
{
170+
title: 'Fourteenth Bulk Doc from helpers',
171+
body: 'Content of fourteenth bulk document.'
172+
},
173+
{ title: 'Fifteenth Bulk Doc from helpers', body: 'Content of fifteenth bulk document.' },
174+
{ title: 'Sixteenth Bulk Doc from helpers', body: 'Content of sixteenth bulk document.' }
175+
]
176+
await client.helpers.bulk({
177+
datasource: operations,
178+
onDocument() {
179+
return {
180+
index: { _index: DB_INDEX_2 }
181+
}
182+
},
183+
refreshOnCompletion: true
184+
})
185+
t.ok(transaction, 'transaction should still be visible after bulk create')
186+
const trace = transaction.trace
187+
t.ok(trace?.root?.children?.[0], 'trace, trace root, and first child should exist')
188+
t.ok(trace?.root?.children?.[1], 'trace, trace root, and second child should exist')
189+
// helper interface results in a first child of timers.setTimeout, with the second child related to the operation
190+
const secondChild = trace.root.children[1]
191+
t.equal(
192+
secondChild.name,
193+
'Datastore/statement/ElasticSearch/any/bulk.create',
194+
'should record bulk operation'
195+
)
196+
})
197+
})
198+
153199
t.test('should record search with query string', async function (t) {
154200
// enable slow queries
155201
agent.config.transaction_tracer.explain_threshold = 0
156202
agent.config.transaction_tracer.record_sql = 'raw'
157203
agent.config.slow_sql.enabled = true
158204
await helper.runInTransaction(agent, async function transactionInScope(transaction) {
159-
const expectedQuery = { q: 'sixth' }
205+
const expectedQuery = { q: SEARCHTERM_1 }
160206
const search = await client.search({ index: DB_INDEX_2, ...expectedQuery })
161207
t.ok(search, 'search should return a result')
162208
t.ok(transaction, 'transaction should still be visible after search')
@@ -263,29 +309,29 @@ test('Elasticsearch instrumentation', (t) => {
263309
await helper.runInTransaction(agent, async function transactionInScope(transaction) {
264310
const expectedQuery = [
265311
{}, // cross-index searches have can have an empty metadata section
266-
{ query: { match: { body: 'sixth' } } },
312+
{ query: { match: { body: SEARCHTERM_1 } } },
267313
{},
268314
{ query: { match: { body: 'bulk' } } }
269315
]
270316
const requestBody = setMsearch(expectedQuery, pkgVersion)
271317
const search = await client.msearch(requestBody)
272318
// 7 and 8 have different result responses
273319
let results = search?.responses
274-
if (semver.lt(pkgVersion, '8.0.0')) {
320+
if (!search?.responses && semver.lt(pkgVersion, '8.0.0')) {
275321
results = search?.body?.responses
276322
}
277323

278324
t.ok(results, 'msearch should return results')
279325
t.equal(results?.length, 2, 'there should be two responses--one per search')
280326
t.equal(results?.[0]?.hits?.hits?.length, 1, 'first search should return one result')
281-
t.equal(results?.[1]?.hits?.hits?.length, 8, 'second search should return eight results')
327+
t.equal(results?.[1]?.hits?.hits?.length, 10, 'second search should return ten results')
282328
t.ok(transaction, 'transaction should still be visible after search')
283329
const trace = transaction.trace
284330
t.ok(trace?.root?.children?.[0], 'trace, trace root, and first child should exist')
285331
const firstChild = trace.root.children[0]
286332
t.match(
287333
firstChild.name,
288-
'Datastore/statement/ElasticSearch/any/msearch',
334+
'Datastore/statement/ElasticSearch/any/msearch.create',
289335
'child name should show msearch'
290336
)
291337
const attrs = firstChild.getAttributes()
@@ -304,6 +350,39 @@ test('Elasticsearch instrumentation', (t) => {
304350
})
305351
})
306352

353+
t.test('should record msearch via helpers', async function (t) {
354+
agent.config.transaction_tracer.explain_threshold = 0
355+
agent.config.transaction_tracer.record_sql = 'raw'
356+
agent.config.slow_sql.enabled = true
357+
await helper.runInTransaction(agent, async function transactionInScope(transaction) {
358+
const m = client.helpers.msearch()
359+
const searchA = await m.search({}, { query: { match: { body: SEARCHTERM_1 } } })
360+
const searchB = await m.search({}, { query: { match: { body: 'bulk' } } })
361+
const resultsA = searchA?.body?.hits
362+
const resultsB = searchB?.body?.hits
363+
364+
t.ok(resultsA, 'msearch for sixth should return results')
365+
t.ok(resultsB, 'msearch for bulk should return results')
366+
t.equal(resultsA?.hits?.length, 1, 'first search should return one result')
367+
t.equal(resultsB?.hits?.length, 10, 'second search should return ten results')
368+
t.ok(transaction, 'transaction should still be visible after search')
369+
const trace = transaction.trace
370+
t.ok(trace?.root?.children?.[0], 'trace, trace root, and first child should exist')
371+
const firstChild = trace.root.children[0]
372+
t.match(
373+
firstChild.name,
374+
'timers.setTimeout',
375+
'helpers, for some reason, generates a setTimeout metric first'
376+
)
377+
transaction.end()
378+
t.ok(agent.queries.samples.size > 0, 'there should be a query sample')
379+
for (const query of agent.queries.samples.values()) {
380+
// which query gets captured in helper.msearch is non-deterministic
381+
t.ok(query.total > 0, 'the samples should have positive duration')
382+
}
383+
})
384+
})
385+
307386
t.test('should create correct metrics', async function (t) {
308387
const id = `key-${randomString()}`
309388
t.plan(28)
@@ -417,6 +496,96 @@ test('Elasticsearch instrumentation', (t) => {
417496
})
418497
})
419498

499+
test('Elasticsearch uninstrumented behavior, to check helpers', { skip: false }, (t) => {
500+
t.autoend()
501+
502+
let client
503+
// eslint-disable-next-line no-unused-vars
504+
let pkgVersion
505+
506+
t.before(async () => {
507+
// Determine version. ElasticSearch v7 did not export package, so we have to read the file
508+
// instead of requiring it, as we can with 8+.
509+
const pkg = await readFile(`${__dirname}/node_modules/@elastic/elasticsearch/package.json`)
510+
;({ version: pkgVersion } = JSON.parse(pkg.toString()))
511+
512+
const { Client } = require('@elastic/elasticsearch')
513+
client = new Client({
514+
node: `http://${params.elastic_host}:${params.elastic_port}`
515+
})
516+
517+
return Promise.all([client.indices.create({ index: DB_INDEX_3 })])
518+
})
519+
520+
t.teardown(() => {
521+
return Promise.all([client.indices.delete({ index: DB_INDEX_3 })])
522+
})
523+
524+
t.test('should record bulk operations triggered by client helpers', async (t) => {
525+
const operations = [
526+
{
527+
title: 'Uninstrumented First Bulk Doc from helpers',
528+
body: 'Content of uninstrumented first bulk document'
529+
},
530+
{
531+
title: 'Uninstrumented Second Bulk Doc from helpers',
532+
body: 'Content of uninstrumented second bulk document.'
533+
},
534+
{
535+
title: 'Uninstrumented Third Bulk Doc from helpers',
536+
body: 'Content of uninstrumented third bulk document.'
537+
},
538+
{
539+
title: 'Uninstrumented Fourth Bulk Doc from helpers',
540+
body: 'Content of uninstrumented fourth bulk document.'
541+
},
542+
{
543+
title: 'Uninstrumented Fifth Bulk Doc from helpers',
544+
body: 'Content of uninstrumented fifth bulk document'
545+
},
546+
{
547+
title: 'Uninstrumented Sixth Bulk Doc from helpers',
548+
body: 'Content of uninstrumented sixth bulk document.'
549+
},
550+
{
551+
title: 'Uninstrumented Seventh Bulk Doc from helpers',
552+
body: 'Content of uninstrumented seventh bulk document.'
553+
},
554+
{
555+
title: 'Uninstrumented Eighth Bulk Doc from helpers',
556+
body: 'Content of uninstrumented eighth bulk document.'
557+
}
558+
]
559+
const result = await client.helpers.bulk({
560+
datasource: operations,
561+
onDocument() {
562+
return {
563+
index: { _index: DB_INDEX_3 }
564+
}
565+
}
566+
// refreshOnCompletion: true
567+
}) // setBulkBody(operations, pkgVersion)
568+
t.ok(result, 'We should have been able to create bulk entries without error')
569+
t.equal(result.total, 8, 'We should have been inserted eight records')
570+
})
571+
t.test('should be able to check bulk insert with msearch via helpers', async function (t) {
572+
const m = client.helpers.msearch()
573+
const searchA = await m.search({ index: DB_INDEX_3 }, { query: { match: { body: 'sixth' } } })
574+
const searchB = await m.search(
575+
{ index: DB_INDEX_3 },
576+
{ query: { match: { body: 'uninstrumented' } } }
577+
)
578+
const resultsA = searchA?.body?.hits
579+
const resultsB = searchB?.body?.hits
580+
581+
t.ok(resultsA, 'msearch should return a response for A')
582+
t.ok(resultsB, 'msearch should return results for B')
583+
// some versions of helper msearch seem not to return results for the first search.
584+
// t.equal(resultsA?.hits?.length, 1, 'first search should return one result')
585+
t.equal(resultsB?.hits?.length, 8, 'second search should return eight results')
586+
})
587+
})
588+
420589
function checkMetrics(t, metrics, expected) {
421590
Object.keys(expected).forEach(function (name) {
422591
t.ok(metrics[name], 'should have metric ' + name)

test/versioned/elastic/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"node": ">=16"
1212
},
1313
"dependencies": {
14-
"@elastic/elasticsearch": "7.10.0"
14+
"@elastic/elasticsearch": "7.13.0"
1515
},
1616
"files": [
1717
"elasticsearchNoop.tap.js"
@@ -22,7 +22,7 @@
2222
"node": ">=16"
2323
},
2424
"dependencies": {
25-
"@elastic/elasticsearch": ">=7.13.0"
25+
"@elastic/elasticsearch": ">=7.16.0"
2626
},
2727
"files": [
2828
"elasticsearch.tap.js"

0 commit comments

Comments
 (0)