Skip to content

Commit 15431f2

Browse files
jrodewigrw-access
andauthored
[DOCS] EQL: Document sequences (#56721)
Co-authored-by: Ross Wolf <[email protected]>
1 parent b769f76 commit 15431f2

File tree

3 files changed

+273
-15
lines changed

3 files changed

+273
-15
lines changed

docs/reference/eql/eql-search-api.asciidoc

Lines changed: 191 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -168,23 +168,23 @@ If `true`, the request timed out before completion.
168168

169169
`hits`::
170170
(object)
171-
Contains returned events and metadata.
171+
Contains matching events and metadata.
172172
+
173173
.Properties of `hits`
174174
[%collapsible%open]
175175
====
176176
177177
`total`::
178178
(object)
179-
Metadata about the number of returned events.
179+
Metadata about the number of matching events.
180180
+
181181
.Properties of `total`
182182
[%collapsible%open]
183183
=====
184184

185185
`value`::
186186
(integer)
187-
Total number of returned events.
187+
Total number of matching events.
188188

189189
`relation`::
190190
+
@@ -199,29 +199,80 @@ Returned values are:
199199
--
200200
=====
201201
202+
`sequences`::
203+
(array of objects)
204+
Contains event sequences matching the query. Each object represents a
205+
matching sequence. This parameter is only returned for EQL queries containing
206+
a <<eql-sequences,sequence>>.
207+
+
208+
.Properties of `sequences` objects
209+
[%collapsible%open]
210+
=====
211+
`join_keys`::
212+
(array of strings)
213+
Shared field values used to constrain matches in the sequence. These are defined
214+
using the <<eql-sequences,`by` keyword>> in the EQL query syntax.
215+
202216
`events`::
203217
(array of objects)
204-
Contains returned events matching the query. Each object represents a
218+
Contains events matching the query. Each object represents a
205219
matching event.
206220
+
207221
.Properties of `events` objects
208222
[%collapsible%open]
223+
======
224+
`_index`::
225+
(string)
226+
Name of the index containing the event.
227+
228+
`_id`::
229+
(string)
230+
(string)
231+
Unique identifier for the event.
232+
This ID is only unique within the index.
233+
234+
`_score`::
235+
(float)
236+
Positive 32-bit floating point number used to determine the relevance of the
237+
event. See <<relevance-scores>>.
238+
239+
`_source`::
240+
(object)
241+
Original JSON body passed for the event at index time.
242+
243+
`sort`::
244+
(array)
245+
Integer used as the sort value for the event.
246+
+
247+
By default, this is the event's <<eql-search-api-timestamp-field,timestamp
248+
value>>, converted to milliseconds since the
249+
https://en.wikipedia.org/wiki/Unix_time[Unix epoch].
250+
======
209251
=====
210252
253+
[[eql-search-api-response-events]]
254+
`events`::
255+
(array of objects)
256+
Contains events matching the query. Each object represents a
257+
matching event.
258+
+
259+
.Properties of `events` objects
260+
[%collapsible%open]
261+
=====
211262
`_index`::
212263
(string)
213-
Name of the index containing the returned event.
264+
Name of the index containing the event.
214265

215266
`_id`::
216267
(string)
217268
(string)
218-
Unique identifier for the returned event.
219-
This ID is only unique within the returned index.
269+
Unique identifier for the event.
270+
This ID is only unique within the index.
220271

221272
`_score`::
222273
(float)
223274
Positive 32-bit floating point number used to determine the relevance of the
224-
returned event. See <<relevance-scores>>.
275+
event. See <<relevance-scores>>.
225276

226277
`_source`::
227278
(object)
@@ -240,11 +291,14 @@ https://en.wikipedia.org/wiki/Unix_time[Unix epoch].
240291
[[eql-search-api-example]]
241292
==== {api-examples-title}
242293

294+
[[eql-search-api-basic-query-ex]]
295+
==== Basic query example
296+
243297
The following EQL search request searches for events with an `event.category` of
244298
`file` that meet the following conditions:
245299

246300
* A `file.name` of `cmd.exe`
247-
* An `agent.id` that is _not_ `my_user`
301+
* An `agent.id` other than `my_user`
248302

249303
[source,console]
250304
----
@@ -256,9 +310,10 @@ GET my_index/_eql/search
256310
}
257311
----
258312

259-
The API returns the following response. Events in the response are sorted by
260-
<<eql-search-api-timestamp-field,timestamp>>, converted to milliseconds since
261-
the https://en.wikipedia.org/wiki/Unix_time[Unix epoch], in ascending order.
313+
The API returns the following response. Matching events in the `hits.events`
314+
property are sorted by <<eql-search-api-timestamp-field,timestamp>>, converted
315+
to milliseconds since the https://en.wikipedia.org/wiki/Unix_time[Unix epoch],
316+
in ascending order.
262317

263318
[source,console-result]
264319
----
@@ -331,4 +386,127 @@ the https://en.wikipedia.org/wiki/Unix_time[Unix epoch], in ascending order.
331386
}
332387
}
333388
----
334-
// TESTRESPONSE[s/"took": 6/"took": $body.took/]
389+
// TESTRESPONSE[s/"took": 6/"took": $body.took/]
390+
391+
[[eql-search-api-sequence-ex]]
392+
==== Sequence query example
393+
394+
The following EQL search request matches a <<eql-sequences,sequence>> of events
395+
that:
396+
397+
. Start with an event with:
398+
+
399+
--
400+
* An `event.category` of `file`
401+
* A `file.name` of `cmd.exe`
402+
* An `agent.id` other than `my_user`
403+
--
404+
. Followed by an event with:
405+
+
406+
--
407+
* An `event.category` of `process`
408+
* A `process.path` that contains the substring `regsvr32`
409+
--
410+
411+
These events must also share the same `agent.id` value.
412+
413+
[source,console]
414+
----
415+
GET my_index/_eql/search
416+
{
417+
"query": """
418+
sequence by agent.id
419+
[ file where file.name == "cmd.exe" and agent.id != "my_user" ]
420+
[ process where stringContains(process.path, "regsvr32") ]
421+
"""
422+
}
423+
----
424+
425+
The API returns the following response. The `hits.sequences.join_keys` property
426+
contains the shared `agent.id` value for each matching event. Matching events in
427+
the `hits.sequences.events` property are sorted by
428+
<<eql-search-api-timestamp-field,timestamp>>, converted to milliseconds since
429+
the https://en.wikipedia.org/wiki/Unix_time[Unix epoch], in ascending order.
430+
431+
[source,console-result]
432+
----
433+
{
434+
"took": 6,
435+
"timed_out": false,
436+
"hits": {
437+
"total": {
438+
"value": 1,
439+
"relation": "eq"
440+
},
441+
"sequences": [
442+
{
443+
"join_keys": [
444+
"8a4f500d"
445+
],
446+
"events": [
447+
{
448+
"_index": "my_index",
449+
"_id": "4",
450+
"_score": null,
451+
"_source": {
452+
"@timestamp": "2020-12-07T11:07:08.000Z",
453+
"agent": {
454+
"id": "8a4f500d"
455+
},
456+
"event": {
457+
"category": "file"
458+
},
459+
"file": {
460+
"accessed": "2020-12-07T11:07:08.000Z",
461+
"name": "cmd.exe",
462+
"path": "C:\\Windows\\System32\\cmd.exe",
463+
"type": "file",
464+
"size": 16384
465+
},
466+
"process": {
467+
"name": "cmd.exe",
468+
"path": "C:\\Windows\\System32\\cmd.exe"
469+
}
470+
},
471+
"fields": {
472+
"@timestamp": [
473+
"1607339228000"
474+
]
475+
},
476+
"sort": [
477+
1607339228000
478+
]
479+
},
480+
{
481+
"_index": "my_index",
482+
"_id": "5",
483+
"_score": null,
484+
"_source": {
485+
"@timestamp": "2020-12-07T11:07:09.000Z",
486+
"agent": {
487+
"id": "8a4f500d"
488+
},
489+
"event": {
490+
"category": "process"
491+
},
492+
"process": {
493+
"name": "regsvr32.exe",
494+
"path": "C:\\Windows\\System32\\regsvr32.exe"
495+
}
496+
},
497+
"fields": {
498+
"@timestamp": [
499+
"1607339229000"
500+
]
501+
},
502+
"sort": [
503+
1607339229000
504+
]
505+
}
506+
]
507+
}
508+
]
509+
}
510+
}
511+
----
512+
// TESTRESPONSE[s/"took": 6/"took": $body.took/]

docs/reference/eql/limitations.asciidoc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,6 @@ queries that contain:
3737

3838
* {eql-ref}/pipes.html[Pipes]
3939

40-
* {eql-ref}/sequences.html[Sequences]
40+
* {eql-ref}/sequences.html[State and timespan-related sequence keywords]:
41+
** `with maxspan`
42+
** `until`

docs/reference/eql/syntax.asciidoc

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,84 @@ dots (`.`), hyphens (`-`), or spaces, must be escaped using backticks (+++`+++).
341341
`my field`
342342
----
343343

344+
[discrete]
345+
[[eql-sequences]]
346+
=== Sequences
347+
348+
You can use EQL sequences to describe and match an ordered series of events.
349+
Each item in a sequence is an event category and event condition,
350+
surrounded by square brackets. Events are listed in ascending chronological
351+
order, with the most recent event listed last.
352+
353+
[source,eql]
354+
----
355+
sequence
356+
[ event_category_1 where condition_1 ]
357+
[ event_category_2 where condition_2 ]
358+
...
359+
----
360+
361+
.*Example*
362+
[%collapsible]
363+
====
364+
The following EQL query matches this series of ordered events:
365+
366+
. Start with an event with:
367+
+
368+
--
369+
* An event category of `file`
370+
* A `file.extension` of `exe`
371+
--
372+
. Followed by an event with an event category of `process`
373+
374+
[source,eql]
375+
----
376+
sequence
377+
[ file where file.extension == "exe" ]
378+
[ process where true ]
379+
----
380+
====
381+
382+
You can use the `by` keyword with sequences to only match events that share the
383+
same field values. If a field value should be shared across all events, you
384+
can use `sequence by`.
385+
386+
[source,eql]
387+
----
388+
sequence by field_foo
389+
[ event_category_1 where condition_1 ] by field_baz
390+
[ event_category_2 where condition_2 ] by field_bar
391+
...
392+
----
393+
394+
.*Example*
395+
[%collapsible]
396+
====
397+
The following sequence uses the `by` keyword to constrain matching events to:
398+
399+
* Events with the same `user.name` value
400+
* `file` events with a `file.path` value equal to the following `process`
401+
event's `process.path` value.
402+
403+
[source,eql]
404+
----
405+
sequence
406+
[ file where file.extension == "exe" ] by user.name, file.path
407+
[ process where true ] by user.name, process.path
408+
----
409+
410+
Because the `user.name` field is shared across all events in the sequence, it
411+
can be included using `sequence by`. The following sequence is equivalent to the
412+
prior one.
413+
414+
[source,eql]
415+
----
416+
sequence by user.name
417+
[ file where file.extension == "exe" ] by file.path
418+
[ process where true ] by process.path
419+
----
420+
====
421+
344422
[discrete]
345423
[[eql-functions]]
346424
=== Functions
@@ -394,4 +472,4 @@ file where file.extension in ("exe", "dll")
394472
395473
We recommend testing and benchmarking any indexing changes before deploying them
396474
in production. See <<tune-for-indexing-speed>> and <<tune-for-search-speed>>.
397-
====
475+
====

0 commit comments

Comments
 (0)