mirror of
https://github.com/elastic/logstash.git
synced 2025-04-25 07:07:54 -04:00
Add metadata via @metadata field
This makes @metadata basically a way to store data along with an event that is *NOT* included when serialized to an output. Use cases: - For elasticsearch output, set the index, type, document_id, routing key, etc with metadata and you won't be burdened by storing a filed named 'index' in your document! - For elasticsearch input, we can set @metadata fields for the index/type/document_id instead of polluting the event data itself. - No need for "short-lived fields" such as timestamps. For example, a common pattern is to use grok to capture a timestamp text and give that to the date filter and finally use mutate to remove that captured text field. - Provide a kind of scratch space for events that are not part of the event data. Fixes #1834 Fixes #1836
This commit is contained in:
parent
6cf77cf867
commit
12d8e82df6
3 changed files with 121 additions and 5 deletions
|
@ -8,8 +8,16 @@ class LogStash::Codecs::RubyDebug < LogStash::Codecs::Base
|
||||||
config_name "rubydebug"
|
config_name "rubydebug"
|
||||||
milestone 3
|
milestone 3
|
||||||
|
|
||||||
|
# Should the event's metadata be included?
|
||||||
|
config :metadata, :validate => :boolean, :default => false
|
||||||
|
|
||||||
def register
|
def register
|
||||||
require "ap"
|
require "ap"
|
||||||
|
if @metadata
|
||||||
|
@encoder = method(:encode_with_metadata)
|
||||||
|
else
|
||||||
|
@encoder = method(:encode_default)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
public
|
public
|
||||||
|
@ -19,7 +27,15 @@ class LogStash::Codecs::RubyDebug < LogStash::Codecs::Base
|
||||||
|
|
||||||
public
|
public
|
||||||
def encode(event)
|
def encode(event)
|
||||||
|
@encoder.call(event)
|
||||||
|
end
|
||||||
|
|
||||||
|
def encode_default(event)
|
||||||
@on_event.call(event.to_hash.awesome_inspect + NL)
|
@on_event.call(event.to_hash.awesome_inspect + NL)
|
||||||
end # def encode
|
end # def encode_default
|
||||||
|
|
||||||
|
def encode_with_metadata(event)
|
||||||
|
@on_event.call(event.to_hash_with_metadata.awesome_inspect + NL)
|
||||||
|
end # def encode_with_metadata
|
||||||
|
|
||||||
end # class LogStash::Codecs::Dots
|
end # class LogStash::Codecs::Dots
|
||||||
|
|
|
@ -61,6 +61,13 @@ class LogStash::Event
|
||||||
@accessors = LogStash::Util::Accessors.new(data)
|
@accessors = LogStash::Util::Accessors.new(data)
|
||||||
@data[VERSION] ||= VERSION_ONE
|
@data[VERSION] ||= VERSION_ONE
|
||||||
@data[TIMESTAMP] = init_timestamp(@data[TIMESTAMP])
|
@data[TIMESTAMP] = init_timestamp(@data[TIMESTAMP])
|
||||||
|
|
||||||
|
@metadata = if @data.include?("@metadata")
|
||||||
|
@data.delete("@metadata")
|
||||||
|
else
|
||||||
|
{}
|
||||||
|
end
|
||||||
|
@metadata_accessors = LogStash::Util::Accessors.new(@metadata)
|
||||||
end # def initialize
|
end # def initialize
|
||||||
|
|
||||||
public
|
public
|
||||||
|
@ -114,9 +121,17 @@ class LogStash::Event
|
||||||
end # def unix_timestamp
|
end # def unix_timestamp
|
||||||
|
|
||||||
# field-related access
|
# field-related access
|
||||||
|
METADATA = "@metadata".freeze
|
||||||
|
METADATA_BRACKETS = "[#{METADATA}]".freeze
|
||||||
public
|
public
|
||||||
def [](fieldref)
|
def [](fieldref)
|
||||||
@accessors.get(fieldref)
|
if fieldref.start_with?(METADATA_BRACKETS)
|
||||||
|
@metadata_accessors.get(fieldref[METADATA_BRACKETS.length .. -1])
|
||||||
|
elsif fieldref == METADATA
|
||||||
|
@metadata
|
||||||
|
else
|
||||||
|
@accessors.get(fieldref)
|
||||||
|
end
|
||||||
end # def []
|
end # def []
|
||||||
|
|
||||||
public
|
public
|
||||||
|
@ -126,7 +141,13 @@ class LogStash::Event
|
||||||
if fieldref == TIMESTAMP && !value.is_a?(LogStash::Timestamp)
|
if fieldref == TIMESTAMP && !value.is_a?(LogStash::Timestamp)
|
||||||
raise TypeError, "The field '@timestamp' must be a (LogStash::Timestamp, not a #{value.class} (#{value})"
|
raise TypeError, "The field '@timestamp' must be a (LogStash::Timestamp, not a #{value.class} (#{value})"
|
||||||
end
|
end
|
||||||
@accessors.set(fieldref, value)
|
if fieldref.start_with?(METADATA_BRACKETS)
|
||||||
|
@metadata_accessors.set(fieldref[METADATA_BRACKETS.length .. -1], value)
|
||||||
|
elsif fieldref == METADATA
|
||||||
|
@metadata = value
|
||||||
|
else
|
||||||
|
@accessors.set(fieldref, value)
|
||||||
|
end
|
||||||
end # def []=
|
end # def []=
|
||||||
|
|
||||||
public
|
public
|
||||||
|
@ -265,4 +286,19 @@ class LogStash::Event
|
||||||
|
|
||||||
LogStash::Timestamp.now
|
LogStash::Timestamp.now
|
||||||
end
|
end
|
||||||
|
|
||||||
|
public
|
||||||
|
def to_hash_with_metadata
|
||||||
|
if @metadata.nil?
|
||||||
|
to_hash
|
||||||
|
else
|
||||||
|
to_hash.merge("@metadata" => @metadata)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
public
|
||||||
|
def to_json_with_metadata(*args)
|
||||||
|
# ignore arguments to respect accepted to_json method signature
|
||||||
|
LogStash::Json.dump(to_hash_with_metadata)
|
||||||
|
end # def to_json
|
||||||
end # class LogStash::Event
|
end # class LogStash::Event
|
||||||
|
|
|
@ -34,7 +34,7 @@ describe LogStash::Event do
|
||||||
|
|
||||||
it "should assign simple fields" do
|
it "should assign simple fields" do
|
||||||
insist { subject["foo"] }.nil?
|
insist { subject["foo"] }.nil?
|
||||||
insist { subject["foo"] = "bar"} == "bar"
|
insist { subject["foo"] = "bar" } == "bar"
|
||||||
insist { subject["foo"] } == "bar"
|
insist { subject["foo"] } == "bar"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -200,7 +200,7 @@ describe LogStash::Event do
|
||||||
|
|
||||||
data = { "@timestamp" => "2013-12-21T07:25:06.605Z" }
|
data = { "@timestamp" => "2013-12-21T07:25:06.605Z" }
|
||||||
event = LogStash::Event.new(data)
|
event = LogStash::Event.new(data)
|
||||||
insist { event["@timestamp"] }.is_a?(Time)
|
insist { event["@timestamp"] }.is_a?(LogStash::Timestamp)
|
||||||
|
|
||||||
duration = 0
|
duration = 0
|
||||||
[warmup, count].each do |i|
|
[warmup, count].each do |i|
|
||||||
|
@ -317,4 +317,68 @@ describe LogStash::Event do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "metadata" do
|
||||||
|
context "with existing metadata" do
|
||||||
|
subject { LogStash::Event.new("hello" => "world", "@metadata" => { "fancy" => "pants" }) }
|
||||||
|
it "should not include metadata in to_hash" do
|
||||||
|
reject { subject.to_hash.keys }.include?("@metadata")
|
||||||
|
|
||||||
|
# 'hello', '@timestamp', and '@version'
|
||||||
|
insist { subject.to_hash.keys.count } == 3
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should still allow normal field access" do
|
||||||
|
insist { subject["hello"] } == "world"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with set metadata" do
|
||||||
|
let(:fieldref) { "[@metadata][foo][bar]" }
|
||||||
|
let(:value) { "bar" }
|
||||||
|
subject { LogStash::Event.new("normal" => "normal") }
|
||||||
|
before do
|
||||||
|
# Verify the test is configured correctly.
|
||||||
|
insist { fieldref }.start_with?("[@metadata]")
|
||||||
|
|
||||||
|
# Set it.
|
||||||
|
subject[fieldref] = value
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should still allow normal field access" do
|
||||||
|
insist { subject["normal"] } == "normal"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should allow getting" do
|
||||||
|
insist { subject[fieldref] } == value
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should be hidden from .to_json" do
|
||||||
|
require "json"
|
||||||
|
obj = JSON.parse(subject.to_json)
|
||||||
|
reject { obj }.include?("@metadata")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should be hidden from .to_hash" do
|
||||||
|
reject { subject.to_hash }.include?("@metadata")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should be accessible through #to_hash_with_metadata" do
|
||||||
|
obj = subject.to_hash_with_metadata
|
||||||
|
insist { obj }.include?("@metadata")
|
||||||
|
insist { obj["@metadata"]["foo"]["bar"] } == value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "with no metadata" do
|
||||||
|
subject { LogStash::Event.new("foo" => "bar") }
|
||||||
|
it "should have no metadata" do
|
||||||
|
insist { subject["@metadata"] }.empty?
|
||||||
|
end
|
||||||
|
it "should still allow normal field access" do
|
||||||
|
insist { subject["foo"] } == "bar"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue