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.
- data/bin/logstash +13 -2
- data/bin/logstash-test +1 -3
- data/lib/logstash.rb +1 -1
- data/lib/logstash/agent.rb +37 -40
- data/lib/logstash/event.rb +20 -5
- data/lib/logstash/filters.rb +1 -1
- data/lib/logstash/filters/base.rb +6 -1
- data/lib/logstash/filters/date.rb +4 -0
- data/lib/logstash/filters/field.rb +4 -5
- data/lib/logstash/filters/grep.rb +39 -3
- data/lib/logstash/filters/grok.rb +10 -3
- data/lib/logstash/filters/grokdiscovery.rb +4 -1
- data/lib/logstash/filters/multiline.rb +6 -2
- data/lib/logstash/inputs.rb +6 -2
- data/lib/logstash/inputs/amqp.rb +5 -2
- data/lib/logstash/inputs/base.rb +17 -4
- data/lib/logstash/inputs/beanstalk.rb +5 -2
- data/lib/logstash/inputs/file.rb +7 -2
- data/lib/logstash/inputs/internal.rb +5 -2
- data/lib/logstash/inputs/stdin.rb +38 -0
- data/lib/logstash/inputs/stomp.rb +14 -12
- data/lib/logstash/inputs/syslog.rb +10 -5
- data/lib/logstash/inputs/tcp.rb +8 -3
- data/lib/logstash/inputs/twitter.rb +81 -0
- data/lib/logstash/logging.rb +4 -1
- data/lib/logstash/namespace.rb +0 -1
- data/lib/logstash/outputs.rb +1 -1
- data/lib/logstash/outputs/amqp.rb +9 -2
- data/lib/logstash/outputs/base.rb +7 -3
- data/lib/logstash/outputs/beanstalk.rb +4 -0
- data/lib/logstash/outputs/elasticsearch.rb +86 -18
- data/lib/logstash/outputs/gelf.rb +5 -6
- data/lib/logstash/outputs/internal.rb +7 -1
- data/lib/logstash/outputs/mongodb.rb +10 -10
- data/lib/logstash/outputs/nagios.rb +6 -2
- data/lib/logstash/outputs/stdout.rb +3 -4
- data/lib/logstash/outputs/stomp.rb +4 -0
- data/lib/logstash/outputs/tcp.rb +3 -4
- data/lib/logstash/outputs/websocket.rb +5 -6
- data/lib/logstash/ruby_fixes.rb +1 -3
- data/lib/logstash/stomp/handler.rb +29 -4
- data/lib/logstash/web/lib/elasticsearch.rb +8 -4
- data/lib/logstash/web/public/js/logstash.js +25 -5
- data/lib/logstash/web/public/ws/index.html +9 -7
- data/lib/logstash/web/server.rb +50 -12
- data/lib/logstash/web/views/search/ajax.haml +5 -2
- data/lib/logstash/web/views/search/results.txt.erb +10 -0
- metadata +7 -4
@@ -1,20 +1,24 @@
|
|
1
1
|
require "logstash/outputs/base"
|
2
|
+
require "logstash/namespace"
|
2
3
|
require "logstash/stomp/handler"
|
3
4
|
|
4
5
|
class LogStash::Outputs::Stomp < LogStash::Outputs::Base
|
5
6
|
attr_reader :url
|
6
7
|
|
8
|
+
public
|
7
9
|
def initialize(url, config={}, &block)
|
8
10
|
super
|
9
11
|
|
10
12
|
@logger.debug(["Initialize", { :url => @url }])
|
11
13
|
end # def initialize
|
12
14
|
|
15
|
+
public
|
13
16
|
def register
|
14
17
|
@logger.info(["Registering output", { :url => @url }])
|
15
18
|
@connection = EventMachine::connect(@url.host, @url.port, LogStash::Stomp::Handler, self, @logger, @url)
|
16
19
|
end # def register
|
17
20
|
|
21
|
+
public
|
18
22
|
def receive(event)
|
19
23
|
@logger.debug(["Sending event", { :url => @url, :event => event }])
|
20
24
|
@connection.send(@url.path, event.to_json)
|
data/lib/logstash/outputs/tcp.rb
CHANGED
@@ -1,10 +1,8 @@
|
|
1
1
|
require "logstash/outputs/base"
|
2
|
+
require "logstash/namespace"
|
2
3
|
|
3
4
|
class LogStash::Outputs::Tcp < LogStash::Outputs::Base
|
4
|
-
|
5
|
-
super
|
6
|
-
end
|
7
|
-
|
5
|
+
public
|
8
6
|
def register
|
9
7
|
# TODO(sissel): Write generic validation methods
|
10
8
|
if !@url.host or !@url.port
|
@@ -16,6 +14,7 @@ class LogStash::Outputs::Tcp < LogStash::Outputs::Base
|
|
16
14
|
@connection = EventMachine::connect(@url.host, @url.port)
|
17
15
|
end # def register
|
18
16
|
|
17
|
+
public
|
19
18
|
def receive(event)
|
20
19
|
@connection.send_data(event.to_hash.to_json)
|
21
20
|
@connection.send_data("\n")
|
@@ -1,11 +1,9 @@
|
|
1
|
-
require "logstash/outputs/base"
|
2
1
|
require "em-websocket" # rubygem 'em-websocket'
|
2
|
+
require "logstash/namespace"
|
3
|
+
require "logstash/outputs/base"
|
3
4
|
|
4
5
|
class LogStash::Outputs::Websocket < LogStash::Outputs::Base
|
5
|
-
|
6
|
-
super
|
7
|
-
end
|
8
|
-
|
6
|
+
public
|
9
7
|
def register
|
10
8
|
@channel = EventMachine::Channel.new
|
11
9
|
@subscribers = 0
|
@@ -27,6 +25,7 @@ class LogStash::Outputs::Websocket < LogStash::Outputs::Base
|
|
27
25
|
end
|
28
26
|
end # def register
|
29
27
|
|
28
|
+
public
|
30
29
|
def receive(event)
|
31
30
|
# Only publish the event to websockets if there are subscribers
|
32
31
|
# TODO(sissel): send a patch to eventmachine to fix this.
|
@@ -34,5 +33,5 @@ class LogStash::Outputs::Websocket < LogStash::Outputs::Base
|
|
34
33
|
@logger.info("Sending event to websocket.")
|
35
34
|
@channel.push event.to_json
|
36
35
|
end
|
37
|
-
end # def
|
36
|
+
end # def receive
|
38
37
|
end # class LogStash::Outputs::Websocket
|
data/lib/logstash/ruby_fixes.rb
CHANGED
@@ -1,12 +1,10 @@
|
|
1
|
-
|
2
|
-
|
3
1
|
# Ruby 1.8.7 added String#start_with? - monkeypatch the
|
4
2
|
# String class if it isn't supported (<= ruby 1.8.6)
|
5
3
|
if !String.instance_methods.include?("start_with?")
|
6
4
|
class String
|
5
|
+
public
|
7
6
|
def start_with?(str)
|
8
7
|
return self[0 .. (str.length-1)] == str
|
9
8
|
end
|
10
9
|
end
|
11
10
|
end
|
12
|
-
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require "logstash/namespace"
|
2
|
+
|
1
3
|
# Base of Stomp Handler
|
2
4
|
# it handles connecting and subscribing to the stomp broker which
|
3
5
|
# is used in both stomp input and output
|
@@ -5,29 +7,52 @@ class LogStash::Stomp
|
|
5
7
|
class Handler < EventMachine::Connection
|
6
8
|
include EM::Protocols::Stomp
|
7
9
|
|
10
|
+
attr_accessor :should_subscribe
|
11
|
+
attr_accessor :ready
|
12
|
+
|
13
|
+
public
|
8
14
|
def initialize(*args)
|
9
15
|
super
|
10
16
|
|
11
17
|
@input = args[0]
|
12
18
|
@logger = args[1]
|
13
19
|
@url = args[2]
|
20
|
+
@should_subscribe = true
|
21
|
+
@ready = false
|
14
22
|
end # def initialize
|
15
23
|
|
24
|
+
public
|
16
25
|
def connection_completed
|
17
26
|
@logger.debug("Connected")
|
18
27
|
connect :login => @url.user, :passcode => @url.password
|
28
|
+
@ready = true
|
19
29
|
end # def connection_completed
|
20
30
|
|
31
|
+
public
|
21
32
|
def unbind
|
22
|
-
|
33
|
+
if $EVENTMACHINE_STOPPING
|
34
|
+
@logger.debug(["Connection to stomp broker died (probably since we are exiting)",
|
35
|
+
{ :url => @url }])
|
36
|
+
return
|
37
|
+
end
|
38
|
+
|
39
|
+
@logger.error(["Connection to stomp broker died, retrying.", { :url => @url }])
|
40
|
+
@ready = false
|
41
|
+
EventMachine::Timer.new(1) do
|
42
|
+
reconnect(@url.host, @url.port)
|
43
|
+
end
|
23
44
|
end # def unbind
|
24
45
|
|
46
|
+
public
|
25
47
|
def receive_msg(message)
|
26
48
|
@logger.debug(["receiving message", { :msg => message }])
|
27
49
|
if message.command == "CONNECTED"
|
28
|
-
|
29
|
-
|
30
|
-
|
50
|
+
if @should_subscribe
|
51
|
+
@logger.debug(["subscribing to", { :path => @url.path }])
|
52
|
+
subscribe @url.path
|
53
|
+
return
|
54
|
+
end
|
55
|
+
@ready = true
|
31
56
|
end
|
32
57
|
end # def receive_msg
|
33
58
|
end # class Handler
|
@@ -5,11 +5,14 @@ require "logstash/logging"
|
|
5
5
|
require "logstash/event"
|
6
6
|
|
7
7
|
module LogStash::Web; end
|
8
|
+
|
8
9
|
class LogStash::Web::ElasticSearch
|
10
|
+
public
|
9
11
|
def initialize
|
10
12
|
@logger = LogStash::Logger.new(STDOUT)
|
11
13
|
end
|
12
14
|
|
15
|
+
public
|
13
16
|
def search(params)
|
14
17
|
http = EventMachine::HttpRequest.new("http://localhost:9200/_search")
|
15
18
|
params[:offset] ||= 0
|
@@ -37,7 +40,8 @@ class LogStash::Web::ElasticSearch
|
|
37
40
|
"from" => params[:offset],
|
38
41
|
"size" => params[:count],
|
39
42
|
}
|
40
|
-
|
43
|
+
|
44
|
+
@logger.info("ElasticSearch Query: #{esreq.to_json}")
|
41
45
|
start_time = Time.now
|
42
46
|
req = http.get :body => esreq.to_json
|
43
47
|
req.callback do
|
@@ -69,13 +73,13 @@ class LogStash::Web::ElasticSearch
|
|
69
73
|
{ :query => params[:q], :duration => data["duration"]}])
|
70
74
|
#@logger.info(data)
|
71
75
|
if req.response_header.status != 200
|
72
|
-
@error = data["error"]
|
76
|
+
@error = data["error"] || req.inspect
|
73
77
|
end
|
74
78
|
yield data
|
75
79
|
end
|
76
80
|
req.errback do
|
77
|
-
@logger.warn(["Query failed", params, req.response])
|
81
|
+
@logger.warn(["Query failed", params, req, req.response])
|
78
82
|
yield({ "error" => req.response })
|
79
83
|
end
|
80
84
|
end # def search
|
81
|
-
end
|
85
|
+
end # class LogStash::Web::ElasticSearch
|
@@ -7,12 +7,28 @@
|
|
7
7
|
},
|
8
8
|
|
9
9
|
search: function(query) {
|
10
|
+
if (query == undefined || query == "") {
|
11
|
+
return;
|
12
|
+
}
|
13
|
+
var display_query = query.replace("<", "<").replace(">", ">")
|
14
|
+
$("#querystatus").html("Loading query '" + display_query + "'")
|
10
15
|
logstash.params.q = query;
|
11
16
|
document.location.hash = escape(JSON.stringify(logstash.params));
|
12
17
|
$("#results").load("/search/ajax", logstash.params);
|
13
18
|
$("#query").val(logstash.params.q);
|
14
19
|
}, /* search */
|
15
20
|
|
21
|
+
parse_params: function(href) {
|
22
|
+
var params = href.replace(/^[^?]*\?/, "").split("&")
|
23
|
+
for (var p in params) {
|
24
|
+
var a = params[p].split("=");
|
25
|
+
var key = a[0]
|
26
|
+
var value = a[1]
|
27
|
+
logstash.params[key] = unescape(value)
|
28
|
+
}
|
29
|
+
return params;
|
30
|
+
},
|
31
|
+
|
16
32
|
appendquery: function(query) {
|
17
33
|
var newquery = $("#query").val();
|
18
34
|
newquery += " " + query;
|
@@ -70,6 +86,13 @@
|
|
70
86
|
// Do nothing
|
71
87
|
}
|
72
88
|
logstash.search(logstash.params.q);
|
89
|
+
} else {
|
90
|
+
/* No hash. See if there's a query param. */
|
91
|
+
var params = logstash.parse_params(location.href);
|
92
|
+
for (var p in params) {
|
93
|
+
logstash.params[p] = params[p];
|
94
|
+
}
|
95
|
+
logstash.search(logstash.params.q)
|
73
96
|
}
|
74
97
|
|
75
98
|
$(window).hashchange(function() {
|
@@ -83,12 +106,9 @@
|
|
83
106
|
|
84
107
|
$("a.pager").live("click", function() {
|
85
108
|
var href = $(this).attr("href");
|
86
|
-
var params =
|
109
|
+
var params = logstash.parse_params(location.href);
|
87
110
|
for (var p in params) {
|
88
|
-
|
89
|
-
var key = a[0]
|
90
|
-
var value = a[1]
|
91
|
-
logstash.params[key] = unescape(value)
|
111
|
+
logstash.params[p] = params[p];
|
92
112
|
}
|
93
113
|
logstash.search(logstash.params.q)
|
94
114
|
return false;
|
@@ -57,16 +57,18 @@
|
|
57
57
|
//console.log(["WebSocket open", ws])
|
58
58
|
};
|
59
59
|
ws.onmessage = function(event) {
|
60
|
-
|
60
|
+
var data = JSON.parse(event.data);
|
61
61
|
var el = $("#message-template").tmpl(data, { "message": data["@message"], "timestamp": data["@timestamp"] });
|
62
|
+
//.css("display", "none")
|
63
|
+
//.fadeIn()
|
62
64
|
el.addClass("message")
|
63
|
-
.css("display", "none")
|
64
65
|
.appendTo($("#radiator"))
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
66
|
+
//.delay(10000)
|
67
|
+
//.hide(2000, function() {
|
68
|
+
//$(this).remove();
|
69
|
+
//});
|
70
|
+
setTimeout(function() { $(el).remove() }, 12000)
|
71
|
+
//.fadeOut(2000, function() {
|
70
72
|
};
|
71
73
|
});
|
72
74
|
</script>
|
data/lib/logstash/web/server.rb
CHANGED
@@ -4,13 +4,13 @@
|
|
4
4
|
$:.unshift("%s/../lib" % File.dirname(__FILE__))
|
5
5
|
$:.unshift(File.dirname(__FILE__))
|
6
6
|
|
7
|
-
require "rubygems"
|
8
|
-
require "json"
|
9
7
|
require "eventmachine"
|
10
|
-
require "
|
11
|
-
require "sinatra/async"
|
8
|
+
require "json"
|
12
9
|
require "lib/elasticsearch"
|
13
10
|
require "logstash/namespace"
|
11
|
+
require "rack"
|
12
|
+
require "rubygems"
|
13
|
+
require "sinatra/async"
|
14
14
|
|
15
15
|
class EventMachine::ConnectionError < RuntimeError; end
|
16
16
|
|
@@ -25,24 +25,58 @@ class LogStash::Web::Server < Sinatra::Base
|
|
25
25
|
aget '/style.css' do
|
26
26
|
headers "Content-Type" => "text/css; charset=utf8"
|
27
27
|
body sass :style
|
28
|
-
end
|
28
|
+
end # /style.css
|
29
29
|
|
30
30
|
aget '/' do
|
31
31
|
redirect "/search"
|
32
32
|
end # '/'
|
33
33
|
|
34
34
|
aget '/search' do
|
35
|
-
|
35
|
+
result_callback = proc do
|
36
|
+
status 500 if @error
|
37
|
+
|
38
|
+
params[:format] ||= "html"
|
39
|
+
case params[:format]
|
40
|
+
when "html"
|
41
|
+
headers({"Content-Type" => "text/html" })
|
42
|
+
body haml :"search/results", :layout => !request.xhr?
|
43
|
+
when "text"
|
44
|
+
headers({"Content-Type" => "text/plain" })
|
45
|
+
body erb :"search/results.txt", :layout => false
|
46
|
+
when "txt"
|
47
|
+
headers({"Content-Type" => "text/plain" })
|
48
|
+
body erb :"search/results.txt", :layout => false
|
49
|
+
when "json"
|
50
|
+
headers({"Content-Type" => "text/plain" })
|
51
|
+
hits = @hits.collect { |h| h["_source"] }
|
52
|
+
response = {
|
53
|
+
"hits" => hits,
|
54
|
+
"facets" => (@results["facets"] rescue nil),
|
55
|
+
}
|
56
|
+
|
57
|
+
response["error"] = @error if @error
|
58
|
+
body response.to_json
|
59
|
+
end # case params[:format]
|
60
|
+
end # proc result_callback
|
61
|
+
|
62
|
+
# We'll still do a search query here even though most users
|
63
|
+
# have javascript enabled, we need to show the results in
|
64
|
+
# case a user doesn't have javascript.
|
36
65
|
if params[:q] and params[:q] != ""
|
37
66
|
elasticsearch.search(params) do |@results|
|
38
67
|
@hits = (@results["hits"]["hits"] rescue [])
|
39
|
-
|
40
|
-
|
68
|
+
begin
|
69
|
+
result_callback.call
|
70
|
+
rescue => e
|
71
|
+
puts e
|
72
|
+
end
|
73
|
+
end # elasticsearch.search
|
41
74
|
else
|
75
|
+
#@error = "No query given."
|
42
76
|
@hits = []
|
43
|
-
|
77
|
+
result_callback.call
|
44
78
|
end
|
45
|
-
end
|
79
|
+
end # aget '/search'
|
46
80
|
|
47
81
|
apost '/search/ajax' do
|
48
82
|
headers({"Content-Type" => "text/html" })
|
@@ -99,10 +133,9 @@ class LogStash::Web::Server < Sinatra::Base
|
|
99
133
|
body haml :"search/ajax", :layout => !request.xhr?
|
100
134
|
end # elasticsearch.search
|
101
135
|
end # apost '/search/ajax'
|
102
|
-
end # class
|
136
|
+
end # class LogStash::Web::Server
|
103
137
|
|
104
138
|
require "optparse"
|
105
|
-
|
106
139
|
Settings = Struct.new(:daemonize, :logfile)
|
107
140
|
settings = Settings.new
|
108
141
|
progname = File.basename($0)
|
@@ -133,6 +166,11 @@ if settings.logfile
|
|
133
166
|
logfile = File.open(settings.logfile, "w")
|
134
167
|
STDOUT.reopen(logfile)
|
135
168
|
STDERR.reopen(logfile)
|
169
|
+
elsif settings.daemonize
|
170
|
+
# Write to /dev/null if
|
171
|
+
devnull = File.open("/dev/null", "w")
|
172
|
+
STDOUT.reopen(devnull)
|
173
|
+
STDERR.reopen(devnull)
|
136
174
|
end
|
137
175
|
|
138
176
|
Rack::Handler::Thin.run(
|
@@ -31,9 +31,12 @@
|
|
31
31
|
last
|
32
32
|
- if @hits.length == 0
|
33
33
|
- if !params[:q]
|
34
|
-
|
34
|
+
/ We default to a '+2 days' in the future to capture 'today at 00:00'
|
35
|
+
/ plus tomorrow, inclusive, in case you are 23 hours behind the international
|
36
|
+
/ dateline.
|
37
|
+
%h3#querystatus No query given. How about <a href="?q=* @timestamp:[#{(Time.now - 7*24*60*60).strftime("%Y-%m-%d")} TO #{(Time.now + 2*24*60*60).strftime("%Y-%m-%d")}]" class="querychanger">this?</a>
|
35
38
|
- else
|
36
|
-
No results for query '#{params[:q]}'
|
39
|
+
%h3#querystatus No results for query '#{params[:q]}'
|
37
40
|
- else
|
38
41
|
%table.results
|
39
42
|
%tr
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<%
|
2
|
+
# Sinatra currently doesn't do ERB with newline trimming, so we
|
3
|
+
# have to write this funky mishmosh that is hard to read.
|
4
|
+
if @error %>Error: <%= @error %><% else
|
5
|
+
@hits.each do |hit|
|
6
|
+
event = LogStash::Event.new(hit["_source"])
|
7
|
+
%><%= event.message || event.to_hash.to_json %>
|
8
|
+
<% end
|
9
|
+
end
|
10
|
+
%>
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstash-lite
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 40220224230017
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
version: 0.2.
|
9
|
+
- 20110112115019
|
10
|
+
version: 0.2.20110112115019
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Jordan Sissel
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date:
|
19
|
+
date: 2011-01-12 00:00:00 -08:00
|
20
20
|
default_executable:
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|
@@ -95,8 +95,10 @@ files:
|
|
95
95
|
- lib/logstash/inputs/internal.rb
|
96
96
|
- lib/logstash/inputs/syslog.rb
|
97
97
|
- lib/logstash/inputs/file.rb
|
98
|
+
- lib/logstash/inputs/stdin.rb
|
98
99
|
- lib/logstash/inputs/base.rb
|
99
100
|
- lib/logstash/inputs/amqp.rb
|
101
|
+
- lib/logstash/inputs/twitter.rb
|
100
102
|
- lib/logstash/inputs/stomp.rb
|
101
103
|
- lib/logstash/inputs/beanstalk.rb
|
102
104
|
- lib/logstash/inputs/tcp.rb
|
@@ -209,6 +211,7 @@ files:
|
|
209
211
|
- lib/logstash/web/views/style.sass
|
210
212
|
- lib/logstash/web/views/main/index.haml
|
211
213
|
- lib/logstash/web/views/layout.haml
|
214
|
+
- lib/logstash/web/views/search/results.txt.erb
|
212
215
|
- lib/logstash/web/views/search/ajax.haml
|
213
216
|
- lib/logstash/web/views/search/results.haml
|
214
217
|
- lib/logstash/web/views/search/error.haml
|