logstash-logger 0.4.1 → 0.5.0
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rspec +3 -0
- data/.travis.yml +6 -3
- data/Appraisals +11 -0
- data/CHANGELOG.md +20 -13
- data/Gemfile +1 -7
- data/README.md +94 -35
- data/Rakefile +3 -5
- data/gemfiles/rails_3.2.gemfile +7 -0
- data/gemfiles/rails_4.0.gemfile +7 -0
- data/gemfiles/rails_4.1.gemfile +7 -0
- data/lib/logstash-logger.rb +4 -3
- data/lib/logstash-logger/device.rb +28 -0
- data/lib/logstash-logger/device/base.rb +30 -0
- data/lib/logstash-logger/device/socket.rb +56 -0
- data/lib/logstash-logger/device/stdout.rb +14 -0
- data/lib/logstash-logger/device/tcp.rb +43 -0
- data/lib/logstash-logger/device/udp.rb +11 -0
- data/lib/logstash-logger/formatter.rb +51 -0
- data/lib/logstash-logger/logger.rb +32 -46
- data/lib/logstash-logger/railtie.rb +23 -0
- data/lib/logstash-logger/tagged_logging.rb +40 -0
- data/lib/logstash-logger/version.rb +2 -4
- data/logstash-logger.gemspec +5 -1
- data/samples/example.crt +16 -0
- data/samples/example.key +15 -0
- data/samples/ssl.conf +15 -0
- data/samples/tcp.conf +11 -0
- data/samples/udp.conf +11 -0
- data/spec/device/socket_spec.rb +15 -0
- data/spec/device/stdout_spec.rb +14 -0
- data/spec/device/tcp_spec.rb +36 -0
- data/spec/device/udp_spec.rb +9 -0
- data/spec/device_spec.rb +11 -0
- data/spec/logger_spec.rb +16 -30
- data/spec/rails_spec.rb +52 -0
- data/spec/spec_helper.rb +38 -5
- data/spec/tagged_logging_spec.rb +32 -0
- metadata +78 -4
- data/lib/logstash-logger/socket.rb +0 -34
@@ -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,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
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
def
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
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
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|
-
|
48
|
-
|
49
|
-
|
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
|
data/logstash-logger.gemspec
CHANGED
@@ -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
|
-
|
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
|
data/samples/example.crt
ADDED
@@ -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-----
|
data/samples/example.key
ADDED
@@ -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
data/samples/tcp.conf
ADDED
data/samples/udp.conf
ADDED
@@ -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
|