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.
Files changed (134) hide show
  1. data/bin/logstash +56 -0
  2. data/bin/logstash-web +6 -0
  3. data/etc/logstash-elasticsearch-rabbitmq-river.yaml +41 -0
  4. data/etc/logstash-mongodb-storage.yaml +5 -0
  5. data/etc/logstash-parser.yaml +20 -0
  6. data/etc/logstash-reader.yaml +8 -0
  7. data/etc/logstash-shipper.yaml +18 -0
  8. data/etc/logstash-standalone.yaml +47 -0
  9. data/etc/prod.yaml +38 -0
  10. data/etc/redhat/logstash +92 -0
  11. data/etc/redhat/logstash-agent +83 -0
  12. data/etc/redhat/logstash-agent.sysconfig +7 -0
  13. data/etc/redhat/logstash.spec +171 -0
  14. data/etc/redhat/logstash.sysconfig +18 -0
  15. data/etc/tograylog.yaml +37 -0
  16. data/examples/test.rb +38 -0
  17. data/lib/logstash.rb +3 -0
  18. data/lib/logstash/agent.rb +116 -0
  19. data/lib/logstash/event.rb +70 -0
  20. data/lib/logstash/filters.rb +17 -0
  21. data/lib/logstash/filters/base.rb +17 -0
  22. data/lib/logstash/filters/date.rb +59 -0
  23. data/lib/logstash/filters/field.rb +29 -0
  24. data/lib/logstash/filters/grok.rb +74 -0
  25. data/lib/logstash/filters/grokdiscovery.rb +60 -0
  26. data/lib/logstash/inputs.rb +18 -0
  27. data/lib/logstash/inputs/amqp.rb +48 -0
  28. data/lib/logstash/inputs/base.rb +32 -0
  29. data/lib/logstash/inputs/file.rb +47 -0
  30. data/lib/logstash/inputs/syslog.rb +123 -0
  31. data/lib/logstash/inputs/tcp.rb +51 -0
  32. data/lib/logstash/logging.rb +82 -0
  33. data/lib/logstash/namespace.rb +6 -0
  34. data/lib/logstash/outputs.rb +15 -0
  35. data/lib/logstash/outputs/amqp.rb +48 -0
  36. data/lib/logstash/outputs/base.rb +29 -0
  37. data/lib/logstash/outputs/elasticsearch.rb +71 -0
  38. data/lib/logstash/outputs/gelf.rb +35 -0
  39. data/lib/logstash/outputs/mongodb.rb +19 -0
  40. data/lib/logstash/outputs/stdout.rb +15 -0
  41. data/lib/logstash/outputs/websocket.rb +35 -0
  42. data/lib/logstash/time.rb +27 -0
  43. data/lib/logstash/web/lib/elasticsearch.rb +79 -0
  44. data/lib/logstash/web/public/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  45. data/lib/logstash/web/public/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  46. data/lib/logstash/web/public/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  47. data/lib/logstash/web/public/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  48. data/lib/logstash/web/public/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  49. data/lib/logstash/web/public/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  50. data/lib/logstash/web/public/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  51. data/lib/logstash/web/public/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  52. data/lib/logstash/web/public/css/smoothness/images/ui-icons_222222_256x240.png +0 -0
  53. data/lib/logstash/web/public/css/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  54. data/lib/logstash/web/public/css/smoothness/images/ui-icons_454545_256x240.png +0 -0
  55. data/lib/logstash/web/public/css/smoothness/images/ui-icons_888888_256x240.png +0 -0
  56. data/lib/logstash/web/public/css/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  57. data/lib/logstash/web/public/css/smoothness/jquery-ui-1.8.5.custom.css +572 -0
  58. data/lib/logstash/web/public/js/flot/API.txt +1024 -0
  59. data/lib/logstash/web/public/js/flot/FAQ.txt +71 -0
  60. data/lib/logstash/web/public/js/flot/LICENSE.txt +22 -0
  61. data/lib/logstash/web/public/js/flot/Makefile +15 -0
  62. data/lib/logstash/web/public/js/flot/NEWS.txt +340 -0
  63. data/lib/logstash/web/public/js/flot/PLUGINS.txt +105 -0
  64. data/lib/logstash/web/public/js/flot/README.txt +81 -0
  65. data/lib/logstash/web/public/js/flot/examples/ajax.html +143 -0
  66. data/lib/logstash/web/public/js/flot/examples/annotating.html +75 -0
  67. data/lib/logstash/web/public/js/flot/examples/arrow-down.gif +0 -0
  68. data/lib/logstash/web/public/js/flot/examples/arrow-left.gif +0 -0
  69. data/lib/logstash/web/public/js/flot/examples/arrow-right.gif +0 -0
  70. data/lib/logstash/web/public/js/flot/examples/arrow-up.gif +0 -0
  71. data/lib/logstash/web/public/js/flot/examples/basic.html +38 -0
  72. data/lib/logstash/web/public/js/flot/examples/data-eu-gdp-growth-1.json +4 -0
  73. data/lib/logstash/web/public/js/flot/examples/data-eu-gdp-growth-2.json +4 -0
  74. data/lib/logstash/web/public/js/flot/examples/data-eu-gdp-growth-3.json +4 -0
  75. data/lib/logstash/web/public/js/flot/examples/data-eu-gdp-growth-4.json +4 -0
  76. data/lib/logstash/web/public/js/flot/examples/data-eu-gdp-growth-5.json +4 -0
  77. data/lib/logstash/web/public/js/flot/examples/data-eu-gdp-growth.json +4 -0
  78. data/lib/logstash/web/public/js/flot/examples/data-japan-gdp-growth.json +4 -0
  79. data/lib/logstash/web/public/js/flot/examples/data-usa-gdp-growth.json +4 -0
  80. data/lib/logstash/web/public/js/flot/examples/dual-axis.html +39 -0
  81. data/lib/logstash/web/public/js/flot/examples/graph-types.html +75 -0
  82. data/lib/logstash/web/public/js/flot/examples/hs-2004-27-a-large_web.jpg +0 -0
  83. data/lib/logstash/web/public/js/flot/examples/image.html +45 -0
  84. data/lib/logstash/web/public/js/flot/examples/index.html +43 -0
  85. data/lib/logstash/web/public/js/flot/examples/interacting.html +93 -0
  86. data/lib/logstash/web/public/js/flot/examples/layout.css +6 -0
  87. data/lib/logstash/web/public/js/flot/examples/navigate.html +118 -0
  88. data/lib/logstash/web/public/js/flot/examples/selection.html +114 -0
  89. data/lib/logstash/web/public/js/flot/examples/setting-options.html +65 -0
  90. data/lib/logstash/web/public/js/flot/examples/stacking.html +77 -0
  91. data/lib/logstash/web/public/js/flot/examples/thresholding.html +54 -0
  92. data/lib/logstash/web/public/js/flot/examples/time.html +71 -0
  93. data/lib/logstash/web/public/js/flot/examples/tracking.html +95 -0
  94. data/lib/logstash/web/public/js/flot/examples/turning-series.html +98 -0
  95. data/lib/logstash/web/public/js/flot/examples/visitors.html +90 -0
  96. data/lib/logstash/web/public/js/flot/examples/zooming.html +98 -0
  97. data/lib/logstash/web/public/js/flot/excanvas.js +1427 -0
  98. data/lib/logstash/web/public/js/flot/excanvas.min.js +1 -0
  99. data/lib/logstash/web/public/js/flot/jquery.colorhelpers.js +174 -0
  100. data/lib/logstash/web/public/js/flot/jquery.colorhelpers.min.js +1 -0
  101. data/lib/logstash/web/public/js/flot/jquery.flot.crosshair.js +156 -0
  102. data/lib/logstash/web/public/js/flot/jquery.flot.crosshair.min.js +1 -0
  103. data/lib/logstash/web/public/js/flot/jquery.flot.image.js +237 -0
  104. data/lib/logstash/web/public/js/flot/jquery.flot.image.min.js +1 -0
  105. data/lib/logstash/web/public/js/flot/jquery.flot.js +2119 -0
  106. data/lib/logstash/web/public/js/flot/jquery.flot.min.js +1 -0
  107. data/lib/logstash/web/public/js/flot/jquery.flot.navigate.js +272 -0
  108. data/lib/logstash/web/public/js/flot/jquery.flot.navigate.min.js +1 -0
  109. data/lib/logstash/web/public/js/flot/jquery.flot.selection.js +299 -0
  110. data/lib/logstash/web/public/js/flot/jquery.flot.selection.min.js +1 -0
  111. data/lib/logstash/web/public/js/flot/jquery.flot.stack.js +152 -0
  112. data/lib/logstash/web/public/js/flot/jquery.flot.stack.min.js +1 -0
  113. data/lib/logstash/web/public/js/flot/jquery.flot.threshold.js +103 -0
  114. data/lib/logstash/web/public/js/flot/jquery.flot.threshold.min.js +1 -0
  115. data/lib/logstash/web/public/js/flot/jquery.js +4376 -0
  116. data/lib/logstash/web/public/js/flot/jquery.min.js +19 -0
  117. data/lib/logstash/web/public/js/jquery-hashchange-1.0.0.js +121 -0
  118. data/lib/logstash/web/public/js/jquery.livequery.js +250 -0
  119. data/lib/logstash/web/public/js/jquery.tmpl.min.js +1 -0
  120. data/lib/logstash/web/public/js/logstash.js +202 -0
  121. data/lib/logstash/web/server.rb +90 -0
  122. data/lib/logstash/web/views/header.haml +8 -0
  123. data/lib/logstash/web/views/layout.haml +21 -0
  124. data/lib/logstash/web/views/main/index.haml +5 -0
  125. data/lib/logstash/web/views/search/ajax.haml +32 -0
  126. data/lib/logstash/web/views/search/results.haml +17 -0
  127. data/lib/logstash/web/views/style.sass +50 -0
  128. data/patterns/firewalls +2 -0
  129. data/patterns/grok-patterns +90 -0
  130. data/patterns/haproxy +5 -0
  131. data/patterns/linux-syslog +7 -0
  132. data/patterns/nagios +7 -0
  133. data/patterns/ruby +2 -0
  134. metadata +228 -0
@@ -0,0 +1,60 @@
1
+ require "logstash/filters/base"
2
+
3
+ gem "jls-grok", ">=0.2.3071"
4
+ require "grok" # rubygem 'jls-grok'
5
+
6
+ class LogStash::Filters::Grokdiscovery < LogStash::Filters::Base
7
+ def initialize(config = {})
8
+ super
9
+
10
+ @discover_fields = {}
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
+ @grok = Grok.new
18
+ Dir.glob("patterns/*").each do |path|
19
+ @grok.add_patterns_from_file(path)
20
+ end
21
+ @discover_fields[type] = typeconfig
22
+ @logger.debug(["Enabling discovery", { :type => type, :fields => typeconfig }])
23
+ @logger.warn(@discover_fields)
24
+ end # @config.each
25
+ end # def register
26
+
27
+ def filter(event)
28
+ # parse it with grok
29
+ message = event.message
30
+ match = false
31
+
32
+ if event.type and @discover_fields.include?(event.type)
33
+ discover = @discover_fields[event.type] & event.fields.keys
34
+ discover.each do |field|
35
+ value = event.fields[field]
36
+ value = [value] if value.is_a?(String)
37
+
38
+ value.each do |v|
39
+ pattern = @grok.discover(v)
40
+ @logger.warn("Trying #{v} => #{pattern}")
41
+ @grok.compile(pattern)
42
+ match = @grok.match(v)
43
+ if match
44
+ @logger.warn(["Match", match.captures])
45
+ event.fields.merge!(match.captures) do |key, oldval, newval|
46
+ @logger.warn(["Merging #{key}", oldval, newval])
47
+ oldval + newval # should both be arrays...
48
+ end
49
+ else
50
+ @logger.warn(["Discovery produced something not matchable?", { :input => v }])
51
+ end
52
+ end # value.each
53
+ end # discover.each
54
+ else
55
+ @logger.info("Unknown type for #{event.source} (type: #{event.type})")
56
+ @logger.debug(event.to_hash)
57
+ end
58
+ @logger.debug(["Event now: ", event.to_hash])
59
+ end # def filter
60
+ end # class LogStash::Filters::Grokdiscovery
@@ -0,0 +1,18 @@
1
+
2
+ require "logstash/namespace"
3
+ require "uri"
4
+
5
+ module LogStash::Inputs
6
+ def self.from_url(url, type, &block)
7
+ # Assume file paths if we start with "/"
8
+ url = "file://#{url}" if url.start_with?("/")
9
+
10
+ uri = URI.parse(url)
11
+ # TODO(sissel): Add error handling
12
+ # TODO(sissel): Allow plugin paths
13
+ klass = uri.scheme.capitalize
14
+ file = uri.scheme
15
+ require "logstash/inputs/#{file}"
16
+ LogStash::Inputs.const_get(klass).new(uri, type, &block)
17
+ end # def from_url
18
+ end # module LogStash::Inputs
@@ -0,0 +1,48 @@
1
+ require "logstash/inputs/base"
2
+ require "amqp" # rubygem 'amqp'
3
+ require "mq" # rubygem 'amqp'
4
+ require "uuidtools" # rubygem 'uuidtools'
5
+
6
+ class LogStash::Inputs::Amqp < LogStash::Inputs::Base
7
+ MQTYPES = [ "fanout", "queue", "topic" ]
8
+
9
+ def initialize(url, type, config={}, &block)
10
+ super
11
+
12
+ @mq = nil
13
+
14
+ # Handle path /<type>/<name>
15
+ unused, @mqtype, @name = @url.path.split("/", 3)
16
+ if @mqtype == nil or @name == nil
17
+ raise "amqp urls must have a path of /<type>/name where <type> is #{MQTYPES.join(", ")}"
18
+ end
19
+
20
+ if !MQTYPES.include?(@mqtype)
21
+ raise "Invalid type '#{@mqtype}' must be one of #{MQTYPES.JOIN(", ")}"
22
+ end
23
+ end
24
+
25
+ def register
26
+ @logger.info("Registering #{@url}")
27
+ @amqp = AMQP.connect(:host => @url.host)
28
+ @mq = MQ.new(@amqp)
29
+ @target = nil
30
+
31
+ @target = @mq.queue(UUIDTools::UUID.timestamp_create)
32
+ case @mqtype
33
+ when "fanout"
34
+ #@target.bind(MQ.fanout(@url.path, :durable => true))
35
+ @target.bind(@mq.fanout(@name))
36
+ when "direct"
37
+ @target.bind(@mq.direct(@name))
38
+ when "topic"
39
+ @target.bind(@mq.topic(@name))
40
+ end # case @mqtype
41
+
42
+ @target.subscribe(:ack => true) do |header, message|
43
+ event = LogStash::Event.from_json(message)
44
+ receive(event)
45
+ header.ack
46
+ end
47
+ end # def register
48
+ end # class LogStash::Inputs::Amqp
@@ -0,0 +1,32 @@
1
+ require "logstash/namespace"
2
+ require "logstash/event"
3
+ require "logstash/logging"
4
+ require "uri"
5
+
6
+ class LogStash::Inputs::Base
7
+ def initialize(url, type, config={}, &block)
8
+ @logger = LogStash::Logger.new(STDERR)
9
+ @url = url
10
+ @url = URI.parse(url) if url.is_a? String
11
+ @config = config
12
+ @callback = block
13
+ @type = type
14
+ @tags = []
15
+ end
16
+
17
+ def register
18
+ raise "#{self.class}#register must be overidden"
19
+ end
20
+
21
+ def tag(newtag)
22
+ @tags << newtag
23
+ end
24
+
25
+ def receive(event)
26
+ @logger.debug(["Got event", { :url => @url, :event => event }])
27
+ # Only override the type if it doesn't have one
28
+ event.type = @type if !event.type
29
+ event.tags |= @tags # set union
30
+ @callback.call(event)
31
+ end
32
+ end # class LogStash::Inputs::Base
@@ -0,0 +1,47 @@
1
+ require "logstash/inputs/base"
2
+ require "eventmachine-tail"
3
+ require "socket" # for Socket.gethostname
4
+
5
+ class LogStash::Inputs::File < LogStash::Inputs::Base
6
+ def initialize(url, type, config={}, &block)
7
+ super
8
+
9
+ # Hack the hostname into the url.
10
+ # This works since file:// urls don't generally have a host in it.
11
+ @url.host = Socket.gethostname
12
+ end
13
+
14
+ def register
15
+ EventMachine::FileGlobWatchTail.new(@url.path, Reader, interval=60,
16
+ exclude=[], receiver=self)
17
+ end # def register
18
+
19
+ def receive(filetail, event)
20
+ url = @url.clone
21
+ url.path = filetail.path
22
+ @logger.debug(["original url", { :originalurl => @url, :newurl => url }])
23
+ event = LogStash::Event.new({
24
+ "@source" => url,
25
+ "@message" => event,
26
+ "@type" => @type,
27
+ "@tags" => @tags.clone,
28
+ })
29
+ @logger.debug(["Got event", event])
30
+ @callback.call(event)
31
+ end # def receive
32
+
33
+ class Reader < EventMachine::FileTail
34
+ def initialize(path, receiver)
35
+ super(path)
36
+ @receiver = receiver
37
+ @buffer = BufferedTokenizer.new # From eventmachine
38
+ end
39
+
40
+ def receive_data(data)
41
+ # TODO(2.0): Support multiline log data
42
+ @buffer.extract(data).each do |line|
43
+ @receiver.receive(self, line)
44
+ end
45
+ end # def receive_data
46
+ end # class Reader
47
+ end # class LogStash::Inputs::File
@@ -0,0 +1,123 @@
1
+ require "logstash/inputs/base"
2
+ require "eventmachine-tail"
3
+ require "socket" # for Socket.gethostname
4
+ require "date"
5
+ require "logstash/time" # should really use the filters/date.rb bits
6
+
7
+
8
+ class LogStash::Inputs::Syslog < LogStash::Inputs::Base
9
+ def register
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
+ @logger.info("Starting tcp listener for #{@url}")
17
+ EventMachine::start_server(@url.host, @url.port, TCPInput, self, @logger)
18
+
19
+ @logger.info("Starting udp listener for #{@url}")
20
+ EventMachine::open_datagram_socket(@url.host, @url.port, UDPInput, self,
21
+ @logger)
22
+
23
+ # This comes from RFC3164, mostly.
24
+ @@syslog_re ||= \
25
+ /<([0-9]{1,3})>([A-z]{3} [0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}) (\S+) (.*)/
26
+ #<priority timestamp Mmm dd hh:mm:ss host msg
27
+ end # def register
28
+
29
+ def receive(host, port, message)
30
+ url = @url.clone
31
+ url.host = host
32
+ url.port = port
33
+
34
+ # Do some syslog relay-like behavior.
35
+ # * Add syslog headers if there are none
36
+ event = LogStash::Event.new({
37
+ "@message" => message,
38
+ "@type" => @type,
39
+ "@tags" => @tags.clone,
40
+ })
41
+ syslog_relay(event, url)
42
+ @logger.debug(["Got event", event.class, event.to_hash])
43
+ @callback.call(event)
44
+ end # def receive
45
+
46
+ # Following RFC3164 where sane, we'll try to parse a received message
47
+ # as if you were relaying a syslog message to it.
48
+ # If the message cannot be recognized (see @@syslog_re), we'll
49
+ # treat it like the whole event.message is correct and try to fill
50
+ # the missing pieces (host, priority, etc)
51
+ def syslog_relay(event, url)
52
+ match = @@syslog_re.match(event.message)
53
+ if match
54
+ # match[1,2,3,4] = {pri, timestamp, hostname, message}
55
+ # Per RFC3164, priority = (facility * 8) + severity
56
+ # = (facility << 3) & (severity)
57
+ priority = match[1].to_i
58
+ severity = priority & 7 # 7 is 111 (3 bits)
59
+ facility = priority >> 3
60
+ event.fields["priority"] = priority
61
+ event.fields["severity"] = severity
62
+ event.fields["facility"] = facility
63
+
64
+ # TODO(sissel): Use the date filter, somehow.
65
+ event.timestamp = LogStash::Time.to_iso8601(
66
+ DateTime.strptime(match[2], "%b %d %H:%M:%S"))
67
+
68
+ # At least the hostname is simple...
69
+ url.host = match[3]
70
+ url.port = nil
71
+ event.source = url
72
+
73
+ event.message = match[4]
74
+ else
75
+ @logger.info(["NOT SYSLOG", event.message])
76
+ url.host = Socket.gethostname if url.host == "127.0.0.1"
77
+
78
+ # RFC3164 says unknown messages get pri=13
79
+ priority = 13
80
+ severity = priority & 7 # 7 is 111 (3 bits)
81
+ facility = priority >> 3
82
+ event.fields["priority"] = 13
83
+ event.fields["severity"] = 5 # 13 & 7 == 5
84
+ event.fields["facility"] = 1 # 13 >> 3 == 1
85
+
86
+ # Don't need to modify the message, here.
87
+ # event.message = ...
88
+
89
+ event.source = url
90
+ end
91
+ end # def syslog_relay
92
+
93
+ class TCPInput < EventMachine::Connection
94
+ def initialize(receiver, logger)
95
+ @logger = logger
96
+ @receiver = receiver
97
+ @buffer = BufferedTokenizer.new # From eventmachine
98
+ end # def initialize
99
+
100
+ # Messages over TCP may not be received all at once, chunk by newline.
101
+ def receive_data(data)
102
+ @buffer.extract(data).each do |line|
103
+ port, host = Socket.unpack_sockaddr_in(self.get_peername)
104
+ # Trim trailing newlines
105
+ @receiver.receive(host, port, line.chomp)
106
+ end
107
+ end # def receive_data
108
+ end # class TCPInput
109
+
110
+ class UDPInput < EventMachine::Connection
111
+ def initialize(receiver, logger)
112
+ @logger = logger
113
+ @receiver = receiver
114
+ end # def initialize
115
+
116
+ # Every udp packet is a unique message.
117
+ def receive_data(data)
118
+ port, host = Socket.unpack_sockaddr_in(self.get_peername)
119
+ # Trim trailing newlines
120
+ @receiver.receive(host, port, data.chomp)
121
+ end # def receive_data
122
+ end # class UDPInput
123
+ end # class LogStash::Inputs::Tcp
@@ -0,0 +1,51 @@
1
+ require "logstash/inputs/base"
2
+ require "eventmachine-tail"
3
+ require "socket" # for Socket.gethostname
4
+
5
+ class LogStash::Inputs::Tcp < LogStash::Inputs::Base
6
+ def initialize(url, type, config={}, &block)
7
+ super
8
+ end
9
+
10
+ def register
11
+ if !@url.host or !@url.port
12
+ @logger.fatal("No host or port given in #{self.class}: #{@url}")
13
+ # TODO(sissel): Make this an actual exception class
14
+ raise "configuration error"
15
+ end
16
+
17
+ @logger.info("Starting tcp listener for #{@url}")
18
+ EventMachine::start_server(@url.host, @url.port, TCPInput, @url, self, @logger)
19
+ end
20
+
21
+ def receive(host, port, event)
22
+ url = @url.clone
23
+ url.host = host
24
+ url.port = port
25
+ @logger.debug(["original url", { :originalurl => @url, :newurl => url }])
26
+ event = LogStash::Event.new({
27
+ "@source" => url,
28
+ "@message" => event,
29
+ "@type" => @type,
30
+ "@tags" => @tags.clone,
31
+ })
32
+ @logger.debug(["Got event", event])
33
+ @callback.call(event)
34
+ end # def receive
35
+
36
+ class TCPInput < EventMachine::Connection
37
+ def initialize(url, receiver, logger)
38
+ @logger = logger
39
+ @receiver = receiver
40
+ @url = url;
41
+ @buffer = BufferedTokenizer.new # From eventmachine
42
+ end # def initialize
43
+
44
+ def receive_data(data)
45
+ @buffer.extract(data).each do |line|
46
+ port, host = Socket.unpack_sockaddr_in(self.get_peername)
47
+ @receiver.receive(host, port, line)
48
+ end
49
+ end # def receive_data
50
+ end # class TCPInput
51
+ end # class LogStash::Inputs::Tcp
@@ -0,0 +1,82 @@
1
+ require "logstash/namespace"
2
+ require "logger"
3
+
4
+ class LogStash::Logger < Logger
5
+ # Try to load awesome_print, if it fails, log it later
6
+ # but otherwise we should continue to operate as normal.
7
+ begin
8
+ require "ap"
9
+ @@have_awesome_print = true
10
+ rescue LoadError => e
11
+ @@have_awesome_print = false
12
+ @@notify_awesome_print_load_failed = e
13
+ end
14
+
15
+ def initialize(*args)
16
+ super(*args)
17
+ @formatter = LogStash::Logger::Formatter.new
18
+
19
+ # Set default loglevel to WARN unless $DEBUG is set (run with 'ruby -d')
20
+ self.level = $DEBUG ? Logger::DEBUG: Logger::INFO
21
+
22
+ # Conditional support for awesome_print
23
+ if !@@have_awesome_print && @@notify_awesome_print_load_failed
24
+ info [ "Failed: require 'ap' (aka awesome_print); some " \
25
+ "logging features may be disabled",
26
+ @@notify_awesome_print_load_failed ]
27
+ @@notify_awesome_print_load_failed = nil
28
+ end
29
+
30
+ @formatter.progname = self.progname = File.basename($0)
31
+ end # def initialize
32
+
33
+ def level=(level)
34
+ super(level)
35
+ @formatter.level = level
36
+ end # def level=
37
+ end # class LogStash::Logger
38
+
39
+ # Implement a custom Logger::Formatter that uses awesome_inspect on non-strings.
40
+ class LogStash::Logger::Formatter < Logger::Formatter
41
+ attr_accessor :level
42
+ attr_accessor :progname
43
+
44
+ def call(severity, timestamp, who, object)
45
+ # override progname to be the caller if the log level threshold is DEBUG
46
+ # We only do this if the logger level is DEBUG because inspecting the
47
+ # stack and doing extra string manipulation can have performance impacts
48
+ # under high logging rates.
49
+ if @level == Logger::DEBUG
50
+ # callstack inspection, include our caller
51
+ # turn this: "/usr/lib/ruby/1.8/irb/workspace.rb:52:in `irb_binding'"
52
+ # into this: ["/usr/lib/ruby/1.8/irb/workspace.rb", "52", "irb_binding"]
53
+ #
54
+ # caller[3] is actually who invoked the Logger#<type>
55
+ # This only works if you use the severity methods
56
+ path, line, method = caller[3].split(/(?::in `|:|')/)
57
+ # Trim RUBYLIB path from 'file' if we can
58
+ #whence = $:.select { |p| path.start_with?(p) }[0]
59
+ whence = $:.detect { |p| path.start_with?(p) }
60
+ if !whence
61
+ # We get here if the path is not in $:
62
+ file = path
63
+ else
64
+ file = path[whence.length + 1..-1]
65
+ end
66
+ who = "#{file}:#{line}##{method}"
67
+ end
68
+
69
+ # Log like normal if we got a string.
70
+ if object.is_a?(String)
71
+ super(severity, timestamp, who, object)
72
+ else
73
+ # If we logged an object, use .awesome_inspect (or just .inspect)
74
+ # to stringify it for higher sanity logging.
75
+ if object.respond_to?(:awesome_inspect)
76
+ super(severity, timestamp, who, object.awesome_inspect)
77
+ else
78
+ super(severity, timestamp, who, object.inspect)
79
+ end
80
+ end
81
+ end # def call
82
+ end # class LogStash::Logger::Formatter