md-logstasher 1.0.5 → 1.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 4563d96cf88d8a5e5fa8c1a263ed5e79c2fa2acc
4
- data.tar.gz: edbcb27c41a3068d29fb1d896131a81035391c3d
2
+ SHA256:
3
+ metadata.gz: 5f6a2e729c225c8fb2cf06174d9fc5282ae0b2ee660fd89d675a30e7fcd19eb3
4
+ data.tar.gz: 9a8dea2258d1ed2c0fb1c01227bf7ea6b78421ca342ba122a32cc8f1351b7440
5
5
  SHA512:
6
- metadata.gz: f2bcdf71a918cbed00947a631abbd3a444dee9918afd8eb3d1947e4f092fc8569327ee088bb5aa890d5900fc959879dc3e9da3fcac96d675d36a6ea2db66e08f
7
- data.tar.gz: 77f0394fb5e701c380176ae702412d07c8b24faa31d6f67ec60969ad3e5f42499c763bcd4e6d78efbb19ba1750750619d074e9e4e011e65d306b1d50a231c3cc
6
+ metadata.gz: d23d146376ea21233a2b1189366586cbecc46f4a5694ffb1b7cae480881098828f7e9e79f171cf7f1c52372b793f53aff40d86dd444a4aee4e8a12e9334e2e7a
7
+ data.tar.gz: f6a8c91e937935dac803868c098e8b6826cb0b27f72fe5718bf8fcebad2685acdeb899e8055d6ee6cc2a4420bcf3465a7e3557e99875b8b2fbf8fbccd5c90618
@@ -59,7 +59,7 @@ module LogStasher
59
59
 
60
60
  def validate_options
61
61
  unless ['list', 'channel'].include?(options['data_type'])
62
- fail 'Expected data_type to be either "list" or "channel"'
62
+ fail RuntimeError, 'Expected data_type to be either "list" or "channel"'
63
63
  end
64
64
  end
65
65
  end
@@ -2,34 +2,27 @@
2
2
 
3
3
  require 'logstasher/device'
4
4
  require 'syslog'
5
- require 'thread'
6
5
 
7
6
  module LogStasher
8
7
  module Device
9
8
  class Syslog
10
9
  include ::LogStasher::Device
11
10
 
12
- SEMAPHORE = Mutex.new
13
-
14
11
  attr_reader :options
15
12
 
16
13
  def initialize(options = {})
17
14
  raw_options = default_options.merge(stringify_keys(options))
18
15
 
19
16
  @options = parse_options(raw_options)
20
- @closed = false
17
+ open_syslog
21
18
  end
22
19
 
23
20
  def close
24
- SEMAPHORE.synchronize do
25
- ::Syslog.close if ::Syslog.opened?
26
- end
27
-
28
- @closed = true
21
+ ::Syslog.close rescue nil
29
22
  end
30
23
 
31
24
  def closed?
32
- @closed
25
+ !::Syslog.opened?
33
26
  end
34
27
 
35
28
  def facility
@@ -49,11 +42,10 @@ module LogStasher
49
42
  end
50
43
 
51
44
  def write(log)
52
- fail ::RuntimeError, 'Cannot write. The device has been closed.' if closed?
45
+ fail ::RuntimeError, 'Syslog has been closed.' if closed?
46
+ fail ::RuntimeError, 'Syslog re-configured unexpectedly.' if syslog_config_changed?
53
47
 
54
- with_syslog_open do
55
- ::Syslog.log(priority, '%s', log)
56
- end
48
+ ::Syslog.log(priority, '%s', log)
57
49
  end
58
50
 
59
51
  private
@@ -63,10 +55,18 @@ module LogStasher
63
55
  'identity' => 'logstasher',
64
56
  'facility' => ::Syslog::LOG_LOCAL0,
65
57
  'priority' => ::Syslog::LOG_INFO,
66
- 'flags' => ::Syslog::LOG_PID | ::Syslog::LOG_CONS
58
+ 'flags' => ::Syslog::LOG_PID | ::Syslog::LOG_CONS,
67
59
  }
68
60
  end
69
61
 
62
+ def open_syslog
63
+ if ::Syslog.opened?
64
+ ::Syslog.reopen(identity, flags, facility)
65
+ else
66
+ ::Syslog.open(identity, flags, facility)
67
+ end
68
+ end
69
+
70
70
  def parse_option(value)
71
71
  case value
72
72
  when ::String
@@ -85,20 +85,8 @@ module LogStasher
85
85
  options
86
86
  end
87
87
 
88
- def syslog_configured?
89
- ::Syslog.ident == identity && ::Syslog.options == flags && ::Syslog.facility == facility
90
- end
91
-
92
- def with_syslog_open
93
- SEMAPHORE.synchronize do
94
- if ::Syslog.opened?
95
- ::Syslog.reopen(identity, flags, facility) unless syslog_configured?
96
- else
97
- ::Syslog.open(identity, flags, facility)
98
- end
99
-
100
- yield
101
- end
88
+ def syslog_config_changed?
89
+ ::Syslog.ident != identity || ::Syslog.options != flags || ::Syslog.facility != facility
102
90
  end
103
91
  end
104
92
  end
@@ -0,0 +1,40 @@
1
+ # simple UDP logger
2
+
3
+ require 'logstasher/device'
4
+ require 'socket'
5
+
6
+
7
+ module LogStasher
8
+ module Device
9
+ class UDP
10
+ include ::LogStasher::Device
11
+
12
+ attr_reader :options, :socket
13
+
14
+ def initialize(options = {})
15
+ @options = default_options.merge(stringify_keys(options))
16
+ @socket = UDPSocket.new
17
+ end
18
+
19
+ def close
20
+ @socket.close
21
+ end
22
+
23
+ def write(log)
24
+ @socket.send(log, 0, options['hostname'], options['port'])
25
+ end
26
+
27
+ private
28
+
29
+ def default_options
30
+ {
31
+ 'hostname' => '127.0.0.1',
32
+ 'port' => 31459,
33
+ }
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+
40
+
@@ -11,6 +11,9 @@ module LogStasher
11
11
  when "syslog", :syslog then
12
12
  require 'logstasher/device/syslog'
13
13
  ::LogStasher::Device::Syslog.new(config)
14
+ when "udp", :udp then
15
+ require 'logstasher/device/udp'
16
+ ::LogStasher::Device::UDP.new(config)
14
17
  else
15
18
  fail ArgumentError, "Unknown type: #{type}"
16
19
  end
@@ -21,7 +21,6 @@ module LogStasher
21
21
  payload = event.payload
22
22
  tags = extract_tags(payload)
23
23
  fields = extract_request(payload)
24
-
25
24
  fields.merge! extract_status(payload)
26
25
  fields.merge! runtimes(event)
27
26
  fields.merge! location
@@ -52,15 +51,19 @@ module LogStasher
52
51
  end
53
52
 
54
53
  def extract_request(payload)
55
- {
54
+ result = {
56
55
  :action => payload[:action],
57
56
  :controller => payload[:controller],
58
57
  :format => extract_format(payload),
59
58
  :ip => request.remote_ip,
59
+ :request_id => request.env["action_dispatch.request_id"],
60
60
  :method => payload[:method],
61
61
  :path => extract_path(payload),
62
62
  :route => "#{payload[:controller]}##{payload[:action]}"
63
63
  }
64
+ metadata = ::LogStasher.metadata
65
+ result.merge!(:metadata => metadata) unless metadata&.empty?
66
+ result
64
67
  end
65
68
 
66
69
  # Monkey patching to enable exception logging
@@ -86,7 +89,6 @@ module LogStasher
86
89
  def extract_parameters(payload)
87
90
  if LogStasher.include_parameters?
88
91
  external_params = payload[:params].except(*INTERNAL_PARAMS)
89
-
90
92
  if LogStasher.serialize_parameters?
91
93
  { :params => JSON.generate(external_params) }
92
94
  else
@@ -8,6 +8,7 @@ module LogStasher
8
8
  config.logstasher.logger = nil
9
9
  config.logstasher.log_level = ::Logger::INFO
10
10
 
11
+ config.logstasher.metadata = {}
11
12
  config.before_initialize do
12
13
  options = config.logstasher
13
14
 
@@ -17,6 +18,7 @@ module LogStasher
17
18
  ::LogStasher.silence_standard_logging = options.silence_standard_logging
18
19
  ::LogStasher.logger = options.logger || default_logger
19
20
  ::LogStasher.logger.level = options.log_level
21
+ ::LogStasher.metadata = options.metadata
20
22
  end
21
23
 
22
24
  initializer 'logstasher.load' do
@@ -1,3 +1,3 @@
1
1
  module LogStasher
2
- VERSION = "1.0.5"
2
+ VERSION = "1.4.0"
3
3
  end
data/lib/logstasher.rb CHANGED
@@ -8,6 +8,7 @@ module LogStasher
8
8
  attr_writer :include_parameters
9
9
  attr_writer :serialize_parameters
10
10
  attr_writer :silence_standard_logging
11
+ attr_accessor :metadata
11
12
 
12
13
  def append_fields(&block)
13
14
  @append_fields_callback = block
@@ -40,7 +40,7 @@ describe LogStasher::Device::Redis do
40
40
  it 'does not allow unsupported data types' do
41
41
  expect {
42
42
  device = LogStasher::Device::Redis.new(data_type: 'blargh')
43
- }.to raise_error()
43
+ }.to raise_error(::RuntimeError)
44
44
  end
45
45
 
46
46
  it 'quits the redis connection on #close' do
@@ -14,9 +14,9 @@ describe LogStasher::Device::Syslog do
14
14
  before { allow(::Syslog).to receive(:log) }
15
15
 
16
16
  around do |example|
17
- ::Syslog.close if ::Syslog.opened?
17
+ ::Syslog.close rescue nil
18
18
  example.run
19
- ::Syslog.close if ::Syslog.opened?
19
+ ::Syslog.close rescue nil
20
20
  end
21
21
 
22
22
  it 'has default options' do
@@ -64,25 +64,37 @@ describe LogStasher::Device::Syslog do
64
64
  expect(device.flags).to eq(::Syslog::LOG_NOWAIT | ::Syslog::LOG_ODELAY)
65
65
  end
66
66
 
67
- describe '#write' do
68
- subject { LogStasher::Device::Syslog.new }
67
+ it 'opens syslog when it is closed' do
68
+ expect(::Syslog).to receive(:open).with(
69
+ default_options['identity'],
70
+ default_options['flags'],
71
+ default_options['facility'],
72
+ )
69
73
 
70
- it 'opens syslog when syslog is closed' do
71
- expect(::Syslog).to receive(:open).with(subject.identity, subject.flags, subject.facility)
72
- subject.write('a log')
73
- end
74
+ LogStasher::Device::Syslog.new
75
+ end
74
76
 
75
- it 'does not re-open syslog when its config is in sync' do
76
- ::Syslog.open(subject.identity, subject.flags, subject.facility)
77
- expect(::Syslog).not_to receive(:open)
78
- expect(::Syslog).not_to receive(:reopen)
79
- subject.write('a log')
80
- end
77
+ it 're-opens syslog when it is already opened' do
78
+ ::Syslog.open('temp', ::Syslog::LOG_NDELAY, ::Syslog::LOG_AUTH)
81
79
 
82
- it 're-opens syslog when its config is out of sync' do
83
- ::Syslog.open('temp', ::Syslog::LOG_NDELAY, ::Syslog::LOG_AUTH)
84
- expect(::Syslog).to receive(:reopen).with(subject.identity, subject.flags, subject.facility)
85
- subject.write('a log')
80
+ expect(::Syslog).to receive(:reopen).with(
81
+ default_options['identity'],
82
+ default_options['flags'],
83
+ default_options['facility'],
84
+ )
85
+
86
+ LogStasher::Device::Syslog.new
87
+ end
88
+
89
+ describe '#write' do
90
+ subject { LogStasher::Device::Syslog.new }
91
+
92
+ it 'fails when the syslog config is out of sync' do
93
+ subject
94
+ ::Syslog.reopen('temp', ::Syslog::LOG_NDELAY, ::Syslog::LOG_AUTH)
95
+ expect {
96
+ subject.write('a log')
97
+ }.to raise_error(::RuntimeError, 'Syslog re-configured unexpectedly.')
86
98
  end
87
99
 
88
100
  it 'writes the log to syslog' do
@@ -94,7 +106,7 @@ describe LogStasher::Device::Syslog do
94
106
  subject.close
95
107
  expect {
96
108
  subject.write('a log')
97
- }.to raise_error(::RuntimeError, 'Cannot write. The device has been closed.')
109
+ }.to raise_error(::RuntimeError, 'Syslog has been closed.')
98
110
  end
99
111
  end
100
112
 
@@ -106,15 +118,9 @@ describe LogStasher::Device::Syslog do
106
118
  expect(subject).to be_closed
107
119
  end
108
120
 
109
- it 'closes syslog when syslog is open' do
110
- ::Syslog.open(subject.identity, subject.flags, subject.facility)
121
+ it 'closes syslog' do
111
122
  expect(::Syslog).to receive(:close)
112
123
  subject.close
113
124
  end
114
-
115
- it 'does not close syslog if it is already closed' do
116
- expect(::Syslog).not_to receive(:close)
117
- subject.close
118
- end
119
125
  end
120
126
  end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ require 'logstasher/device/udp'
4
+
5
+ describe LogStasher::Device::UDP do
6
+
7
+ let(:default_options) {{
8
+ 'hostname' => '127.0.0.1',
9
+ 'port' => 31459
10
+ }}
11
+
12
+ it 'has default options' do
13
+ device = LogStasher::Device::UDP.new
14
+ expect(device.options).to eq(default_options)
15
+ end
16
+
17
+ it 'closes the udp socket on #close' do
18
+ device = LogStasher::Device::UDP.new
19
+ expect(device.socket).to receive(:close)
20
+ device.close
21
+ end
22
+
23
+ it 'works as a logger device' do
24
+ device = LogStasher::Device::UDP.new
25
+ expect(device).to receive(:write).with('foo')
26
+ logger = Logger.new(device)
27
+ logger << 'foo'
28
+ end
29
+
30
+ describe '#write' do
31
+ subject { LogStasher::Device::UDP.new }
32
+ it 'writes the log to the the socket' do
33
+ expect(subject.socket).to receive(:send).with('a log', 0, default_options['hostname'], default_options['port'])
34
+ subject.write('a log')
35
+ end
36
+ end
37
+ end
@@ -3,6 +3,7 @@ require "spec_helper"
3
3
  require "logstasher/device"
4
4
  require "logstasher/device/redis"
5
5
  require "logstasher/device/syslog"
6
+ require "logstasher/device/udp"
6
7
 
7
8
  describe LogStasher::Device do
8
9
  describe ".factory" do
@@ -47,7 +48,17 @@ describe LogStasher::Device do
47
48
  device = ::LogStasher::Device.factory(:type => "syslog")
48
49
  expect(device).to be_a_kind_of(::LogStasher::Device::Syslog)
49
50
  end
51
+
52
+ it "can create udp devices" do
53
+ expect(
54
+ ::LogStasher::Device
55
+ ).to receive(:require).with("logstasher/device/udp")
56
+
57
+ device = ::LogStasher::Device.factory(:type => "udp")
58
+ expect(device).to be_a_kind_of(::LogStasher::Device::UDP)
59
+ end
50
60
 
61
+
51
62
  it "fails to create unknown devices" do
52
63
  expect {
53
64
  ::LogStasher::Device.factory(:type => "unknown")
@@ -10,6 +10,12 @@ class MockController
10
10
  end
11
11
 
12
12
  class MockRequest
13
+ attr_accessor :env
14
+
15
+ def initialize
16
+ @env = { 'action_dispatch.request_id' => 1 }
17
+ end
18
+
13
19
  def remote_ip
14
20
  '127.0.0.1'
15
21
  end
@@ -19,6 +25,7 @@ describe LogStasher::LogSubscriber do
19
25
  subject { described_class.new }
20
26
 
21
27
  let(:logger) { ::Logger.new('/dev/null') }
28
+
22
29
  let(:mock_controller) { MockController.new }
23
30
  let(:mock_request) { MockRequest.new }
24
31
  let(:context) {{ :controller => mock_controller, :request => mock_request }}
@@ -46,10 +53,12 @@ describe LogStasher::LogSubscriber do
46
53
  :path => '/users/1',
47
54
  :status => 200
48
55
  }}
56
+ let(:data) { { "namespace" => "test", "appversion" => "v1" } }
49
57
 
50
58
  let(:event) { double(:payload => payload, :duration => duration) }
51
59
 
52
60
  it 'logs the event in logstash format' do
61
+ ::LogStasher.metadata = data
53
62
  expect(logger).to receive(:<<) do |json|
54
63
  expect(JSON.parse(json)).to eq({
55
64
  '@timestamp' => timestamp,
@@ -64,7 +73,9 @@ describe LogStasher::LogSubscriber do
64
73
  'path' => payload[:path],
65
74
  'route' => "#{payload[:controller]}##{payload[:action]}",
66
75
  'status' => payload[:status],
67
- 'runtime' => { 'total' => duration }
76
+ 'runtime' => { 'total' => duration },
77
+ 'request_id' => 1,
78
+ 'metadata' => data
68
79
  })
69
80
  end
70
81
 
@@ -19,12 +19,6 @@ describe ::LogStasher::Railtie do
19
19
  let(:config) { described_class.config.logstasher }
20
20
 
21
21
  describe 'logstasher.configure' do
22
- subject do
23
- described_class.instance.initializers.find do |initializer|
24
- initializer.name == 'logstasher.configure'
25
- end
26
- end
27
-
28
22
  it 'should configure LogStasher' do
29
23
  config.logger = ::Logger.new('/dev/null')
30
24
  config.log_level = "log_level"
@@ -40,7 +34,7 @@ describe ::LogStasher::Railtie do
40
34
  expect(::LogStasher).to receive(:logger=).with(config.logger).and_call_original
41
35
  expect(config.logger).to receive(:level=).with("log_level")
42
36
 
43
- subject.run
37
+ ActiveSupport.run_load_hooks(:before_initialize)
44
38
  end
45
39
  end
46
40
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: md-logstasher
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.5
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Devin Christensen
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-12 00:00:00.000000000 Z
11
+ date: 2022-01-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: logstash-event
@@ -85,6 +85,7 @@ files:
85
85
  - lib/logstasher/device.rb
86
86
  - lib/logstasher/device/redis.rb
87
87
  - lib/logstasher/device/syslog.rb
88
+ - lib/logstasher/device/udp.rb
88
89
  - lib/logstasher/log_subscriber.rb
89
90
  - lib/logstasher/railtie.rb
90
91
  - lib/logstasher/silent_logger.rb
@@ -96,6 +97,7 @@ files:
96
97
  - logstasher.gemspec
97
98
  - spec/lib/logstasher/device/redis_spec.rb
98
99
  - spec/lib/logstasher/device/syslog_spec.rb
100
+ - spec/lib/logstasher/device/udp_spec.rb
99
101
  - spec/lib/logstasher/device_spec.rb
100
102
  - spec/lib/logstasher/log_subscriber_spec.rb
101
103
  - spec/lib/logstasher/railtie_spec.rb
@@ -105,7 +107,7 @@ homepage: https://github.com/moneydesktop/logstasher
105
107
  licenses:
106
108
  - MIT
107
109
  metadata: {}
108
- post_install_message:
110
+ post_install_message:
109
111
  rdoc_options: []
110
112
  require_paths:
111
113
  - lib
@@ -120,14 +122,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
120
122
  - !ruby/object:Gem::Version
121
123
  version: '0'
122
124
  requirements: []
123
- rubyforge_project:
124
- rubygems_version: 2.2.2
125
- signing_key:
125
+ rubygems_version: 3.2.28
126
+ signing_key:
126
127
  specification_version: 4
127
128
  summary: Awesome rails logs
128
129
  test_files:
129
130
  - spec/lib/logstasher/device/redis_spec.rb
130
131
  - spec/lib/logstasher/device/syslog_spec.rb
132
+ - spec/lib/logstasher/device/udp_spec.rb
131
133
  - spec/lib/logstasher/device_spec.rb
132
134
  - spec/lib/logstasher/log_subscriber_spec.rb
133
135
  - spec/lib/logstasher/railtie_spec.rb