logstash-logger 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,14 @@
1
+ module LogStashLogger
2
+ module Device
3
+ class Stdout < Base
4
+ def initialize(opts={})
5
+ @io = $stdout
6
+ end
7
+
8
+ def close
9
+ # no-op
10
+ # Calling $stdout.close would be a bad idea
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,43 @@
1
+ require 'openssl'
2
+
3
+ module LogStashLogger
4
+ module Device
5
+ class TCP < Socket
6
+ attr_reader :ssl_certificate
7
+
8
+ def initialize(opts)
9
+ super
10
+
11
+ @ssl_certificate = opts[:ssl_certificate]
12
+ @use_ssl = !!(@ssl_certificate || opts[:use_ssl] || opts[:ssl_enable])
13
+ end
14
+
15
+ def use_ssl?
16
+ @use_ssl || !@ssl_certificate.nil?
17
+ end
18
+
19
+ protected
20
+
21
+ def connect
22
+ if use_ssl?
23
+ ssl_connect
24
+ else
25
+ non_ssl_connect
26
+ end
27
+
28
+ @io
29
+ end
30
+
31
+ def non_ssl_connect
32
+ @io = TCPSocket.new(@host, @port)
33
+ end
34
+
35
+ def ssl_connect
36
+ non_ssl_connect
37
+ #openssl_cert = OpenSSL::X509::Certificate.new(::File.read(@ssl_certificate))
38
+ @io = OpenSSL::SSL::SSLSocket.new(@io)
39
+ @io.connect
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,11 @@
1
+ module LogStashLogger
2
+ module Device
3
+ class UDP < Socket
4
+ def connect
5
+ @io = UDPSocket.new.tap do |socket|
6
+ socket.connect(@host, @port)
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,51 @@
1
+ require 'logger'
2
+ require 'socket'
3
+ require 'time'
4
+
5
+ module LogStashLogger
6
+ HOST = ::Socket.gethostname
7
+
8
+ class Formatter < ::Logger::Formatter
9
+ include TaggedLogging::Formatter
10
+
11
+ def call(severity, time, progname, message)
12
+ event = build_event(message, severity, time)
13
+ "#{event.to_json}\n"
14
+ end
15
+
16
+ protected
17
+
18
+ def build_event(message, severity, time)
19
+ data = message
20
+ if data.is_a?(String) && data.start_with?('{')
21
+ data = (JSON.parse(message) rescue nil) || message
22
+ end
23
+
24
+ event = case data
25
+ when LogStash::Event
26
+ data.clone
27
+ when Hash
28
+ event_data = data.merge("@timestamp" => time)
29
+ LogStash::Event.new(event_data)
30
+ when String
31
+ LogStash::Event.new("message" => data, "@timestamp" => time)
32
+ end
33
+
34
+ event['severity'] ||= severity
35
+ #event.type = progname
36
+
37
+ event['host'] ||= HOST
38
+
39
+ current_tags.each do |tag|
40
+ event.tag(tag)
41
+ end
42
+
43
+ # In case Time#to_json has been overridden
44
+ if event.timestamp.is_a?(Time)
45
+ event.timestamp = event.timestamp.iso8601(3)
46
+ end
47
+
48
+ event
49
+ end
50
+ end
51
+ end
@@ -1,54 +1,40 @@
1
- class LogStashLogger < ::Logger
2
-
3
- HOST = ::Socket.gethostname
4
-
5
- def initialize(host, port, socket_type=:udp)
6
- super(::LogStashLogger::Socket.new(host, port, socket_type))
7
- end
8
-
9
- def add(severity, message = nil, progname = nil, &block)
10
- severity ||= UNKNOWN
11
- if severity < @level
12
- return true
1
+ require 'logger'
2
+ require 'logstash-logger/tagged_logging'
3
+
4
+ module LogStashLogger
5
+ def self.new(*args)
6
+ opts = extract_opts(*args)
7
+ @device = Device.new(opts)
8
+
9
+ ::Logger.new(@device).tap do |logger|
10
+ logger.extend(self)
11
+ logger.extend(TaggedLogging)
12
+ logger.formatter = Formatter.new
13
13
  end
14
- progname ||= @progname
15
- if message.nil?
16
- if block_given?
17
- message = yield
18
- else
19
- message = progname
20
- progname = @progname
14
+ end
15
+
16
+ def self.included(base)
17
+ base.instance_eval do
18
+ attr_reader :device
19
+
20
+ def flush
21
+ !!@device.flush
21
22
  end
22
23
  end
23
- @logdev.write(
24
- format_message(format_severity(severity), Time.now, progname, message))
25
- true
26
24
  end
27
-
28
- def format_message(severity, time, progname, message)
29
- data = message
30
- if data.is_a?(String) && data.start_with?('{')
31
- data = (JSON.parse(message) rescue nil) || message
32
- end
33
-
34
- event = case data
35
- when LogStash::Event
36
- data.clone
37
- when Hash
38
- event_data = data.merge("@timestamp" => time)
39
- LogStash::Event.new(event_data)
40
- when String
41
- LogStash::Event.new("message" => data, "@timestamp" => time)
42
- end
43
-
44
- event['severity'] ||= severity
45
- #event.type = progname
46
25
 
47
- event['source'] ||= HOST
48
- if event['source'] == 'unknown'
49
- event['source'] = HOST
26
+ protected
27
+
28
+ def self.extract_opts(*args)
29
+ if args.length > 1
30
+ puts "[LogStashLogger] (host, port, type) constructor is deprecated. Please use an options hash instead."
31
+ host, port, type = *args
32
+ {host: host, port: port, type: type}
33
+ elsif Hash === args[0]
34
+ args[0]
35
+ else
36
+ fail ArgumentError, "Invalid LogStashLogger options"
50
37
  end
51
-
52
- event
53
38
  end
39
+
54
40
  end
@@ -0,0 +1,23 @@
1
+ require 'rails/railtie'
2
+
3
+ module LogStashLogger
4
+ def self.setup(app)
5
+ return unless app.config.logstash.present?
6
+
7
+ logger_options = app.config.logstash
8
+
9
+ logger = LogStashLogger.new(logger_options)
10
+
11
+ logger.level = ::Logger.const_get(app.config.log_level.to_s.upcase)
12
+
13
+ app.config.logger = logger
14
+ end
15
+
16
+ class Railtie < ::Rails::Railtie
17
+ config.logstash = ActiveSupport::OrderedOptions.new
18
+
19
+ initializer :logstash_logger, before: :initialize_logger do |app|
20
+ LogStashLogger.setup(app)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,40 @@
1
+ module LogStashLogger
2
+ # Shamelessly copied from ActiveSupport::TaggedLogging
3
+ module TaggedLogging
4
+ def tagged(*tags)
5
+ formatter.tagged(*tags) { yield self }
6
+ end
7
+
8
+ def flush
9
+ formatter.clear_tags!
10
+ super if defined?(super)
11
+ end
12
+
13
+ module Formatter
14
+ def tagged(*tags)
15
+ new_tags = push_tags(*tags)
16
+ yield self
17
+ ensure
18
+ pop_tags(new_tags.size)
19
+ end
20
+
21
+ def push_tags(*tags)
22
+ tags.flatten.reject(&:empty?).tap do |new_tags|
23
+ current_tags.concat new_tags
24
+ end
25
+ end
26
+
27
+ def pop_tags(size = 1)
28
+ current_tags.pop size
29
+ end
30
+
31
+ def clear_tags!
32
+ current_tags.clear
33
+ end
34
+
35
+ def current_tags
36
+ Thread.current[:logstash_logger_tags] ||= []
37
+ end
38
+ end
39
+ end
40
+ end
@@ -1,5 +1,3 @@
1
- require 'logger'
2
-
3
- class LogStashLogger < ::Logger
4
- VERSION = "0.4.1"
1
+ module LogStashLogger
2
+ VERSION = "0.5.0"
5
3
  end
@@ -19,7 +19,11 @@ Gem::Specification.new do |gem|
19
19
  gem.require_paths = ["lib"]
20
20
 
21
21
  gem.add_runtime_dependency 'logstash-event', '~> 1.2'
22
- gem.add_development_dependency 'rspec'
22
+
23
+ gem.add_development_dependency 'rails'
24
+ gem.add_development_dependency 'rspec', '>= 3'
23
25
  gem.add_development_dependency 'rake'
26
+ gem.add_development_dependency 'pry'
24
27
  gem.add_development_dependency 'wwtd'
28
+ gem.add_development_dependency 'appraisal'
25
29
  end
@@ -0,0 +1,16 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIICdTCCAd4CCQDLMpdv+B+sYDANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJV
3
+ UzETMBEGA1UECBMKQ2FsaWZvcm5pYTERMA8GA1UEBxMIUGFzYWRlbmExDzANBgNV
4
+ BAoTBkJ1dGxlcjEVMBMGA1UEAxMMRGF2aWQgQnV0bGVyMSAwHgYJKoZIhvcNAQkB
5
+ FhFkd2J1dGxlckB1Y2xhLmVkdTAeFw0xNDA2MDkwNjIyMTZaFw0xNTA2MDkwNjIy
6
+ MTZaMH8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMREwDwYDVQQH
7
+ EwhQYXNhZGVuYTEPMA0GA1UEChMGQnV0bGVyMRUwEwYDVQQDEwxEYXZpZCBCdXRs
8
+ ZXIxIDAeBgkqhkiG9w0BCQEWEWR3YnV0bGVyQHVjbGEuZWR1MIGfMA0GCSqGSIb3
9
+ DQEBAQUAA4GNADCBiQKBgQDbBJ1t2m8RA72GZZ8XOUCsLI1EhRqZqWx0zYHpZbc4
10
+ kVbfMeb5uyfpx1gd5QngZrsD0cvTf46F9z9Ng805Ns9jE5QBJxefl1b6iJ6f/Y9s
11
+ W+WYQJgtNOcJahWWLeiBXqApPUllFI2ME/52+/umuSYVtSVAW7QmPx3YSLPpVjkQ
12
+ 3wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAKiZm6yNzRXKJ9LBLL+Nep87WPlkdFmx
13
+ YUoEtTF8XpgMNfOdzF8DlD4FmoNz/SD7uVOk+tARUoEQFVK+iqpd3/dLDVa/pslX
14
+ a5v6AcmgfSFUHgLvKQZNvgY50jhLdqruf8PCgVnq+4L0ItguJx/viYMxF0p0fJTG
15
+ oGX8W4ul0W5F
16
+ -----END CERTIFICATE-----
@@ -0,0 +1,15 @@
1
+ -----BEGIN RSA PRIVATE KEY-----
2
+ MIICWwIBAAKBgQDbBJ1t2m8RA72GZZ8XOUCsLI1EhRqZqWx0zYHpZbc4kVbfMeb5
3
+ uyfpx1gd5QngZrsD0cvTf46F9z9Ng805Ns9jE5QBJxefl1b6iJ6f/Y9sW+WYQJgt
4
+ NOcJahWWLeiBXqApPUllFI2ME/52+/umuSYVtSVAW7QmPx3YSLPpVjkQ3wIDAQAB
5
+ AoGAYaFXBAchB3ahX22hU1rkJ1vcxTSIPQM3I4IQbRg4anDvRqMaESyKiD2iXAEj
6
+ O/LPXs6Ai5EK2VDz2Pvt2ZlDLFX3GKMEChtIa2mpiQqIdoJS+42ibqfHrv3nlnTK
7
+ OTeTcw+SbAAFTKFPJO94lGcBXhsYYW/LAFH08bVqp+Jhi1ECQQDzkz4O0eYH05Wb
8
+ 1bAwjNcjj+X6JKIRGgWYb1kkk3VyAFuD6qCEKBfS2t4nZs1yy83Ch4Bk9YmDHx1Q
9
+ gdYCjPsLAkEA5jCwo51KqboxAz6m0pZwdiKlCav94TMdHMKTFcUE5fDoWrwzrIyH
10
+ 8rr7q7cl3culX7pUcPdKMl78Nw6/4JFF/QJARwNfrWxut0ttq+BSHOWC98BFWXeC
11
+ tJ+0j+uuvqYrMJCAHeay47TYtUXQTQaA0X4vwA5HVafsbokMv+MKpPW7XwJAF713
12
+ yjgDpkOMoIAKpndbe+OQz9GMKniiDQBIORuLqMdSv2Dfl3Ea6D6+i/QklJ5XHOtT
13
+ oB7w6QcAzhDYWynAZQJAX0UF9alkX8CQq1rvsAG6zzh3bD+Udy7cU0Yonx/byZoz
14
+ K6G/seM5YFTMVrnbY9V23aIhjJSxGWOB5fDNPG5p4w==
15
+ -----END RSA PRIVATE KEY-----
data/samples/ssl.conf ADDED
@@ -0,0 +1,15 @@
1
+ input {
2
+ tcp {
3
+ port => 8443
4
+ ssl_enable => true
5
+ ssl_cert => "samples/example.crt"
6
+ ssl_key => "samples/example.key"
7
+ codec => json_lines
8
+ }
9
+ }
10
+ output {
11
+ stdout {
12
+ codec => json_lines
13
+ }
14
+ }
15
+
data/samples/tcp.conf ADDED
@@ -0,0 +1,11 @@
1
+ input {
2
+ tcp {
3
+ port => 5228
4
+ codec => json_lines
5
+ }
6
+ }
7
+ output {
8
+ stdout {
9
+ codec => json_lines
10
+ }
11
+ }
data/samples/udp.conf ADDED
@@ -0,0 +1,11 @@
1
+ input {
2
+ udp {
3
+ port => 5228
4
+ codec => json_lines
5
+ }
6
+ }
7
+ output {
8
+ stdout {
9
+ codec => json_lines
10
+ }
11
+ }
@@ -0,0 +1,15 @@
1
+ require 'logstash-logger'
2
+
3
+ describe LogStashLogger::Device::Socket do
4
+ include_context 'device'
5
+
6
+ it "defaults host to 0.0.0.0" do
7
+ expect(device_with_port.host).to eq("0.0.0.0")
8
+ end
9
+
10
+ context "when port is not specified" do
11
+ it "raises an exception" do
12
+ expect { described_class.new }.to raise_error
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ require 'logstash-logger'
2
+
3
+ describe LogStashLogger::Device::Stdout do
4
+ it "writes to $stdout" do
5
+ expect(subject.to_io).to eq($stdout)
6
+ expect($stdout).to receive(:write).once
7
+ subject.write("test")
8
+ end
9
+
10
+ it "ignores #close" do
11
+ expect($stdout).not_to receive(:close)
12
+ subject.close
13
+ end
14
+ end
@@ -0,0 +1,36 @@
1
+ require 'logstash-logger'
2
+
3
+ describe LogStashLogger::Device::TCP do
4
+ include_context 'device'
5
+
6
+ let(:tcp_socket) { double('TCPSocket') }
7
+ let(:ssl_socket) { double('SSLSocket') }
8
+
9
+ before(:each) do
10
+ allow(TCPSocket).to receive(:new) { tcp_socket }
11
+ allow(OpenSSL::SSL::SSLSocket).to receive(:new) { ssl_socket }
12
+ allow(ssl_socket).to receive(:connect)
13
+ end
14
+
15
+ context "when not using SSL" do
16
+ it "writes to a TCP socket" do
17
+ expect(tcp_socket).to receive(:write)
18
+ tcp_device.write('test')
19
+ end
20
+
21
+ it "returns false for #use_ssl?" do
22
+ expect(tcp_device.use_ssl?).to be_falsey
23
+ end
24
+ end
25
+
26
+ context "when using SSL" do
27
+ it "writes to an SSL TCP socket" do
28
+ expect(ssl_socket).to receive(:write)
29
+ ssl_tcp_device.write('test')
30
+ end
31
+
32
+ it "returns false for #use_ssl?" do
33
+ expect(ssl_tcp_device.use_ssl?).to be_truthy
34
+ end
35
+ end
36
+ end