stasher 0.1.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.
@@ -0,0 +1,246 @@
1
+ require 'spec_helper'
2
+
3
+ describe Stasher do
4
+ describe "when removing Rails' log subscribers" do
5
+ after do
6
+ ActionController::LogSubscriber.attach_to :action_controller
7
+ ActionView::LogSubscriber.attach_to :action_view
8
+ end
9
+
10
+ it "should remove subscribers for controller events" do
11
+ expect {
12
+ Stasher.remove_existing_log_subscriptions
13
+ }.to change {
14
+ ActiveSupport::Notifications.notifier.listeners_for('process_action.action_controller')
15
+ }
16
+ end
17
+
18
+ it "should remove subscribers for all events" do
19
+ expect {
20
+ Stasher.remove_existing_log_subscriptions
21
+ }.to change {
22
+ ActiveSupport::Notifications.notifier.listeners_for('render_template.action_view')
23
+ }
24
+ end
25
+
26
+ it "shouldn't remove subscribers that aren't from Rails" do
27
+ blk = -> {}
28
+ ActiveSupport::Notifications.subscribe("process_action.action_controller", &blk)
29
+ Stasher.remove_existing_log_subscriptions
30
+ listeners = ActiveSupport::Notifications.notifier.listeners_for('process_action.action_controller')
31
+ listeners.size.should > 0
32
+ end
33
+ end
34
+
35
+ describe '.add_default_fields_to_scope' do
36
+ let(:scope) { {} }
37
+ let(:request) { double(:params => {}, :remote_ip => '10.0.0.1', :uuid => "uuid" )}
38
+
39
+ it 'appends default parameters to payload' do
40
+ Stasher.add_default_fields_to_scope(scope, request)
41
+
42
+ scope.should == { :uuid => "uuid" }
43
+ end
44
+ end
45
+
46
+ describe '.add_custom_fields' do
47
+ let(:block) { ->{} }
48
+
49
+ it 'defines a method in ActionController::Metal' do
50
+ ActionController::Metal.should_receive(:send).with(:define_method, :stasher_add_custom_fields_to_scope, &block)
51
+ Stasher.add_custom_fields(&block)
52
+ end
53
+ end
54
+
55
+ describe '.setup' do
56
+ let(:logger) { double }
57
+ let(:stasher_config) { double(:logger => logger, :redirect_logger => true, :attach_to => [:active_record], :log_level => nil, :suppress_app_log => nil ) }
58
+ let(:config) { double(:stasher => stasher_config) }
59
+ let(:app) { double(:config => config) }
60
+
61
+ before :each do
62
+ logger.stub(:level=)
63
+ config.stub(:action_dispatch => double(:rack_cache => false))
64
+ end
65
+
66
+ context "when suppress_app_log is true" do
67
+ before :each do
68
+ stasher_config.stub(:suppress_app_log).and_return(true)
69
+ end
70
+
71
+ it 'suppresses the default logger' do
72
+ Stasher.should_receive(:suppress_app_logs).with(app)
73
+ Stasher.setup(app)
74
+ end
75
+ end
76
+
77
+ context "when suppress_app_log is false" do
78
+ before :each do
79
+ stasher_config.stub(:suppress_app_log).and_return(false)
80
+ end
81
+
82
+ it 'does not suppress the default logger' do
83
+ Stasher.should_not_receive(:suppress_app_logs).with(app)
84
+
85
+ Stasher.setup(app)
86
+ end
87
+ end
88
+
89
+ it "attaches to the requested notifiers" do
90
+ Stasher::LogSubscriber.should_receive(:attach_to).with(:active_record)
91
+
92
+ Stasher.setup(app)
93
+ end
94
+
95
+ context "when a log level is configured" do
96
+ before :each do
97
+ stasher_config.stub(:log_level).and_return(:debug)
98
+ end
99
+
100
+ it "sets the configured log level" do
101
+ logger.should_receive(:level=).with(::Logger::DEBUG)
102
+
103
+ Stasher.setup(app)
104
+ end
105
+ end
106
+
107
+ context "when a log level is not configured" do
108
+ it "defaults to WARN" do
109
+ logger.should_receive(:level=).with(::Logger::WARN)
110
+
111
+ Stasher.setup(app)
112
+ end
113
+ end
114
+
115
+ it "sets itself as enabled" do
116
+ Stasher.setup(app)
117
+ Stasher.enabled.should be_true
118
+ end
119
+
120
+ it "sets its source" do
121
+ Stasher.stub(:hostname).and_return('hostname')
122
+
123
+ Stasher.setup(app)
124
+ Stasher.source.should == "rails://hostname/r_spec/mocks"
125
+ end
126
+ end
127
+
128
+ describe '.suppress_app_logs' do
129
+ let(:stasher_config){ double(:stasher => double.as_null_object).as_null_object }
130
+ let(:app){ double(:config => stasher_config)}
131
+
132
+ it 'removes existing subscriptions' do
133
+ Stasher.should_receive(:require).with('stasher/rails_ext/rack/logger')
134
+ Stasher.should_receive(:remove_existing_log_subscriptions)
135
+ Stasher.suppress_app_logs(app)
136
+ end
137
+ end
138
+
139
+ describe '.format_exception' do
140
+ let(:type_name) { 'type' }
141
+ let(:message) { 'message' }
142
+ let(:backtrace) { 'backtrace' }
143
+
144
+ it "returns a hash of exception details" do
145
+ Stasher.format_exception(type_name, message, backtrace).should == {
146
+ :exception => {
147
+ :name => type_name,
148
+ :message => message,
149
+ :backtrace => backtrace
150
+ }
151
+ }
152
+ end
153
+ end
154
+
155
+ describe '.log' do
156
+ let(:logger) { MockLogger.new }
157
+
158
+ before :each do
159
+ Stasher.logger = logger
160
+ Stasher.source = "source"
161
+ LogStash::Time.stub(:now => 'timestamp')
162
+ end
163
+
164
+ it 'ensures the log is configured to log at the given level' do
165
+ logger.should_receive(:send).with('warn?').and_return(true)
166
+ Stasher.log('warn', 'WARNING')
167
+ end
168
+
169
+ it "does not log if the log level is higher than the severity" do
170
+ expect {
171
+ Stasher.log('debug', 'DEBUG')
172
+ }.not_to change{logger.messages.size}
173
+ end
174
+
175
+ it 'adds to log with specified level' do
176
+ Stasher.log('warn', 'WARNING')
177
+
178
+ logger.messages.first.should include '"@fields":{"severity":"WARN"}'
179
+ end
180
+
181
+ it "adds the 'log' tag" do
182
+ Stasher.log('warn', 'WARNING')
183
+ logger.messages.first.should match %r|"@tags":\[[^\[]*"log"[^\]]*\]|
184
+ end
185
+
186
+ it "adds a tag indicating the severity" do
187
+ Stasher.log('warn', 'WARNING')
188
+ logger.messages.first.should match %r|"@tags":\[[^\[]*"warn"[^\]]*\]|
189
+ end
190
+
191
+ it "logs the message to @message" do
192
+ Stasher.log('warn', "MESSAGE")
193
+ logger.messages.first.should include '"@message":"MESSAGE"'
194
+ end
195
+
196
+ it "logs the source to @source" do
197
+ Stasher.log('warn', "MESSAGE")
198
+ logger.messages.first.should include '"@source":"source"'
199
+ end
200
+
201
+ it "strips out ANSI color sequences" do
202
+ Stasher.log('warn', "\e[7;1mHELLO\e[0m WORLD")
203
+ logger.messages.first.should include '"@message":"HELLO WORLD"'
204
+ end
205
+
206
+ context "with fields in the current scope" do
207
+ before :each do
208
+ Stasher::CurrentScope.fields = { :field => "value" }
209
+ end
210
+
211
+ it 'includes the current scope fields' do
212
+ Stasher.log('warn', 'WARNING')
213
+
214
+ logger.messages.first.should match %r|"@fields":{[^}]*"field":"value"[^}]*}|
215
+ end
216
+ end
217
+
218
+ context "when logging an Exception" do
219
+ let(:exception) { Exception.new("Message") }
220
+
221
+ before :each do
222
+ exception.set_backtrace ["first", "second"]
223
+ end
224
+
225
+ it "logs the exception details" do
226
+ Stasher.log('error', exception)
227
+ logger.messages.first.should match %r|"exception":{"name":"Exception","message":"Message","backtrace":"first\\nsecond"}|
228
+ end
229
+
230
+ it "adds the 'exception' tag" do
231
+ Stasher.log('error', exception)
232
+ logger.messages.first.should match %r|\"@tags\":\[[^\[]*\"exception\"[^\]]*\]|
233
+ end
234
+ end
235
+ end
236
+
237
+ %w( fatal error warn info debug unknown ).each do |severity|
238
+ describe ".#{severity}" do
239
+ let(:message) { "This is a #{severity} message" }
240
+ it 'should log with specified level' do
241
+ Stasher.should_receive(:log).with(severity.to_sym, message)
242
+ Stasher.send(severity, message )
243
+ end
244
+ end
245
+ end
246
+ end
@@ -0,0 +1,64 @@
1
+ # Notice there is a .rspec file in the root folder. It defines rspec arguments
2
+
3
+ # Ruby 1.9 uses simplecov. The ENV['COVERAGE'] is set when rake coverage is run in ruby 1.9
4
+ if ENV['COVERAGE']
5
+ require 'simplecov'
6
+ SimpleCov.start do
7
+ # Remove the spec folder from coverage. By default all code files are included. For more config options see
8
+ # https://github.com/colszowka/simplecov
9
+ add_filter File.expand_path('../../spec', __FILE__)
10
+ end
11
+ end
12
+
13
+ # Modify load path so you can require 'multi_config' directly.
14
+ $LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__))
15
+
16
+ require 'rubygems'
17
+ # Loads bundler setup tasks. Now if I run spec without installing gems then it would say gem not installed and
18
+ # do bundle install instead of ugly load error on require.
19
+ require 'bundler/setup'
20
+
21
+ # This will require me all the gems automatically for the groups. If I do only .setup then I will have to require gems
22
+ # manually. Note that you have still have to require some gems if they are part of bigger gem like ActiveRecord which is
23
+ # part of Rails. You can say :require => false in gemfile to always use explicit requiring
24
+ Bundler.require(:default, :test)
25
+
26
+ # Set Rails environment as test
27
+ ENV['RAILS_ENV'] = 'test'
28
+
29
+ require 'action_pack'
30
+ require 'action_controller'
31
+ require 'active_record'
32
+ require 'socket'
33
+ require 'stasher'
34
+ require 'active_support/notifications'
35
+ require 'active_support/core_ext/string'
36
+ require 'active_support/log_subscriber'
37
+ require 'active_record/log_subscriber'
38
+ require 'action_controller/log_subscriber'
39
+ require 'action_view/log_subscriber'
40
+ require 'active_support/core_ext/hash/except'
41
+ require 'active_support/core_ext/hash/indifferent_access'
42
+ require 'active_support/core_ext/hash/slice'
43
+ require 'active_support/core_ext/string'
44
+ require 'active_support/core_ext/time/zones'
45
+ require 'abstract_controller/base'
46
+ require 'logger'
47
+ require 'logstash-event'
48
+
49
+ FactoryGirl.find_definitions
50
+
51
+ Dir[File.expand_path("spec/support/**/*.rb")].each {|f| require f}
52
+
53
+ RSpec.configure do |config|
54
+ config.treat_symbols_as_metadata_keys_with_true_values = true
55
+ config.run_all_when_everything_filtered = true
56
+ config.filter_run :focus
57
+ config.order = 'random'
58
+
59
+ config.before :each do
60
+ # Clear the current scope object, if it's set
61
+ Stasher::CurrentScope.clear!
62
+ end
63
+
64
+ end
@@ -0,0 +1,19 @@
1
+ ##
2
+ # A standard Logger that logs messages to an array (accessible as #messages)
3
+ class MockLogger < ::Logger
4
+ def initialize(log_level = ::Logger::WARN)
5
+ super(nil)
6
+ @messages = []
7
+ self.level = log_level
8
+ end
9
+
10
+ attr_reader :messages
11
+
12
+ def reset!
13
+ @messages = []
14
+ end
15
+
16
+ def <<(message)
17
+ @messages << message
18
+ end
19
+ end
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'stasher/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "stasher"
8
+ spec.version = Stasher::VERSION
9
+ spec.authors = ["Chris Micacchi"]
10
+ spec.email = ["cdmicacc@gmail.com"]
11
+ spec.description = %q{Send Rails log messages to logstash}
12
+ spec.summary = %q{Send Rails log messages to logstash}
13
+ spec.homepage = "https://github.com/cdmicacc/stasher"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_runtime_dependency "logstash-event"
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.3"
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "rspec"
26
+ spec.add_development_dependency "rails", ">= 3.2"
27
+ end
metadata ADDED
@@ -0,0 +1,164 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: stasher
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Chris Micacchi
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-08-26 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: logstash-event
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: bundler
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '1.3'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '1.3'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rake
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rspec
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: rails
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '3.2'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '3.2'
94
+ description: Send Rails log messages to logstash
95
+ email:
96
+ - cdmicacc@gmail.com
97
+ executables: []
98
+ extensions: []
99
+ extra_rdoc_files: []
100
+ files:
101
+ - .gitattributes
102
+ - .gitignore
103
+ - .rspec
104
+ - .ruby-gemset
105
+ - Gemfile
106
+ - Guardfile
107
+ - LICENSE.txt
108
+ - README.md
109
+ - Rakefile
110
+ - lib/stasher.rb
111
+ - lib/stasher/current_scope.rb
112
+ - lib/stasher/log_subscriber.rb
113
+ - lib/stasher/logger.rb
114
+ - lib/stasher/rails_ext/action_controller/metal/instrumentation.rb
115
+ - lib/stasher/rails_ext/rack/logger.rb
116
+ - lib/stasher/railtie.rb
117
+ - lib/stasher/version.rb
118
+ - spec/factories/payloads.rb
119
+ - spec/lib/stasher/current_scope_spec.rb
120
+ - spec/lib/stasher/log_subscriber_spec.rb
121
+ - spec/lib/stasher/logger_spec.rb
122
+ - spec/lib/stasher_spec.rb
123
+ - spec/spec_helper.rb
124
+ - spec/support/mock_logger.rb
125
+ - stasher.gemspec
126
+ homepage: https://github.com/cdmicacc/stasher
127
+ licenses:
128
+ - MIT
129
+ post_install_message:
130
+ rdoc_options: []
131
+ require_paths:
132
+ - lib
133
+ required_ruby_version: !ruby/object:Gem::Requirement
134
+ none: false
135
+ requirements:
136
+ - - ! '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ segments:
140
+ - 0
141
+ hash: 2540691357130130508
142
+ required_rubygems_version: !ruby/object:Gem::Requirement
143
+ none: false
144
+ requirements:
145
+ - - ! '>='
146
+ - !ruby/object:Gem::Version
147
+ version: '0'
148
+ segments:
149
+ - 0
150
+ hash: 2540691357130130508
151
+ requirements: []
152
+ rubyforge_project:
153
+ rubygems_version: 1.8.25
154
+ signing_key:
155
+ specification_version: 3
156
+ summary: Send Rails log messages to logstash
157
+ test_files:
158
+ - spec/factories/payloads.rb
159
+ - spec/lib/stasher/current_scope_spec.rb
160
+ - spec/lib/stasher/log_subscriber_spec.rb
161
+ - spec/lib/stasher/logger_spec.rb
162
+ - spec/lib/stasher_spec.rb
163
+ - spec/spec_helper.rb
164
+ - spec/support/mock_logger.rb