logstash-lite 0.2.20101120024757 → 0.2.20101123133737
Sign up to get free protection for your applications and to get access to all the features.
- data/examples/sample-agent-in-ruby.rb +56 -0
- data/lib/logstash/agent.rb +13 -2
- data/lib/logstash/inputs.rb +1 -0
- data/lib/logstash/inputs/amqp.rb +1 -1
- data/lib/logstash/inputs/internal.rb +36 -0
- data/lib/logstash/logging.rb +12 -5
- data/lib/logstash/outputs/amqp.rb +1 -0
- data/lib/logstash/outputs/gelf.rb +1 -0
- data/lib/logstash/outputs/internal.rb +30 -0
- data/lib/logstash/outputs/tcp.rb +23 -0
- data/lib/logstash/ruby_fixes.rb +12 -0
- data/lib/logstash/time.rb +3 -2
- data/lib/logstash/web/lib/elasticsearch.rb +1 -1
- data/lib/logstash/web/public/ws/index.html +73 -0
- data/lib/logstash/web/server.rb +21 -2
- data/lib/logstash/web/views/search/ajax.haml +7 -0
- data/lib/logstash/web/views/search/error.haml +3 -0
- data/lib/logstash/web/views/style.sass +2 -0
- metadata +11 -4
@@ -0,0 +1,56 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$: << "lib"
|
3
|
+
|
4
|
+
require "rubygems"
|
5
|
+
require "logstash/agent"
|
6
|
+
require "yaml"
|
7
|
+
|
8
|
+
collector_config = YAML.load <<"YAML"
|
9
|
+
---
|
10
|
+
inputs:
|
11
|
+
foo:
|
12
|
+
- internal:///
|
13
|
+
outputs:
|
14
|
+
- amqp://localhost/topic/logstash/testing
|
15
|
+
YAML
|
16
|
+
|
17
|
+
receiver_config = YAML.load <<"YAML"
|
18
|
+
---
|
19
|
+
inputs:
|
20
|
+
foo:
|
21
|
+
- amqp://localhost/topic/logstash/testing
|
22
|
+
outputs:
|
23
|
+
- internal:///
|
24
|
+
YAML
|
25
|
+
|
26
|
+
collector_agent = LogStash::Agent.new(collector_config)
|
27
|
+
receiver_agent = LogStash::Agent.new(receiver_config)
|
28
|
+
|
29
|
+
data = ["hello world", "foo", "bar"]
|
30
|
+
|
31
|
+
EventMachine::run do
|
32
|
+
receiver_agent.register
|
33
|
+
collector_agent.register
|
34
|
+
|
35
|
+
EM::next_tick do
|
36
|
+
# Register output callback on the receiver
|
37
|
+
receiver_agent.outputs\
|
38
|
+
.find { |o| o.is_a?(LogStash::Outputs::Internal) }\
|
39
|
+
.callback do |event|
|
40
|
+
puts event
|
41
|
+
#puts expect.first == event.message
|
42
|
+
#expect.shift
|
43
|
+
#agent.stop
|
44
|
+
end
|
45
|
+
|
46
|
+
EM::next_tick do
|
47
|
+
# Send input to the collector
|
48
|
+
expect = data.clone
|
49
|
+
input = collector_agent.inputs\
|
50
|
+
.find { |i| i.is_a?(LogStash::Inputs::Internal) }
|
51
|
+
channel = input.channel
|
52
|
+
data.each { |message| channel.push(message) }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
data/lib/logstash/agent.rb
CHANGED
@@ -9,6 +9,9 @@ require "logstash/logging"
|
|
9
9
|
# Collect logs, ship them out.
|
10
10
|
class LogStash::Agent
|
11
11
|
attr_reader :config
|
12
|
+
attr_reader :inputs
|
13
|
+
attr_reader :outputs
|
14
|
+
attr_reader :filters
|
12
15
|
|
13
16
|
def initialize(config)
|
14
17
|
@logger = LogStash::Logger.new(STDERR)
|
@@ -26,7 +29,7 @@ class LogStash::Agent
|
|
26
29
|
# Register any event handlers with EventMachine
|
27
30
|
# Technically, this agent could listen for anything (files, sockets, amqp,
|
28
31
|
# stomp, etc).
|
29
|
-
|
32
|
+
public
|
30
33
|
def register
|
31
34
|
# TODO(sissel): warn when no inputs and no outputs are defined.
|
32
35
|
# TODO(sissel): Refactor this madness into a config lib
|
@@ -80,12 +83,20 @@ class LogStash::Agent
|
|
80
83
|
end # def register
|
81
84
|
|
82
85
|
public
|
83
|
-
def run
|
86
|
+
def run(&block)
|
84
87
|
EventMachine.run do
|
85
88
|
self.register
|
89
|
+
yield if block_given?
|
86
90
|
end # EventMachine.run
|
87
91
|
end # def run
|
88
92
|
|
93
|
+
public
|
94
|
+
def stop
|
95
|
+
# TODO(sissel): Stop inputs, fluch outputs, wait for finish,
|
96
|
+
# then stop the event loop
|
97
|
+
EventMachine.stop_event_loop
|
98
|
+
end
|
99
|
+
|
89
100
|
protected
|
90
101
|
def filter(event)
|
91
102
|
@filters.each do |f|
|
data/lib/logstash/inputs.rb
CHANGED
data/lib/logstash/inputs/amqp.rb
CHANGED
@@ -0,0 +1,36 @@
|
|
1
|
+
|
2
|
+
require "logstash/inputs/base"
|
3
|
+
require "eventmachine-tail"
|
4
|
+
require "socket" # for Socket.gethostname
|
5
|
+
|
6
|
+
class LogStash::Inputs::Internal < LogStash::Inputs::Base
|
7
|
+
attr_reader :channel
|
8
|
+
|
9
|
+
def initialize(url, type, config={}, &block)
|
10
|
+
super
|
11
|
+
|
12
|
+
# Default host to the machine's hostname if it's not set
|
13
|
+
@url.host ||= Socket.gethostname
|
14
|
+
@channel = EventMachine::Channel.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def register
|
18
|
+
@logger.info("Registering input #{@url}")
|
19
|
+
@channel.subscribe do |event|
|
20
|
+
receive(event)
|
21
|
+
end
|
22
|
+
end # def register
|
23
|
+
|
24
|
+
def receive(event)
|
25
|
+
if !event.is_a?(LogStash::Event)
|
26
|
+
event = LogStash::Event.new({
|
27
|
+
"@message" => event,
|
28
|
+
"@type" => @type,
|
29
|
+
"@tags" => @tags.clone,
|
30
|
+
"@source" => @url,
|
31
|
+
})
|
32
|
+
end
|
33
|
+
@logger.debug(["Got event", event])
|
34
|
+
@callback.call(event)
|
35
|
+
end # def receive
|
36
|
+
end # class LogStash::Inputs::Internal
|
data/lib/logstash/logging.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require "logstash/namespace"
|
2
|
+
require "logstash/ruby_fixes"
|
2
3
|
require "logger"
|
3
4
|
|
4
5
|
class LogStash::Logger < Logger
|
@@ -18,16 +19,22 @@ class LogStash::Logger < Logger
|
|
18
19
|
|
19
20
|
# Set default loglevel to WARN unless $DEBUG is set (run with 'ruby -d')
|
20
21
|
self.level = $DEBUG ? Logger::DEBUG: Logger::INFO
|
22
|
+
if ENV["LOGSTASH_DEBUG"]
|
23
|
+
self.level = Logger::DEBUG
|
24
|
+
end
|
25
|
+
|
26
|
+
@formatter.progname = self.progname = File.basename($0)
|
21
27
|
|
22
28
|
# Conditional support for awesome_print
|
23
29
|
if !@@have_awesome_print && @@notify_awesome_print_load_failed
|
24
|
-
|
25
|
-
|
26
|
-
|
30
|
+
debug [ "awesome_print not found, falling back to Object#inspect." \
|
31
|
+
"If you want prettier log output, run 'gem install "\
|
32
|
+
"awesome_print'",
|
33
|
+
{ :exception @@notify_awesome_print_load_failed }]
|
34
|
+
|
35
|
+
# Only show this once.
|
27
36
|
@@notify_awesome_print_load_failed = nil
|
28
37
|
end
|
29
|
-
|
30
|
-
@formatter.progname = self.progname = File.basename($0)
|
31
38
|
end # def initialize
|
32
39
|
|
33
40
|
def level=(level)
|
@@ -26,6 +26,7 @@ class LogStash::Outputs::Gelf < LogStash::Outputs::Base
|
|
26
26
|
gelf.file = event["@source_path"]
|
27
27
|
|
28
28
|
event.fields.each do |name, value|
|
29
|
+
next if value == nil or value.empty?
|
29
30
|
gelf.add_additional name, value
|
30
31
|
end
|
31
32
|
gelf.add_additional "event_timestamp", event.timestamp
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "logstash/outputs/base"
|
2
|
+
|
3
|
+
class LogStash::Outputs::Internal < LogStash::Outputs::Base
|
4
|
+
def initialize(url, config={}, &block)
|
5
|
+
super
|
6
|
+
@callback = block
|
7
|
+
end
|
8
|
+
|
9
|
+
def register
|
10
|
+
@logger.info("Registering output #{@url}")
|
11
|
+
end # def register
|
12
|
+
|
13
|
+
def receive(event)
|
14
|
+
if !@callback
|
15
|
+
@logger.error("No callback for output #{@url}, cannot receive")
|
16
|
+
return
|
17
|
+
end
|
18
|
+
@callback.call(event)
|
19
|
+
end # def event
|
20
|
+
|
21
|
+
# Set the callback by passing a block of code
|
22
|
+
def callback(&block)
|
23
|
+
@callback = block
|
24
|
+
end
|
25
|
+
|
26
|
+
# Set the callback by passing a proc object
|
27
|
+
def callback=(proc_block)
|
28
|
+
@callback = proc_block
|
29
|
+
end
|
30
|
+
end # class LogStash::Outputs::Internal
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "logstash/outputs/base"
|
2
|
+
|
3
|
+
class LogStash::Outputs::Tcp < LogStash::Outputs::Base
|
4
|
+
def initialize(url, config={}, &block)
|
5
|
+
super
|
6
|
+
end
|
7
|
+
|
8
|
+
def register
|
9
|
+
# TODO(sissel): Write generic validation methods
|
10
|
+
if !@url.host or !@url.port
|
11
|
+
@logger.fatal("No host or port given in #{self.class}: #{@url}")
|
12
|
+
# TODO(sissel): Make this an actual exception class
|
13
|
+
raise "configuration error"
|
14
|
+
end
|
15
|
+
|
16
|
+
@connection = EventMachine::connect(@url.host, @url.port)
|
17
|
+
end # def register
|
18
|
+
|
19
|
+
def receive(event)
|
20
|
+
@connection.send_data(event.to_hash.to_json)
|
21
|
+
@connection.send_data("\n")
|
22
|
+
end # def receive
|
23
|
+
end # class LogStash::Outputs::Tcp
|
@@ -0,0 +1,12 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
# Ruby 1.8.7 added String#start_with? - monkeypatch the
|
4
|
+
# String class if it isn't supported (<= ruby 1.8.6)
|
5
|
+
if !String.instance_methods.include?("start_with?")
|
6
|
+
class String
|
7
|
+
def start_with?(str)
|
8
|
+
return self[0 .. (str.length-1)] == str
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
data/lib/logstash/time.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require "logstash/namespace"
|
1
2
|
|
2
3
|
# Provide our own Time wrapper for ISO8601 support
|
3
4
|
# Example:
|
@@ -6,7 +7,7 @@
|
|
6
7
|
#
|
7
8
|
# >> LogStash::Time.now.utc.to_iso8601
|
8
9
|
# => "2010-10-17 07:25:26.788704Z"
|
9
|
-
|
10
|
+
class LogStash::Time < ::Time
|
10
11
|
ISO8601 = "%Y-%m-%dT%H:%M:%S"
|
11
12
|
|
12
13
|
# Return a string that is this time in ISO8601 format.
|
@@ -24,4 +25,4 @@ module LogStash; class Time < ::Time
|
|
24
25
|
raise "Can't convert object of type #{obj.class} (#{obj}) to iso8601."
|
25
26
|
end
|
26
27
|
end
|
27
|
-
end
|
28
|
+
end # class LogStash::Time
|
@@ -0,0 +1,73 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js"></script>
|
5
|
+
<script src="../js/jquery.tmpl.min.js"></script>
|
6
|
+
<style type="text/css">
|
7
|
+
#radiator {
|
8
|
+
margin-top: 1em;
|
9
|
+
padding-left:10px;
|
10
|
+
padding-right:10px;
|
11
|
+
font-size: 120%;
|
12
|
+
border-top: 1px solid black;
|
13
|
+
width: 100%;
|
14
|
+
}
|
15
|
+
|
16
|
+
#radiator .entry:nth-child(2n) {
|
17
|
+
background-color: #C4FFC6;
|
18
|
+
}
|
19
|
+
|
20
|
+
#radiator .timestamp {
|
21
|
+
white-space: nowrap;
|
22
|
+
text-align: left;
|
23
|
+
vertical-align: top;
|
24
|
+
font-family: monospace;
|
25
|
+
font-size: 75%;
|
26
|
+
padding-right: 1em;
|
27
|
+
width: 14em;
|
28
|
+
border-right: 1px solid grey;
|
29
|
+
}
|
30
|
+
|
31
|
+
#radiator .message {
|
32
|
+
font-family: monospace;
|
33
|
+
//text-indent: -2em;
|
34
|
+
//padding-left: 3em;
|
35
|
+
}
|
36
|
+
</style>
|
37
|
+
</head>
|
38
|
+
<body>
|
39
|
+
<h1> logstash information radiator </h1>
|
40
|
+
|
41
|
+
New log data will be streamed here in real-time as logstash
|
42
|
+
receives it.
|
43
|
+
|
44
|
+
<table id="radiator"></table>
|
45
|
+
|
46
|
+
<script id="message-template" type="text/x-jquery-tmpl"><![CDATA[
|
47
|
+
<tr>
|
48
|
+
<td class="timestamp">${received_timestamp}</td>
|
49
|
+
<td class="message">${message}</td>
|
50
|
+
</tr>
|
51
|
+
]]></script>
|
52
|
+
|
53
|
+
<script>
|
54
|
+
$(document).ready(function() {
|
55
|
+
var ws = new WebSocket("ws://snack.home:3000");
|
56
|
+
ws.onmessage = function(event) {
|
57
|
+
eval("var data = " + event.data);
|
58
|
+
//var el = $("<div></div>")
|
59
|
+
//el.html(data.message)
|
60
|
+
var el = $("#message-template").tmpl(data);
|
61
|
+
el.addClass("message")
|
62
|
+
.css("display", "none")
|
63
|
+
.appendTo($("#radiator"))
|
64
|
+
.fadeIn()
|
65
|
+
.delay(10000)
|
66
|
+
.fadeOut(2000, function() {
|
67
|
+
$(this).remove();
|
68
|
+
});
|
69
|
+
}
|
70
|
+
});
|
71
|
+
</script>
|
72
|
+
</body>
|
73
|
+
</html>
|
data/lib/logstash/web/server.rb
CHANGED
@@ -49,11 +49,21 @@ class LogStash::Web::Server < Sinatra::Base
|
|
49
49
|
count = params["count"] = (params["count"] or 50).to_i
|
50
50
|
offset = params["offset"] = (params["offset"] or 0).to_i
|
51
51
|
elasticsearch.search(params) do |@results|
|
52
|
+
#p instance_variables
|
53
|
+
if @results.include?("error")
|
54
|
+
body haml :"search/error", :layout => !request.xhr?
|
55
|
+
next
|
56
|
+
end
|
57
|
+
|
52
58
|
@hits = (@results["hits"]["hits"] rescue [])
|
53
59
|
@total = (@results["hits"]["total"] rescue 0)
|
54
60
|
@graphpoints = []
|
55
|
-
|
56
|
-
@
|
61
|
+
begin
|
62
|
+
@results["facets"]["by_hour"]["entries"].each do |entry|
|
63
|
+
@graphpoints << [entry["key"], entry["count"]]
|
64
|
+
end
|
65
|
+
rescue => e
|
66
|
+
puts e
|
57
67
|
end
|
58
68
|
|
59
69
|
if count and offset
|
@@ -69,12 +79,21 @@ class LogStash::Web::Server < Sinatra::Base
|
|
69
79
|
next_params = params.clone
|
70
80
|
next_params["offset"] = [offset + count, @total - count].min
|
71
81
|
@next_href = "?" + next_params.collect { |k,v| [URI.escape(k.to_s), URI.escape(v.to_s)].join("=") }.join("&")
|
82
|
+
last_params = next_params.clone
|
83
|
+
last_params["offset"] = @total - offset
|
84
|
+
@last_href = "?" + last_params.collect { |k,v| [URI.escape(k.to_s), URI.escape(v.to_s)].join("=") }.join("&")
|
72
85
|
end
|
73
86
|
|
74
87
|
if offset > 0
|
75
88
|
prev_params = params.clone
|
76
89
|
prev_params["offset"] = [offset - count, 0].max
|
77
90
|
@prev_href = "?" + prev_params.collect { |k,v| [URI.escape(k.to_s), URI.escape(v.to_s)].join("=") }.join("&")
|
91
|
+
|
92
|
+
if prev_params["offset"] > 0
|
93
|
+
first_params = prev_params.clone
|
94
|
+
first_params["offset"] = 0
|
95
|
+
@first_href = "?" + first_params.collect { |k,v| [URI.escape(k.to_s), URI.escape(v.to_s)].join("=") }.join("&")
|
96
|
+
end
|
78
97
|
end
|
79
98
|
|
80
99
|
body haml :"search/ajax", :layout => !request.xhr?
|
@@ -14,6 +14,9 @@
|
|
14
14
|
%strong
|
15
15
|
Results #{@result_start} - #{@result_end} of #{@total}
|
16
16
|
|
|
17
|
+
- if @first_href
|
18
|
+
%a.pager{ :href => @first_href } first
|
19
|
+
|
|
17
20
|
- if @prev_href
|
18
21
|
%a.pager{ :href => @prev_href }
|
19
22
|
prev
|
@@ -22,6 +25,10 @@
|
|
22
25
|
- if @next_href
|
23
26
|
%a.pager{ :href => @next_href }
|
24
27
|
next
|
28
|
+
- if @last_href
|
29
|
+
|
|
30
|
+
%a.pager{ :href => @last_href }
|
31
|
+
last
|
25
32
|
- if @hits.length == 0
|
26
33
|
- if !params[:q]
|
27
34
|
No query given. How about <a href="?q=*" class="querychanger">this?</a>
|
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: 40202246267461
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
version: 0.2.
|
9
|
+
- 20101123133737
|
10
|
+
version: 0.2.20101123133737
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Jordan Sissel
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-11-
|
18
|
+
date: 2010-11-23 00:00:00 -08:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -59,6 +59,8 @@ files:
|
|
59
59
|
- lib/logstash.rb
|
60
60
|
- lib/logstash/agent.rb
|
61
61
|
- lib/logstash/inputs.rb
|
62
|
+
- lib/logstash/ruby_fixes.rb
|
63
|
+
- lib/logstash/inputs/internal.rb
|
62
64
|
- lib/logstash/inputs/syslog.rb
|
63
65
|
- lib/logstash/inputs/file.rb
|
64
66
|
- lib/logstash/inputs/base.rb
|
@@ -66,11 +68,13 @@ files:
|
|
66
68
|
- lib/logstash/inputs/tcp.rb
|
67
69
|
- lib/logstash/outputs/gelf.rb
|
68
70
|
- lib/logstash/outputs/elasticsearch.rb
|
71
|
+
- lib/logstash/outputs/internal.rb
|
69
72
|
- lib/logstash/outputs/mongodb.rb
|
70
73
|
- lib/logstash/outputs/stdout.rb
|
71
74
|
- lib/logstash/outputs/websocket.rb
|
72
75
|
- lib/logstash/outputs/base.rb
|
73
76
|
- lib/logstash/outputs/amqp.rb
|
77
|
+
- lib/logstash/outputs/tcp.rb
|
74
78
|
- lib/logstash/namespace.rb
|
75
79
|
- lib/logstash/time.rb
|
76
80
|
- lib/logstash/filters.rb
|
@@ -98,6 +102,7 @@ files:
|
|
98
102
|
- lib/logstash/web/public/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png
|
99
103
|
- lib/logstash/web/public/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png
|
100
104
|
- lib/logstash/web/public/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png
|
105
|
+
- lib/logstash/web/public/ws/index.html
|
101
106
|
- lib/logstash/web/public/js/jquery.livequery.js
|
102
107
|
- lib/logstash/web/public/js/logstash.js
|
103
108
|
- lib/logstash/web/public/js/jquery-hashchange-1.0.0.js
|
@@ -167,8 +172,10 @@ files:
|
|
167
172
|
- lib/logstash/web/views/layout.haml
|
168
173
|
- lib/logstash/web/views/search/ajax.haml
|
169
174
|
- lib/logstash/web/views/search/results.haml
|
175
|
+
- lib/logstash/web/views/search/error.haml
|
170
176
|
- lib/logstash/web/views/header.haml
|
171
177
|
- examples/test.rb
|
178
|
+
- examples/sample-agent-in-ruby.rb
|
172
179
|
- etc/tograylog.yaml
|
173
180
|
- etc/logstash-elasticsearch-rabbitmq-river.yaml
|
174
181
|
- etc/logstash-reader.yaml
|