logstasher 0.5.3 → 0.6.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 +8 -8
- data/README.md +10 -1
- data/lib/logstasher.rb +34 -3
- data/lib/logstasher/log_subscriber.rb +31 -0
- data/lib/logstasher/rails_ext/action_controller/metal/instrumentation.rb +11 -0
- data/lib/logstasher/version.rb +1 -1
- data/logstasher.gemspec +1 -1
- data/spec/lib/logstasher/device/redis_spec.rb +11 -11
- data/spec/lib/logstasher/instrumentation_spec.rb +62 -0
- data/spec/lib/logstasher/log_subscriber_spec.rb +109 -34
- data/spec/lib/logstasher_spec.rb +84 -36
- data/spec/spec_helper.rb +3 -1
- data/spec/support/sample_mailer.rb +16 -0
- metadata +9 -5
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
MmUyOWU0M2UwMGY1YzRjZDU0ZDRmNGExM2E2YTZjZDVhMGEyYWRjMQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
NGI2M2M3NGNjYjc2OGZjMWI0NGU3MTM3ZjljMDY5ZGNhYTk5OTYxNQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
YjM5YzhmMGU0YTcyYTAxMWMxYzAxZWE5NTgyN2RmYTM3MWM0ZDE0MTY1YWQ2
|
10
|
+
YzIzOWQ4MjFkODA0NDMwNDk3YWY4MmNkYzY1M2ViNmU4NjZmYzdjMDZlMGU2
|
11
|
+
ZGM2MGY0ZmNjYzk3NTYwODRiMTc3ZDg1OTYzZWFiMTgzNmEyZjA=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
NTk2MDFmNGM4MDFlOGE2OGI1NjE3MDMwZmZmYjRlZTM0NDQwMTU1OGZiMzBl
|
14
|
+
N2VlYzViNzQ2MDFjODk4OWYyYThhZGRjNzUyMDRhNzBiZjU3YTdhM2E0ZjJj
|
15
|
+
ZTRlYTA2Y2UyM2UzN2M0YTY5MDFkY2IyNzk1NmY5MzM5MjJlOGQ=
|
data/README.md
CHANGED
@@ -94,6 +94,15 @@ Since some fields are very specific to your application for e.g. *user_name*, so
|
|
94
94
|
end
|
95
95
|
end
|
96
96
|
|
97
|
+
## Logging ActionMailer events
|
98
|
+
|
99
|
+
Logstasher can easily log messages from `ActionMailer`, such as incoming/outgoing e-mails and e-mail content generation (Rails >= 4.1).
|
100
|
+
This functionality is automatically enabled. Since the relationship between a concrete HTTP request and a mailer invocation is lost
|
101
|
+
once in an `ActionMailer` instance method, global (per-request) state is kept to correlate HTTP requests and events from other parts
|
102
|
+
of rails, such as `ActionMailer`. Every time a request is invoked, a `request_id` key is added which is present on every `ActionMailer` event.
|
103
|
+
|
104
|
+
Note: Since mailers are executed within the lifetime of a request, they will show up in logs prior to the actual request.
|
105
|
+
|
97
106
|
## Listening to `ActiveSupport::Notifications` events
|
98
107
|
|
99
108
|
It is possible to listen to any `ActiveSupport::Notifications` events and store arbitrary data to be included in the final JSON log entry:
|
@@ -135,7 +144,7 @@ You can easily share the same store between different types of notifications, by
|
|
135
144
|
java -jar logstash-1.3.3-flatjar.jar agent -f quickstart.conf -- web
|
136
145
|
```
|
137
146
|
* Visit http://localhost:9292/ to see the Kibana interface and your parsed logs
|
138
|
-
* For advanced options see the latest logstash documentation at [logstash.net](http://www.logstash.net/) or visit my blog at
|
147
|
+
* For advanced options see the latest logstash documentation at [logstash.net](http://www.logstash.net/) or visit my blog at [shadabahmed.com](http://shadabahmed.com/blog/2013/04/30/logstasher-for-awesome-rails-logging) (slightly outdated but will sure give you ideas for distributed setup etc.)
|
139
148
|
|
140
149
|
## Versions
|
141
150
|
All versions require Rails 3.0.x and higher and Ruby 1.9.2+. Tested on Rails 4 and Ruby 2.0
|
data/lib/logstasher.rb
CHANGED
@@ -8,8 +8,9 @@ require 'active_support/ordered_options'
|
|
8
8
|
module LogStasher
|
9
9
|
extend self
|
10
10
|
STORE_KEY = :logstasher_data
|
11
|
+
REQUEST_CONTEXT_KEY = :logstasher_request_context
|
11
12
|
|
12
|
-
attr_accessor :logger, :enabled, :log_controller_parameters, :source
|
13
|
+
attr_accessor :logger, :logger_path, :enabled, :log_controller_parameters, :source
|
13
14
|
# Setting the default to 'unknown' to define the default behaviour
|
14
15
|
@source = 'unknown'
|
15
16
|
|
@@ -20,6 +21,8 @@ module LogStasher
|
|
20
21
|
unsubscribe(:action_view, subscriber)
|
21
22
|
when ActionController::LogSubscriber
|
22
23
|
unsubscribe(:action_controller, subscriber)
|
24
|
+
when ActionMailer::LogSubscriber
|
25
|
+
unsubscribe(:action_mailer, subscriber)
|
23
26
|
end
|
24
27
|
end
|
25
28
|
end
|
@@ -38,7 +41,8 @@ module LogStasher
|
|
38
41
|
def add_default_fields_to_payload(payload, request)
|
39
42
|
payload[:ip] = request.remote_ip
|
40
43
|
payload[:route] = "#{request.params[:controller]}##{request.params[:action]}"
|
41
|
-
|
44
|
+
payload[:request_id] = request.env['action_dispatch.request_id']
|
45
|
+
self.custom_fields += [:ip, :route, :request_id]
|
42
46
|
if self.log_controller_parameters
|
43
47
|
payload[:parameters] = payload[:params].except(*ActionController::LogSubscriber::INTERNAL_PARAMS)
|
44
48
|
self.custom_fields += [:parameters]
|
@@ -54,6 +58,23 @@ module LogStasher
|
|
54
58
|
ActionController::Base.send(:define_method, :logtasher_add_custom_fields_to_payload, &wrapped_block)
|
55
59
|
end
|
56
60
|
|
61
|
+
def add_custom_fields_to_request_context(&block)
|
62
|
+
wrapped_block = Proc.new do |fields|
|
63
|
+
instance_exec(fields, &block)
|
64
|
+
LogStasher.custom_fields.concat(fields.keys)
|
65
|
+
end
|
66
|
+
ActionController::Metal.send(:define_method, :logstasher_add_custom_fields_to_request_context, &wrapped_block)
|
67
|
+
ActionController::Base.send(:define_method, :logstasher_add_custom_fields_to_request_context, &wrapped_block)
|
68
|
+
end
|
69
|
+
|
70
|
+
def add_default_fields_to_request_context(request)
|
71
|
+
request_context[:request_id] = request.env['action_dispatch.request_id']
|
72
|
+
end
|
73
|
+
|
74
|
+
def clear_request_context
|
75
|
+
request_context.clear
|
76
|
+
end
|
77
|
+
|
57
78
|
def setup(app)
|
58
79
|
app.config.action_dispatch.rack_cache[:verbose] = false if app.config.action_dispatch.rack_cache
|
59
80
|
# Path instrumentation class to insert our hook
|
@@ -61,7 +82,9 @@ module LogStasher
|
|
61
82
|
require 'logstash-event'
|
62
83
|
self.suppress_app_logs(app)
|
63
84
|
LogStasher::RequestLogSubscriber.attach_to :action_controller
|
64
|
-
|
85
|
+
LogStasher::MailerLogSubscriber.attach_to :action_mailer
|
86
|
+
self.logger_path = app.config.logstasher.logger_path || "#{Rails.root}/log/logstash_#{Rails.env}.log"
|
87
|
+
self.logger = app.config.logstasher.logger || new_logger(self.logger_path)
|
65
88
|
self.logger.level = app.config.logstasher.log_level || Logger::WARN
|
66
89
|
self.source = app.config.logstasher.source unless app.config.logstasher.source.nil?
|
67
90
|
self.enabled = true
|
@@ -103,6 +126,10 @@ module LogStasher
|
|
103
126
|
RequestStore.store[STORE_KEY]
|
104
127
|
end
|
105
128
|
|
129
|
+
def request_context
|
130
|
+
RequestStore.store[REQUEST_CONTEXT_KEY] ||= {}
|
131
|
+
end
|
132
|
+
|
106
133
|
def watch(event, opts = {}, &block)
|
107
134
|
event_group = opts[:event_group] || event
|
108
135
|
ActiveSupport::Notifications.subscribe(event) do |*args|
|
@@ -119,6 +146,10 @@ module LogStasher
|
|
119
146
|
EOM
|
120
147
|
end
|
121
148
|
|
149
|
+
def enabled?
|
150
|
+
self.enabled
|
151
|
+
end
|
152
|
+
|
122
153
|
private
|
123
154
|
|
124
155
|
def new_logger(path)
|
@@ -93,4 +93,35 @@ module LogStasher
|
|
93
93
|
custom_fields
|
94
94
|
end
|
95
95
|
end
|
96
|
+
|
97
|
+
class MailerLogSubscriber < ActiveSupport::LogSubscriber
|
98
|
+
MAILER_FIELDS = [:mailer, :action, :message_id, :from, :to]
|
99
|
+
|
100
|
+
def deliver(event)
|
101
|
+
process_event(event, ['mailer', 'deliver'])
|
102
|
+
end
|
103
|
+
|
104
|
+
def receive(event)
|
105
|
+
process_event(event, ['mailer', 'receive'])
|
106
|
+
end
|
107
|
+
|
108
|
+
def process(event)
|
109
|
+
process_event(event, ['mailer', 'process'])
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
def process_event(event, tags)
|
114
|
+
data = LogStasher.request_context.merge(extract_metadata(event.payload))
|
115
|
+
event = LogStash::Event.new('@source' => LogStasher.source, '@fields' => data, '@tags' => tags)
|
116
|
+
logger << event.to_json + "\n"
|
117
|
+
end
|
118
|
+
|
119
|
+
def extract_metadata(payload)
|
120
|
+
payload.slice(*MAILER_FIELDS)
|
121
|
+
end
|
122
|
+
|
123
|
+
def logger
|
124
|
+
LogStasher.logger
|
125
|
+
end
|
126
|
+
end
|
96
127
|
end
|
@@ -12,9 +12,16 @@ module ActionController
|
|
12
12
|
|
13
13
|
LogStasher.add_default_fields_to_payload(raw_payload, request)
|
14
14
|
|
15
|
+
LogStasher.clear_request_context
|
16
|
+
LogStasher.add_default_fields_to_request_context(request)
|
17
|
+
|
15
18
|
ActiveSupport::Notifications.instrument("start_processing.action_controller", raw_payload.dup)
|
16
19
|
|
17
20
|
ActiveSupport::Notifications.instrument("process_action.action_controller", raw_payload) do |payload|
|
21
|
+
if self.respond_to?(:logstasher_add_custom_fields_to_request_context)
|
22
|
+
logstasher_add_custom_fields_to_request_context(LogStasher.request_context)
|
23
|
+
end
|
24
|
+
|
18
25
|
result = super
|
19
26
|
|
20
27
|
if self.respond_to?(:logtasher_add_custom_fields_to_payload)
|
@@ -30,6 +37,10 @@ module ActionController
|
|
30
37
|
LogStasher.store.each do |key, value|
|
31
38
|
payload[key] = value
|
32
39
|
end
|
40
|
+
|
41
|
+
LogStasher.request_context.each do |key, value|
|
42
|
+
payload[key] = value
|
43
|
+
end
|
33
44
|
result
|
34
45
|
end
|
35
46
|
end
|
data/lib/logstasher/version.rb
CHANGED
data/logstasher.gemspec
CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |s|
|
|
21
21
|
s.add_runtime_dependency "request_store"
|
22
22
|
|
23
23
|
# specify any dependencies here; for example:
|
24
|
-
s.add_development_dependency "rspec"
|
24
|
+
s.add_development_dependency "rspec", [">= 2.14"]
|
25
25
|
s.add_development_dependency("bundler", [">= 1.0.0"])
|
26
26
|
s.add_development_dependency("rails", [">= 3.0"])
|
27
27
|
end
|
@@ -13,28 +13,28 @@ describe LogStasher::Device::Redis do
|
|
13
13
|
|
14
14
|
it 'has default options' do
|
15
15
|
device = LogStasher::Device::Redis.new
|
16
|
-
device.options.
|
16
|
+
expect(device.options).to eq(default_options)
|
17
17
|
end
|
18
18
|
|
19
19
|
it 'creates a redis instance' do
|
20
|
-
::Redis.
|
20
|
+
expect(::Redis).to receive(:new).with({})
|
21
21
|
LogStasher::Device::Redis.new()
|
22
22
|
end
|
23
23
|
|
24
24
|
it 'assumes unknown options are for redis' do
|
25
|
-
::Redis.
|
25
|
+
expect(::Redis).to receive(:new).with(hash_including(db: '0'))
|
26
26
|
device = LogStasher::Device::Redis.new(db: '0')
|
27
|
-
device.redis_options.
|
27
|
+
expect(device.redis_options).to eq(db: '0')
|
28
28
|
end
|
29
29
|
|
30
30
|
it 'has a key' do
|
31
31
|
device = LogStasher::Device::Redis.new(key: 'the_key')
|
32
|
-
device.key.
|
32
|
+
expect(device.key).to eq('the_key')
|
33
33
|
end
|
34
34
|
|
35
35
|
it 'has a data_type' do
|
36
36
|
device = LogStasher::Device::Redis.new(data_type: 'channel')
|
37
|
-
device.data_type.
|
37
|
+
expect(device.data_type).to eq('channel')
|
38
38
|
end
|
39
39
|
|
40
40
|
it 'does not allow unsupported data types' do
|
@@ -45,13 +45,13 @@ describe LogStasher::Device::Redis do
|
|
45
45
|
|
46
46
|
it 'quits the redis connection on #close' do
|
47
47
|
device = LogStasher::Device::Redis.new
|
48
|
-
device.redis.
|
48
|
+
expect(device.redis).to receive(:quit)
|
49
49
|
device.close
|
50
50
|
end
|
51
51
|
|
52
52
|
it 'works as a logger device' do
|
53
53
|
device = LogStasher::Device::Redis.new
|
54
|
-
device.
|
54
|
+
expect(device).to receive(:write).with('blargh')
|
55
55
|
logger = Logger.new(device)
|
56
56
|
logger << 'blargh'
|
57
57
|
end
|
@@ -59,19 +59,19 @@ describe LogStasher::Device::Redis do
|
|
59
59
|
describe '#write' do
|
60
60
|
it "rpushes logs onto a list" do
|
61
61
|
device = LogStasher::Device::Redis.new(data_type: 'list')
|
62
|
-
device.redis.
|
62
|
+
expect(device.redis).to receive(:rpush).with('logstash', 'the log')
|
63
63
|
device.write('the log')
|
64
64
|
end
|
65
65
|
|
66
66
|
it "rpushes logs onto a custom key" do
|
67
67
|
device = LogStasher::Device::Redis.new(data_type: 'list', key: 'custom')
|
68
|
-
device.redis.
|
68
|
+
expect(device.redis).to receive(:rpush).with('custom', 'the log')
|
69
69
|
device.write('the log')
|
70
70
|
end
|
71
71
|
|
72
72
|
it "publishes logs onto a channel" do
|
73
73
|
device = LogStasher::Device::Redis.new(data_type: 'channel', key: 'custom')
|
74
|
-
device.redis.
|
74
|
+
expect(device.redis).to receive(:publish).with('custom', 'the log')
|
75
75
|
device.write('the log')
|
76
76
|
end
|
77
77
|
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'logstasher/rails_ext/action_controller/metal/instrumentation'
|
3
|
+
|
4
|
+
describe ActionController::Base do
|
5
|
+
before :each do
|
6
|
+
subject.request = ActionDispatch::TestRequest.new
|
7
|
+
subject.response = ActionDispatch::TestResponse.new
|
8
|
+
|
9
|
+
def subject.index(*args)
|
10
|
+
render text: 'OK'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe ".process_action" do
|
15
|
+
it "adds default fields to payload" do
|
16
|
+
expect(LogStasher).to receive(:add_default_fields_to_payload).once
|
17
|
+
expect(LogStasher).to receive(:add_default_fields_to_request_context).once
|
18
|
+
subject.process_action(:index)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "creates the request context before processing" do
|
22
|
+
LogStasher.request_context[:some_key] = 'value'
|
23
|
+
expect(LogStasher).to receive(:clear_request_context).once.and_call_original
|
24
|
+
expect {
|
25
|
+
subject.process_action(:index)
|
26
|
+
}.to change { LogStasher.request_context }
|
27
|
+
end
|
28
|
+
|
29
|
+
it "notifies rails of a request coming in" do
|
30
|
+
expect(ActiveSupport::Notifications).to receive(:instrument).with("start_processing.action_controller", anything).once
|
31
|
+
expect(ActiveSupport::Notifications).to receive(:instrument).with("process_action.action_controller", anything).once
|
32
|
+
subject.process_action(:index)
|
33
|
+
end
|
34
|
+
|
35
|
+
context "request context has custom fields defined" do
|
36
|
+
before :each do
|
37
|
+
LogStasher.add_custom_fields_to_request_context do |fields|
|
38
|
+
fields[:some_field] = 'value'
|
39
|
+
end
|
40
|
+
|
41
|
+
ActiveSupport::Notifications.subscribe('process_action.action_controller') do |_, _, _, _, payload|
|
42
|
+
@payload = payload
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should retain the value in the request context" do
|
47
|
+
subject.process_action(:index)
|
48
|
+
end
|
49
|
+
|
50
|
+
after :each do
|
51
|
+
expect(@payload[:some_field]).to eq('value')
|
52
|
+
|
53
|
+
ActionController::Metal.class_eval do
|
54
|
+
undef logstasher_add_custom_fields_to_request_context
|
55
|
+
end
|
56
|
+
ActionController::Base.class_eval do
|
57
|
+
undef logstasher_add_custom_fields_to_request_context
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -45,17 +45,17 @@ describe LogStasher::RequestLogSubscriber do
|
|
45
45
|
let(:logger) { double }
|
46
46
|
let(:json) { "{\"@source\":\"unknown\",\"@tags\":[\"request\"],\"@fields\":{\"request\":true,\"status\":true,\"runtimes\":true,\"location\":true,\"exception\":true,\"custom\":true},\"@timestamp\":\"timestamp\"}\n" }
|
47
47
|
before do
|
48
|
-
LogStasher.
|
49
|
-
LogStash::Time.
|
48
|
+
allow(LogStasher).to receive(:logger).and_return(logger)
|
49
|
+
allow(LogStash::Time).to receive(:now).and_return('timestamp')
|
50
50
|
end
|
51
51
|
it 'calls all extractors and outputs the json' do
|
52
|
-
request_subscriber.
|
53
|
-
request_subscriber.
|
54
|
-
request_subscriber.
|
55
|
-
request_subscriber.
|
56
|
-
request_subscriber.
|
57
|
-
request_subscriber.
|
58
|
-
LogStasher.logger.
|
52
|
+
expect(request_subscriber).to receive(:extract_request).with(payload).and_return({:request => true})
|
53
|
+
expect(request_subscriber).to receive(:extract_status).with(payload).and_return({:status => true})
|
54
|
+
expect(request_subscriber).to receive(:runtimes).with(event).and_return({:runtimes => true})
|
55
|
+
expect(request_subscriber).to receive(:location).with(event).and_return({:location => true})
|
56
|
+
expect(request_subscriber).to receive(:extract_exception).with(payload).and_return({:exception => true})
|
57
|
+
expect(request_subscriber).to receive(:extract_custom_fields).with(payload).and_return({:custom => true})
|
58
|
+
expect(LogStasher.logger).to receive(:<<).with(json)
|
59
59
|
request_subscriber.process_action(event)
|
60
60
|
end
|
61
61
|
end
|
@@ -64,47 +64,47 @@ describe LogStasher::RequestLogSubscriber do
|
|
64
64
|
|
65
65
|
it "should contain request tag" do
|
66
66
|
subscriber.process_action(event)
|
67
|
-
log_output.json['@tags'].
|
67
|
+
expect(log_output.json['@tags']).to include 'request'
|
68
68
|
end
|
69
69
|
|
70
70
|
it "should contain HTTP method" do
|
71
71
|
subscriber.process_action(event)
|
72
|
-
log_output.json['@fields']['method'].
|
72
|
+
expect(log_output.json['@fields']['method']).to eq 'GET'
|
73
73
|
end
|
74
74
|
|
75
75
|
it "should include the path in the log output" do
|
76
76
|
subscriber.process_action(event)
|
77
|
-
log_output.json['@fields']['path'].
|
77
|
+
expect(log_output.json['@fields']['path']).to eq '/home'
|
78
78
|
end
|
79
79
|
|
80
80
|
it "should include the format in the log output" do
|
81
81
|
subscriber.process_action(event)
|
82
|
-
log_output.json['@fields']['format'].
|
82
|
+
expect(log_output.json['@fields']['format']).to eq 'application/json'
|
83
83
|
end
|
84
84
|
|
85
85
|
it "should include the status code" do
|
86
86
|
subscriber.process_action(event)
|
87
|
-
log_output.json['@fields']['status'].
|
87
|
+
expect(log_output.json['@fields']['status']).to eq 200
|
88
88
|
end
|
89
89
|
|
90
90
|
it "should include the controller" do
|
91
91
|
subscriber.process_action(event)
|
92
|
-
log_output.json['@fields']['controller'].
|
92
|
+
expect(log_output.json['@fields']['controller']).to eq 'home'
|
93
93
|
end
|
94
94
|
|
95
95
|
it "should include the action" do
|
96
96
|
subscriber.process_action(event)
|
97
|
-
log_output.json['@fields']['action'].
|
97
|
+
expect(log_output.json['@fields']['action']).to eq 'index'
|
98
98
|
end
|
99
99
|
|
100
100
|
it "should include the view rendering time" do
|
101
101
|
subscriber.process_action(event)
|
102
|
-
log_output.json['@fields']['view'].
|
102
|
+
expect(log_output.json['@fields']['view']).to eq 0.01
|
103
103
|
end
|
104
104
|
|
105
105
|
it "should include the database rendering time" do
|
106
106
|
subscriber.process_action(event)
|
107
|
-
log_output.json['@fields']['db'].
|
107
|
+
expect(log_output.json['@fields']['db']).to eq 0.02
|
108
108
|
end
|
109
109
|
|
110
110
|
it "should add a valid status when an exception occurred" do
|
@@ -115,10 +115,10 @@ describe LogStasher::RequestLogSubscriber do
|
|
115
115
|
event.payload[:status] = nil
|
116
116
|
event.payload[:exception] = ['AbstractController::ActionNotFound', 'Route not found']
|
117
117
|
subscriber.process_action(event)
|
118
|
-
log_output.json['@fields']['status'].
|
119
|
-
log_output.json['@fields']['error'].
|
120
|
-
log_output.json['@tags'].
|
121
|
-
log_output.json['@tags'].
|
118
|
+
expect(log_output.json['@fields']['status']).to be >= 400
|
119
|
+
expect(log_output.json['@fields']['error']).to be =~ /AbstractController::ActionNotFound.*Route not found.*logstasher\/spec\/lib\/logstasher\/log_subscriber_spec\.rb/m
|
120
|
+
expect(log_output.json['@tags']).to include 'request'
|
121
|
+
expect(log_output.json['@tags']).to include 'exception'
|
122
122
|
end
|
123
123
|
end
|
124
124
|
|
@@ -126,7 +126,7 @@ describe LogStasher::RequestLogSubscriber do
|
|
126
126
|
event.payload[:status] = nil
|
127
127
|
event.payload[:exception] = nil
|
128
128
|
subscriber.process_action(event)
|
129
|
-
log_output.json['@fields']['status'].
|
129
|
+
expect(log_output.json['@fields']['status']).to eq 0
|
130
130
|
end
|
131
131
|
|
132
132
|
describe "with a redirect" do
|
@@ -136,36 +136,36 @@ describe LogStasher::RequestLogSubscriber do
|
|
136
136
|
|
137
137
|
it "should add the location to the log line" do
|
138
138
|
subscriber.process_action(event)
|
139
|
-
log_output.json['@fields']['location'].
|
139
|
+
expect(log_output.json['@fields']['location']).to eq 'http://www.example.com'
|
140
140
|
end
|
141
141
|
|
142
142
|
it "should remove the thread local variable" do
|
143
143
|
subscriber.process_action(event)
|
144
|
-
Thread.current[:logstasher_location].
|
144
|
+
expect(Thread.current[:logstasher_location]).to be_nil
|
145
145
|
end
|
146
146
|
end
|
147
147
|
|
148
148
|
it "should not include a location by default" do
|
149
149
|
subscriber.process_action(event)
|
150
|
-
log_output.json['@fields']['location'].
|
150
|
+
expect(log_output.json['@fields']['location']).to be_nil
|
151
151
|
end
|
152
152
|
end
|
153
153
|
|
154
154
|
describe "with append_custom_params block specified" do
|
155
|
-
let(:request) { double(:remote_ip => '10.0.0.1')}
|
155
|
+
let(:request) { double(:remote_ip => '10.0.0.1', :env => {})}
|
156
156
|
it "should add default custom data to the output" do
|
157
|
-
request.
|
157
|
+
allow(request).to receive_messages(:params => event.payload[:params])
|
158
158
|
LogStasher.add_default_fields_to_payload(event.payload, request)
|
159
159
|
subscriber.process_action(event)
|
160
|
-
log_output.json['@fields']['ip'].
|
161
|
-
log_output.json['@fields']['route'].
|
162
|
-
log_output.json['@fields']['parameters'].
|
160
|
+
expect(log_output.json['@fields']['ip']).to eq '10.0.0.1'
|
161
|
+
expect(log_output.json['@fields']['route']).to eq'home#index'
|
162
|
+
expect(log_output.json['@fields']['parameters']).to eq 'foo' => 'bar'
|
163
163
|
end
|
164
164
|
end
|
165
165
|
|
166
166
|
describe "with append_custom_params block specified" do
|
167
167
|
before do
|
168
|
-
LogStasher.
|
168
|
+
allow(LogStasher).to receive(:add_custom_fields) do |&block|
|
169
169
|
@block = block
|
170
170
|
end
|
171
171
|
LogStasher.add_custom_fields do |payload|
|
@@ -177,14 +177,89 @@ describe LogStasher::RequestLogSubscriber do
|
|
177
177
|
it "should add the custom data to the output" do
|
178
178
|
@block.call(event.payload)
|
179
179
|
subscriber.process_action(event)
|
180
|
-
log_output.json['@fields']['user'].
|
180
|
+
expect(log_output.json['@fields']['user']).to eq 'user'
|
181
181
|
end
|
182
182
|
end
|
183
183
|
|
184
184
|
describe "when processing a redirect" do
|
185
185
|
it "should store the location in a thread local variable" do
|
186
186
|
subscriber.redirect_to(redirect)
|
187
|
-
Thread.current[:logstasher_location].
|
187
|
+
expect(Thread.current[:logstasher_location]).to eq "http://example.com"
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
describe LogStasher::MailerLogSubscriber do
|
193
|
+
let(:log_output) {StringIO.new}
|
194
|
+
let(:logger) {
|
195
|
+
logger = Logger.new(log_output)
|
196
|
+
logger.formatter = ->(_, _, _, msg) {
|
197
|
+
msg
|
198
|
+
}
|
199
|
+
def log_output.json
|
200
|
+
JSON.parse!(self.string.split("\n").last)
|
201
|
+
end
|
202
|
+
logger
|
203
|
+
}
|
204
|
+
|
205
|
+
before :all do
|
206
|
+
SampleMailer.delivery_method = :test
|
207
|
+
LogStasher::MailerLogSubscriber.attach_to(:action_mailer)
|
208
|
+
end
|
209
|
+
|
210
|
+
before do
|
211
|
+
LogStasher.logger = logger
|
212
|
+
expect(LogStasher.request_context).to receive(:merge).at_most(2).times.and_call_original
|
213
|
+
end
|
214
|
+
|
215
|
+
let :message do
|
216
|
+
Mail.new do
|
217
|
+
from 'some-dude@example.com'
|
218
|
+
to 'some-other-dude@example.com'
|
219
|
+
subject 'Goodbye'
|
220
|
+
body 'LOL'
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
it 'receive an e-mail' do
|
225
|
+
SampleMailer.receive(message.encoded)
|
226
|
+
log_output.json.tap do |json|
|
227
|
+
expect(json['@source']).to eq(LogStasher.source)
|
228
|
+
expect(json['@tags']).to eq(['mailer', 'receive'])
|
229
|
+
json['@fields'].tap do |fields|
|
230
|
+
expect(fields['mailer']).to eq('SampleMailer')
|
231
|
+
expect(fields['from']).to eq(['some-dude@example.com'])
|
232
|
+
expect(fields['to']).to eq(['some-other-dude@example.com'])
|
233
|
+
expect(fields['message_id']).to eq(message.message_id)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
it 'deliver an outgoing e-mail' do
|
239
|
+
email = SampleMailer.welcome
|
240
|
+
|
241
|
+
if version = ENV['RAILS_VERSION'] and version >= '4.1'
|
242
|
+
log_output.json.tap do |json|
|
243
|
+
expect(json['@source']).to eq(LogStasher.source)
|
244
|
+
expect(json['@tags']).to eq(['mailer', 'process'])
|
245
|
+
json['@fields'].tap do |fields|
|
246
|
+
expect(fields['mailer']).to eq('SampleMailer')
|
247
|
+
expect(fields['action']).to eq('welcome')
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
email.deliver
|
253
|
+
log_output.json.tap do |json|
|
254
|
+
expect(json['@source']).to eq(LogStasher.source)
|
255
|
+
expect(json['@tags']).to eq(['mailer', 'deliver'])
|
256
|
+
json['@fields'].tap do |fields|
|
257
|
+
expect(fields['mailer']).to eq('SampleMailer')
|
258
|
+
expect(fields['from']).to eq(['some-dude@example.com'])
|
259
|
+
expect(fields['to']).to eq(['some-other-dude@example.com'])
|
260
|
+
# Message-Id appears not to be yet available at this point in time.
|
261
|
+
expect(fields['message_id']).to be_nil
|
262
|
+
end
|
188
263
|
end
|
189
264
|
end
|
190
265
|
end
|
data/spec/lib/logstasher_spec.rb
CHANGED
@@ -5,6 +5,7 @@ describe LogStasher do
|
|
5
5
|
after do
|
6
6
|
ActionController::LogSubscriber.attach_to :action_controller
|
7
7
|
ActionView::LogSubscriber.attach_to :action_view
|
8
|
+
ActionMailer::LogSubscriber.attach_to :action_mailer
|
8
9
|
end
|
9
10
|
|
10
11
|
it "should remove subscribers for controller events" do
|
@@ -23,19 +24,27 @@ describe LogStasher do
|
|
23
24
|
}
|
24
25
|
end
|
25
26
|
|
27
|
+
it "should remove subscribsers for mailer events" do
|
28
|
+
expect {
|
29
|
+
LogStasher.remove_existing_log_subscriptions
|
30
|
+
}.to change {
|
31
|
+
ActiveSupport::Notifications.notifier.listeners_for('deliver.action_mailer')
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
26
35
|
it "shouldn't remove subscribers that aren't from Rails" do
|
27
36
|
blk = -> {}
|
28
37
|
ActiveSupport::Notifications.subscribe("process_action.action_controller", &blk)
|
29
38
|
LogStasher.remove_existing_log_subscriptions
|
30
39
|
listeners = ActiveSupport::Notifications.notifier.listeners_for('process_action.action_controller')
|
31
|
-
listeners.
|
40
|
+
expect(listeners).to_not be_empty
|
32
41
|
end
|
33
42
|
end
|
34
43
|
|
35
44
|
describe '.appened_default_info_to_payload' do
|
36
45
|
let(:params) { {'a' => '1', 'b' => 2, 'action' => 'action', 'controller' => 'test'}.with_indifferent_access }
|
37
46
|
let(:payload) { {:params => params} }
|
38
|
-
let(:request) { double(:params => params, :remote_ip => '10.0.0.1')}
|
47
|
+
let(:request) { double(:params => params, :remote_ip => '10.0.0.1', :env => {})}
|
39
48
|
after do
|
40
49
|
LogStasher.custom_fields = []
|
41
50
|
LogStasher.log_controller_parameters = false
|
@@ -44,53 +53,75 @@ describe LogStasher do
|
|
44
53
|
LogStasher.log_controller_parameters = true
|
45
54
|
LogStasher.custom_fields = []
|
46
55
|
LogStasher.add_default_fields_to_payload(payload, request)
|
47
|
-
payload[:ip].
|
48
|
-
payload[:route].
|
49
|
-
payload[:parameters].
|
50
|
-
LogStasher.custom_fields.
|
56
|
+
expect(payload[:ip]).to eq '10.0.0.1'
|
57
|
+
expect(payload[:route]).to eq 'test#action'
|
58
|
+
expect(payload[:parameters]).to eq 'a' => '1', 'b' => 2
|
59
|
+
expect(LogStasher.custom_fields).to eq [:ip, :route, :request_id, :parameters]
|
51
60
|
end
|
52
61
|
|
53
62
|
it 'does not include parameters when not configured to' do
|
54
63
|
LogStasher.custom_fields = []
|
55
64
|
LogStasher.add_default_fields_to_payload(payload, request)
|
56
|
-
payload.
|
57
|
-
LogStasher.custom_fields.
|
65
|
+
expect(payload).to_not have_key(:parameters)
|
66
|
+
expect(LogStasher.custom_fields).to eq [:ip, :route, :request_id]
|
58
67
|
end
|
59
68
|
end
|
60
69
|
|
61
70
|
describe '.append_custom_params' do
|
62
|
-
let(:block) { ->{} }
|
71
|
+
let(:block) { ->(_, _){} }
|
63
72
|
it 'defines a method in ActionController::Base' do
|
64
|
-
ActionController::Base.
|
73
|
+
expect(ActionController::Base).to receive(:send).with(:define_method, :logtasher_add_custom_fields_to_payload, &block)
|
65
74
|
LogStasher.add_custom_fields(&block)
|
66
75
|
end
|
67
76
|
end
|
68
77
|
|
78
|
+
describe '.add_custom_fields_to_request_context' do
|
79
|
+
let(:block) { ->(_, _){} }
|
80
|
+
it 'defines a method in ActionController::Base' do
|
81
|
+
expect(ActionController::Base).to receive(:send).with(:define_method, :logstasher_add_custom_fields_to_request_context, &block)
|
82
|
+
expect(ActionController::Metal).to receive(:send).with(:define_method, :logstasher_add_custom_fields_to_request_context, &block)
|
83
|
+
LogStasher.add_custom_fields_to_request_context(&block)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe '.add_default_fields_to_request_context' do
|
88
|
+
it 'adds a request_id to the request context' do
|
89
|
+
LogStasher.clear_request_context
|
90
|
+
LogStasher.add_default_fields_to_request_context(double(env: {'action_dispatch.request_id' => 'lol'}))
|
91
|
+
expect(LogStasher.request_context).to eq({ request_id: 'lol' })
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
69
95
|
shared_examples 'setup' do
|
70
|
-
let(:
|
71
|
-
let(:logstasher_config) { double(:logger => logger, :log_level => 'warn', :log_controller_parameters => nil, :source => logstasher_source) }
|
96
|
+
let(:logstasher_source) { nil }
|
97
|
+
let(:logstasher_config) { double(:logger => logger, :log_level => 'warn', :log_controller_parameters => nil, :source => logstasher_source, :logger_path => logger_path) }
|
72
98
|
let(:config) { double(:logstasher => logstasher_config) }
|
73
99
|
let(:app) { double(:config => config) }
|
74
100
|
before do
|
75
101
|
@previous_source = LogStasher.source
|
76
|
-
config.
|
102
|
+
allow(config).to receive_messages(:action_dispatch => double(:rack_cache => false))
|
103
|
+
allow_message_expectations_on_nil
|
77
104
|
end
|
78
105
|
after { LogStasher.source = @previous_source } # Need to restore old source for specs
|
79
106
|
it 'defines a method in ActionController::Base' do
|
80
|
-
LogStasher.
|
81
|
-
LogStasher.
|
82
|
-
LogStasher.
|
83
|
-
LogStasher::RequestLogSubscriber.
|
84
|
-
|
107
|
+
expect(LogStasher).to receive(:require).with('logstasher/rails_ext/action_controller/metal/instrumentation')
|
108
|
+
expect(LogStasher).to receive(:require).with('logstash-event')
|
109
|
+
expect(LogStasher).to receive(:suppress_app_logs).with(app)
|
110
|
+
expect(LogStasher::RequestLogSubscriber).to receive(:attach_to).with(:action_controller)
|
111
|
+
expect(LogStasher::MailerLogSubscriber).to receive(:attach_to).with(:action_mailer)
|
112
|
+
expect(logger).to receive(:level=).with('warn')
|
85
113
|
LogStasher.setup(app)
|
86
|
-
LogStasher.source.
|
87
|
-
LogStasher.
|
88
|
-
LogStasher.custom_fields.
|
89
|
-
LogStasher.log_controller_parameters.
|
114
|
+
expect(LogStasher.source).to eq (logstasher_source || 'unknown')
|
115
|
+
expect(LogStasher).to be_enabled
|
116
|
+
expect(LogStasher.custom_fields).to be_empty
|
117
|
+
expect(LogStasher.log_controller_parameters).to eq false
|
90
118
|
end
|
91
119
|
end
|
92
120
|
|
93
121
|
describe '.setup' do
|
122
|
+
let(:logger) { double }
|
123
|
+
let(:logger_path) { nil }
|
124
|
+
|
94
125
|
describe 'with source set' do
|
95
126
|
let(:logstasher_source) { 'foo' }
|
96
127
|
it_behaves_like 'setup'
|
@@ -100,21 +131,37 @@ describe LogStasher do
|
|
100
131
|
let(:logstasher_source) { nil }
|
101
132
|
it_behaves_like 'setup'
|
102
133
|
end
|
134
|
+
|
135
|
+
describe 'with customized logging' do
|
136
|
+
let(:logger) { nil }
|
137
|
+
|
138
|
+
context 'with no logger passed in' do
|
139
|
+
before { expect(LogStasher).to receive(:new_logger).with('/log/logstash_test.log') }
|
140
|
+
it_behaves_like 'setup'
|
141
|
+
end
|
142
|
+
|
143
|
+
context 'with custom logger path passed in' do
|
144
|
+
let(:logger_path) { double }
|
145
|
+
|
146
|
+
before { expect(LogStasher).to receive(:new_logger).with(logger_path) }
|
147
|
+
it_behaves_like 'setup'
|
148
|
+
end
|
149
|
+
end
|
103
150
|
end
|
104
151
|
|
105
152
|
describe '.suppress_app_logs' do
|
106
153
|
let(:logstasher_config){ double(:logstasher => double(:suppress_app_log => true))}
|
107
154
|
let(:app){ double(:config => logstasher_config)}
|
108
155
|
it 'removes existing subscription if enabled' do
|
109
|
-
LogStasher.
|
110
|
-
LogStasher.
|
156
|
+
expect(LogStasher).to receive(:require).with('logstasher/rails_ext/rack/logger')
|
157
|
+
expect(LogStasher).to receive(:remove_existing_log_subscriptions)
|
111
158
|
LogStasher.suppress_app_logs(app)
|
112
159
|
end
|
113
160
|
|
114
161
|
context 'when disabled' do
|
115
162
|
let(:logstasher_config){ double(:logstasher => double(:suppress_app_log => false)) }
|
116
163
|
it 'does not remove existing subscription' do
|
117
|
-
LogStasher.
|
164
|
+
expect(LogStasher).to_not receive(:remove_existing_log_subscriptions)
|
118
165
|
LogStasher.suppress_app_logs(app)
|
119
166
|
end
|
120
167
|
|
@@ -122,7 +169,7 @@ describe LogStasher do
|
|
122
169
|
context 'with spelling "supress_app_log"' do
|
123
170
|
let(:logstasher_config){ double(:logstasher => double(:suppress_app_log => nil, :supress_app_log => false)) }
|
124
171
|
it 'does not remove existing subscription' do
|
125
|
-
LogStasher.
|
172
|
+
expect(LogStasher).to_not receive(:remove_existing_log_subscriptions)
|
126
173
|
LogStasher.suppress_app_logs(app)
|
127
174
|
end
|
128
175
|
end
|
@@ -133,14 +180,14 @@ describe LogStasher do
|
|
133
180
|
describe '.appended_params' do
|
134
181
|
it 'returns the stored var in current thread' do
|
135
182
|
Thread.current[:logstasher_custom_fields] = :test
|
136
|
-
LogStasher.custom_fields.
|
183
|
+
expect(LogStasher.custom_fields).to eq :test
|
137
184
|
end
|
138
185
|
end
|
139
186
|
|
140
187
|
describe '.appended_params=' do
|
141
188
|
it 'returns the stored var in current thread' do
|
142
189
|
LogStasher.custom_fields = :test
|
143
|
-
Thread.current[:logstasher_custom_fields].
|
190
|
+
expect(Thread.current[:logstasher_custom_fields]).to eq :test
|
144
191
|
end
|
145
192
|
end
|
146
193
|
|
@@ -148,11 +195,12 @@ describe LogStasher do
|
|
148
195
|
let(:logger) { double() }
|
149
196
|
before do
|
150
197
|
LogStasher.logger = logger
|
151
|
-
LogStash::Time.
|
198
|
+
allow(LogStash::Time).to receive_messages(:now => 'timestamp')
|
199
|
+
allow_message_expectations_on_nil
|
152
200
|
end
|
153
201
|
it 'adds to log with specified level' do
|
154
|
-
logger.
|
155
|
-
logger.
|
202
|
+
expect(logger).to receive(:send).with('warn?').and_return(true)
|
203
|
+
expect(logger).to receive(:send).with('warn',"{\"@source\":\"unknown\",\"@tags\":[\"log\"],\"@fields\":{\"message\":\"WARNING\",\"level\":\"warn\"},\"@timestamp\":\"timestamp\"}")
|
156
204
|
LogStasher.log('warn', 'WARNING')
|
157
205
|
end
|
158
206
|
context 'with a source specified' do
|
@@ -160,8 +208,8 @@ describe LogStasher do
|
|
160
208
|
LogStasher.source = 'foo'
|
161
209
|
end
|
162
210
|
it 'sets the correct source' do
|
163
|
-
logger.
|
164
|
-
logger.
|
211
|
+
expect(logger).to receive(:send).with('warn?').and_return(true)
|
212
|
+
expect(logger).to receive(:send).with('warn',"{\"@source\":\"foo\",\"@tags\":[\"log\"],\"@fields\":{\"message\":\"WARNING\",\"level\":\"warn\"},\"@timestamp\":\"timestamp\"}")
|
165
213
|
LogStasher.log('warn', 'WARNING')
|
166
214
|
end
|
167
215
|
end
|
@@ -171,7 +219,7 @@ describe LogStasher do
|
|
171
219
|
describe ".#{severity}" do
|
172
220
|
let(:message) { "This is a #{severity} message" }
|
173
221
|
it 'should log with specified level' do
|
174
|
-
LogStasher.
|
222
|
+
expect(LogStasher).to receive(:log).with(severity.to_sym, message)
|
175
223
|
LogStasher.send(severity, message )
|
176
224
|
end
|
177
225
|
end
|
@@ -192,7 +240,7 @@ describe LogStasher do
|
|
192
240
|
before(:each) { LogStasher.custom_fields = [] }
|
193
241
|
|
194
242
|
it "subscribes to the required event" do
|
195
|
-
ActiveSupport::Notifications.
|
243
|
+
expect(ActiveSupport::Notifications).to receive(:subscribe).with('event_name')
|
196
244
|
LogStasher.watch('event_name')
|
197
245
|
end
|
198
246
|
|
@@ -208,7 +256,7 @@ describe LogStasher do
|
|
208
256
|
probe = lambda { |*args, store| store[:foo] = :bar }
|
209
257
|
LogStasher.watch('custom.event.bar', &probe)
|
210
258
|
ActiveSupport::Notifications.instrument('custom.event.bar', {})
|
211
|
-
LogStasher.store['custom.event.bar'].
|
259
|
+
expect(LogStasher.store['custom.event.bar']).to eq :foo => :bar
|
212
260
|
end
|
213
261
|
end
|
214
262
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -23,6 +23,8 @@ require 'bundler/setup'
|
|
23
23
|
# part of Rails. You can say :require => false in gemfile to always use explicit requiring
|
24
24
|
Bundler.require(:default, :test)
|
25
25
|
|
26
|
+
Dir[File.join("./spec/support/**/*.rb")].each { |f| require f }
|
27
|
+
|
26
28
|
# Set Rails environment as test
|
27
29
|
ENV['RAILS_ENV'] = 'test'
|
28
30
|
|
@@ -40,11 +42,11 @@ require 'active_support/core_ext/hash/slice'
|
|
40
42
|
require 'active_support/core_ext/string'
|
41
43
|
require 'active_support/core_ext/time/zones'
|
42
44
|
require 'abstract_controller/base'
|
45
|
+
require 'action_mailer'
|
43
46
|
require 'logger'
|
44
47
|
require 'logstash-event'
|
45
48
|
|
46
49
|
RSpec.configure do |config|
|
47
|
-
config.treat_symbols_as_metadata_keys_with_true_values = true
|
48
50
|
config.run_all_when_everything_filtered = true
|
49
51
|
config.filter_run :focus
|
50
52
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'action_mailer'
|
2
|
+
|
3
|
+
class SampleMailer < ActionMailer::Base
|
4
|
+
def welcome
|
5
|
+
mail(from: 'some-dude@example.com', to: 'some-other-dude@example.com', subject: 'Hello, there') do |format|
|
6
|
+
format.text { render plain: 'OK' }
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def receive(email)
|
11
|
+
end
|
12
|
+
|
13
|
+
def _render_template(_)
|
14
|
+
""
|
15
|
+
end
|
16
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: logstasher
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shadab Ahmed
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-08-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: logstash-event
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - ! '>='
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '2.14'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '2.14'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: bundler
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -104,9 +104,11 @@ files:
|
|
104
104
|
- logstasher.gemspec
|
105
105
|
- sample_logstash_configurations/quickstart.conf
|
106
106
|
- spec/lib/logstasher/device/redis_spec.rb
|
107
|
+
- spec/lib/logstasher/instrumentation_spec.rb
|
107
108
|
- spec/lib/logstasher/log_subscriber_spec.rb
|
108
109
|
- spec/lib/logstasher_spec.rb
|
109
110
|
- spec/spec_helper.rb
|
111
|
+
- spec/support/sample_mailer.rb
|
110
112
|
homepage: https://github.com/shadabahmed/logstasher
|
111
113
|
licenses: []
|
112
114
|
metadata: {}
|
@@ -126,12 +128,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
126
128
|
version: '0'
|
127
129
|
requirements: []
|
128
130
|
rubyforge_project: logstasher
|
129
|
-
rubygems_version: 2.
|
131
|
+
rubygems_version: 2.2.2
|
130
132
|
signing_key:
|
131
133
|
specification_version: 4
|
132
134
|
summary: Awesome rails logs
|
133
135
|
test_files:
|
134
136
|
- spec/lib/logstasher/device/redis_spec.rb
|
137
|
+
- spec/lib/logstasher/instrumentation_spec.rb
|
135
138
|
- spec/lib/logstasher/log_subscriber_spec.rb
|
136
139
|
- spec/lib/logstasher_spec.rb
|
137
140
|
- spec/spec_helper.rb
|
141
|
+
- spec/support/sample_mailer.rb
|