Skip to content

Commit 0f17460

Browse files
authored
X-Opaque-Id support (#997)
* Added X-Opaque-Id support * Updated type definitions * Updated test * Updated docs
1 parent 1e12523 commit 0f17460

File tree

7 files changed

+147
-2
lines changed

7 files changed

+147
-2
lines changed

docs/configuration.asciidoc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,11 @@ function generateRequestId (params, options) {
181181
|`string` - The name to identify the client instance in the events. +
182182
_Default:_ `elasticsearch-js`
183183

184+
|`opaqueIdPrefix`
185+
|`string` - A string that will be use to prefix any `X-Opaque-Id` header. +
186+
See https://www.elastic.co/guide/en/elasticsearch/client/javascript-api/current/observability.html#_x-opaque-id_support[`X-Opaque-Id` support] for more details. +
187+
_Default:_ `null`
188+
184189
|`headers`
185190
|`object` - A set of custom headers to send in every request. +
186191
_Default:_ `{}`

docs/observability.asciidoc

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,3 +248,46 @@ child.search({
248248
if (err) console.log(err)
249249
})
250250
----
251+
252+
=== X-Opaque-Id support
253+
To improve the overall observability, the client offers an easy way to configure the `X-Opaque-Id` header. If you set the `X-Opaque-Id` in a specific request, this will allow you to discover this identifier in the https://www.elastic.co/guide/en/elasticsearch/reference/master/logging.html#deprecation-logging[deprecation logs], help you with https://www.elastic.co/guide/en/elasticsearch/reference/master/index-modules-slowlog.html#_identifying_search_slow_log_origin[identifying search slow log origin] as well as https://www.elastic.co/guide/en/elasticsearch/reference/master/tasks.html#_identifying_running_tasks[identifying running tasks].
254+
255+
The `X-Opaque-Id` should be configured in each request, for doing that you can use the `opaqueId` option, as you can see in the following example. +
256+
The resulting header will be `{ 'X-Opaque-Id': 'my-search' }`.
257+
258+
[source,js]
259+
----
260+
const { Client } = require('@elastic/elasticsearch')
261+
const client = new Client({
262+
node: 'http://localhost:9200'
263+
})
264+
265+
client.search({
266+
index: 'my-index',
267+
body: { foo: 'bar' }
268+
}, {
269+
opaqueId: 'my-search'
270+
}, (err, result) => {
271+
if (err) console.log(err)
272+
})
273+
----
274+
275+
Sometimes it may be useful to prefix all the `X-Opaque-Id` headers with a specific string, in case you need to identify a specific client or server. For doing this, the client offers a top-level configuration option: `opaqueIdPrefix`. +
276+
In the following example, the resulting header will be `{ 'X-Opaque-Id': 'proxy-client::my-search' }`.
277+
[source,js]
278+
----
279+
const { Client } = require('@elastic/elasticsearch')
280+
const client = new Client({
281+
node: 'http://localhost:9200',
282+
opaqueIdPrefix: 'proxy-client::'
283+
})
284+
285+
client.search({
286+
index: 'my-index',
287+
body: { foo: 'bar' }
288+
}, {
289+
opaqueId: 'my-search'
290+
}, (err, result) => {
291+
if (err) console.log(err)
292+
})
293+
----

index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ interface ClientOptions {
9494
nodeFilter?: nodeFilterFn;
9595
nodeSelector?: nodeSelectorFn | string;
9696
headers?: anyObject;
97+
opaqueIdPrefix?: string;
9798
generateRequestId?: generateRequestIdFn;
9899
name?: string;
99100
auth?: BasicAuth | ApiKeyAuth;

index.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ class Client extends EventEmitter {
7979
nodeSelector: 'round-robin',
8080
generateRequestId: null,
8181
name: 'elasticsearch-js',
82-
auth: null
82+
auth: null,
83+
opaqueIdPrefix: null
8384
}, opts)
8485

8586
this[kInitialOptions] = options
@@ -121,7 +122,8 @@ class Client extends EventEmitter {
121122
nodeFilter: options.nodeFilter,
122123
nodeSelector: options.nodeSelector,
123124
generateRequestId: options.generateRequestId,
124-
name: options.name
125+
name: options.name,
126+
opaqueIdPrefix: options.opaqueIdPrefix
125127
})
126128

127129
const apis = buildApi({

lib/Transport.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ interface TransportOptions {
3838
headers?: anyObject;
3939
generateRequestId?: generateRequestIdFn;
4040
name: string;
41+
opaqueIdPrefix?: string;
4142
}
4243

4344
export interface RequestEvent<T = any, C = any> {
@@ -90,6 +91,7 @@ export interface TransportRequestOptions {
9091
id?: any;
9192
context?: any;
9293
warnings?: [string];
94+
opaqueId?: string;
9395
}
9496

9597
export interface TransportRequestCallback {
@@ -121,6 +123,7 @@ export default class Transport {
121123
compression: 'gzip' | false;
122124
sniffInterval: number;
123125
sniffOnConnectionFault: boolean;
126+
opaqueIdPrefix: string | null;
124127
sniffEndpoint: string;
125128
_sniffEnabled: boolean;
126129
_nextSniff: number;

lib/Transport.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ class Transport {
4141
this.sniffEndpoint = opts.sniffEndpoint
4242
this.generateRequestId = opts.generateRequestId || generateRequestId()
4343
this.name = opts.name
44+
this.opaqueIdPrefix = opts.opaqueIdPrefix
4445

4546
this.nodeFilter = opts.nodeFilter || defaultNodeFilter
4647
if (typeof opts.nodeSelector === 'function') {
@@ -114,6 +115,12 @@ class Transport {
114115
// TODO: make this assignment FAST
115116
const headers = Object.assign({}, this.headers, options.headers)
116117

118+
if (options.opaqueId !== undefined) {
119+
headers['X-Opaque-Id'] = this.opaqueIdPrefix !== null
120+
? this.opaqueIdPrefix + options.opaqueId
121+
: options.opaqueId
122+
}
123+
117124
// handle json body
118125
if (params.body != null) {
119126
if (shouldSerialize(params.body) === true) {

test/unit/client.test.js

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -851,3 +851,87 @@ test('Elastic cloud config', t => {
851851

852852
t.end()
853853
})
854+
855+
test('Opaque Id support', t => {
856+
t.test('No opaqueId', t => {
857+
t.plan(3)
858+
859+
function handler (req, res) {
860+
t.strictEqual(req.headers['x-opaque-id'], undefined)
861+
res.setHeader('Content-Type', 'application/json;utf=8')
862+
res.end(JSON.stringify({ hello: 'world' }))
863+
}
864+
865+
buildServer(handler, ({ port }, server) => {
866+
const client = new Client({
867+
node: `http://localhost:${port}`
868+
})
869+
870+
client.search({
871+
index: 'test',
872+
q: 'foo:bar'
873+
}, (err, { body }) => {
874+
t.error(err)
875+
t.deepEqual(body, { hello: 'world' })
876+
server.stop()
877+
})
878+
})
879+
})
880+
881+
t.test('No prefix', t => {
882+
t.plan(3)
883+
884+
function handler (req, res) {
885+
t.strictEqual(req.headers['x-opaque-id'], 'bar')
886+
res.setHeader('Content-Type', 'application/json;utf=8')
887+
res.end(JSON.stringify({ hello: 'world' }))
888+
}
889+
890+
buildServer(handler, ({ port }, server) => {
891+
const client = new Client({
892+
node: `http://localhost:${port}`
893+
})
894+
895+
client.search({
896+
index: 'test',
897+
q: 'foo:bar'
898+
}, {
899+
opaqueId: 'bar'
900+
}, (err, { body }) => {
901+
t.error(err)
902+
t.deepEqual(body, { hello: 'world' })
903+
server.stop()
904+
})
905+
})
906+
})
907+
908+
t.test('With prefix', t => {
909+
t.plan(3)
910+
911+
function handler (req, res) {
912+
t.strictEqual(req.headers['x-opaque-id'], 'foo-bar')
913+
res.setHeader('Content-Type', 'application/json;utf=8')
914+
res.end(JSON.stringify({ hello: 'world' }))
915+
}
916+
917+
buildServer(handler, ({ port }, server) => {
918+
const client = new Client({
919+
node: `http://localhost:${port}`,
920+
opaqueIdPrefix: 'foo-'
921+
})
922+
923+
client.search({
924+
index: 'test',
925+
q: 'foo:bar'
926+
}, {
927+
opaqueId: 'bar'
928+
}, (err, { body }) => {
929+
t.error(err)
930+
t.deepEqual(body, { hello: 'world' })
931+
server.stop()
932+
})
933+
})
934+
})
935+
936+
t.end()
937+
})

0 commit comments

Comments
 (0)