Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use journald for system module on Debian 12 #41061

Merged
merged 38 commits into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
7677ba6
Use journald for system/syslog module on Debian 12
belimawr Sep 17, 2024
eb0a798
Add variables to force logs our journald
belimawr Sep 19, 2024
5165201
Update docs
belimawr Sep 20, 2024
ba0b713
[journald] enable facility filtering
belimawr Sep 20, 2024
1503234
Add facility filtering to system module + journald
belimawr Sep 20, 2024
9300272
Different pipelines for journald and files
belimawr Sep 30, 2024
198c632
Implement journald ingest pipeline
belimawr Oct 1, 2024
15e56bf
Implement Journald system/auth ingest pipeline
belimawr Oct 1, 2024
f1d10d6
Add paths config for system module with journald input
belimawr Oct 1, 2024
8e013bc
Add tests for system.auth and fix ingest pipelines
belimawr Oct 1, 2024
e6905f5
Use .log and .journal files in tests
belimawr Oct 1, 2024
84e2554
fix syslog journald ingest pipeline
belimawr Oct 1, 2024
1841a02
Add journald tests for system.syslog
belimawr Oct 1, 2024
ae126c8
Fix lint issues, update docs and changelog
belimawr Oct 2, 2024
4b06572
fix tests and improve docs
belimawr Oct 2, 2024
dd7b43a
Improve template documentation
belimawr Oct 2, 2024
24f9895
Update docs and tests
belimawr Oct 2, 2024
f14f41c
update generated files
belimawr Oct 2, 2024
d7d37d6
Fix lint issues
belimawr Oct 2, 2024
fcc6cac
Update journal files to a compatible format
belimawr Oct 3, 2024
fe5bdb1
Improve system test error handling
belimawr Oct 3, 2024
e86d97e
Create a new input to instantiate a jouranld or log input
belimawr Oct 8, 2024
5c84f4a
Choose between journald and log input based on flag, update module
belimawr Oct 8, 2024
bcc81e5
Update configuration and docs
belimawr Oct 8, 2024
333cf0b
Update configs
belimawr Oct 8, 2024
0a1d441
update pipeline and tests
belimawr Oct 9, 2024
d8fe075
Add processors
belimawr Oct 9, 2024
607ef82
Fix test_module.py
belimawr Oct 9, 2024
d9e297d
Check if files exist to choose between jouranld and files
belimawr Oct 10, 2024
4fce6a0
Finish toJournaldConfig and toFilesConfig
belimawr Oct 10, 2024
056d9e7
Update pipelines and config not to rely on non-input fields/config
belimawr Oct 10, 2024
9270dc3
Fix tests and ingest pipeline
belimawr Oct 11, 2024
3328fce
Update golden files
belimawr Oct 11, 2024
648200d
Update golden files to new input type
belimawr Oct 11, 2024
2bafcf0
set input type back to the old config
belimawr Oct 11, 2024
11e6655
Remove un-used code and small updates
belimawr Oct 11, 2024
fbfdbbe
move grok step to a separated pipeline
belimawr Oct 11, 2024
ea2e833
Add build constraints to support non-linux systems
belimawr Oct 11, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.next.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff]
- Added `container.image.name` to `journald` Filebeat input's Docker-specific translated fields. {pull}40450[40450]
- Change log.file.path field in awscloudwatch input to nested object. {pull}41099[41099]
- Remove deprecated awscloudwatch field from Filebeat. {pull}41089[41089]
- System module events now contain `input.type: systemlogs` instead of `input.type: log` when harvesting log files. {pull}41061[41061]


*Heartbeat*
Expand Down Expand Up @@ -324,6 +325,8 @@ https://github.com/elastic/beats/compare/v8.8.1\...main[Check the HEAD diff]
- Improved GCS input documentation. {pull}41143[41143]
- Add CSV decoding capacity to azureblobstorage input {pull}40978[40978]
- Add CSV decoding capacity to gcs input {pull}40979[40979]
- Jounrald input now supports filtering by facilities {pull}41061[41061]
- System module now supports reading from jounrald. {pull}41061[41061]

*Auditbeat*

Expand Down
12 changes: 12 additions & 0 deletions filebeat/docs/include/use-journald.asciidoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
*`var.use_journald`*::

A boolean that when set to `true` will read logs from Journald. When
Journald is used all events contain the tag `journald`

*`var.use_files`*::

A boolean that when set to `true` will read logs from the log files
defined by `vars.paths`.

If neither `var.use_journald` nor `var.use_files` are set (or both are
`false`) {beatname_uc} will auto-detect the source for the logs.
2 changes: 1 addition & 1 deletion filebeat/docs/include/var-paths.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ are also supported here. For example, you can use wildcards to fetch all files
from a predefined level of subdirectories: `/path/to/log/*/*.log`. This
fetches all `.log` files from the subfolders of `/path/to/log`. It does not
fetch log files from the `/path/to/log` folder itself. If this setting is left
empty, {beatname_uc} will choose log paths based on your operating system.
empty, {beatname_uc} will choose log paths based on your operating system.
7 changes: 7 additions & 0 deletions filebeat/docs/inputs/input-journald.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,13 @@ Valid transports:
* stdout: messages from a service's standard output or error output
* kernel: messages from the kernel

[float]
[id="{beatname_lc}-input-{type}-facilities"]
==== `facilities`

Filter entries by facilities, facilities must be specified using their
numeric code.

[float]
[id="{beatname_lc}-input-{type}-include-matches"]
==== `include_matches`
Expand Down
6 changes: 5 additions & 1 deletion filebeat/docs/modules/system.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ include::../include/gs-link.asciidoc[]
=== Compatibility

This module was tested with logs from OSes like Ubuntu 12.04, Centos 7, and
macOS Sierra.
macOS Sierra. For Debian 12 Journald is used to read the system logs.

This module is not available for Windows.

Expand Down Expand Up @@ -65,11 +65,15 @@ include::../include/config-option-intro.asciidoc[]

include::../include/var-paths.asciidoc[]

include::../include/use-journald.asciidoc[]

[float]
==== `auth` fileset settings

include::../include/var-paths.asciidoc[]

include::../include/use-journald.asciidoc[]

*`var.tags`*::

A list of tags to include in events. Including `forwarded` indicates that the
Expand Down
30 changes: 29 additions & 1 deletion filebeat/filebeat.reference.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,18 @@ filebeat.modules:
# Filebeat will choose the paths depending on your OS.
#var.paths:

# Input configuration (advanced). Any input configuration option
# Force using journald to collect system logs
#var.use_journald: true|false

# Force using log files to collect system logs
#var.use_files: true|false

# If use_journald and use_files are false, then
# Filebeat will autodetect whether use to journald
# to collect system logs.

# Input configuration (advanced).
# Any input configuration option
# can be added under this section.
#input:

Expand All @@ -33,6 +44,23 @@ filebeat.modules:
# Filebeat will choose the paths depending on your OS.
#var.paths:

# Force using journald to collect system logs
#var.use_journald: true|false

# Force using log files to collect system logs
#var.use_files: true|false

# If use_journald and use_files are false, then
# Filebeat will autodetect whether use to journald
# to collect system logs.

# A list of tags to include in events. Including 'forwarded'
# indicates that the events did not originate on this host and
# causes host.name to not be added to events. Include
# 'preserve_orginal_event' causes the pipeline to retain the raw log
# in event.original. Defaults to [].
#var.tags: []

# Input configuration (advanced). Any input configuration option
# can be added under this section.
#input:
Expand Down
31 changes: 18 additions & 13 deletions filebeat/fileset/fileset.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"reflect"
Expand Down Expand Up @@ -143,11 +142,11 @@ type ProcessorRequirement struct {
func (fs *Fileset) readManifest() (*manifest, error) {
cfg, err := common.LoadFile(filepath.Join(fs.modulePath, fs.name, "manifest.yml"))
if err != nil {
return nil, fmt.Errorf("Error reading manifest file: %v", err)
return nil, fmt.Errorf("Error reading manifest file: %w", err)
}
manifest, err := newManifest(cfg)
if err != nil {
return nil, fmt.Errorf("Error unpacking manifest: %v", err)
return nil, fmt.Errorf("Error unpacking manifest: %w", err)
}
return manifest, nil
}
Expand Down Expand Up @@ -183,7 +182,7 @@ func (fs *Fileset) evaluateVars(info beat.Info) (map[string]interface{}, error)

vars[name], err = resolveVariable(vars, value)
if err != nil {
return nil, fmt.Errorf("Error resolving variables on %s: %v", name, err)
return nil, fmt.Errorf("Error resolving variables on %s: %w", name, err)
}
}

Expand Down Expand Up @@ -246,7 +245,7 @@ func resolveVariable(vars map[string]interface{}, value interface{}) (interface{
if ok {
transf, err := ApplyTemplate(vars, s, false)
if err != nil {
return nil, fmt.Errorf("array: %v", err)
return nil, fmt.Errorf("array: %w", err)
}
transformed = append(transformed, transf)
} else {
Expand Down Expand Up @@ -322,33 +321,35 @@ func getTemplateFunctions(vars map[string]interface{}) (template.FuncMap, error)
// getBuiltinVars computes the supported built in variables and groups them
// in a dictionary
func (fs *Fileset) getBuiltinVars(info beat.Info) (map[string]interface{}, error) {
host, err := os.Hostname()
if err != nil || len(host) == 0 {
osHost, err := os.Hostname()
if err != nil || len(osHost) == 0 {
return nil, fmt.Errorf("Error getting the hostname: %w", err)
}
split := strings.SplitN(host, ".", 2)
split := strings.SplitN(osHost, ".", 2)
hostname := split[0]
domain := ""
if len(split) > 1 {
domain = split[1]
}

return map[string]interface{}{
vars := map[string]interface{}{
"prefix": info.IndexPrefix,
"hostname": hostname,
"domain": domain,
"module": fs.mname,
"fileset": fs.name,
"beatVersion": info.Version,
}, nil
}

return vars, nil
}

func (fs *Fileset) getInputConfig() (*conf.C, error) {
path, err := ApplyTemplate(fs.vars, fs.manifest.Input, false)
if err != nil {
return nil, fmt.Errorf("Error expanding vars on the input path: %w", err)
}
contents, err := ioutil.ReadFile(filepath.Join(fs.modulePath, fs.name, path))
contents, err := os.ReadFile(filepath.Join(fs.modulePath, fs.name, path))
if err != nil {
return nil, fmt.Errorf("Error reading input file %s: %w", path, err)
}
Expand Down Expand Up @@ -434,7 +435,7 @@ func (fs *Fileset) GetPipelines(esVersion version.V) (pipelines []pipeline, err
return nil, fmt.Errorf("Error expanding vars on the ingest pipeline path: %w", err)
}

strContents, err := ioutil.ReadFile(filepath.Join(fs.modulePath, fs.name, path))
strContents, err := os.ReadFile(filepath.Join(fs.modulePath, fs.name, path))
if err != nil {
return nil, fmt.Errorf("Error reading pipeline file %s: %w", path, err)
}
Expand All @@ -458,7 +459,11 @@ func (fs *Fileset) GetPipelines(esVersion version.V) (pipelines []pipeline, err
if err != nil {
return nil, fmt.Errorf("Failed to sanitize the YAML pipeline file: %s: %w", path, err)
}
content = newContent.(map[string]interface{})
var ok bool
content, ok = newContent.(map[string]interface{})
if !ok {
return nil, errors.New("cannot convert newContent to map[string]interface{}")
}
default:
return nil, fmt.Errorf("Unsupported extension '%s' for pipeline file: %s", extension, path)
}
Expand Down
1 change: 1 addition & 0 deletions filebeat/include/list.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions filebeat/input/default-inputs/inputs_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package inputs

import (
"github.com/elastic/beats/v7/filebeat/input/journald"
"github.com/elastic/beats/v7/filebeat/input/systemlogs"
v2 "github.com/elastic/beats/v7/filebeat/input/v2"
cursor "github.com/elastic/beats/v7/filebeat/input/v2/input-cursor"
"github.com/elastic/beats/v7/libbeat/beat"
Expand All @@ -37,6 +38,7 @@ func osInputs(info beat.Info, log *logp.Logger, components osComponents) []v2.Pl
zeroPlugin := v2.Plugin{}
if journald := journald.Plugin(log, components); journald != zeroPlugin {
plugins = append(plugins, journald)
plugins = append(plugins, systemlogs.PluginV2(log, components))
}

return plugins
Expand Down
57 changes: 57 additions & 0 deletions filebeat/input/journald/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Journald input

The Journald input reads journal entries by calling `journalctl`.

## Adding entries to the journal
The easiest way to add entries to the journal is to use `systemd-cat`:
```
root@vagrant-debian-12:~/filebeat# echo "Hello Journal!" | systemd-cat
root@vagrant-debian-12:~/filebeat# journalctl -n 1
Oct 02 04:17:01 vagrant-debian-12 CRON[1912]: pam_unix(cron:session): session closed for user root
```

The syslog identifier can be specified with the `-t` parameter:
```
root@vagrant-debian-12:~/filebeat# echo "Hello Journal!" | systemd-cat -t my-test
root@vagrant-debian-12:~/filebeat# journalctl -n 1
Oct 02 04:17:50 vagrant-debian-12 my-test[1924]: Hello Journal!
```

## Crafting a journal file
The easiest way to craft a journal file with the entries you need is
to use
[`systemd-journald-remote`](https://www.freedesktop.org/software/systemd/man/latest/systemd-journal-remote.service.html).
First we need to export some entries to a file:
```
root@vagrant-debian-12:~/filebeat# journalctl -g "Hello" -o export >export
```
One good thing of the `-o export` is that you can just concatenate the
output of any number of runs and the result will be a valid file.

Then you can use `systemd-journald-remote` to generate the journal
file:
```
root@vagrant-debian-12:~/filebeat# /usr/lib/systemd/systemd-journal-remote -o example.journal export
Finishing after writing 2 entries
``
Or you can run as a one liner:
```
root@vagrant-debian-12:~/filebeat# journalctl -g "Hello" -o export | /usr/lib/systemd/systemd-journal-remote -o example.journal -
```

Then you can read the newly created file:
```
root@vagrant-debian-12:~/filebeat# journalctl --file ./example.journal
Oct 02 04:16:54 vagrant-debian-12 unknown[1908]: Hello Journal!
Oct 02 04:17:50 vagrant-debian-12 my-test[1924]: Hello Journal!
root@vagrant-debian-12:~/filebeat#
```

Bear in mind that `systemd-journal-remote` will **append** to the
output file.

## References
- https://systemd.io/JOURNAL_NATIVE_PROTOCOL/
- https://www.freedesktop.org/software/systemd/man/latest/journalctl.html
- https://www.freedesktop.org/software/systemd/man/latest/systemd-cat.html
- https://www.freedesktop.org/software/systemd/man/latest/systemd-journal-remote.service.html
3 changes: 3 additions & 0 deletions filebeat/input/journald/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ type config struct {
// SaveRemoteHostname defines if the original source of the entry needs to be saved.
SaveRemoteHostname bool `config:"save_remote_hostname"`

// Facility is a list of facilities to filter journal messages
Facilities []int `config:"facilities"`

// Parsers configuration
Parsers parser.Config `config:",inline"`
}
Expand Down
8 changes: 6 additions & 2 deletions filebeat/input/journald/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ type journald struct {
Units []string
Transports []string
Identifiers []string
Facilities []int
SaveRemoteHostname bool
Parsers parser.Config
Journalctl bool
Expand Down Expand Up @@ -79,7 +80,7 @@ func Plugin(log *logp.Logger, store cursor.StateStore) input.Plugin {
Logger: log,
StateStore: store,
Type: pluginName,
Configure: configure,
Configure: Configure,
},
}
}
Expand All @@ -90,7 +91,7 @@ var cursorVersion = 1

func (p pathSource) Name() string { return string(p) }

func configure(cfg *conf.C) ([]cursor.Source, cursor.Input, error) {
func Configure(cfg *conf.C) ([]cursor.Source, cursor.Input, error) {
config := defaultConfig()
if err := cfg.Unpack(&config); err != nil {
return nil, nil, err
Expand All @@ -113,6 +114,7 @@ func configure(cfg *conf.C) ([]cursor.Source, cursor.Input, error) {
Units: config.Units,
Transports: config.Transports,
Identifiers: config.Identifiers,
Facilities: config.Facilities,
SaveRemoteHostname: config.SaveRemoteHostname,
Parsers: config.Parsers,
}, nil
Expand All @@ -128,6 +130,7 @@ func (inp *journald) Test(src cursor.Source, ctx input.TestContext) error {
inp.Identifiers,
inp.Transports,
inp.Matches,
inp.Facilities,
journalctl.SeekHead,
"",
inp.Since,
Expand Down Expand Up @@ -158,6 +161,7 @@ func (inp *journald) Run(
inp.Identifiers,
inp.Transports,
inp.Matches,
inp.Facilities,
mode,
pos,
inp.Since,
Expand Down
5 changes: 5 additions & 0 deletions filebeat/input/journald/pkg/journalctl/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@
syslogIdentifiers []string,
transports []string,
matchers journalfield.IncludeMatches,
facilities []int,
mode SeekMode,
cursor string,
since time.Duration,
Expand Down Expand Up @@ -166,6 +167,10 @@
args = append(args, fmt.Sprintf("_TRANSPORT=%s", m))
}

for _, facility := range facilities {
args = append(args, "--facility", fmt.Sprintf("%d", facility))
}

otherArgs := handleSeekAndCursor(mode, since, cursor)

jctl, err := newJctl(canceler, logger.Named("journalctl-runner"), "journalctl", append(args, otherArgs...)...)
Expand Down Expand Up @@ -229,7 +234,7 @@
// We recreate the backoff so r.backoff.Last().IsZero()
// will return true next time it's called making us to
// wait in case jouranlctl crashes in less than 5s.
if !r.backoff.Last().IsZero() && time.Now().Sub(r.backoff.Last()) > 5*time.Second {

Check failure on line 237 in filebeat/input/journald/pkg/journalctl/reader.go

View workflow job for this annotation

GitHub Actions / lint (windows)

S1012: should use `time.Since` instead of `time.Now().Sub` (gosimple)

Check failure on line 237 in filebeat/input/journald/pkg/journalctl/reader.go

View workflow job for this annotation

GitHub Actions / lint (linux)

S1012: should use `time.Since` instead of `time.Now().Sub` (gosimple)
r.backoff = backoff.NewExpBackoff(cancel.Done(), 100*time.Millisecond, 2*time.Second)
} else {
r.backoff.Wait()
Expand Down
2 changes: 1 addition & 1 deletion filebeat/input/journald/pkg/journalctl/reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func TestRestartsJournalctlOnError(t *testing.T) {
return &mock, nil
}

reader, err := New(logp.L(), ctx, nil, nil, nil, journalfield.IncludeMatches{}, SeekHead, "", 0, "", factory)
reader, err := New(logp.L(), ctx, nil, nil, nil, journalfield.IncludeMatches{}, []int{}, SeekHead, "", 0, "", factory)
if err != nil {
t.Fatalf("cannot instantiate journalctl reader: %s", err)
}
Expand Down
Loading
Loading