Skip to content

Commit

Permalink
Add Journalbeat (elastic#8703)
Browse files Browse the repository at this point in the history
* Initialize Journalbeat (elastic#8277)

This is the first PR to initialize Journalbeat with minimal functionality.

The architecture is mimicing Filebeat so it can be merged into FB in the future. It means it has multiple inputs which can share configuration (`backoff`, `backoff_factor`, etc.). Inputs can have multiple readers, each reader reads from a journal specified in the list of `paths`. The readers are not going to implement the interface `Harverster` until it's merged into Filebeat, because it would overcomplicate event publishing unnecessarily and would need to duplicate too much Filebeat code.

Checkpointing is copied from Winlogbeat. Once the new registry file is merged, it will be migrated.

Example configuration to read from the beginning of the local journal

```yml
journalbeat.inputs:
- paths: []
  seek: head
```

Features
* read from local journal, journal file and directory
* position tracking by using check-pointing as it's done in Winlogbeat
* seek to "tail", "head", "cursor"
* minimal E2E tests
* fields.yml and documentation

Vendored:
* github.com/coreos/go-systemd/sdjournal

* Journalbeat matches support && minor additions (elastic#8324)

From now on it's possible to match for journal entry fields in Journalbeat using the new option `matches`. This requires a list of key value pairs separated by "=". The key has to be a journalbeat event key (e.g systemd.unit) and the value is the exact value journal reader needs to find in the entries.

Example configuration which returns NGINX and dhclient entries from the journal:
```yml
include_matches:
  - "systemd.unit=nginx"
  - "process.name=dhclient"
```
Added docker fields from: https://docs.docker.com/config/containers/logging/journald/
- `container.id`
- `container.id_truncated`
- `container.name`
- `container.image.tag`
- `container.partial`

Journalbeat parses the timestamp of the entry and adds it to the event as `@timestamp`. The time of reading by Journalbeat is saved in `read_timestamp`.

Custom fields by various sources are stored under `custom`. Field names are normalized, meaning `"_"` prefix is removed and every letter is lowercase.

From now on it is possible to configure `processors` and `fields`, etc on `input` level.

The size of each open reader is reporting in bytes:
```
{
  "journalbeat": {
    "journals": {
      "journal_1": {
         "path": "system.journal",
         "size_in_bytes": 123124214,
       }
    }
}
```

* Minor improvements to Journalbeat (elastic#8618)

* Packaging of journalbeat (elastic#8702)

Journalbeat is going to be built using the new Debian 8 container, because systemd version in Debian 7 is too old (v44 instead of the required v187).

Minor changes:
* add missing X-Pack folder to journalbeat
* do not crosscompile journalbeat due to missing dependencies locally

* Add journalbeat docs (elastic#8735)

* Add journalbeat docs

(cherry picked from commit 24d0e08)
  • Loading branch information
kvch committed Oct 24, 2018
1 parent a51804f commit e679d69
Show file tree
Hide file tree
Showing 80 changed files with 7,963 additions and 18 deletions.
17 changes: 17 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,22 @@ jobs:
go: $GO_VERSION
stage: test

# Functionbeat
- os: linux
env: TARGETS="-C x-pack/functionbeat testsuite"
go: $GO_VERSION
stage: test
- os: osx
env: TARGETS="TEST_ENVIRONMENT=0 -C x-pack/functionbeat testsuite"
go: $GO_VERSION
stage: test

# Journalbeat
- os: linux
env: TARGETS="-C journalbeat testsuite"
go: $GO_VERSION
stage: test

# Generators
- os: linux
env: TARGETS="-C generator/metricbeat test"
Expand Down Expand Up @@ -150,6 +166,7 @@ addons:
- libpcap-dev
- xsltproc
- libxml2-utils
- libsystemd-journal-dev

before_install:
- python --version
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ https://github.com/elastic/beats/compare/v6.4.0...6.x[Check the HEAD diff]

*Heartbeat*

*Journalbeat*

*Metricbeat*

*Packetbeat*
Expand Down Expand Up @@ -67,6 +69,8 @@ https://github.com/elastic/beats/compare/v6.4.0...6.x[Check the HEAD diff]

- Fixed bug where HTTP responses with larger bodies would incorrectly report connection errors. {pull}8660[8660]

*Journalbeat*

*Metricbeat*

- Fix golang.heap.gc.cpu_fraction type from long to float in Golang module. {pull}7789[7789]
Expand Down Expand Up @@ -129,6 +133,10 @@ https://github.com/elastic/beats/compare/v6.4.0...6.x[Check the HEAD diff]
- Added support for extra TLS/x509 metadata. {pull}7944[7944]
- Added stats and state metrics for number of monitors and endpoints started. {pull}8621[8621]

*Journalbeat*

- Add journalbeat. {pull}8703[8703]

*Metricbeat*

- Add `replstatus` metricset to MongoDB module {pull}7604[7604]
Expand Down Expand Up @@ -167,6 +175,8 @@ https://github.com/elastic/beats/compare/v6.4.0...6.x[Check the HEAD diff]
*Heartbeat*
- watch.poll_file is now deprecated and superceded by automatic config file reloading.

*Journalbeat*

*Metricbeat*
- Redis `info` `replication.master_offset` has been deprecated in favor of `replication.master.offset`.{pull}7695[7695]
- Redis `info` clients fields `longest_output_list` and `biggest_input_buf` have been renamed to `max_output_buffer` and `max_input_buffer` based on the names they will have in Redis 5.0, both fields will coexist during a time with the same value {pull}8167[8167].
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
BUILD_DIR=$(CURDIR)/build
COVERAGE_DIR=$(BUILD_DIR)/coverage
BEATS?=auditbeat filebeat heartbeat metricbeat packetbeat winlogbeat
BEATS?=auditbeat filebeat heartbeat journalbeat metricbeat packetbeat winlogbeat
PROJECTS=libbeat $(BEATS)
PROJECTS_ENV=libbeat filebeat metricbeat
PYTHON_ENV?=$(BUILD_DIR)/python-env
Expand Down
31 changes: 31 additions & 0 deletions NOTICE.txt
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,37 @@ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

--------------------------------------------------------------------
Dependency: github.com/coreos/go-systemd
Version: v17
Revision: 39ca1b05acc7ad1220e09f133283b8859a8b71ab
License type (autodetected): Apache-2.0
./vendor/github.com/coreos/go-systemd/LICENSE:
--------------------------------------------------------------------
Apache License 2.0

-------NOTICE-----
CoreOS Project
Copyright 2018 CoreOS, Inc

This product includes software developed at CoreOS, Inc.
(http://www.coreos.com/).

--------------------------------------------------------------------
Dependency: github.com/coreos/pkg
Revision: 97fdf19511ea361ae1c100dd393cc47f8dcfa1e1
License type (autodetected): Apache-2.0
./vendor/github.com/coreos/pkg/LICENSE:
--------------------------------------------------------------------
Apache License 2.0

-------NOTICE-----
CoreOS Project
Copyright 2014 CoreOS, Inc

This product includes software developed at CoreOS, Inc.
(http://www.coreos.com/).

--------------------------------------------------------------------
Dependency: github.com/davecgh/go-spew
Version: v1.1.0
Expand Down
36 changes: 24 additions & 12 deletions dev-tools/mage/crossbuild.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ func init() {
// CrossBuildOption defines a option to the CrossBuild target.
type CrossBuildOption func(params *crossBuildParams)

// ImageSelectorFunc returns the name of the builder image.
type ImageSelectorFunc func(platform string) (string, error)

// ForPlatforms filters the platforms based on the given expression.
func ForPlatforms(expr string) func(params *crossBuildParams) {
return func(params *crossBuildParams) {
Expand Down Expand Up @@ -78,16 +81,24 @@ func Serially() func(params *crossBuildParams) {
}
}

// ImageSelector returns the name of the selected builder image.
func ImageSelector(f ImageSelectorFunc) func(params *crossBuildParams) {
return func(params *crossBuildParams) {
params.ImageSelector = f
}
}

type crossBuildParams struct {
Platforms BuildPlatformList
Target string
Serial bool
InDir string
Platforms BuildPlatformList
Target string
Serial bool
InDir string
ImageSelector ImageSelectorFunc
}

// CrossBuild executes a given build target once for each target platform.
func CrossBuild(options ...CrossBuildOption) error {
params := crossBuildParams{Platforms: Platforms, Target: defaultCrossBuildTarget}
params := crossBuildParams{Platforms: Platforms, Target: defaultCrossBuildTarget, ImageSelector: crossBuildImage}
for _, opt := range options {
opt(&params)
}
Expand All @@ -111,10 +122,10 @@ func CrossBuild(options ...CrossBuildOption) error {
if !buildPlatform.Flags.CanCrossBuild() {
return fmt.Errorf("unsupported cross build platform %v", buildPlatform.Name)
}
builder := GolangCrossBuilder{buildPlatform.Name, params.Target, params.InDir}
builder := GolangCrossBuilder{buildPlatform.Name, params.Target, params.InDir, params.ImageSelector}
if params.Serial {
if err := builder.Build(); err != nil {
return errors.Wrapf(err, "failed cross-building target=%v for platform=%v",
return errors.Wrapf(err, "failed cross-building target=%v for platform=%v %v", params.ImageSelector,
params.Target, buildPlatform.Name)
}
} else {
Expand Down Expand Up @@ -174,15 +185,16 @@ func crossBuildImage(platform string) (string, error) {
return "", err
}

return beatsCrossBuildImage + ":" + goVersion + "-" + tagSuffix, nil
return BeatsCrossBuildImage + ":" + goVersion + "-" + tagSuffix, nil
}

// GolangCrossBuilder executes the specified mage target inside of the
// associated golang-crossbuild container image for the platform.
type GolangCrossBuilder struct {
Platform string
Target string
InDir string
Platform string
Target string
InDir string
ImageSelector ImageSelectorFunc
}

// Build executes the build inside of Docker.
Expand All @@ -208,7 +220,7 @@ func (b GolangCrossBuilder) Build() error {
}

dockerRun := sh.RunCmd("docker", "run")
image, err := crossBuildImage(b.Platform)
image, err := b.ImageSelector(b.Platform)
if err != nil {
return errors.Wrap(err, "failed to determine golang-crossbuild image tag")
}
Expand Down
12 changes: 10 additions & 2 deletions dev-tools/mage/godaemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ import (
"os"
)

var (
defaultCrossBuildGoDaemon = []CrossBuildOption{
ForPlatforms("linux"),
WithTarget("buildGoDaemon"),
}
)

// BuildGoDaemon builds the go-deamon binary.
func BuildGoDaemon() error {
if GOOS != "linux" {
Expand Down Expand Up @@ -67,6 +74,7 @@ func BuildGoDaemon() error {

// CrossBuildGoDaemon cross-build the go-daemon binary using the
// golang-crossbuild environment.
func CrossBuildGoDaemon() error {
return CrossBuild(ForPlatforms("linux"), WithTarget("buildGoDaemon"))
func CrossBuildGoDaemon(options ...CrossBuildOption) error {
opts := append(defaultCrossBuildGoDaemon, options...)
return CrossBuild(opts...)
}
5 changes: 3 additions & 2 deletions dev-tools/mage/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,9 @@ const (
fpmVersion = "1.10.0"

// Docker images. See https://github.com/elastic/golang-crossbuild.
beatsFPMImage = "docker.elastic.co/beats-dev/fpm"
beatsCrossBuildImage = "docker.elastic.co/beats-dev/golang-crossbuild"
beatsFPMImage = "docker.elastic.co/beats-dev/fpm"
// BeatsCrossBuildImage is the image used for crossbuilding Beats.
BeatsCrossBuildImage = "docker.elastic.co/beats-dev/golang-crossbuild"

elasticBeatsImportPath = "github.com/elastic/beats"
)
Expand Down
9 changes: 9 additions & 0 deletions journalbeat/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/.idea
/build
.DS_Store
.journalbeat_position
/journalbeat
/journalbeat.test
*.pyc
data/meta.json
/*.journal
17 changes: 17 additions & 0 deletions journalbeat/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
FROM golang:1.10.3
MAINTAINER Noémi Ványi <noemi.vanyi@elastic.co>

RUN set -x && \
apt-get update && \
apt-get install -y --no-install-recommends \
python-pip virtualenv libsystemd-dev libc6-dev-i386 gcc-arm-linux-gnueabi && \
apt-get clean

RUN pip install --upgrade setuptools

# Setup work environment
ENV JOURNALBEAT_PATH /go/src/github.com/elastic/beats/journalbeat

RUN mkdir -p $JOURNALBEAT_PATH/build/coverage
WORKDIR $JOURNALBEAT_PATH
HEALTHCHECK CMD exit 0
15 changes: 15 additions & 0 deletions journalbeat/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
BEAT_NAME=journalbeat
BEAT_TITLE=Journalbeat
SYSTEM_TESTS=false
TEST_ENVIRONMENT=false
ES_BEATS?=..

# Path to the libbeat Makefile
-include $(ES_BEATS)/libbeat/scripts/Makefile

.PHONY: before-build
before-build:

# Collects all dependencies and then calls update
.PHONY: collect
collect:
5 changes: 5 additions & 0 deletions journalbeat/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Journalbeat

Journalbeat is an open source data collector to read and forward journal entries from Linuxes with systemd.

## Getting started
56 changes: 56 additions & 0 deletions journalbeat/_meta/beat.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
###################### Journalbeat Configuration Example #########################

# This file is an example configuration file highlighting only the most common
# options. The journalbeat.reference.yml file from the same directory contains all the
# supported options with more comments. You can use it as a reference.
#
# You can find the full configuration reference here:
# https://www.elastic.co/guide/en/beats/journalbeat/index.html

# For more available modules and options, please see the journalbeat.reference.yml sample
# configuration file.

#=========================== Journalbeat inputs =============================

journalbeat.inputs:
# Paths that should be crawled and fetched. Possible values files and directories.
# When setting a directory, all journals under it are merged.
# When empty starts to read from local journal.
- paths: []

# The number of seconds to wait before trying to read again from journals.
#backoff: 1s
# The maximum number of seconds to wait before attempting to read again from journals.
#max_backoff: 60s

# Position to start reading from journal. Valid values: head, tail, cursor
seek: tail

# Exact matching for field values of events.
# Matching for nginx entries: "systemd.unit=nginx"
#include_matches: []

# Optional fields that you can specify to add additional information to the
# output. Fields can be scalar values, arrays, dictionaries, or any nested
# combination of these.
#fields:
# env: staging


#========================= Journalbeat global options ============================
#journalbeat:
# Name of the registry file. If a relative path is used, it is considered relative to the
# data path.
#registry_file: registry

# The number of seconds to wait before trying to read again from journals.
#backoff: 1s
# The maximum number of seconds to wait before attempting to read again from journals.
#max_backoff: 60s

# Position to start reading from all journal. Possible values: head, tail, cursor
#seek: head

# Exact matching for field values of events.
# Matching for nginx entries: "systemd.unit=nginx"
#matches: []
Loading

0 comments on commit e679d69

Please sign in to comment.