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

Add the ability to set custom fields #1092

Merged
merged 1 commit into from
Mar 3, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions CHANGELOG.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ https://github.com/elastic/beats/compare/v1.1.0...master[Check the HEAD diff]

*Filebeat*
- Default config for ignore_older is now infinite instead of 24h, means ignore_older is disabled by default. Use close_older to only close file handlers.
- Scalar values in used in the `fields` configuration setting are no longer automatically converted to strings. {pull}1092[1092]

*Winlogbeat*

Expand Down Expand Up @@ -72,6 +73,7 @@ https://github.com/elastic/beats/compare/v1.1.0...master[Check the HEAD diff]
- Improve logstash and elasticsearch backoff behavior. {pull}927[927]
- Add experimental Kafka output. {pull}942[942]
- Add config file option to configure GOMAXPROCS. {pull}969[969]
- Added a `fields` and `fields_under_root` as options available under the `shipper` configuration {pull}1092[1092]

*Packetbeat*
- Change the DNS library used throughout the dns package to github.com/miekg/dns. {pull}803[803]
Expand All @@ -84,10 +86,12 @@ https://github.com/elastic/beats/compare/v1.1.0...master[Check the HEAD diff]
- Add multiline support for combining multiple related lines into one event. {issue}461[461]
- Add close_older configuration option to complete ignore_older https://github.com/elastic/filebeat/issues/181[181]
- Add experimental option to enable filebeat publisher pipeline to operate asynchonrously {pull}782[782]
- Added the ability to set a list of tags for each prospector {pull}1092[1092]

*Winlogbeat*
- Add caching of event metadata handles and the system render context for the wineventlog API {pull}888[888]
- Improve config validation by checking for unknown top-level YAML keys. {pull}1100[1100]
- Added the ability to set tags, fields, and fields_under_root as options for each event log {pull}1092[1092]

==== Deprecated

Expand Down
4 changes: 2 additions & 2 deletions filebeat/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ type ProspectorConfig struct {
}

type HarvesterConfig struct {
common.EventMetadata `config:",inline"` // Fields and tags to add to events.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 on approaching this directly with an eventMetadata object. That makes it easy to extend it later with other fields.


BufferSize int `config:"harvester_buffer_size"`
DocumentType string `config:"document_type"`
Encoding string `config:"encoding"`
Fields common.MapStr
FieldsUnderRoot bool `config:"fields_under_root"`
InputType string `config:"input_type"`
TailFiles bool `config:"tail_files"`
Backoff string `config:"backoff"`
Expand Down
48 changes: 36 additions & 12 deletions filebeat/docs/reference/configuration/filebeat-options.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -92,27 +92,51 @@ The following example configures Filebeat to ignore all the files that have a `g
exclude_files: [".gz$"]
-------------------------------------------------------------------------------------

===== tags

A list of tags that the Beat includes in the `tags` field of each published
event. Tags make it easy to select specific events in Kibana or apply
conditional filtering in Logstash. These tags will be appended to the list of
tags specified in the `shipper` configuration.

Example:

[source,yaml]
--------------------------------------------------------------------------------
filebeat:
prospectors:
- paths: ["/var/log/app/*.json"]
tags: ["json"]
--------------------------------------------------------------------------------

[[configuration-fields]]
===== fields

Optional fields that you can specify to add additional information to the output. For
example, you might add fields that you can use for filtering log data. Fields can be
scalar values, arrays, dictionaries, or any nested combination of these. All scalar values will be interpreted as strings. By default,
the fields that you specify here will be grouped under a `fields` sub-dictionary in the output document. To store the custom fields as top-level fields, set the `fields_under_root` option to true.
Optional fields that you can specify to add additional information to the
output. For example, you might add fields that you can use for filtering log
data. Fields can be scalar values, arrays, dictionaries, or any nested
combination of these. By default, the fields that you specify here will be
grouped under a `fields` sub-dictionary in the output document. To store the
custom fields as top-level fields, set the `fields_under_root` option to true.
If a duplicate field is declared in the `shipper` configuration, then its value
will be overwritten by the value declared here.

[source,yaml]
-------------------------------------------------------------------------------------
fields:
level: debug
review: 1
--------------------------------------------------------------------------------
filebeat:
prospectors:
- paths: ["/var/log/app/*.log"]
fields:
app_id: query_engine_12
--------------------------------------------------------------------------------

-------------------------------------------------------------------------------------
[[fields-under-root]]
===== fields_under_root

If this option is set to true, the custom <<configuration-fields>> are stored as top-level fields
in the output document instead of being grouped under a `fields` sub-dictionary.
If the custom field names conflict with other field names added by Filebeat, the custom fields overwrite the other fields.
If this option is set to true, the custom <<configuration-fields>> are stored as
top-level fields in the output document instead of being grouped under a
`fields` sub-dictionary. If the custom field names conflict with other field
names added by Filebeat, then the custom fields overwrite the other fields.

[[ignore-older]]
===== ignore_older
Expand Down
11 changes: 11 additions & 0 deletions filebeat/filebeat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,17 @@ shipper:
# logical properties.
#tags: ["service-X", "web-tier"]

# 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

# If this option is set to true, the custom fields are stored as top-level
# fields in the output document instead of being grouped under a fields
# sub-dictionary. Default is false.
#fields_under_root: false

# Uncomment the following if you want to ignore transactions created
# by the server on which the shipper is installed. This option is useful
# to remove duplicates if shippers are installed on multiple servers.
Expand Down
20 changes: 9 additions & 11 deletions filebeat/harvester/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,20 +127,18 @@ func (h *Harvester) Harvest() {
}

if h.shouldExportLine(text) {
// Sends text to spooler
event := &input.FileEvent{
ReadTime: ts,
Source: &h.Path,
InputType: h.Config.InputType,
DocumentType: h.Config.DocumentType,
Offset: h.Offset,
Bytes: bytesRead,
Text: &text,
Fields: h.Config.Fields,
Fileinfo: &info,
EventMetadata: h.Config.EventMetadata,
ReadTime: ts,
Source: &h.Path,
InputType: h.Config.InputType,
DocumentType: h.Config.DocumentType,
Offset: h.Offset,
Bytes: bytesRead,
Text: &text,
Fileinfo: &info,
}

event.SetFieldsUnderRoot(h.Config.FieldsUnderRoot)
h.SpoolerChan <- event // ship the new event downstream
}

Expand Down
41 changes: 9 additions & 32 deletions filebeat/input/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,15 @@ type File struct {

// FileEvent is sent to the output and must contain all relevant information
type FileEvent struct {
common.EventMetadata
ReadTime time.Time
Source *string
InputType string
DocumentType string
Offset int64
Bytes int
Text *string
Fields common.MapStr
Fileinfo *os.FileInfo

fieldsUnderRoot bool
}

type FileState struct {
Expand Down Expand Up @@ -57,37 +55,16 @@ func (f *FileEvent) GetState() *FileState {
return state
}

// SetFieldsUnderRoot sets whether the fields should be added
// top level to the output documentation (fieldsUnderRoot = true) or
// under a fields dictionary.
func (f *FileEvent) SetFieldsUnderRoot(fieldsUnderRoot bool) {
f.fieldsUnderRoot = fieldsUnderRoot
}

func (f *FileEvent) ToMapStr() common.MapStr {
event := common.MapStr{
"@timestamp": common.Time(f.ReadTime),
"source": f.Source,
"offset": f.Offset, // Offset here is the offset before the starting char.
"message": f.Text,
"type": f.DocumentType,
"input_type": f.InputType,
"count": 1,
}

if f.Fields != nil {
if f.fieldsUnderRoot {
for key, value := range f.Fields {
// in case of conflicts, overwrite
_, found := event[key]
if found {
logp.Warn("Overwriting %s key", key)
}
event[key] = value
}
} else {
event["fields"] = f.Fields
}
common.EventMetadataKey: f.EventMetadata,
"@timestamp": common.Time(f.ReadTime),
"source": f.Source,
"offset": f.Offset, // Offset here is the offset before the starting char.
"message": f.Text,
"type": f.DocumentType,
"input_type": f.InputType,
"count": 1,
}

return event
Expand Down
21 changes: 0 additions & 21 deletions filebeat/input/file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"path/filepath"
"testing"

"github.com/elastic/beats/libbeat/common"
"github.com/stretchr/testify/assert"
)

Expand Down Expand Up @@ -112,23 +111,3 @@ func TestFileEventToMapStr(t *testing.T) {
_, found := mapStr["fields"]
assert.False(t, found)
}

func TestFieldsUnderRoot(t *testing.T) {
event := FileEvent{
Fields: common.MapStr{
"hello": "world",
},
}
event.SetFieldsUnderRoot(true)
mapStr := event.ToMapStr()
_, found := mapStr["fields"]
assert.False(t, found)
assert.Equal(t, "world", mapStr["hello"])

event.SetFieldsUnderRoot(false)
mapStr = event.ToMapStr()
_, found = mapStr["hello"]
assert.False(t, found)
_, found = mapStr["fields"]
assert.True(t, found)
}
3 changes: 2 additions & 1 deletion filebeat/tests/system/test_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def test_custom_fields(self):
"""
self.render_config_template(
path=os.path.abspath(self.working_dir) + "/test.log",
fields={"hello": "world"}
fields={"hello": "world", "number": 2}
)

with open(self.working_dir + "/test.log", "w") as f:
Expand All @@ -28,6 +28,7 @@ def test_custom_fields(self):
output = self.read_output()
doc = output[0]
assert doc["fields.hello"] == "world"
assert doc["fields.number"] == 2

def test_custom_fields_under_root(self):
"""
Expand Down
Loading