stasher 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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