Skip to content

Commit f9a9b32

Browse files
[filebeat] First unifiedlogs implementation (elastic#41791)
* First unifiedlogs implementation * Fix date check and accept multiple predicates * Fix cursor and date walking * Log stderr on error * Add 1s tick * Refactor to do automatic backfill * Add docs and fix resuming from interrupted backfilling * Fix doc config example * Add first unit tests * wip tests * Add stream test * Extract test and make input stable * Improve docs --------- Co-authored-by: r-ung <[email protected]>
1 parent f5e21bb commit f9a9b32

File tree

10 files changed

+1117
-1
lines changed

10 files changed

+1117
-1
lines changed

CHANGELOG.next.asciidoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,7 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff]
358358
- Add ability to remove request trace logs from entityanalytics input. {pull}40004[40004]
359359
- Refactor & cleanup with updates to default values and documentation. {pull}41834[41834]
360360
- Update CEL mito extensions to v1.16.0. {pull}41727[41727]
361+
- Add `unifiedlogs` input for MacOS. {pull}41791[41791]
361362
- Add evaluation state dump debugging option to CEL input. {pull}41335[41335]
362363
- Added support for retry configuration in GCS input. {issue}11580[11580] {pull}41862[41862]
363364
- Improve S3 polling mode states registry when using list prefix option. {pull}41869[41869]

filebeat/docs/filebeat-options.asciidoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ You can configure {beatname_uc} to use the following inputs:
9595
* <<{beatname_lc}-input-syslog>>
9696
* <<{beatname_lc}-input-tcp>>
9797
* <<{beatname_lc}-input-udp>>
98+
* <<{beatname_lc}-input-unifiedlogs>>
9899
* <<{beatname_lc}-input-unix>>
99100
* <<{beatname_lc}-input-winlog>>
100101

@@ -158,6 +159,8 @@ include::inputs/input-tcp.asciidoc[]
158159

159160
include::inputs/input-udp.asciidoc[]
160161

162+
include::../../x-pack/filebeat/docs/inputs/input-unifiedlogs.asciidoc[]
163+
161164
include::inputs/input-unix.asciidoc[]
162165

163166
include::inputs/input-winlog.asciidoc[]
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
[role="xpack"]
2+
3+
:type: unifiedlogs
4+
5+
[id="{beatname_lc}-input-{type}"]
6+
=== Unified Logs input
7+
8+
++++
9+
<titleabbrev>Unified Logs</titleabbrev>
10+
++++
11+
12+
NOTE: Only available for MacOS.
13+
14+
The unified logging system provides a comprehensive and performant API to capture
15+
telemetry across all levels of the system. This system centralizes the storage of
16+
log data in memory and on disk, rather than writing that data to a text-based log file.
17+
18+
The input interacts with the `log` command-line tool to provide access to the events.
19+
20+
The input starts streaming events from the current point in time unless a start date or
21+
the `backfill` options are set. When restarted it will continue where it left off.
22+
23+
Alternatively, it can also do one off operations, such as:
24+
25+
- Stream events contained in a `.logarchive` file.
26+
- Stream events contained in a `.tracev3` file.
27+
- Stream events in a specific time span, by providing a specific end date.
28+
29+
After this one off operations complete, the input will stop.
30+
31+
Other configuration options can be specified to filter what events to process.
32+
33+
NOTE: The input can cause some duplicated events when backfilling and/or
34+
restarting. This is caused by how the underlying fetching method works and
35+
should be taken into account when using the input.
36+
37+
Example configuration:
38+
39+
Process all old and new logs:
40+
41+
["source","yaml",subs="attributes"]
42+
----
43+
{beatname_lc}.inputs:
44+
- type: unifiedlogs
45+
id: unifiedlogs-id
46+
enabled: true
47+
backfill: true
48+
----
49+
50+
Process logs with predicate filters:
51+
52+
["source","yaml",subs="attributes"]
53+
----
54+
{beatname_lc}.inputs:
55+
- type: unifiedlogs
56+
id: unifiedlogs-id
57+
enabled: true
58+
predicate:
59+
# Captures keychain.db unlock events
60+
- 'process == "loginwindow" && sender == "Security"'
61+
# Captures user login events
62+
- 'process == "logind"'
63+
# Captures command line activity run with elevated privileges
64+
- 'process == "sudo"'
65+
----
66+
67+
==== Configuration options
68+
69+
The `unifiedlogs` input supports the following configuration options plus the
70+
<<{beatname_lc}-input-{type}-common-options>> described later.
71+
72+
[float]
73+
==== `archive_file`
74+
75+
Display events stored in the given archive.
76+
The archive must be a valid log archive bundle with the suffix `.logarchive`.
77+
78+
[float]
79+
==== `trace_file`
80+
81+
Display events stored in the given `.tracev3` file.
82+
In order to be decoded, the file must be contained within a valid `.logarchive`
83+
84+
[float]
85+
==== `start`
86+
87+
Shows content starting from the provided date.
88+
The following date/time formats are accepted:
89+
`YYYY-MM-DD`, `YYYY-MM-DD HH:MM:SS`, `YYYY-MM-DD HH:MM:SSZZZZZ`.
90+
91+
[float]
92+
==== `end`
93+
94+
Shows content up to the provided date.
95+
The following date/time formats are accepted:
96+
`YYYY-MM-DD`, `YYYY-MM-DD HH:MM:SS`, `YYYY-MM-DD HH:MM:SSZZZZZ`.
97+
98+
[float]
99+
==== `predicate`
100+
101+
Filters messages using the provided predicate based on NSPredicate.
102+
A compound predicate or multiple predicates can be provided as a list.
103+
104+
For detailed information on the use of predicate based filtering,
105+
please refer to the https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Predicates/Articles/pSyntax.html[Predicate Programming Guide].
106+
107+
[float]
108+
==== `process`
109+
110+
A list of the processes on which to operate. It accepts a PID or process name.
111+
112+
[float]
113+
==== `source`
114+
115+
Include symbol names and source line numbers for messages, if available.
116+
Default: `false`.
117+
118+
[float]
119+
==== `info`
120+
121+
Disable or enable info level messages.
122+
Default: `false`.
123+
124+
[float]
125+
==== `debug`
126+
127+
Disable or enable debug level messages.
128+
Default: `false`.
129+
130+
[float]
131+
==== `backtrace`
132+
133+
Disable or enable display of backtraces.
134+
Default: `false`.
135+
136+
[float]
137+
==== `signpost`
138+
139+
Disable or enable display of signposts.
140+
Default: `false`.
141+
142+
[float]
143+
==== `unreliable`
144+
145+
Annotate events with whether the log was emitted unreliably.
146+
Default: `false`.
147+
148+
[float]
149+
==== `mach_continuous_time`
150+
151+
Use mach continuous time timestamps rather than walltime.
152+
Default: `false`.
153+
154+
[float]
155+
==== `backfill`
156+
157+
If set to true the input will process all available logs since the beginning
158+
of time the first time it starts.
159+
Default: `false`.
160+
161+
162+
[id="{beatname_lc}-input-{type}-common-options"]
163+
include::../../../../filebeat/docs/inputs/input-common-options.asciidoc[]
164+
165+
[float]
166+
=== Metrics
167+
168+
This input exposes metrics under the <<http-endpoint, HTTP monitoring endpoint>>.
169+
These metrics are exposed under the `/inputs/` path. They can be used to
170+
observe the activity of the input.
171+
172+
You must assign a unique `id` to the input to expose metrics.
173+
174+
[options="header"]
175+
|=======
176+
| Metric | Description
177+
| `errors_total` | Total number of errors.
178+
|=======
179+
180+
:type!:
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
2+
// or more contributor license agreements. Licensed under the Elastic License;
3+
// you may not use this file except in compliance with the Elastic License.
4+
5+
//go:build darwin
6+
7+
package inputs
8+
9+
import (
10+
"github.com/elastic/beats/v7/filebeat/beater"
11+
v2 "github.com/elastic/beats/v7/filebeat/input/v2"
12+
"github.com/elastic/beats/v7/libbeat/beat"
13+
"github.com/elastic/beats/v7/x-pack/filebeat/input/awscloudwatch"
14+
"github.com/elastic/beats/v7/x-pack/filebeat/input/awss3"
15+
"github.com/elastic/beats/v7/x-pack/filebeat/input/azureblobstorage"
16+
"github.com/elastic/beats/v7/x-pack/filebeat/input/azureeventhub"
17+
"github.com/elastic/beats/v7/x-pack/filebeat/input/benchmark"
18+
"github.com/elastic/beats/v7/x-pack/filebeat/input/cel"
19+
"github.com/elastic/beats/v7/x-pack/filebeat/input/cloudfoundry"
20+
"github.com/elastic/beats/v7/x-pack/filebeat/input/entityanalytics"
21+
"github.com/elastic/beats/v7/x-pack/filebeat/input/gcs"
22+
"github.com/elastic/beats/v7/x-pack/filebeat/input/http_endpoint"
23+
"github.com/elastic/beats/v7/x-pack/filebeat/input/httpjson"
24+
"github.com/elastic/beats/v7/x-pack/filebeat/input/lumberjack"
25+
"github.com/elastic/beats/v7/x-pack/filebeat/input/netflow"
26+
"github.com/elastic/beats/v7/x-pack/filebeat/input/o365audit"
27+
"github.com/elastic/beats/v7/x-pack/filebeat/input/salesforce"
28+
"github.com/elastic/beats/v7/x-pack/filebeat/input/streaming"
29+
"github.com/elastic/beats/v7/x-pack/filebeat/input/unifiedlogs"
30+
"github.com/elastic/elastic-agent-libs/logp"
31+
)
32+
33+
func xpackInputs(info beat.Info, log *logp.Logger, store beater.StateStore) []v2.Plugin {
34+
return []v2.Plugin{
35+
azureblobstorage.Plugin(log, store),
36+
azureeventhub.Plugin(log),
37+
cel.Plugin(log, store),
38+
cloudfoundry.Plugin(),
39+
entityanalytics.Plugin(log),
40+
gcs.Plugin(log, store),
41+
http_endpoint.Plugin(),
42+
httpjson.Plugin(log, store),
43+
o365audit.Plugin(log, store),
44+
awss3.Plugin(store),
45+
awscloudwatch.Plugin(),
46+
lumberjack.Plugin(),
47+
salesforce.Plugin(log, store),
48+
streaming.Plugin(log, store),
49+
streaming.PluginWebsocketAlias(log, store),
50+
netflow.Plugin(log),
51+
benchmark.Plugin(),
52+
unifiedlogs.Plugin(log, store),
53+
}
54+
}

x-pack/filebeat/input/default-inputs/inputs_other.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// or more contributor license agreements. Licensed under the Elastic License;
33
// you may not use this file except in compliance with the Elastic License.
44

5-
//go:build !aix && !windows
5+
//go:build !aix && !darwin && !windows
66

77
package inputs
88

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
2+
// or more contributor license agreements. Licensed under the Elastic License;
3+
// you may not use this file except in compliance with the Elastic License.
4+
5+
//go:build darwin
6+
7+
package unifiedlogs
8+
9+
import (
10+
"fmt"
11+
"strings"
12+
"time"
13+
)
14+
15+
type config struct {
16+
showConfig
17+
commonConfig
18+
Backfill bool `config:"backfill"`
19+
}
20+
21+
type showConfig struct {
22+
ArchiveFile string `config:"archive_file"`
23+
TraceFile string `config:"trace_file"`
24+
Start string `config:"start"`
25+
End string `config:"end"`
26+
}
27+
28+
type commonConfig struct {
29+
Predicate []string `config:"predicate"`
30+
Process []string `config:"process"`
31+
Source bool `config:"source"`
32+
Info bool `config:"info"`
33+
Debug bool `config:"debug"`
34+
Backtrace bool `config:"backtrace"`
35+
Signpost bool `config:"signpost"`
36+
Unreliable bool `config:"unreliable"`
37+
MachContinuousTime bool `config:"mach_continuous_time"`
38+
}
39+
40+
func (c config) Validate() error {
41+
if err := checkDateFormat(c.Start); err != nil {
42+
return fmt.Errorf("start date is not valid: %w", err)
43+
}
44+
if err := checkDateFormat(c.End); err != nil {
45+
return fmt.Errorf("end date is not valid: %w", err)
46+
}
47+
if c.ArchiveFile != "" && !strings.HasSuffix(c.ArchiveFile, ".logarchive") {
48+
return fmt.Errorf("archive_file %v has the wrong extension", c.ArchiveFile)
49+
}
50+
if c.TraceFile != "" && !strings.HasSuffix(c.TraceFile, ".tracev3") {
51+
return fmt.Errorf("trace_file %v has the wrong extension", c.TraceFile)
52+
}
53+
return nil
54+
}
55+
56+
func defaultConfig() config {
57+
return config{}
58+
}
59+
60+
func checkDateFormat(date string) error {
61+
if date == "" {
62+
return nil
63+
}
64+
acceptedLayouts := []string{
65+
"2006-01-02",
66+
"2006-01-02 15:04:05",
67+
"2006-01-02 15:04:05-0700",
68+
}
69+
for _, layout := range acceptedLayouts {
70+
if _, err := time.Parse(layout, date); err == nil {
71+
return nil
72+
}
73+
}
74+
return fmt.Errorf("not a valid date, accepted layouts are: %v", acceptedLayouts)
75+
}

0 commit comments

Comments
 (0)