logstash-lite 0.2.20101118134500
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/bin/logstash +56 -0
- data/bin/logstash-web +6 -0
- data/etc/logstash-elasticsearch-rabbitmq-river.yaml +41 -0
- data/etc/logstash-mongodb-storage.yaml +5 -0
- data/etc/logstash-parser.yaml +20 -0
- data/etc/logstash-reader.yaml +8 -0
- data/etc/logstash-shipper.yaml +18 -0
- data/etc/logstash-standalone.yaml +47 -0
- data/etc/prod.yaml +38 -0
- data/etc/redhat/logstash +92 -0
- data/etc/redhat/logstash-agent +83 -0
- data/etc/redhat/logstash-agent.sysconfig +7 -0
- data/etc/redhat/logstash.spec +171 -0
- data/etc/redhat/logstash.sysconfig +18 -0
- data/etc/tograylog.yaml +37 -0
- data/examples/test.rb +38 -0
- data/lib/logstash.rb +3 -0
- data/lib/logstash/agent.rb +116 -0
- data/lib/logstash/event.rb +70 -0
- data/lib/logstash/filters.rb +17 -0
- data/lib/logstash/filters/base.rb +17 -0
- data/lib/logstash/filters/date.rb +59 -0
- data/lib/logstash/filters/field.rb +29 -0
- data/lib/logstash/filters/grok.rb +74 -0
- data/lib/logstash/filters/grokdiscovery.rb +60 -0
- data/lib/logstash/inputs.rb +18 -0
- data/lib/logstash/inputs/amqp.rb +48 -0
- data/lib/logstash/inputs/base.rb +32 -0
- data/lib/logstash/inputs/file.rb +47 -0
- data/lib/logstash/inputs/syslog.rb +123 -0
- data/lib/logstash/inputs/tcp.rb +51 -0
- data/lib/logstash/logging.rb +82 -0
- data/lib/logstash/namespace.rb +6 -0
- data/lib/logstash/outputs.rb +15 -0
- data/lib/logstash/outputs/amqp.rb +48 -0
- data/lib/logstash/outputs/base.rb +29 -0
- data/lib/logstash/outputs/elasticsearch.rb +71 -0
- data/lib/logstash/outputs/gelf.rb +35 -0
- data/lib/logstash/outputs/mongodb.rb +19 -0
- data/lib/logstash/outputs/stdout.rb +15 -0
- data/lib/logstash/outputs/websocket.rb +35 -0
- data/lib/logstash/time.rb +27 -0
- data/lib/logstash/web/lib/elasticsearch.rb +79 -0
- data/lib/logstash/web/public/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/lib/logstash/web/public/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/lib/logstash/web/public/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/lib/logstash/web/public/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/lib/logstash/web/public/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/lib/logstash/web/public/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/lib/logstash/web/public/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/lib/logstash/web/public/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/lib/logstash/web/public/css/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/lib/logstash/web/public/css/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/lib/logstash/web/public/css/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/lib/logstash/web/public/css/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/lib/logstash/web/public/css/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/lib/logstash/web/public/css/smoothness/jquery-ui-1.8.5.custom.css +572 -0
- data/lib/logstash/web/public/js/flot/API.txt +1024 -0
- data/lib/logstash/web/public/js/flot/FAQ.txt +71 -0
- data/lib/logstash/web/public/js/flot/LICENSE.txt +22 -0
- data/lib/logstash/web/public/js/flot/Makefile +15 -0
- data/lib/logstash/web/public/js/flot/NEWS.txt +340 -0
- data/lib/logstash/web/public/js/flot/PLUGINS.txt +105 -0
- data/lib/logstash/web/public/js/flot/README.txt +81 -0
- data/lib/logstash/web/public/js/flot/examples/ajax.html +143 -0
- data/lib/logstash/web/public/js/flot/examples/annotating.html +75 -0
- data/lib/logstash/web/public/js/flot/examples/arrow-down.gif +0 -0
- data/lib/logstash/web/public/js/flot/examples/arrow-left.gif +0 -0
- data/lib/logstash/web/public/js/flot/examples/arrow-right.gif +0 -0
- data/lib/logstash/web/public/js/flot/examples/arrow-up.gif +0 -0
- data/lib/logstash/web/public/js/flot/examples/basic.html +38 -0
- data/lib/logstash/web/public/js/flot/examples/data-eu-gdp-growth-1.json +4 -0
- data/lib/logstash/web/public/js/flot/examples/data-eu-gdp-growth-2.json +4 -0
- data/lib/logstash/web/public/js/flot/examples/data-eu-gdp-growth-3.json +4 -0
- data/lib/logstash/web/public/js/flot/examples/data-eu-gdp-growth-4.json +4 -0
- data/lib/logstash/web/public/js/flot/examples/data-eu-gdp-growth-5.json +4 -0
- data/lib/logstash/web/public/js/flot/examples/data-eu-gdp-growth.json +4 -0
- data/lib/logstash/web/public/js/flot/examples/data-japan-gdp-growth.json +4 -0
- data/lib/logstash/web/public/js/flot/examples/data-usa-gdp-growth.json +4 -0
- data/lib/logstash/web/public/js/flot/examples/dual-axis.html +39 -0
- data/lib/logstash/web/public/js/flot/examples/graph-types.html +75 -0
- data/lib/logstash/web/public/js/flot/examples/hs-2004-27-a-large_web.jpg +0 -0
- data/lib/logstash/web/public/js/flot/examples/image.html +45 -0
- data/lib/logstash/web/public/js/flot/examples/index.html +43 -0
- data/lib/logstash/web/public/js/flot/examples/interacting.html +93 -0
- data/lib/logstash/web/public/js/flot/examples/layout.css +6 -0
- data/lib/logstash/web/public/js/flot/examples/navigate.html +118 -0
- data/lib/logstash/web/public/js/flot/examples/selection.html +114 -0
- data/lib/logstash/web/public/js/flot/examples/setting-options.html +65 -0
- data/lib/logstash/web/public/js/flot/examples/stacking.html +77 -0
- data/lib/logstash/web/public/js/flot/examples/thresholding.html +54 -0
- data/lib/logstash/web/public/js/flot/examples/time.html +71 -0
- data/lib/logstash/web/public/js/flot/examples/tracking.html +95 -0
- data/lib/logstash/web/public/js/flot/examples/turning-series.html +98 -0
- data/lib/logstash/web/public/js/flot/examples/visitors.html +90 -0
- data/lib/logstash/web/public/js/flot/examples/zooming.html +98 -0
- data/lib/logstash/web/public/js/flot/excanvas.js +1427 -0
- data/lib/logstash/web/public/js/flot/excanvas.min.js +1 -0
- data/lib/logstash/web/public/js/flot/jquery.colorhelpers.js +174 -0
- data/lib/logstash/web/public/js/flot/jquery.colorhelpers.min.js +1 -0
- data/lib/logstash/web/public/js/flot/jquery.flot.crosshair.js +156 -0
- data/lib/logstash/web/public/js/flot/jquery.flot.crosshair.min.js +1 -0
- data/lib/logstash/web/public/js/flot/jquery.flot.image.js +237 -0
- data/lib/logstash/web/public/js/flot/jquery.flot.image.min.js +1 -0
- data/lib/logstash/web/public/js/flot/jquery.flot.js +2119 -0
- data/lib/logstash/web/public/js/flot/jquery.flot.min.js +1 -0
- data/lib/logstash/web/public/js/flot/jquery.flot.navigate.js +272 -0
- data/lib/logstash/web/public/js/flot/jquery.flot.navigate.min.js +1 -0
- data/lib/logstash/web/public/js/flot/jquery.flot.selection.js +299 -0
- data/lib/logstash/web/public/js/flot/jquery.flot.selection.min.js +1 -0
- data/lib/logstash/web/public/js/flot/jquery.flot.stack.js +152 -0
- data/lib/logstash/web/public/js/flot/jquery.flot.stack.min.js +1 -0
- data/lib/logstash/web/public/js/flot/jquery.flot.threshold.js +103 -0
- data/lib/logstash/web/public/js/flot/jquery.flot.threshold.min.js +1 -0
- data/lib/logstash/web/public/js/flot/jquery.js +4376 -0
- data/lib/logstash/web/public/js/flot/jquery.min.js +19 -0
- data/lib/logstash/web/public/js/jquery-hashchange-1.0.0.js +121 -0
- data/lib/logstash/web/public/js/jquery.livequery.js +250 -0
- data/lib/logstash/web/public/js/jquery.tmpl.min.js +1 -0
- data/lib/logstash/web/public/js/logstash.js +202 -0
- data/lib/logstash/web/server.rb +90 -0
- data/lib/logstash/web/views/header.haml +8 -0
- data/lib/logstash/web/views/layout.haml +21 -0
- data/lib/logstash/web/views/main/index.haml +5 -0
- data/lib/logstash/web/views/search/ajax.haml +32 -0
- data/lib/logstash/web/views/search/results.haml +17 -0
- data/lib/logstash/web/views/style.sass +50 -0
- data/patterns/firewalls +2 -0
- data/patterns/grok-patterns +90 -0
- data/patterns/haproxy +5 -0
- data/patterns/linux-syslog +7 -0
- data/patterns/nagios +7 -0
- data/patterns/ruby +2 -0
- metadata +228 -0
@@ -0,0 +1,18 @@
|
|
1
|
+
# LogStash configuration
|
2
|
+
|
3
|
+
# Run the indexer. This can be set to false to disable the indexer (and
|
4
|
+
# searching) and only parse log lines.
|
5
|
+
INDEXER=true
|
6
|
+
|
7
|
+
# Run one parser. For maximum throughput, run one parser per core.
|
8
|
+
# This can be set to 0 to disable the parser.
|
9
|
+
PARSERS=1
|
10
|
+
|
11
|
+
# Path to config file
|
12
|
+
CONFIG=/opt/logstash/etc/logstashd.yaml
|
13
|
+
|
14
|
+
# Set to true for very verbose debugging output
|
15
|
+
DEBUG=false
|
16
|
+
|
17
|
+
# Run as the logstash user
|
18
|
+
USER=logstash
|
data/etc/tograylog.yaml
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
---
|
2
|
+
inputs:
|
3
|
+
linux-syslog:
|
4
|
+
- /var/log/messages
|
5
|
+
- /var/log/kern.log
|
6
|
+
- /var/log/auth.log
|
7
|
+
- /var/log/user.log
|
8
|
+
apache-access:
|
9
|
+
- /var/log/apache2/access.log
|
10
|
+
- /home/jls/logs/access_log
|
11
|
+
apache-error:
|
12
|
+
- /var/log/apache2/error.log
|
13
|
+
- /home/jls/logs/error_log
|
14
|
+
filters:
|
15
|
+
- grok:
|
16
|
+
linux-syslog: # for logs of type 'linux-syslog'
|
17
|
+
patterns:
|
18
|
+
- %{SYSLOGLINE}
|
19
|
+
apache-access: # for logs of type 'apache-error'
|
20
|
+
patterns:
|
21
|
+
- %{COMBINEDAPACHELOG}
|
22
|
+
nagios:
|
23
|
+
patterns:
|
24
|
+
- %{NAGIOSLOGLINE}
|
25
|
+
- date:
|
26
|
+
linux-syslog: # for logs of type 'linux-syslog'
|
27
|
+
# Look for a field 'timestamp' with this format, parse and it for the timestamp
|
28
|
+
# This field comes from the SYSLOGLINE pattern
|
29
|
+
timestamp: "%b %e %H:%M:%S"
|
30
|
+
timestamp8601: ISO8601
|
31
|
+
apache-access:
|
32
|
+
timestamp: "%d/%b/%Y:%H:%M:%S %Z"
|
33
|
+
nagios:
|
34
|
+
epochtime: %s
|
35
|
+
outputs:
|
36
|
+
- stdout:///
|
37
|
+
- gelf://localhost/
|
data/examples/test.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# How to trigger the 'evil ip' message:
|
4
|
+
# % logger -t "pantscon" "naughty host 14.33.24.55 $RANDOM"
|
5
|
+
|
6
|
+
require "rubygems"
|
7
|
+
require "logstash/agent"
|
8
|
+
|
9
|
+
class MyAgent < LogStash::Agent
|
10
|
+
def receive(event)
|
11
|
+
filter(event) # Invoke any filters
|
12
|
+
|
13
|
+
return unless event["progname"][0] == "pantscon"
|
14
|
+
return unless event.message =~ /naughty host/
|
15
|
+
event["IP"].each do |ip|
|
16
|
+
next unless ip.length > 0
|
17
|
+
puts "Evil IP: #{ip}"
|
18
|
+
end
|
19
|
+
end # def receive
|
20
|
+
end # class MyAgent
|
21
|
+
|
22
|
+
# Read a local file, parse it, and react accordingly (see MyAgent#receive)
|
23
|
+
agent = MyAgent.new({
|
24
|
+
"input" => [
|
25
|
+
"/var/log/messages",
|
26
|
+
],
|
27
|
+
"filter" => [ "grok" ],
|
28
|
+
})
|
29
|
+
agent.run
|
30
|
+
|
31
|
+
# Read messages that we expect to be parsed by another agent. Reads
|
32
|
+
# a particular AMQP topic for messages
|
33
|
+
#agent = MyAgent.new({
|
34
|
+
#"input" => [
|
35
|
+
#"amqp://localhost/topic/parsed",
|
36
|
+
#]
|
37
|
+
#})
|
38
|
+
#agent.run
|
data/lib/logstash.rb
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
require "eventmachine"
|
2
|
+
require "eventmachine-tail"
|
3
|
+
require "logstash/namespace"
|
4
|
+
require "logstash/inputs"
|
5
|
+
require "logstash/outputs"
|
6
|
+
require "logstash/filters"
|
7
|
+
require "logstash/logging"
|
8
|
+
|
9
|
+
# Collect logs, ship them out.
|
10
|
+
class LogStash::Agent
|
11
|
+
attr_reader :config
|
12
|
+
|
13
|
+
def initialize(config)
|
14
|
+
@logger = LogStash::Logger.new(STDERR)
|
15
|
+
|
16
|
+
@config = config
|
17
|
+
@outputs = []
|
18
|
+
@inputs = []
|
19
|
+
@filters = []
|
20
|
+
# Config should have:
|
21
|
+
# - list of logs to monitor
|
22
|
+
# - log config
|
23
|
+
# - where to ship to
|
24
|
+
end # def initialize
|
25
|
+
|
26
|
+
# Register any event handlers with EventMachine
|
27
|
+
# Technically, this agent could listen for anything (files, sockets, amqp,
|
28
|
+
# stomp, etc).
|
29
|
+
protected
|
30
|
+
def register
|
31
|
+
# TODO(sissel): warn when no inputs and no outputs are defined.
|
32
|
+
# TODO(sissel): Refactor this madness into a config lib
|
33
|
+
|
34
|
+
if (["inputs", "outputs"] & @config.keys).length == 0
|
35
|
+
$stderr.puts "No inputs or no outputs configured. This probably isn't what you want."
|
36
|
+
end
|
37
|
+
|
38
|
+
# Register input and output stuff
|
39
|
+
if @config.include?("inputs")
|
40
|
+
inputs = @config["inputs"]
|
41
|
+
inputs.each do |value|
|
42
|
+
# If 'url' is an array, then inputs is a hash and the key is the type
|
43
|
+
if inputs.is_a?(Hash)
|
44
|
+
type, urls = value
|
45
|
+
else
|
46
|
+
raise "config error, no type for url #{urls.inspect}"
|
47
|
+
end
|
48
|
+
|
49
|
+
# url could be a string or an array.
|
50
|
+
urls = [urls] if !urls.is_a?(Array)
|
51
|
+
|
52
|
+
urls.each do |url|
|
53
|
+
@logger.debug("Using input #{url} of type #{type}")
|
54
|
+
input = LogStash::Inputs.from_url(url, type) { |event| receive(event) }
|
55
|
+
input.register
|
56
|
+
@inputs << input
|
57
|
+
end
|
58
|
+
end # each input
|
59
|
+
end
|
60
|
+
|
61
|
+
if @config.include?("filters")
|
62
|
+
filters = @config["filters"]
|
63
|
+
filters.collect { |x| x.to_a[0] }.each do |filter|
|
64
|
+
name, value = filter
|
65
|
+
@logger.debug("Using filter #{name} => #{value.inspect}")
|
66
|
+
filter = LogStash::Filters.from_name(name, value)
|
67
|
+
filter.register
|
68
|
+
@filters << filter
|
69
|
+
end # each filter
|
70
|
+
end
|
71
|
+
|
72
|
+
if @config.include?("outputs")
|
73
|
+
@config["outputs"].each do |url|
|
74
|
+
@logger.debug("Using output #{url}")
|
75
|
+
output = LogStash::Outputs.from_url(url)
|
76
|
+
output.register
|
77
|
+
@outputs << output
|
78
|
+
end # each output
|
79
|
+
end
|
80
|
+
end # def register
|
81
|
+
|
82
|
+
public
|
83
|
+
def run
|
84
|
+
EventMachine.run do
|
85
|
+
self.register
|
86
|
+
end # EventMachine.run
|
87
|
+
end # def run
|
88
|
+
|
89
|
+
protected
|
90
|
+
def filter(event)
|
91
|
+
@filters.each do |f|
|
92
|
+
# TODO(sissel): Add ability for a filter to cancel/drop a message
|
93
|
+
f.filter(event)
|
94
|
+
if event.cancelled?
|
95
|
+
break
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end # def filter
|
99
|
+
|
100
|
+
protected
|
101
|
+
def output(event)
|
102
|
+
@outputs.each do |o|
|
103
|
+
o.receive(event)
|
104
|
+
end # each output
|
105
|
+
end # def output
|
106
|
+
|
107
|
+
protected
|
108
|
+
# Process a message
|
109
|
+
def receive(event)
|
110
|
+
filter(event)
|
111
|
+
|
112
|
+
if !event.cancelled?
|
113
|
+
output(event)
|
114
|
+
end
|
115
|
+
end # def input
|
116
|
+
end # class LogStash::Components::Agent
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require "json"
|
2
|
+
require "logstash/time"
|
3
|
+
require "uri"
|
4
|
+
|
5
|
+
# General event type. Will expand this in the future.
|
6
|
+
module LogStash; class Event
|
7
|
+
def initialize(data)
|
8
|
+
@cancelled = false
|
9
|
+
@data = {
|
10
|
+
"@source" => "unknown",
|
11
|
+
"@type" => nil,
|
12
|
+
"@tags" => [],
|
13
|
+
"@fields" => {},
|
14
|
+
}.merge(data)
|
15
|
+
|
16
|
+
if !@data.include?("@timestamp")
|
17
|
+
@data["@timestamp"] = LogStash::Time.now.utc.to_iso8601
|
18
|
+
end
|
19
|
+
end # def initialize
|
20
|
+
|
21
|
+
def self.from_json(json)
|
22
|
+
return Event.new(JSON.parse(json))
|
23
|
+
end # def self.from_json
|
24
|
+
|
25
|
+
def cancel
|
26
|
+
@cancelled = true
|
27
|
+
end
|
28
|
+
|
29
|
+
def cancelled?
|
30
|
+
return @cancelled
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_s
|
34
|
+
return "#{timestamp} #{source}: #{message}"
|
35
|
+
end # def to_s
|
36
|
+
|
37
|
+
def timestamp; @data["@timestamp"]; end # def timestamp
|
38
|
+
def timestamp=(val); @data["@timestamp"] = val; end # def timestamp=
|
39
|
+
|
40
|
+
def source; @data["@source"]; end # def source
|
41
|
+
def source=(val)
|
42
|
+
if val.is_a?(URI)
|
43
|
+
@data["@source"] = val.to_s
|
44
|
+
@data["@source_host"] = val.host
|
45
|
+
@data["@source_path"] = val.path
|
46
|
+
else
|
47
|
+
@data["@source"] = val
|
48
|
+
end
|
49
|
+
end # def source=
|
50
|
+
|
51
|
+
def message; @data["@message"]; end # def message
|
52
|
+
def message=(val); @data["@message"] = val; end # def message=
|
53
|
+
|
54
|
+
def type; @data["@type"]; end # def type
|
55
|
+
def type=(val); @data["@type"] = val; end # def type=
|
56
|
+
|
57
|
+
def tags; @data["@tags"]; end # def tags
|
58
|
+
def tags=(val); @data["@tags"] = val; end # def tags=
|
59
|
+
|
60
|
+
# field-related access
|
61
|
+
def [](key); @data["@fields"][key] end # def []
|
62
|
+
def []=(key, value); @data["@fields"][key] = value end # def []=
|
63
|
+
def fields; return @data["@fields"] end # def fields
|
64
|
+
|
65
|
+
def to_json; return @data.to_json end # def to_json
|
66
|
+
|
67
|
+
def to_hash; return @data end # def to_hash
|
68
|
+
|
69
|
+
def include?(key); return @data.include?(key) end
|
70
|
+
end; end # class LogStash::Event
|
@@ -0,0 +1,17 @@
|
|
1
|
+
|
2
|
+
require "logstash/namespace"
|
3
|
+
|
4
|
+
module LogStash::Filters
|
5
|
+
def self.from_name(name, *args)
|
6
|
+
# TODO(sissel): Add error handling
|
7
|
+
# TODO(sissel): Allow plugin paths
|
8
|
+
klass = name.capitalize
|
9
|
+
|
10
|
+
# Load the class if we haven't already.
|
11
|
+
require "logstash/filters/#{name}"
|
12
|
+
|
13
|
+
# Get the class name from the Filters namespace and create a new instance.
|
14
|
+
# for name == 'foo' this will call LogStash::Filters::Foo.new
|
15
|
+
LogStash::Filters.const_get(klass).new(*args)
|
16
|
+
end # def from_url
|
17
|
+
end # module LogStash::Filters
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "logstash/namespace"
|
2
|
+
require "logstash/logging"
|
3
|
+
|
4
|
+
class LogStash::Filters::Base
|
5
|
+
def initialize(config = {})
|
6
|
+
@logger = LogStash::Logger.new(STDERR)
|
7
|
+
@config = config
|
8
|
+
end # def initialize
|
9
|
+
|
10
|
+
def register
|
11
|
+
raise "#{self.class}#register must be overidden"
|
12
|
+
end # def register
|
13
|
+
|
14
|
+
def filter(event)
|
15
|
+
raise "#{self.class}#filter must be overidden"
|
16
|
+
end # def filter
|
17
|
+
end # class LogStash::Filters::Base
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require "logstash/filters/base"
|
2
|
+
require "logstash/time"
|
3
|
+
|
4
|
+
class LogStash::Filters::Date < LogStash::Filters::Base
|
5
|
+
# The 'date' filter will take a value from your event and use it as the
|
6
|
+
# event timestamp. This is useful for parsing logs generated on remote
|
7
|
+
# servers or for importing old logs.
|
8
|
+
#
|
9
|
+
# The config looks like this:
|
10
|
+
#
|
11
|
+
# filters:
|
12
|
+
# date:
|
13
|
+
# <type>:
|
14
|
+
# <fieldname>: <format>
|
15
|
+
# <type>
|
16
|
+
# <fieldname>: <format>
|
17
|
+
#
|
18
|
+
# The format is whatever is supported by Ruby's DateTime.strptime
|
19
|
+
def initialize(config = {})
|
20
|
+
super
|
21
|
+
|
22
|
+
@types = Hash.new { |h,k| h[k] = [] }
|
23
|
+
end # def initialize
|
24
|
+
|
25
|
+
def register
|
26
|
+
@config.each do |type, typeconfig|
|
27
|
+
@logger.debug "Setting type #{type.inspect} to the config #{typeconfig.inspect}"
|
28
|
+
raise "date filter type \"#{type}\" defined more than once" unless @types[type].empty?
|
29
|
+
@types[type] = typeconfig
|
30
|
+
end # @config.each
|
31
|
+
end # def register
|
32
|
+
|
33
|
+
def filter(event)
|
34
|
+
@logger.debug "DATE FILTER: received event of type #{event.type}"
|
35
|
+
return unless @types.member?(event.type)
|
36
|
+
@types[event.type].each do |field, format|
|
37
|
+
@logger.debug "DATE FILTER: type #{event.type}, looking for field #{field.inspect} with format #{format.inspect}"
|
38
|
+
# TODO(sissel): check event.message, too.
|
39
|
+
if event.fields.member?(field)
|
40
|
+
fieldvalue = event.fields[field]
|
41
|
+
fieldvalue = [fieldvalue] if fieldvalue.is_a?(String)
|
42
|
+
fieldvalue.each do |value|
|
43
|
+
begin
|
44
|
+
case format
|
45
|
+
when "ISO8601"
|
46
|
+
time = DateTime.parse(value)
|
47
|
+
else
|
48
|
+
time = DateTime.strptime(value, format)
|
49
|
+
end
|
50
|
+
event.timestamp = LogStash::Time.to_iso8601(time)
|
51
|
+
@logger.debug "Parsed #{value.inspect} as #{event.timestamp}"
|
52
|
+
rescue
|
53
|
+
@logger.warn "Failed parsing date #{value.inspect} from field #{field} with format #{format.inspect}: #{$!}"
|
54
|
+
end
|
55
|
+
end # fieldvalue.each
|
56
|
+
end # if this event has a field we expect to be a timestamp
|
57
|
+
end # @types[event.type].each
|
58
|
+
end # def filter
|
59
|
+
end # class LogStash::Filters::Date
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "logstash/filters/base"
|
2
|
+
require "ostruct"
|
3
|
+
|
4
|
+
class LogStash::Filters::Field < LogStash::Filters::Base
|
5
|
+
class EvalSpace < OpenStruct
|
6
|
+
def get_binding
|
7
|
+
return binding
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(config = {})
|
12
|
+
super
|
13
|
+
end # def initialize
|
14
|
+
|
15
|
+
def register
|
16
|
+
# nothing to do
|
17
|
+
end # def register
|
18
|
+
|
19
|
+
def filter(event)
|
20
|
+
data = EvalSpace.new(event.to_hash)
|
21
|
+
|
22
|
+
@config.each do |condition|
|
23
|
+
if data.instance_eval(condition)
|
24
|
+
return # This event is OK, matches the condition.
|
25
|
+
end
|
26
|
+
end
|
27
|
+
event.cancel
|
28
|
+
end
|
29
|
+
end # class LogStash::Filters::Field
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require "logstash/filters/base"
|
2
|
+
|
3
|
+
gem "jls-grok", ">=0.2.3071"
|
4
|
+
require "grok" # rubygem 'jls-grok'
|
5
|
+
|
6
|
+
class LogStash::Filters::Grok < LogStash::Filters::Base
|
7
|
+
def initialize(config = {})
|
8
|
+
super
|
9
|
+
|
10
|
+
@grokpiles = {}
|
11
|
+
end # def initialize
|
12
|
+
|
13
|
+
def register
|
14
|
+
# TODO(sissel): Make patterns files come from the config
|
15
|
+
@config.each do |type, typeconfig|
|
16
|
+
@logger.debug("Registering type with grok: #{type}")
|
17
|
+
pile = Grok::Pile.new
|
18
|
+
patterndir = "#{File.dirname(__FILE__)}/../../../patterns/*"
|
19
|
+
Dir.glob(patterndir).each do |path|
|
20
|
+
pile.add_patterns_from_file(path)
|
21
|
+
end
|
22
|
+
typeconfig["patterns"].each do |pattern|
|
23
|
+
groks = pile.compile(pattern)
|
24
|
+
@logger.debug(["Compiled pattern", pattern, groks[-1].expanded_pattern])
|
25
|
+
end
|
26
|
+
@grokpiles[type] = pile
|
27
|
+
end # @config.each
|
28
|
+
end # def register
|
29
|
+
|
30
|
+
def filter(event)
|
31
|
+
# parse it with grok
|
32
|
+
message = event.message
|
33
|
+
match = false
|
34
|
+
|
35
|
+
if event.type
|
36
|
+
if @grokpiles.include?(event.type)
|
37
|
+
@logger.debug(["Running grok filter", event])
|
38
|
+
pile = @grokpiles[event.type]
|
39
|
+
grok, match = pile.match(message)
|
40
|
+
end # @grokpiles.include?(event.type)
|
41
|
+
# TODO(2.0): support grok pattern discovery
|
42
|
+
else
|
43
|
+
@logger.info("Unknown type for #{event.source} (type: #{event.type})")
|
44
|
+
@logger.debug(event.to_hash)
|
45
|
+
end
|
46
|
+
|
47
|
+
if match
|
48
|
+
match.each_capture do |key, value|
|
49
|
+
if key.include?(":")
|
50
|
+
key = key.split(":")[1]
|
51
|
+
end
|
52
|
+
if event.message == value
|
53
|
+
# Skip patterns that match the entire line
|
54
|
+
@logger.debug("Skipping capture '#{key}' since it matches the whole line.")
|
55
|
+
next
|
56
|
+
end
|
57
|
+
|
58
|
+
if event.fields[key].is_a?(String)
|
59
|
+
event.fields[key] = [event.fields[key]]
|
60
|
+
elsif event.fields[key] == nil
|
61
|
+
event.fields[key] = []
|
62
|
+
end
|
63
|
+
|
64
|
+
event.fields[key] << value
|
65
|
+
end
|
66
|
+
else
|
67
|
+
# Tag this event if we can't parse it. We can use this later to
|
68
|
+
# reparse+reindex logs if we improve the patterns given .
|
69
|
+
event.tags << "_grokparsefailure"
|
70
|
+
end
|
71
|
+
|
72
|
+
@logger.debug(["Event now: ", event.to_hash])
|
73
|
+
end # def filter
|
74
|
+
end # class LogStash::Filters::Grok
|