logstash-lite 0.2.20101222161646 → 0.2.20110112115019

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/bin/logstash +13 -2
  2. data/bin/logstash-test +1 -3
  3. data/lib/logstash.rb +1 -1
  4. data/lib/logstash/agent.rb +37 -40
  5. data/lib/logstash/event.rb +20 -5
  6. data/lib/logstash/filters.rb +1 -1
  7. data/lib/logstash/filters/base.rb +6 -1
  8. data/lib/logstash/filters/date.rb +4 -0
  9. data/lib/logstash/filters/field.rb +4 -5
  10. data/lib/logstash/filters/grep.rb +39 -3
  11. data/lib/logstash/filters/grok.rb +10 -3
  12. data/lib/logstash/filters/grokdiscovery.rb +4 -1
  13. data/lib/logstash/filters/multiline.rb +6 -2
  14. data/lib/logstash/inputs.rb +6 -2
  15. data/lib/logstash/inputs/amqp.rb +5 -2
  16. data/lib/logstash/inputs/base.rb +17 -4
  17. data/lib/logstash/inputs/beanstalk.rb +5 -2
  18. data/lib/logstash/inputs/file.rb +7 -2
  19. data/lib/logstash/inputs/internal.rb +5 -2
  20. data/lib/logstash/inputs/stdin.rb +38 -0
  21. data/lib/logstash/inputs/stomp.rb +14 -12
  22. data/lib/logstash/inputs/syslog.rb +10 -5
  23. data/lib/logstash/inputs/tcp.rb +8 -3
  24. data/lib/logstash/inputs/twitter.rb +81 -0
  25. data/lib/logstash/logging.rb +4 -1
  26. data/lib/logstash/namespace.rb +0 -1
  27. data/lib/logstash/outputs.rb +1 -1
  28. data/lib/logstash/outputs/amqp.rb +9 -2
  29. data/lib/logstash/outputs/base.rb +7 -3
  30. data/lib/logstash/outputs/beanstalk.rb +4 -0
  31. data/lib/logstash/outputs/elasticsearch.rb +86 -18
  32. data/lib/logstash/outputs/gelf.rb +5 -6
  33. data/lib/logstash/outputs/internal.rb +7 -1
  34. data/lib/logstash/outputs/mongodb.rb +10 -10
  35. data/lib/logstash/outputs/nagios.rb +6 -2
  36. data/lib/logstash/outputs/stdout.rb +3 -4
  37. data/lib/logstash/outputs/stomp.rb +4 -0
  38. data/lib/logstash/outputs/tcp.rb +3 -4
  39. data/lib/logstash/outputs/websocket.rb +5 -6
  40. data/lib/logstash/ruby_fixes.rb +1 -3
  41. data/lib/logstash/stomp/handler.rb +29 -4
  42. data/lib/logstash/web/lib/elasticsearch.rb +8 -4
  43. data/lib/logstash/web/public/js/logstash.js +25 -5
  44. data/lib/logstash/web/public/ws/index.html +9 -7
  45. data/lib/logstash/web/server.rb +50 -12
  46. data/lib/logstash/web/views/search/ajax.haml +5 -2
  47. data/lib/logstash/web/views/search/results.txt.erb +10 -0
  48. metadata +7 -4
@@ -4,7 +4,7 @@ require "logger"
4
4
 
5
5
  class LogStash::Logger < Logger
6
6
  # Try to load awesome_print, if it fails, log it later
7
- # but otherwise we should continue to operate as normal.
7
+ # but otherwise we will continue to operate as normal.
8
8
  begin
9
9
  require "ap"
10
10
  @@have_awesome_print = true
@@ -13,6 +13,7 @@ class LogStash::Logger < Logger
13
13
  @@notify_awesome_print_load_failed = e
14
14
  end
15
15
 
16
+ public
16
17
  def initialize(*args)
17
18
  super(*args)
18
19
  @formatter = LogStash::Logger::Formatter.new
@@ -37,6 +38,7 @@ class LogStash::Logger < Logger
37
38
  end
38
39
  end # def initialize
39
40
 
41
+ public
40
42
  def level=(level)
41
43
  super(level)
42
44
  @formatter.level = level
@@ -48,6 +50,7 @@ class LogStash::Logger::Formatter < Logger::Formatter
48
50
  attr_accessor :level
49
51
  attr_accessor :progname
50
52
 
53
+ public
51
54
  def call(severity, timestamp, who, object)
52
55
  # override progname to be the caller if the log level threshold is DEBUG
53
56
  # We only do this if the logger level is DEBUG because inspecting the
@@ -1,4 +1,3 @@
1
-
2
1
  module LogStash
3
2
  module Inputs; end
4
3
  module Outputs; end
@@ -1,8 +1,8 @@
1
-
2
1
  require "logstash/namespace"
3
2
  require "uri"
4
3
 
5
4
  module LogStash::Outputs
5
+ public
6
6
  def self.from_url(url, &block)
7
7
  uri = URI.parse(url)
8
8
  # TODO(sissel): Add error handling
@@ -1,9 +1,12 @@
1
- require "logstash/outputs/base"
2
1
  require "amqp" # rubygem 'amqp'
2
+ require "logstash/outputs/base"
3
+ require "logstash/namespace"
3
4
  require "mq" # rubygem 'amqp'
4
5
 
5
6
  class LogStash::Outputs::Amqp < LogStash::Outputs::Base
6
7
  MQTYPES = [ "fanout", "queue", "topic" ]
8
+
9
+ public
7
10
  def initialize(url, config={}, &block)
8
11
  super
9
12
 
@@ -18,9 +21,10 @@ class LogStash::Outputs::Amqp < LogStash::Outputs::Base
18
21
  end
19
22
  end # def initialize
20
23
 
24
+ public
21
25
  def register
22
26
  @logger.info("Registering output #{@url}")
23
- @amqp = AMQP.connect(:host => @url.host)
27
+ @amqp = AMQP.connect(:host => @url.host, :port => (@url.port or 5672))
24
28
  @mq = MQ.new(@amqp)
25
29
  @target = nil
26
30
 
@@ -34,11 +38,14 @@ class LogStash::Outputs::Amqp < LogStash::Outputs::Base
34
38
  end # case @mqtype
35
39
  end # def register
36
40
 
41
+ public
37
42
  def receive(event)
38
43
  @logger.debug(["Sending event", { :url => @url, :event => event }])
39
44
  @target.publish(event.to_json)
40
45
  end # def receive
41
46
 
47
+ # This is used by the ElasticSearch AMQP/River output.
48
+ public
42
49
  def receive_raw(raw)
43
50
  if @target == nil
44
51
  raise "had trouble registering AMQP URL #{@url.to_s}, @target is nil"
@@ -1,11 +1,13 @@
1
- require "logstash/namespace"
1
+ require "cgi"
2
2
  require "logstash/event"
3
3
  require "logstash/logging"
4
- require "cgi"
4
+ require "logstash/namespace"
5
5
  require "uri"
6
6
 
7
7
  class LogStash::Outputs::Base
8
8
  attr_accessor :logger
9
+
10
+ public
9
11
  def initialize(url, config={}, &block)
10
12
  @url = url
11
13
  @url = URI.parse(url) if url.is_a? String
@@ -20,11 +22,13 @@ class LogStash::Outputs::Base
20
22
  end
21
23
  end
22
24
 
25
+ public
23
26
  def register
24
27
  raise "#{self.class}#register must be overidden"
25
28
  end # def register
26
29
 
30
+ public
27
31
  def receive(event)
28
32
  raise "#{self.class}#receive must be overidden"
29
- end
33
+ end # def receive
30
34
  end # class LogStash::Outputs::Base
@@ -1,7 +1,9 @@
1
1
  require "logstash/outputs/base"
2
+ require "logstash/namespace"
2
3
  require "em-jack"
3
4
 
4
5
  class LogStash::Outputs::Beanstalk < LogStash::Outputs::Base
6
+ public
5
7
  def initialize(url, config={}, &block)
6
8
  super
7
9
 
@@ -11,6 +13,7 @@ class LogStash::Outputs::Beanstalk < LogStash::Outputs::Base
11
13
  end
12
14
  end
13
15
 
16
+ public
14
17
  def register
15
18
  tube = @url.path[1..-1] # Skip leading '/'
16
19
  port = @url.port || 11300
@@ -19,6 +22,7 @@ class LogStash::Outputs::Beanstalk < LogStash::Outputs::Base
19
22
  :tube => tube)
20
23
  end # def register
21
24
 
25
+ public
22
26
  def receive(event)
23
27
  @beanstalk.put(event.to_json, :ttr => @ttr)
24
28
  end # def receive
@@ -1,36 +1,78 @@
1
- require "logstash/outputs/base"
2
- require "logstash/outputs/amqp"
3
1
  require "em-http-request"
2
+ require "logstash/namespace"
3
+ require "logstash/outputs/amqp"
4
+ require "logstash/outputs/base"
4
5
 
5
6
  class LogStash::Outputs::Elasticsearch < LogStash::Outputs::Base
6
- def initialize(url, config={}, &block)
7
- super
8
- end
9
-
7
+ public
10
8
  def register
9
+ @pending = []
11
10
  # Port?
12
11
  # Authentication?
13
- @httpurl = @url.clone
14
- @httpurl.scheme = "http"
12
+ @esurl = @url.clone
13
+ @esurl.scheme = "http"
14
+ @esurl.path = "/" + @url.path.split("/")[1]
15
15
  defaults = {"method" => "http"}
16
16
  params = defaults.merge(@urlopts)
17
17
 
18
+ # Describe this index to elasticsearch
19
+ indexmap = {
20
+ # The name of the index
21
+ "settings" => {
22
+ @url.path.split("/")[-1] => {
23
+ "mappings" => {
24
+ "@source" => { "type" => "string" },
25
+ "@source_host" => { "type" => "string" },
26
+ "@source_path" => { "type" => "string" },
27
+ "@timestamp" => { "type" => "date" },
28
+ "@tags" => { "type" => "string" },
29
+ "@message" => { "type" => "string" },
30
+
31
+ # TODO(sissel): Hack for now until this bug is resolved:
32
+ # https://github.com/elasticsearch/elasticsearch/issues/issue/604
33
+ "@fields" => {
34
+ "type" => "object",
35
+ "properties" => {
36
+ "HOSTNAME" => { "type" => "string" },
37
+ },
38
+ }, # "@fields"
39
+ }, # "properties"
40
+ }, # index map for this index type.
41
+ }, # "settings"
42
+ } # ES Index
43
+
44
+ indexurl = @esurl.to_s
45
+ indexmap_http = EventMachine::HttpRequest.new(indexurl)
46
+ indexmap_req = indexmap_http.put :body => indexmap.to_json
47
+ indexmap_req.callback do
48
+ @logger.info(["Done configuring index", indexurl, indexmap])
49
+ ready(params)
50
+ end
51
+ indexmap_req.errback do
52
+ @logger.warn(["Failure configuring index", @esurl.to_s, indexmap])
53
+ end
54
+ end # def register
55
+
56
+ public
57
+ def ready(params)
18
58
  case params["method"]
19
59
  when "http"
20
- @logger.debug "ElasticSearch using http with URL #{@httpurl.to_s}"
21
- @http = EventMachine::HttpRequest.new(@httpurl.to_s)
60
+ @logger.debug "ElasticSearch using http with URL #{@url.to_s}"
61
+ @http = EventMachine::HttpRequest.new(@url.to_s)
22
62
  @callback = self.method(:receive_http)
23
63
  when "river"
24
- mq_url = URI::parse("amqp://#{params["host"]}/queue/#{params["queue"]}?durable=1")
64
+ params["port"] ||= 5672
65
+ mq_url = URI::parse("amqp://#{params["host"]}:#{params["port"]}/queue/#{params["queue"]}?durable=1")
25
66
  @mq = LogStash::Outputs::Amqp.new(mq_url.to_s)
26
67
  @mq.register
27
68
  @callback = self.method(:receive_river)
28
- em_url = URI.parse("http://#{@httpurl.host}:#{@httpurl.port}/_river/logstash#{@httpurl.path.tr("/", "_")}/_meta")
29
- unused, @es_index, @es_type = @httpurl.path.split("/", 3)
69
+ em_url = URI.parse("http://#{@url.host}:#{@url.port}/_river/logstash#{@url.path.tr("/", "_")}/_meta")
70
+ unused, @es_index, @es_type = @url.path.split("/", 3)
30
71
 
31
72
  river_config = {"type" => params["type"],
32
73
  params["type"] => {"host" => params["host"],
33
74
  "user" => params["user"],
75
+ "port" => params["port"],
34
76
  "pass" => params["pass"],
35
77
  "vhost" => params["vhost"],
36
78
  "queue" => params["queue"],
@@ -46,21 +88,47 @@ class LogStash::Outputs::Elasticsearch < LogStash::Outputs::Base
46
88
  req.errback do
47
89
  @logger.warn "Error setting up river: #{req.response}"
48
90
  end
91
+ @callback = self.method(:receive_river)
49
92
  else raise "unknown elasticsearch method #{params["method"].inspect}"
50
93
  end
51
- end # def register
52
94
 
95
+ receive(LogStash::Event.new({
96
+ "@source" => "@logstashinit",
97
+ "@type" => "@none",
98
+ "@message" => "Starting logstash output to elasticsearch",
99
+ "@fields" => {
100
+ "HOSTNAME" => Socket.gethostname
101
+ },
102
+ }))
103
+
104
+ pending = @pending
105
+ @pending = []
106
+ pending.each do |event|
107
+ receive(event)
108
+ end
109
+ end # def ready
110
+
111
+ public
53
112
  def receive(event)
54
- @callback.call(event)
113
+ if @callback
114
+ @callback.call(event)
115
+ else
116
+ @pending << event
117
+ end
55
118
  end # def receive
56
119
 
57
- def receive_http(event)
120
+ public
121
+ def receive_http(event, tries=5)
58
122
  req = @http.post :body => event.to_json
59
123
  req.errback do
60
- $stderr.puts "Request to index to #{@httpurl.to_s} failed. Event was #{event.to_s}"
124
+ $stderr.puts "Request to index to #{@url.to_s} failed (will retry, #{tries} tries left). Event was #{event.to_s}"
125
+ EventMachine::add_timer(2) do
126
+ receive_http(event, tries - 1)
127
+ end
61
128
  end
62
129
  end # def receive_http
63
130
 
131
+ public
64
132
  def receive_river(event)
65
133
  # bulk format; see http://www.elasticsearch.com/docs/elasticsearch/river/rabbitmq/
66
134
  index_message = {"index" => {"_index" => @es_index, "_type" => @es_type}}.to_json + "\n"
@@ -68,4 +136,4 @@ class LogStash::Outputs::Elasticsearch < LogStash::Outputs::Base
68
136
  index_message += event.to_hash.to_json + "\n"
69
137
  @mq.receive_raw(index_message)
70
138
  end # def receive_river
71
- end # class LogStash::Outputs::Websocket
139
+ end # class LogStash::Outputs::Elasticsearch
@@ -4,18 +4,17 @@
4
4
  # This class doesn't currently use 'eventmachine'-style code, so it may
5
5
  # block things. Whatever, we can fix that later ;)
6
6
 
7
- require "gelf"
7
+ require "gelf" # rubygem 'gelf'
8
+ require "logstash/namespace"
8
9
  require "logstash/outputs/base"
9
10
 
10
11
  class LogStash::Outputs::Gelf < LogStash::Outputs::Base
11
- def initialize(url, config={}, &block)
12
- super
13
- end
14
-
12
+ public
15
13
  def register
16
14
  # nothing to do
17
15
  end # def register
18
16
 
17
+ public
19
18
  def receive(event)
20
19
  # TODO(sissel): Use Gelf::Message instead
21
20
  gelf = Gelf.new(@url.host, (@url.port or 12201))
@@ -31,5 +30,5 @@ class LogStash::Outputs::Gelf < LogStash::Outputs::Base
31
30
  end
32
31
  gelf.add_additional "event_timestamp", event.timestamp
33
32
  gelf.send
34
- end # def event
33
+ end # def receive
35
34
  end # class LogStash::Outputs::Gelf
@@ -1,15 +1,19 @@
1
+ require "logstash/namespace"
1
2
  require "logstash/outputs/base"
2
3
 
3
4
  class LogStash::Outputs::Internal < LogStash::Outputs::Base
5
+ public
4
6
  def initialize(url, config={}, &block)
5
7
  super
6
8
  @callback = block
7
- end
9
+ end # def initialize
8
10
 
11
+ public
9
12
  def register
10
13
  @logger.info("Registering output #{@url}")
11
14
  end # def register
12
15
 
16
+ public
13
17
  def receive(event)
14
18
  if !@callback
15
19
  @logger.error("No callback for output #{@url}, cannot receive")
@@ -19,11 +23,13 @@ class LogStash::Outputs::Internal < LogStash::Outputs::Base
19
23
  end # def event
20
24
 
21
25
  # Set the callback by passing a block of code
26
+ public
22
27
  def callback(&block)
23
28
  @callback = block
24
29
  end
25
30
 
26
31
  # Set the callback by passing a proc object
32
+ public
27
33
  def callback=(proc_block)
28
34
  @callback = proc_block
29
35
  end
@@ -1,19 +1,19 @@
1
1
  require "logstash/outputs/base"
2
+ require "logstash/namespace"
2
3
  require "em-mongo"
3
4
 
4
5
  class LogStash::Outputs::Mongodb < LogStash::Outputs::Base
5
- def initialize(url, config={}, &block)
6
- super
7
- end
8
-
6
+ public
9
7
  def register
10
- # Port?
11
- # Authentication?
12
- db = @url.path[1..-1] # Skip leading '/'
13
- @mongodb = EventMachine::Mongo::Connection.new(@url.host).db(db)
8
+ # TODO(sissel): Port?
9
+ # TODO(sissel): Authentication?
10
+ # db and collection are mongodb://.../db/collection
11
+ unused, @db, @collection = @url.path.split("/", 3)
12
+ @mongodb = EventMachine::Mongo::Connection.new(@url.host).db(@db)
14
13
  end # def register
15
14
 
15
+ public
16
16
  def receive(event)
17
- @mongodb.collection("events").insert(event.to_hash)
18
- end # def event
17
+ @mongodb.collection(@collection).insert(event.to_hash)
18
+ end # def receive
19
19
  end # class LogStash::Outputs::Mongodb
@@ -1,9 +1,11 @@
1
+ require "logstash/namespace"
1
2
  require "logstash/outputs/base"
2
3
 
3
4
  class LogStash::Outputs::Nagios < LogStash::Outputs::Base
4
5
  NAGIOS_CRITICAL = 2
5
6
  NAGIOS_WARN = 1
6
7
 
8
+ public
7
9
  def initialize(url, config={}, &block)
8
10
  super
9
11
 
@@ -12,12 +14,14 @@ class LogStash::Outputs::Nagios < LogStash::Outputs::Base
12
14
  else
13
15
  @cmdfile = @url.path
14
16
  end
15
- end
17
+ end # def initialize
16
18
 
19
+ public
17
20
  def register
18
21
  # nothing to do
19
22
  end # def register
20
23
 
24
+ public
21
25
  def receive(event)
22
26
  if !File.exists?(@cmdfile)
23
27
  @logger.warn(["Skipping nagios output; command file is missing",
@@ -68,5 +72,5 @@ class LogStash::Outputs::Nagios < LogStash::Outputs::Base
68
72
  {"error" => $!, "cmdfile" => @cmdfile,
69
73
  "missed_event" => event}])
70
74
  end
71
- end # def event
75
+ end # def receive
72
76
  end # class LogStash::Outputs::Nagios
@@ -1,14 +1,13 @@
1
1
  require "logstash/outputs/base"
2
+ require "logstash/namespace"
2
3
 
3
4
  class LogStash::Outputs::Stdout < LogStash::Outputs::Base
4
- def initialize(url, config={}, &block)
5
- super
6
- end
7
-
5
+ public
8
6
  def register
9
7
  # nothing to do
10
8
  end # def register
11
9
 
10
+ public
12
11
  def receive(event)
13
12
  puts event
14
13
  end # def event