logstash-logger-p 0.26.1
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 +7 -0
- data/.gitignore +21 -0
- data/.rspec +3 -0
- data/.rubocop.yml +1156 -0
- data/.travis.yml +26 -0
- data/Appraisals +23 -0
- data/CHANGELOG.md +199 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +880 -0
- data/Rakefile +23 -0
- data/gemfiles/rails_3.2.gemfile +9 -0
- data/gemfiles/rails_4.0.gemfile +9 -0
- data/gemfiles/rails_4.1.gemfile +9 -0
- data/gemfiles/rails_4.2.gemfile +9 -0
- data/gemfiles/rails_5.0.gemfile +9 -0
- data/gemfiles/rails_5.1.gemfile +9 -0
- data/lib/logstash-logger/buffer.rb +336 -0
- data/lib/logstash-logger/configuration.rb +29 -0
- data/lib/logstash-logger/device/aws_stream.rb +94 -0
- data/lib/logstash-logger/device/balancer.rb +40 -0
- data/lib/logstash-logger/device/base.rb +73 -0
- data/lib/logstash-logger/device/connectable.rb +131 -0
- data/lib/logstash-logger/device/file.rb +23 -0
- data/lib/logstash-logger/device/firehose.rb +42 -0
- data/lib/logstash-logger/device/io.rb +11 -0
- data/lib/logstash-logger/device/kafka.rb +57 -0
- data/lib/logstash-logger/device/kinesis.rb +44 -0
- data/lib/logstash-logger/device/multi_delegator.rb +36 -0
- data/lib/logstash-logger/device/redis.rb +76 -0
- data/lib/logstash-logger/device/socket.rb +21 -0
- data/lib/logstash-logger/device/stderr.rb +13 -0
- data/lib/logstash-logger/device/stdout.rb +14 -0
- data/lib/logstash-logger/device/tcp.rb +86 -0
- data/lib/logstash-logger/device/udp.rb +12 -0
- data/lib/logstash-logger/device/unix.rb +18 -0
- data/lib/logstash-logger/device.rb +67 -0
- data/lib/logstash-logger/formatter/base.rb +73 -0
- data/lib/logstash-logger/formatter/cee.rb +11 -0
- data/lib/logstash-logger/formatter/cee_syslog.rb +22 -0
- data/lib/logstash-logger/formatter/json.rb +11 -0
- data/lib/logstash-logger/formatter/json_lines.rb +11 -0
- data/lib/logstash-logger/formatter/logstash_event.rb +6 -0
- data/lib/logstash-logger/formatter.rb +51 -0
- data/lib/logstash-logger/logger.rb +106 -0
- data/lib/logstash-logger/multi_logger.rb +153 -0
- data/lib/logstash-logger/railtie.rb +51 -0
- data/lib/logstash-logger/silenced_logging.rb +83 -0
- data/lib/logstash-logger/tagged_logging.rb +40 -0
- data/lib/logstash-logger/version.rb +3 -0
- data/lib/logstash-logger.rb +11 -0
- data/logstash-logger.gemspec +39 -0
- data/samples/example.crt +16 -0
- data/samples/example.key +15 -0
- data/samples/file.conf +11 -0
- data/samples/redis.conf +12 -0
- data/samples/ssl.conf +15 -0
- data/samples/syslog.conf +10 -0
- data/samples/tcp.conf +11 -0
- data/samples/udp.conf +11 -0
- data/samples/unix.conf +11 -0
- data/spec/configuration_spec.rb +27 -0
- data/spec/constructor_spec.rb +30 -0
- data/spec/device/balancer_spec.rb +31 -0
- data/spec/device/connectable_spec.rb +74 -0
- data/spec/device/file_spec.rb +15 -0
- data/spec/device/firehose_spec.rb +41 -0
- data/spec/device/io_spec.rb +13 -0
- data/spec/device/kafka_spec.rb +32 -0
- data/spec/device/kinesis_spec.rb +41 -0
- data/spec/device/multi_delegator_spec.rb +31 -0
- data/spec/device/redis_spec.rb +52 -0
- data/spec/device/socket_spec.rb +15 -0
- data/spec/device/stderr_spec.rb +16 -0
- data/spec/device/stdout_spec.rb +31 -0
- data/spec/device/tcp_spec.rb +120 -0
- data/spec/device/udp_spec.rb +9 -0
- data/spec/device/unix_spec.rb +23 -0
- data/spec/device_spec.rb +97 -0
- data/spec/formatter/base_spec.rb +125 -0
- data/spec/formatter/cee_spec.rb +15 -0
- data/spec/formatter/cee_syslog_spec.rb +43 -0
- data/spec/formatter/json_lines_spec.rb +14 -0
- data/spec/formatter/json_spec.rb +10 -0
- data/spec/formatter/logstash_event_spec.rb +10 -0
- data/spec/formatter_spec.rb +79 -0
- data/spec/logger_spec.rb +128 -0
- data/spec/multi_logger_spec.rb +59 -0
- data/spec/rails_spec.rb +91 -0
- data/spec/silenced_logging_spec.rb +31 -0
- data/spec/spec_helper.rb +111 -0
- data/spec/syslog_spec.rb +32 -0
- data/spec/tagged_logging_spec.rb +32 -0
- metadata +335 -0
@@ -0,0 +1,120 @@
|
|
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(tcp_socket).to receive(:sync=)
|
12
|
+
|
13
|
+
allow(OpenSSL::SSL::SSLSocket).to receive(:new) { ssl_socket }
|
14
|
+
allow(ssl_socket).to receive(:connect)
|
15
|
+
allow(ssl_socket).to receive(:post_connection_check)
|
16
|
+
allow(ssl_tcp_device).to receive(:warn)
|
17
|
+
end
|
18
|
+
|
19
|
+
context "when not using SSL" do
|
20
|
+
it "writes to a TCP socket" do
|
21
|
+
expect(tcp_socket).to receive(:write)
|
22
|
+
tcp_device.write('test')
|
23
|
+
end
|
24
|
+
|
25
|
+
it "returns false for #use_ssl?" do
|
26
|
+
expect(tcp_device.use_ssl?).to be_falsey
|
27
|
+
end
|
28
|
+
|
29
|
+
it "exposes the TCP socket via #io" do
|
30
|
+
expect(tcp_device.io).to eq tcp_socket
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "when using SSL" do
|
35
|
+
it "writes to an SSL TCP socket" do
|
36
|
+
expect(ssl_socket).to receive(:write)
|
37
|
+
ssl_tcp_device.write('test')
|
38
|
+
end
|
39
|
+
|
40
|
+
it "returns true for #use_ssl?" do
|
41
|
+
expect(ssl_tcp_device.use_ssl?).to be_truthy
|
42
|
+
end
|
43
|
+
|
44
|
+
it "exposes the SSL socket via #io" do
|
45
|
+
expect(ssl_tcp_device.io).to eq ssl_socket
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'hostname validation' do
|
49
|
+
let(:ssl_context) { double('test_ssl_context', verify_mode: OpenSSL::SSL::VERIFY_PEER) }
|
50
|
+
let(:ssl_tcp_options) { { type: :tcp, port: port, sync: true, ssl_context: ssl_context } }
|
51
|
+
|
52
|
+
context 'is enabled by default' do
|
53
|
+
let(:ssl_tcp_device) { LogStashLogger::Device.new(ssl_tcp_options) }
|
54
|
+
|
55
|
+
it 'validates' do
|
56
|
+
expect(ssl_tcp_device.send(:verify_hostname?)).to be_truthy
|
57
|
+
expect(ssl_socket).to receive(:post_connection_check).with HOST
|
58
|
+
ssl_tcp_device.connect
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context 'is disabled explicitly' do
|
63
|
+
let(:ssl_tcp_device) { LogStashLogger::Device.new(ssl_tcp_options.merge(verify_hostname: false)) }
|
64
|
+
|
65
|
+
it 'does not validate' do
|
66
|
+
expect(ssl_tcp_device.send(:verify_hostname?)).to be_falsey
|
67
|
+
expect(ssl_socket).not_to receive(:post_connection_check)
|
68
|
+
ssl_tcp_device.connect
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'is implicitly enabled by providing a hostname' do
|
73
|
+
let(:hostname) { 'www.example.com' }
|
74
|
+
let(:ssl_tcp_device) { LogStashLogger::Device.new(ssl_tcp_options.merge(verify_hostname: hostname)) }
|
75
|
+
|
76
|
+
it 'validates with supplied hostname' do
|
77
|
+
expect(ssl_socket).to receive(:post_connection_check).with hostname
|
78
|
+
ssl_tcp_device.connect
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'with a provided SSL context' do
|
84
|
+
let(:ssl_context) { double('test_ssl_context', verify_mode: OpenSSL::SSL::VERIFY_PEER) }
|
85
|
+
let(:ssl_tcp_device) { LogStashLogger::Device.new(type: :tcp, port: port, sync: true, ssl_context: ssl_context) }
|
86
|
+
|
87
|
+
it 'creates the socket using that context' do
|
88
|
+
expect(OpenSSL::SSL::SSLSocket).to receive(:new).with(tcp_socket, ssl_context)
|
89
|
+
ssl_tcp_device.connect
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'implicitly sets @use_ssl to true' do
|
93
|
+
expect(ssl_tcp_device.use_ssl?).to be_truthy
|
94
|
+
end
|
95
|
+
|
96
|
+
context 'and :ssl_enable explicitly set to false' do
|
97
|
+
let(:ssl_tcp_device) { LogStashLogger::Device.new(type: :tcp, port: port, sync: true, ssl_enable: false, ssl_context: ssl_context) }
|
98
|
+
|
99
|
+
it 'explicitly sets @use_ssl to false' do
|
100
|
+
expect(ssl_tcp_device.use_ssl?).to be_falsey
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context 'without a provided SSL context' do
|
106
|
+
it 'ssl_context returns nil' do
|
107
|
+
expect(ssl_tcp_device.ssl_context).to be_nil
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
context 'only providing a certificate file' do
|
112
|
+
let(:ssl_tcp_device) { LogStashLogger::Device.new(type: :tcp, port: port, ssl_enable: true, sync: true, ssl_certificate: '/path/to/cert.pem') }
|
113
|
+
|
114
|
+
it 'implicitly uses a context with the configured certificate' do
|
115
|
+
expect(ssl_tcp_device.ssl_context.cert).to eq('/path/to/cert.pem')
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'logstash-logger'
|
2
|
+
|
3
|
+
describe LogStashLogger::Device::Unix do
|
4
|
+
include_context 'device'
|
5
|
+
|
6
|
+
let(:unix_socket) { double("UNIXSocket") }
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
allow(::UNIXSocket).to receive(:new) { unix_socket }
|
10
|
+
allow(unix_socket).to receive(:sync=)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "writes to a local unix socket" do
|
14
|
+
expect(unix_socket).to receive(:write)
|
15
|
+
unix_device.write('foo')
|
16
|
+
end
|
17
|
+
|
18
|
+
context "when path is not specified" do
|
19
|
+
it "raises an exception" do
|
20
|
+
expect { described_class.new }.to raise_error(ArgumentError)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/spec/device_spec.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'logstash-logger'
|
2
|
+
|
3
|
+
describe LogStashLogger::Device do
|
4
|
+
include_context 'device'
|
5
|
+
|
6
|
+
context "when port is specified" do
|
7
|
+
it "defaults type to UDP" do
|
8
|
+
expect(device_with_port).to be_a LogStashLogger::Device::UDP
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
context "when passing in configuration" do
|
13
|
+
let(:configuration) { {type: :udp, port: port} }
|
14
|
+
|
15
|
+
subject(:new_device) { described_class.new(configuration) }
|
16
|
+
|
17
|
+
it "does not mutate the passed configuration" do
|
18
|
+
expect{ new_device }.to_not change { configuration }
|
19
|
+
expect( new_device ).to be_a LogStashLogger::Device::UDP
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context "when configuration type is a String" do
|
24
|
+
let(:configuration) { {type: "udp", port: port} }
|
25
|
+
|
26
|
+
subject(:new_device) { described_class.new(configuration) }
|
27
|
+
|
28
|
+
it "it correctly recognizes the device type" do
|
29
|
+
expect(new_device).to be_a LogStashLogger::Device::UDP
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe ".parse_uri_config" do
|
34
|
+
subject(:parse_uri_config) { described_class.parse_uri_config(uri_config) }
|
35
|
+
|
36
|
+
context "when uri_config is valid" do
|
37
|
+
let(:uri_config) { udp_uri_config }
|
38
|
+
it { is_expected.to eq({type: 'udp', host: 'localhost', port: 5228, path: ''}) }
|
39
|
+
end
|
40
|
+
|
41
|
+
context "when uri is invalid" do
|
42
|
+
let(:uri_config) { invalid_uri_config }
|
43
|
+
specify { expect { parse_uri_config }.to raise_error(URI::InvalidURIError) }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "Parsing URI configurations" do
|
48
|
+
subject(:new_device) { described_class.new(uri_config) }
|
49
|
+
|
50
|
+
context "when URI config is udp" do
|
51
|
+
let(:uri_config) { udp_uri_config }
|
52
|
+
it { is_expected.to be_a LogStashLogger::Device::UDP }
|
53
|
+
end
|
54
|
+
|
55
|
+
context "when URI config is tcp" do
|
56
|
+
let(:uri_config) { tcp_uri_config }
|
57
|
+
it { is_expected.to be_a LogStashLogger::Device::TCP }
|
58
|
+
end
|
59
|
+
|
60
|
+
context "when URI config is unix" do
|
61
|
+
let(:uri_config) { unix_uri_config }
|
62
|
+
it { is_expected.to be_a LogStashLogger::Device::Unix }
|
63
|
+
end
|
64
|
+
|
65
|
+
context "when URI config is file" do
|
66
|
+
let(:uri_config) { file_uri_config }
|
67
|
+
it { is_expected.to be_a LogStashLogger::Device::File }
|
68
|
+
end
|
69
|
+
|
70
|
+
context "when URI config is redis" do
|
71
|
+
let(:uri_config) { redis_uri_config }
|
72
|
+
it { is_expected.to be_a LogStashLogger::Device::Redis }
|
73
|
+
context "list specified" do
|
74
|
+
let(:uri_config) { redis_uri_config.merge({list: 'mylist'}) }
|
75
|
+
it 'is expected to have the list option set' do
|
76
|
+
expect(new_device.list).to eq('mylist')
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context "when URI config is kafka" do
|
82
|
+
let(:uri_config) { kafka_uri_config }
|
83
|
+
it { is_expected.to be_a LogStashLogger::Device::Kafka }
|
84
|
+
end
|
85
|
+
|
86
|
+
context "when URI config is stdout" do
|
87
|
+
let(:uri_config) { stdout_uri_config }
|
88
|
+
it { is_expected.to be_a LogStashLogger::Device::Stdout }
|
89
|
+
end
|
90
|
+
|
91
|
+
context 'when URI config is stderr' do
|
92
|
+
let(:uri_config) { stderr_uri_config }
|
93
|
+
it { is_expected.to be_a LogStashLogger::Device::Stderr }
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require 'logstash-logger'
|
2
|
+
|
3
|
+
describe LogStashLogger::Formatter::Base do
|
4
|
+
include_context "formatter"
|
5
|
+
|
6
|
+
describe "#call" do
|
7
|
+
context "when event is not cancelled" do
|
8
|
+
it "returns a formatted message" do
|
9
|
+
expect(subject).to receive(:format_event).once.with(instance_of(LogStash::Event)).and_call_original
|
10
|
+
expect(subject.call(severity, time, progname, message)).to be_a(LogStash::Event)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context "when event is cancelled" do
|
15
|
+
before(:each) do
|
16
|
+
LogStashLogger.configure do |config|
|
17
|
+
config.customize_event(&:cancel)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it "returns `nil`" do
|
22
|
+
expect(subject).not_to receive(:format_event)
|
23
|
+
expect(subject.call(severity, time, progname, message)).to be_nil
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "#build_event" do
|
29
|
+
let(:event) { formatted_message }
|
30
|
+
|
31
|
+
describe "message type" do
|
32
|
+
context "string" do
|
33
|
+
it "puts the message into the message field" do
|
34
|
+
expect(event['message']).to eq(message)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "JSON string" do
|
39
|
+
let(:message) do
|
40
|
+
{ message: 'test', foo: 'bar' }.to_json
|
41
|
+
end
|
42
|
+
|
43
|
+
it "parses the JSON and merges into the event" do
|
44
|
+
expect(event['message']).to eq('test')
|
45
|
+
expect(event['foo']).to eq('bar')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context "hash" do
|
50
|
+
let(:message) do
|
51
|
+
{ 'message' => 'test', 'foo' => 'bar' }
|
52
|
+
end
|
53
|
+
|
54
|
+
it "merges into the event" do
|
55
|
+
expect(event['message']).to eq('test')
|
56
|
+
expect(event['foo']).to eq('bar')
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context "LogStash::Event" do
|
61
|
+
let(:message) { LogStash::Event.new("message" => "foo") }
|
62
|
+
|
63
|
+
it "returns a clone of the original event" do
|
64
|
+
expect(event['message']).to eq("foo")
|
65
|
+
expect(event).to_not equal(message)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context "fallback" do
|
70
|
+
let(:message) { [1, 2, 3] }
|
71
|
+
|
72
|
+
it "calls inspect" do
|
73
|
+
expect(event['message']).to eq(message.inspect)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "extra fields on the event" do
|
79
|
+
it "adds severity" do
|
80
|
+
expect(event['severity']).to eq(severity)
|
81
|
+
end
|
82
|
+
|
83
|
+
it "adds host" do
|
84
|
+
expect(event['host']).to eq(hostname)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe "timestamp" do
|
89
|
+
it "ensures time is in ISO8601 format" do
|
90
|
+
expect(event.timestamp).to eq(time.iso8601(3))
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe "long messages" do
|
95
|
+
|
96
|
+
context "message field is present" do
|
97
|
+
let(:message) { long_message }
|
98
|
+
|
99
|
+
it "truncates long messages when max_message_size is set" do
|
100
|
+
LogStashLogger.configure do |config|
|
101
|
+
config.max_message_size = 2000
|
102
|
+
end
|
103
|
+
|
104
|
+
expect(event['message'].size).to eq(2000)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
context "event without message field" do
|
109
|
+
let(:message) do
|
110
|
+
{ 'test_field' => 'test', 'foo' => 'bar' }
|
111
|
+
end
|
112
|
+
|
113
|
+
it "still works" do
|
114
|
+
LogStashLogger.configure do |config|
|
115
|
+
config.max_message_size = 2000
|
116
|
+
end
|
117
|
+
|
118
|
+
expect(event['message']).to eq(nil)
|
119
|
+
expect(event['test_field']).to eq('test')
|
120
|
+
expect(event['foo']).to eq('bar')
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'logstash-logger'
|
2
|
+
|
3
|
+
describe LogStashLogger::Formatter::Cee do
|
4
|
+
include_context "formatter"
|
5
|
+
|
6
|
+
it "outputs in CEE format" do
|
7
|
+
expect(formatted_message).to match(/\A@cee:/)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "serializes the LogStash::Event data as JSON" do
|
11
|
+
json_data = formatted_message[/\A@cee:\s?(.*)\z/, 1]
|
12
|
+
json_message = JSON.parse(json_data)
|
13
|
+
expect(json_message["message"]).to eq(message)
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'logstash-logger'
|
2
|
+
|
3
|
+
describe LogStashLogger::Formatter::CeeSyslog do
|
4
|
+
include_context "formatter"
|
5
|
+
|
6
|
+
describe "#call" do
|
7
|
+
let(:facility) { "facility" }
|
8
|
+
|
9
|
+
before do
|
10
|
+
allow(subject).to receive(:build_facility).and_return(facility)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "outputs a facility before the @cee" do
|
14
|
+
expect(formatted_message).to match(/\A#{facility}:@cee:/)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "serializes the LogStash::Event data as JSON" do
|
18
|
+
json_data = formatted_message[/\A#{facility}:@cee:\s?(.*)\Z/, 1]
|
19
|
+
json_message = JSON.parse(json_data)
|
20
|
+
expect(json_message["message"]).to eq(message)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#build_facility" do
|
25
|
+
let(:host) { Socket.gethostname }
|
26
|
+
|
27
|
+
before do
|
28
|
+
formatted_message
|
29
|
+
end
|
30
|
+
|
31
|
+
it "includes hostname and progname" do
|
32
|
+
expect(subject.send(:build_facility, host)).to match(/\A#{host}\s#{progname}\z/)
|
33
|
+
end
|
34
|
+
|
35
|
+
context "without progname" do
|
36
|
+
let(:progname) { nil }
|
37
|
+
|
38
|
+
it "only includes hostname" do
|
39
|
+
expect(subject.send(:build_facility, host)).to match(/\A#{host}\z/)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'logstash-logger'
|
2
|
+
|
3
|
+
describe LogStashLogger::Formatter::JsonLines do
|
4
|
+
include_context "formatter"
|
5
|
+
|
6
|
+
it "outputs in JSON format" do
|
7
|
+
json_message = JSON.parse(formatted_message)
|
8
|
+
expect(json_message["message"]).to eq(message)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "terminates with a line break" do
|
12
|
+
expect(formatted_message[-1]).to eq("\n")
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'logstash-logger'
|
2
|
+
|
3
|
+
describe LogStashLogger::Formatter::LogStashEvent do
|
4
|
+
include_context "formatter"
|
5
|
+
|
6
|
+
it "outputs a LogStash::Event" do
|
7
|
+
expect(formatted_message).to be_a LogStash::Event
|
8
|
+
expect(formatted_message["message"]).to eq(message)
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'logstash-logger'
|
2
|
+
|
3
|
+
describe LogStashLogger::Formatter do
|
4
|
+
describe "#new" do
|
5
|
+
context "built in formatters" do
|
6
|
+
it "returns a new JsonLines formatter" do
|
7
|
+
expect(described_class.new(:json_lines)).to be_a LogStashLogger::Formatter::JsonLines
|
8
|
+
end
|
9
|
+
|
10
|
+
it "returns a new Json formatter" do
|
11
|
+
expect(described_class.new(:json)).to be_a LogStashLogger::Formatter::Json
|
12
|
+
end
|
13
|
+
|
14
|
+
it "returns a new Cee formatter" do
|
15
|
+
expect(described_class.new(:cee)).to be_a LogStashLogger::Formatter::Cee
|
16
|
+
end
|
17
|
+
|
18
|
+
it "returns a new CeeSyslog formatter" do
|
19
|
+
expect(described_class.new(:cee_syslog)).to be_a LogStashLogger::Formatter::CeeSyslog
|
20
|
+
end
|
21
|
+
|
22
|
+
it "returns a new LogStashEvent formatter" do
|
23
|
+
expect(described_class.new(:logstash_event)).to be_a LogStashLogger::Formatter::LogStashEvent
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "custom formatter" do
|
28
|
+
subject { described_class.new(formatter) }
|
29
|
+
|
30
|
+
context "formatter class" do
|
31
|
+
let(:formatter) { ::Logger::Formatter }
|
32
|
+
|
33
|
+
it "returns a new instance of the class" do
|
34
|
+
expect(subject).to be_a formatter
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "formatter instance" do
|
39
|
+
let(:formatter) { ::Logger::Formatter.new }
|
40
|
+
|
41
|
+
it "returns the same formatter instance" do
|
42
|
+
expect(subject).to eql(formatter)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "supports tagged logging" do
|
46
|
+
expect(subject).to be_a ::LogStashLogger::TaggedLogging::Formatter
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "formatter proc" do
|
51
|
+
let(:formatter) do
|
52
|
+
proc { |severity, time, progname, msg| msg }
|
53
|
+
end
|
54
|
+
|
55
|
+
it "returns the same formatter proc" do
|
56
|
+
expect(subject).to eql(formatter)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "supports tagged logging" do
|
60
|
+
expect(subject).to be_a ::LogStashLogger::TaggedLogging::Formatter
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context "formatter lambda" do
|
65
|
+
let(:formatter) do
|
66
|
+
->(severity, time, progname, msg) { msg }
|
67
|
+
end
|
68
|
+
|
69
|
+
it "returns the same formatter lambda" do
|
70
|
+
expect(subject).to eql(formatter)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "supports tagged logging" do
|
74
|
+
expect(subject).to be_a ::LogStashLogger::TaggedLogging::Formatter
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
data/spec/logger_spec.rb
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'logstash-logger'
|
2
|
+
|
3
|
+
describe LogStashLogger do
|
4
|
+
include_context 'logger'
|
5
|
+
|
6
|
+
let! :listener do
|
7
|
+
case connection_type
|
8
|
+
when :tcp
|
9
|
+
TCPServer.new(port)
|
10
|
+
when :udp
|
11
|
+
UDPSocket.new.tap {|socket| socket.bind(host, port)}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# The TCP socket written to by the TCP logstash listener server
|
16
|
+
let(:tcp_client) { listener.accept }
|
17
|
+
|
18
|
+
# The logstash event to log
|
19
|
+
let(:logstash_event) do
|
20
|
+
LogStash::Event.new.tap do |event|
|
21
|
+
event['message'] = 'test'
|
22
|
+
event['severity'] = 'INFO'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# The raw input received by the logstash listener
|
27
|
+
let :listener_input do
|
28
|
+
case connection_type
|
29
|
+
when :tcp then tcp_client.readline
|
30
|
+
when :udp then listener.recvfrom(8192)[0]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# The logstash event received by the listener
|
35
|
+
let(:listener_event) { LogStash::Event.new(JSON.parse listener_input) }
|
36
|
+
|
37
|
+
#before(:each) do
|
38
|
+
# Sync socket writes so we can receive them in the listener immediately
|
39
|
+
#@socket = logdev.instance_variable_get(:@dev).send(:connect)
|
40
|
+
#@socket.sync = true
|
41
|
+
#end
|
42
|
+
|
43
|
+
after(:each) do
|
44
|
+
listener.close
|
45
|
+
end
|
46
|
+
|
47
|
+
# The socket that the logger is writing to
|
48
|
+
#let(:socket) { @socket }
|
49
|
+
|
50
|
+
it 'uses a LogStashLogger::Device as the log device' do
|
51
|
+
expect(logdev).to be_a Logger::LogDevice
|
52
|
+
expect(logdev.instance_variable_get(:@dev)).to be_a LogStashLogger::Device::Base
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'takes a string message as input and writes a logstash event' do
|
56
|
+
message = 'test'
|
57
|
+
logger.info(message)
|
58
|
+
|
59
|
+
expect(listener_event['severity']).to eql('INFO')
|
60
|
+
expect(listener_event['message']).to eq(message)
|
61
|
+
expect(listener_event['host']).to eq(hostname)
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'takes a logstash-formatted json string as input and writes out a logstash event' do
|
65
|
+
logger.info(logstash_event.to_json)
|
66
|
+
|
67
|
+
expect(listener_event['message']).to eq(logstash_event['message'])
|
68
|
+
expect(listener_event['host']).to eq(hostname)
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'takes a LogStash::Event as input and writes it out intact' do
|
72
|
+
logger.warn(logstash_event)
|
73
|
+
|
74
|
+
expect(listener_event['message']).to eq(logstash_event['message'])
|
75
|
+
expect(listener_event['severity']).to eq(logstash_event['severity'])
|
76
|
+
expect(listener_event['@timestamp'].iso8601).to eq(logstash_event.timestamp.iso8601)
|
77
|
+
expect(listener_event['host']).to eq(hostname)
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'takes a data hash as input and writes out a logstash event' do
|
81
|
+
data = {
|
82
|
+
'message' => 'test',
|
83
|
+
'severity' => 'INFO',
|
84
|
+
'foo' => 'bar'
|
85
|
+
}
|
86
|
+
|
87
|
+
logger.info(data.dup)
|
88
|
+
|
89
|
+
expect(listener_event['message']).to eq(data["message"])
|
90
|
+
expect(listener_event['severity']).to eq(data['severity'])
|
91
|
+
expect(listener_event['foo']).to eq(data['foo'])
|
92
|
+
expect(listener_event['host']).to eq(hostname)
|
93
|
+
expect(listener_event['@timestamp']).to_not be_nil
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'takes any object as input and writes a logstash event' do
|
97
|
+
message = Time.now
|
98
|
+
|
99
|
+
logger.info(message)
|
100
|
+
|
101
|
+
expect(listener_event['message']).to eq(message.inspect)
|
102
|
+
expect(listener_event['host']).to eq(hostname)
|
103
|
+
expect(listener_event['severity']).to eq('INFO')
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'allows event to be customized via configuration' do
|
107
|
+
LogStashLogger.configure do |config|
|
108
|
+
config.customize_event do |event|
|
109
|
+
event["test1"] = "response1"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
logger.info("test")
|
114
|
+
|
115
|
+
expect(listener_event["test1"]).to eq("response1")
|
116
|
+
end
|
117
|
+
|
118
|
+
describe 'customize_event on instance' do
|
119
|
+
let!(:customize_event) { ->(event){ event['custom'] = 'custom' } }
|
120
|
+
let!(:logger) { LogStashLogger.new(host: host, port: port, type: connection_type, sync: true, customize_event: customize_event)}
|
121
|
+
|
122
|
+
specify 'logger produce messages with custom field' do
|
123
|
+
logger.info('test')
|
124
|
+
expect(listener_event['custom']).to eq('custom')
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|