logstash-logger 0.2.1 → 0.3.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 +7 -0
- data/README.md +34 -6
- data/Rakefile +16 -2
- data/lib/logstash-logger.rb +1 -2
- data/lib/logstash-logger/logger.rb +3 -3
- data/lib/logstash-logger/socket.rb +34 -0
- data/lib/logstash-logger/version.rb +1 -1
- data/spec/logger_spec.rb +80 -30
- metadata +14 -28
- data/lib/logstash-logger/tcp_client.rb +0 -30
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 289d8d944755e6c3be2857d075b37d8e5c560a45
|
4
|
+
data.tar.gz: 8fdff518b64fdb1c71dc60ba6f9f75183a092831
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: dc0992ffd0c6e3478d8018590bcb16fbd436713672c4fc9a6a64595d563002cea11e8f4dae61eb8c99b239f29215213c5ac1dd4dcfccf6ac766a5b241807848c
|
7
|
+
data.tar.gz: ad911e6164b8fc9d53d7f0afb54b68ce0d3f8eef091f4513920cb5fab8645cb5b3366b81c7e7763d491b342140f906bad55a101b341d2857a760252f59789e4c
|
data/README.md
CHANGED
@@ -6,7 +6,7 @@ writing to a file or syslog since logstash can receive the structured data direc
|
|
6
6
|
|
7
7
|
## Features
|
8
8
|
|
9
|
-
* Writes directly to logstash over a TCP connection.
|
9
|
+
* Writes directly to logstash over a UDP or TCP connection.
|
10
10
|
* Always writes in logstash JSON format.
|
11
11
|
* Logger can take a string message, a hash, a LogStash::Event, or a logstash-formatted json string as input.
|
12
12
|
* Events are automatically populated with message, timestamp, host, and severity.
|
@@ -25,14 +25,23 @@ Or install it yourself as:
|
|
25
25
|
|
26
26
|
$ gem install logstash-logger
|
27
27
|
|
28
|
-
## Usage
|
28
|
+
## Basic Usage
|
29
29
|
|
30
|
-
First set up a logstash agent to receive input over a TCP port.
|
30
|
+
First set up a logstash agent to receive input over a UDP or TCP port.
|
31
|
+
Then in ruby, create a LogStashLogger that writes to that port.
|
31
32
|
|
32
33
|
```ruby
|
34
|
+
require 'logstash-logger'
|
35
|
+
|
36
|
+
# Defaults to UDP
|
33
37
|
logger = LogStashLogger.new('localhost', 5228)
|
34
38
|
logger.info 'test'
|
35
|
-
#
|
39
|
+
# Writes the following to UDP port 5228:
|
40
|
+
# {"@source":"server-host-name","@tags":[],"@fields":{"severity":"INFO"},"@message":"test","@timestamp":"2013-04-08T18:56:23.767273+00:00"}
|
41
|
+
|
42
|
+
# Specify UDP or TCP explicitly
|
43
|
+
udp_logger = LogStashLogger.new('localhost', 5228, :udp)
|
44
|
+
tcp_logger = LogStashLogger.new('localhost', 5229, :tcp)
|
36
45
|
```
|
37
46
|
|
38
47
|
## Rails integration
|
@@ -49,7 +58,15 @@ To get Rails to nicely output its logs in structured logstash format, try one of
|
|
49
58
|
* [yarder](https://github.com/rurounijones/yarder)
|
50
59
|
|
51
60
|
Currently these gems output a JSON string, which LogStashLogger then parses.
|
52
|
-
Future versions of these gems could potentially have deeper integration with LogStashLogger.
|
61
|
+
Future versions of these gems could potentially have deeper integration with LogStashLogger (i.e. by writing LogStash::Event objects).
|
62
|
+
|
63
|
+
## UDP vs TCP
|
64
|
+
Should you write to a UDP or TCP listener? It depends on your specific needs, but most applications should use the default (UDP).
|
65
|
+
|
66
|
+
* UDP is faster because it's asynchronous (fire-and-forget). However, this means that log messages could get dropped. This is okay for most applications.
|
67
|
+
* TCP verifies that every message has been received via two-way communication . This could slow your app down to a crawl if the TCP listener is under heavy load.
|
68
|
+
|
69
|
+
For a more detailed discussion of UDP vs TCP, I recommend reading this article: [UDP vs. TCP](http://gafferongames.com/networking-for-game-programmers/udp-vs-tcp/)
|
53
70
|
|
54
71
|
## Ruby compatibility
|
55
72
|
|
@@ -61,7 +78,18 @@ Verified to work with:
|
|
61
78
|
|
62
79
|
Ruby 1.8.7 is not supported because LogStash::Event is not compatible with Ruby 1.8.7. This might change in the future.
|
63
80
|
|
64
|
-
|
81
|
+
The specs don't pass in Rubinius yet, but the logger does work.
|
82
|
+
|
83
|
+
## Breaking change in version 0.3+
|
84
|
+
Earlier versions of this gem (<= 0.2.1) only implemented a TCP connection. Newer versions (>= 0.3) also implement UDP, and use that as the new default.
|
85
|
+
Please be aware if you are using the default constructor and still require TCP, you should add an additional argument:
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
# Now defaults to UDP instead of TCP
|
89
|
+
logger = LogStashLogger.new('localhost', 5228)
|
90
|
+
# Explicitly specify TCP instead of UDP
|
91
|
+
logger = LogStashLogger.new('localhost', 5228, :tcp)
|
92
|
+
```
|
65
93
|
|
66
94
|
## Contributing
|
67
95
|
|
data/Rakefile
CHANGED
@@ -2,10 +2,24 @@
|
|
2
2
|
require "bundler/gem_tasks"
|
3
3
|
require 'rspec/core/rake_task'
|
4
4
|
|
5
|
-
desc "Run all specs"
|
5
|
+
desc "Run all specs with default options"
|
6
6
|
RSpec::Core::RakeTask.new(:spec) do |t|
|
7
7
|
t.rspec_opts = %w[--color]
|
8
8
|
t.verbose = false
|
9
9
|
end
|
10
10
|
|
11
|
-
|
11
|
+
desc "Run specs with TCP socket"
|
12
|
+
RSpec::Core::RakeTask.new("spec:tcp") do |t|
|
13
|
+
ENV['SOCKET_TYPE'] = 'tcp'
|
14
|
+
t.rspec_opts = %w[--color]
|
15
|
+
t.verbose = false
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "Run specs with UDP socket"
|
19
|
+
RSpec::Core::RakeTask.new("spec:udp") do |t|
|
20
|
+
ENV['SOCKET_TYPE'] = 'udp'
|
21
|
+
t.rspec_opts = %w[--color]
|
22
|
+
t.verbose = false
|
23
|
+
end
|
24
|
+
|
25
|
+
task :default => ["spec:tcp", "spec:udp"]
|
data/lib/logstash-logger.rb
CHANGED
@@ -3,10 +3,10 @@ class LogStashLogger < ::Logger
|
|
3
3
|
attr_reader :client
|
4
4
|
|
5
5
|
LOGSTASH_EVENT_FIELDS = %w(@timestamp @tags @type @source @fields @message).freeze
|
6
|
-
HOST = Socket.gethostname
|
6
|
+
HOST = ::Socket.gethostname
|
7
7
|
|
8
|
-
def initialize(host, port)
|
9
|
-
super(::LogStashLogger::
|
8
|
+
def initialize(host, port, socket_type=:udp)
|
9
|
+
super(::LogStashLogger::Socket.new(host, port, socket_type))
|
10
10
|
end
|
11
11
|
|
12
12
|
def add(severity, message = nil, progname = nil, &block)
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class LogStashLogger::Socket
|
2
|
+
def initialize(host, port, socket_type = :udp)
|
3
|
+
@host = host
|
4
|
+
@port = port
|
5
|
+
@type = socket_type
|
6
|
+
@socket = nil
|
7
|
+
end
|
8
|
+
|
9
|
+
def write(event)
|
10
|
+
begin
|
11
|
+
connect unless @socket
|
12
|
+
|
13
|
+
@socket.write("#{event.to_hash.to_json}\n")
|
14
|
+
rescue => e
|
15
|
+
warn "#{self.class} - #{e.class} - #{e.message}"
|
16
|
+
close
|
17
|
+
@socket = nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def close
|
22
|
+
@socket && @socket.close
|
23
|
+
rescue => e
|
24
|
+
warn "#{self.class} - #{e.class} - #{e.message}"
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
def connect
|
29
|
+
@socket = case @type
|
30
|
+
when :udp then UDPSocket.new.tap {|s| s.connect(@host, @port)}
|
31
|
+
when :tcp then TCPSocket.new(@host, @port)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/spec/logger_spec.rb
CHANGED
@@ -1,80 +1,130 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe LogStashLogger do
|
4
|
-
|
4
|
+
# The type of socket we're testing
|
5
|
+
def socket_type
|
6
|
+
@socket_type ||= (ENV['SOCKET_TYPE'] || 'UDP').to_s.downcase.to_sym
|
7
|
+
end
|
8
|
+
|
9
|
+
before(:all) { puts "Testing with #{socket_type.to_s.upcase} socket type" }
|
10
|
+
|
11
|
+
let(:host) { '0.0.0.0' }
|
12
|
+
let(:hostname) { Socket.gethostname }
|
5
13
|
let(:port) { 5228 }
|
6
|
-
let(:server) { TCPServer.new(port) }
|
7
|
-
let(:host) { Socket.gethostname }
|
8
14
|
|
9
|
-
|
10
|
-
|
15
|
+
# The logstash logger
|
16
|
+
let(:logger) { LogStashLogger.new(host, port, socket_type) }
|
17
|
+
# The log device that the logger writes to
|
18
|
+
let(:logdev) { logger.instance_variable_get(:@logdev) }
|
19
|
+
|
20
|
+
let! :listener do
|
21
|
+
case socket_type
|
22
|
+
when :tcp
|
23
|
+
TCPServer.new(port)
|
24
|
+
when :udp
|
25
|
+
UDPSocket.new.tap {|socket| socket.bind(host, port)}
|
26
|
+
end
|
11
27
|
end
|
12
28
|
|
29
|
+
# The TCP socket written to by the TCP logstash listener server
|
30
|
+
let(:tcp_client) { listener.accept }
|
31
|
+
|
32
|
+
# The logstash event to log
|
13
33
|
let(:logstash_event) do
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
34
|
+
LogStash::Event.new.tap do |event|
|
35
|
+
event.message = 'test'
|
36
|
+
event['severity'] = 'INFO'
|
37
|
+
end
|
18
38
|
end
|
19
39
|
|
20
|
-
|
21
|
-
|
40
|
+
# The raw input received by the logstash listener
|
41
|
+
let :listener_input do
|
42
|
+
case socket_type
|
43
|
+
when :tcp then tcp_client.readline
|
44
|
+
when :udp then listener.recvfrom(8192)[0]
|
45
|
+
end
|
22
46
|
end
|
23
47
|
|
24
|
-
|
48
|
+
# The logstash event received by the listener
|
49
|
+
let(:listener_event) { LogStash::Event.new(JSON.parse listener_input) }
|
50
|
+
|
51
|
+
#before(:each) do
|
52
|
+
# Sync socket writes so we can receive them in the listener immediately
|
53
|
+
#@socket = logdev.instance_variable_get(:@dev).send(:connect)
|
54
|
+
#@socket.sync = true
|
55
|
+
#end
|
56
|
+
|
57
|
+
after(:each) do
|
58
|
+
listener.close
|
59
|
+
end
|
60
|
+
|
61
|
+
# The socket that the logger is writing to
|
62
|
+
#let(:socket) { @socket }
|
63
|
+
|
64
|
+
it 'uses a LogStashLogger::Socket as the log device' do
|
25
65
|
logdev.should be_a Logger::LogDevice
|
26
|
-
logdev.instance_variable_get(:@dev).should be_a LogStashLogger::
|
66
|
+
logdev.instance_variable_get(:@dev).should be_a LogStashLogger::Socket
|
27
67
|
end
|
28
68
|
|
29
|
-
it '
|
69
|
+
it 'takes a string message as input and writes a logstash event' do
|
30
70
|
message = 'test'
|
31
|
-
|
32
|
-
logdev.should_receive(:write) do |event|
|
71
|
+
|
72
|
+
logdev.should_receive(:write).and_call_original do |event|
|
33
73
|
event.should be_a LogStash::Event
|
34
|
-
event.source.should eql(
|
74
|
+
event.source.should eql(hostname)
|
35
75
|
event.message.should eql(message)
|
36
76
|
event['severity'].should eql('INFO')
|
37
77
|
end
|
38
78
|
|
39
|
-
|
79
|
+
logger.info(message)
|
80
|
+
|
81
|
+
listener_event.message.should == message
|
40
82
|
end
|
41
83
|
|
42
|
-
it '
|
43
|
-
logdev.should_receive(:write) do |event|
|
84
|
+
it 'takes a logstash-formatted json string as input and writes out a logstash event' do
|
85
|
+
logdev.should_receive(:write).and_call_original do |event|
|
44
86
|
event.should be_a LogStash::Event
|
45
87
|
event.message.should eql(logstash_event.message)
|
46
|
-
event.source.should eql(
|
88
|
+
event.source.should eql(hostname)
|
47
89
|
end
|
48
90
|
|
49
|
-
|
91
|
+
logger.info(logstash_event.to_json)
|
92
|
+
|
93
|
+
listener_event.message.should == logstash_event.message
|
50
94
|
end
|
51
95
|
|
52
|
-
it '
|
53
|
-
logdev.should_receive(:write) do |event|
|
96
|
+
it 'takes a LogStash::Event as input and writes it out intact' do
|
97
|
+
logdev.should_receive(:write).and_call_original do |event|
|
54
98
|
event.should be_a LogStash::Event
|
55
99
|
event.message.should eql(logstash_event.message)
|
56
100
|
event['severity'].should eql(logstash_event['severity'])
|
57
101
|
event.timestamp.should eql(logstash_event.timestamp)
|
58
|
-
event.source.should eql(
|
102
|
+
event.source.should eql(hostname)
|
59
103
|
end
|
60
104
|
|
61
|
-
|
105
|
+
logger.warn(logstash_event)
|
106
|
+
|
107
|
+
listener_event.message.should == logstash_event.message
|
108
|
+
listener_event['severity'].should == logstash_event['severity']
|
62
109
|
end
|
63
110
|
|
64
|
-
it '
|
111
|
+
it 'takes a data hash as input and writes out a logstash event' do
|
65
112
|
data = {
|
66
113
|
"@message" => 'test',
|
67
114
|
'severity' => 'INFO'
|
68
115
|
}
|
69
116
|
|
70
|
-
logdev.should_receive(:write) do |event|
|
117
|
+
logdev.should_receive(:write).and_call_original do |event|
|
71
118
|
event.should be_a LogStash::Event
|
72
119
|
event.message.should eql('test')
|
73
120
|
event['severity'].should eql('INFO')
|
74
|
-
event.source.should eql(
|
121
|
+
event.source.should eql(hostname)
|
75
122
|
end
|
76
123
|
|
77
|
-
|
124
|
+
logger.info(data.dup)
|
125
|
+
|
126
|
+
listener_event.message.should == data["@message"]
|
127
|
+
listener_event['severity'].should == data['severity']
|
78
128
|
end
|
79
129
|
|
80
130
|
end
|
metadata
CHANGED
@@ -1,62 +1,55 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstash-logger
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.3.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- David Butler
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2013-
|
11
|
+
date: 2013-04-08 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: logstash-event
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - '>='
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '0'
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - '>='
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: '0'
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: rspec
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - '>='
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: '0'
|
38
34
|
type: :development
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- -
|
38
|
+
- - '>='
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: '0'
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: rake
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
|
-
- -
|
45
|
+
- - '>='
|
52
46
|
- !ruby/object:Gem::Version
|
53
47
|
version: '0'
|
54
48
|
type: :development
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
|
-
- -
|
52
|
+
- - '>='
|
60
53
|
- !ruby/object:Gem::Version
|
61
54
|
version: '0'
|
62
55
|
description: Ruby logger that writes directly to LogStash
|
@@ -74,40 +67,33 @@ files:
|
|
74
67
|
- Rakefile
|
75
68
|
- lib/logstash-logger.rb
|
76
69
|
- lib/logstash-logger/logger.rb
|
77
|
-
- lib/logstash-logger/
|
70
|
+
- lib/logstash-logger/socket.rb
|
78
71
|
- lib/logstash-logger/version.rb
|
79
72
|
- logstash-logger.gemspec
|
80
73
|
- spec/logger_spec.rb
|
81
74
|
- spec/spec_helper.rb
|
82
75
|
homepage: http://github.com/dwbutler/logstash-logger
|
83
76
|
licenses: []
|
77
|
+
metadata: {}
|
84
78
|
post_install_message:
|
85
79
|
rdoc_options: []
|
86
80
|
require_paths:
|
87
81
|
- lib
|
88
82
|
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
83
|
requirements:
|
91
|
-
- -
|
84
|
+
- - '>='
|
92
85
|
- !ruby/object:Gem::Version
|
93
86
|
version: '0'
|
94
|
-
segments:
|
95
|
-
- 0
|
96
|
-
hash: -3685342851697372128
|
97
87
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
98
|
-
none: false
|
99
88
|
requirements:
|
100
|
-
- -
|
89
|
+
- - '>='
|
101
90
|
- !ruby/object:Gem::Version
|
102
91
|
version: '0'
|
103
|
-
segments:
|
104
|
-
- 0
|
105
|
-
hash: -3685342851697372128
|
106
92
|
requirements: []
|
107
93
|
rubyforge_project:
|
108
|
-
rubygems_version:
|
94
|
+
rubygems_version: 2.0.0
|
109
95
|
signing_key:
|
110
|
-
specification_version:
|
96
|
+
specification_version: 4
|
111
97
|
summary: LogStash Logger for ruby
|
112
98
|
test_files:
|
113
99
|
- spec/logger_spec.rb
|
@@ -1,30 +0,0 @@
|
|
1
|
-
class LogStashLogger::TCPClient
|
2
|
-
def initialize(host, port)
|
3
|
-
@host = host
|
4
|
-
@port = port
|
5
|
-
@socket = nil
|
6
|
-
end
|
7
|
-
|
8
|
-
def write(event)
|
9
|
-
begin
|
10
|
-
connect unless @socket
|
11
|
-
|
12
|
-
@socket.write("#{event.to_hash.to_json}\n")
|
13
|
-
rescue => e
|
14
|
-
warn "LogStashLogger::TCPClient - #{e.class} - #{e.message}"
|
15
|
-
close
|
16
|
-
@socket = nil
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def close
|
21
|
-
@socket && @socket.close
|
22
|
-
rescue => e
|
23
|
-
warn "LogStashLogger::TCPClient - #{e.class} - #{e.message}"
|
24
|
-
end
|
25
|
-
|
26
|
-
private
|
27
|
-
def connect
|
28
|
-
@socket = TCPSocket.new(@host, @port)
|
29
|
-
end
|
30
|
-
end
|