logstash-lite 0.2.20101118134500
Sign up to get free protection for your applications and to get access to all the features.
- 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
|