lograge 0.2.0 → 0.2.1

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.
data/.travis.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  language: ruby
2
2
  rvm:
3
3
  - 1.9.3
4
- - 1.9.2
4
+ - 2.0.0
5
5
  script: bundle exec rspec
data/Gemfile CHANGED
@@ -5,5 +5,5 @@ gemspec
5
5
 
6
6
  group :test do
7
7
  gem 'actionpack'
8
- gem 'logstash-event'
8
+ gem 'logstash-event', '1.1.5'
9
9
  end
data/README.md CHANGED
@@ -70,19 +70,47 @@ MyApp::Application.configure do
70
70
  # if it's a lambda then it must return a hash
71
71
  config.lograge.custom_options = lambda do |event|
72
72
  # capture some specific timing values you are interested in
73
- {:name => "value", :timing => some_float.round(2)}
73
+ {:name => "value", :timing => some_float.round(2), :host => event.payload[:host]}
74
+ end
75
+ end
76
+ ```
77
+
78
+ You can then add custom variables to the event to be used in custom_options
79
+
80
+ ```ruby
81
+ # app/controllers/application_controller.rb
82
+ class ApplicationController < ActionController::Base
83
+ def append_info_to_payload(payload)
84
+ super
85
+ payload[:host] = request.host
86
+ end
87
+ end
88
+ ```
89
+
90
+ To further clean up your logging, you can also tell Lograge to skip log messages
91
+ meeting given criteria. You can skip log messages generated from certain controller
92
+ actions, or you can write a custom handler to skip messages based on data in the log event:
93
+
94
+ ```ruby
95
+ # config/environments/production.rb
96
+ MyApp::Application.configure do
97
+ config.lograge.enabled = true
98
+
99
+ config.lograge.ignore_actions = ['home#index', 'aController#anAction']
100
+ config.lograge.ignore_custom = lambda do |event|
101
+ # return true here if you want to ignore based on the event
74
102
  end
75
103
  end
76
104
  ```
77
105
 
78
106
  Lograge supports multiple output formats. The most common is the default
79
- lograge format described above. Alternatively, you can also generate JSON
80
- logs in the json_event format used by [Logstash](http://logstash.net/).
107
+ lograge key-value format described above. Alternatively, you can also generate
108
+ JSON logs in the json_event format used by [Logstash](http://logstash.net/).
81
109
 
82
110
  ```ruby
83
111
  # config/environments/production.rb
84
112
  MyApp::Application.configure do
85
- config.lograge.log_format = :logstash
113
+ config.lograge.formatter = Lograge::Formatters::Logstash.new
86
114
  end
87
115
  ```
88
116
 
@@ -95,6 +123,26 @@ gem "logstash-event"
95
123
 
96
124
  Done.
97
125
 
126
+ The available formatters are:
127
+
128
+ ```ruby
129
+ Lograge::Formatters::Cee.new
130
+ Lograge::Formatters::Graylog2.new
131
+ Lograge::Formatters::KeyValue.new # default lograge format
132
+ Lograge::Formatters::Logstash.new
133
+ Lograge::Formatters::Raw.new # Returns a ruby hash object
134
+ ```
135
+
136
+ In addition to the formatters, you can manipulate the data your self by passing
137
+ an object which responds to #call:
138
+
139
+ ```ruby
140
+ # config/environments/production.rb
141
+ MyApp::Application.configure do
142
+ config.lograge.formatter = ->(data) { "Called #{data[:controller]}" } # data is a ruby hash
143
+ end
144
+ ```
145
+
98
146
  **Internals**
99
147
 
100
148
  Thanks to the notification system that was introduced in Rails 3, replacing the
data/lib/lograge.rb CHANGED
@@ -1,9 +1,15 @@
1
1
  require 'lograge/version'
2
+ require 'lograge/formatters/cee'
3
+ require 'lograge/formatters/graylog2'
4
+ require 'lograge/formatters/key_value'
5
+ require 'lograge/formatters/logstash'
6
+ require 'lograge/formatters/raw'
2
7
  require 'lograge/log_subscriber'
3
8
  require 'active_support/core_ext/module/attribute_accessors'
4
9
  require 'active_support/core_ext/string/inflections'
5
10
  require 'active_support/ordered_options'
6
11
 
12
+
7
13
  module Lograge
8
14
  mattr_accessor :logger
9
15
 
@@ -24,13 +30,51 @@ module Lograge
24
30
  end
25
31
  end
26
32
 
33
+ # Set conditions for events that should be ignored
34
+ #
35
+ # Currently supported formats are:
36
+ # - A single string representing a controller action, e.g. 'users#sign_in'
37
+ # - An array of strings representing controller actions
38
+ # - An object that responds to call with an event argument and returns
39
+ # true iff the event should be ignored.
40
+ #
41
+ # The action ignores are given to 'ignore_actions'. The callable ignores
42
+ # are given to 'ignore'. Both methods can be called multiple times, which
43
+ # just adds more ignore conditions to a list that is checked before logging.
44
+
45
+ def self.ignore_actions(actions)
46
+ ignore(lambda do |event|
47
+ params = event.payload[:params]
48
+ Array(actions).include?("#{params['controller']}##{params['action']}")
49
+ end)
50
+ end
51
+
52
+ def self.ignore_tests
53
+ @@ignore_tests ||= []
54
+ end
55
+
56
+ def self.ignore(test)
57
+ ignore_tests.push(test) if test
58
+ end
59
+
60
+ def self.ignore_nothing
61
+ @@ignore_tests = []
62
+ end
63
+
64
+ def self.ignore?(event)
65
+ ignore_tests.any?{|ignore_test| ignore_test.call(event)}
66
+ end
67
+
68
+ # Loglines are emitted with this log level
69
+ mattr_accessor :log_level
70
+ self.log_level = :info
71
+
27
72
  # The emitted log format
28
73
  #
29
74
  # Currently supported formats are>
30
75
  # - :lograge - The custom tense lograge format
31
76
  # - :logstash - JSON formatted as a Logstash Event.
32
- mattr_accessor :log_format
33
- self.log_format = :lograge
77
+ mattr_accessor :formatter
34
78
 
35
79
  def self.remove_existing_log_subscriptions
36
80
  ActiveSupport::LogSubscriber.log_subscribers.each do |subscriber|
@@ -60,15 +104,19 @@ module Lograge
60
104
  Lograge.remove_existing_log_subscriptions
61
105
  Lograge::RequestLogSubscriber.attach_to :action_controller
62
106
  Lograge.custom_options = app.config.lograge.custom_options
63
- Lograge.log_format = app.config.lograge.log_format || :lograge
64
- case Lograge.log_format.to_s
65
- when "logstash"
66
- begin
67
- require "logstash-event"
68
- rescue LoadError
69
- puts "You need to install the logstash-event gem to use the logstash output."
70
- raise
71
- end
107
+ Lograge.log_level = app.config.lograge.log_level || :info
108
+ self.support_deprecated_config(app) # TODO: Remove with version 1.0
109
+ Lograge.formatter = app.config.lograge.formatter || Lograge::Formatters::KeyValue.new
110
+ Lograge.ignore_actions(app.config.lograge.ignore_actions)
111
+ Lograge.ignore(app.config.lograge.ignore_custom)
112
+ end
113
+
114
+ # TODO: Remove with version 1.0
115
+ def self.support_deprecated_config(app)
116
+ if legacy_log_format = app.config.lograge.log_format
117
+ ActiveSupport::Deprecation.warn 'config.lograge.log_format is deprecated. Use config.lograge.formatter instead.', caller
118
+ legacy_log_format = :key_value if legacy_log_format == :lograge
119
+ app.config.lograge.formatter = "Lograge::Formatters::#{legacy_log_format.to_s.classify}".constantize.new
72
120
  end
73
121
  end
74
122
  end
@@ -0,0 +1,9 @@
1
+ module Lograge
2
+ module Formatters
3
+ class Cee
4
+ def call(data)
5
+ "@cee: #{JSON.dump(data)}"
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,19 @@
1
+ module Lograge
2
+ module Formatters
3
+ class Graylog2
4
+ def call(data)
5
+ # Cloning because we don't want to mess with the original when mutating keys.
6
+ my = data.clone
7
+
8
+ base = {
9
+ :short_message => "[#{my[:status]}] #{my[:method]} #{my[:path]} (#{my[:controller]}##{my[:action]})"
10
+ }
11
+
12
+ # Add underscore to every key to follow GELF additional field syntax.
13
+ my.keys.each { |k| my["_#{k}".to_sym] = my[k]; my.delete(k) }
14
+
15
+ my.merge(base)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,29 @@
1
+ module Lograge
2
+ module Formatters
3
+ class KeyValue
4
+ LOGRAGE_FIELDS = [
5
+ :method, :path, :format, :controller, :action, :status, :error,
6
+ :duration, :view, :db, :location
7
+ ]
8
+
9
+ def call(data)
10
+ fields = LOGRAGE_FIELDS
11
+ fields += (data.keys - LOGRAGE_FIELDS)
12
+
13
+ event = fields.inject([]) do |message, key|
14
+ next message unless data.has_key?(key)
15
+ # Exactly preserve the previous output
16
+ # Parsing this can be ambigious if the error messages contains
17
+ # a single quote
18
+ data[key] = "'#{data[key]}'" if key == :error
19
+ # Ensure that we always have exactly two decimals
20
+ data[key] = "%.2f" % data[key] if data[key].is_a? Float
21
+
22
+ message << "#{key}=#{data[key]}"
23
+ message
24
+ end
25
+ event.join(" ")
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,19 @@
1
+ module Lograge
2
+ module Formatters
3
+ class Logstash
4
+ def call(data)
5
+ load_dependencies
6
+ event = LogStash::Event.new("@fields" => data)
7
+ event.message = "[#{data[:status]}] #{data[:method]} #{data[:path]} (#{data[:controller]}##{data[:action]})"
8
+ event.to_json
9
+ end
10
+
11
+ def load_dependencies
12
+ require "logstash-event"
13
+ rescue LoadError
14
+ puts "You need to install the logstash-event gem to use the logstash output."
15
+ raise
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,9 @@
1
+ module Lograge
2
+ module Formatters
3
+ class Raw
4
+ def call(data)
5
+ data
6
+ end
7
+ end
8
+ end
9
+ end
@@ -1,9 +1,13 @@
1
+ require 'json'
2
+
1
3
  require 'active_support/core_ext/class/attribute'
2
4
  require 'active_support/log_subscriber'
3
5
 
4
6
  module Lograge
5
7
  class RequestLogSubscriber < ActiveSupport::LogSubscriber
6
8
  def process_action(event)
9
+ return if Lograge.ignore?(event)
10
+
7
11
  payload = event.payload
8
12
 
9
13
  data = extract_request(payload)
@@ -12,49 +16,8 @@ module Lograge
12
16
  data.merge! location(event)
13
17
  data.merge! custom_options(event)
14
18
 
15
- logger.info send(:"process_action_#{Lograge.log_format}", data)
16
- end
17
-
18
- LOGRAGE_FIELDS = [
19
- :method, :path, :format, :controller, :action, :status, :error,
20
- :duration, :view, :db, :location
21
- ]
22
- def process_action_lograge(data)
23
- fields = LOGRAGE_FIELDS
24
- fields += (data.keys - LOGRAGE_FIELDS)
25
-
26
- event = fields.inject([]) do |message, key|
27
- next message unless data.has_key?(key)
28
- # Exactly preserve the previous output
29
- # Parsing this can be ambigious if the error messages contains
30
- # a single quote
31
- data[key] = "'#{data[key]}'" if key == :error
32
- # Ensure that we always have exactly two decimals
33
- data[key] = "%.2f" % data[key] if data[key].is_a? Float
34
-
35
- message << "#{key}=#{data[key]}"
36
- message
37
- end
38
- event.join(" ")
39
- end
40
-
41
- def process_action_logstash(data)
42
- event = LogStash::Event.new("@fields" => data)
43
- event.to_json
44
- end
45
-
46
- def process_action_graylog2(data)
47
- # Cloning because we don't want to mess with the original when mutating keys.
48
- my = data.clone
49
-
50
- base = {
51
- :short_message => "[#{my[:status]}] #{my[:method]} #{my[:path]} (#{my[:controller]}##{my[:action]})"
52
- }
53
-
54
- # Add underscore to every key to follow GELF additional field syntax.
55
- my.keys.each { |k| my["_#{k}".to_sym] = my[k]; my.delete(k) }
56
-
57
- my.merge(base)
19
+ formatted_message = Lograge.formatter.call(data)
20
+ logger.send(Lograge.log_level, formatted_message)
58
21
  end
59
22
 
60
23
  def redirect_to(event)
@@ -63,6 +26,10 @@ module Lograge
63
26
 
64
27
  private
65
28
 
29
+ def logger
30
+ Lograge.logger.presence or super
31
+ end
32
+
66
33
  def extract_request(payload)
67
34
  {
68
35
  :method => payload[:method],
@@ -1,3 +1,4 @@
1
+ require 'active_support/concern'
1
2
  require 'rails/rack/logger'
2
3
 
3
4
  module Rails
@@ -1,3 +1,3 @@
1
1
  module Lograge
2
- VERSION = "0.2.0"
2
+ VERSION = "0.2.1"
3
3
  end
data/lograge.gemspec CHANGED
@@ -21,6 +21,7 @@ Gem::Specification.new do |s|
21
21
  # specify any dependencies here; for example:
22
22
  s.add_development_dependency "rspec"
23
23
  s.add_development_dependency "guard-rspec"
24
- s.add_runtime_dependency "activesupport"
25
- s.add_runtime_dependency "actionpack"
24
+ s.add_runtime_dependency "activesupport", '>= 3'
25
+ s.add_runtime_dependency "actionpack", '>= 3'
26
+ s.add_runtime_dependency "railties", '>= 3'
26
27
  end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+ require 'lograge'
3
+
4
+ describe Lograge::Formatters::Cee do
5
+ it { expect( subject.call({})).to match(/^@cee/) }
6
+ it { expect(subject.call({ custom: 'data'})).to match('{"custom":"data"}') }
7
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+ require 'lograge'
3
+
4
+ describe Lograge::Formatters::Graylog2 do
5
+ let(:payload) do
6
+ {
7
+ custom: 'data',
8
+ status: 200,
9
+ method: 'GET',
10
+ path: '/',
11
+ controller: 'welcome',
12
+ action: 'index'
13
+ }
14
+ end
15
+ subject { described_class.new.call(payload) }
16
+ it { expect(subject[:_custom]).to eq('data') }
17
+ it { expect(subject[:short_message]).to eq('[200] GET / (welcome#index)') }
18
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+ require 'lograge'
3
+
4
+ describe Lograge::Formatters::KeyValue do
5
+ let(:payload) do
6
+ {
7
+ custom: 'data',
8
+ status: 200,
9
+ method: 'GET',
10
+ path: '/',
11
+ controller: 'welcome',
12
+ action: 'index'
13
+ }
14
+ end
15
+ subject { described_class.new.call(payload) }
16
+
17
+ it { should include('method=GET') }
18
+ it { should include('path=/') }
19
+ it { should include('controller=welcome') }
20
+ it { should include('action=index') }
21
+ it { should include('status=200') }
22
+ it { should include('custom=data') }
23
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+ require 'lograge'
3
+
4
+ describe Lograge::Formatters::Logstash do
5
+ let(:payload) do
6
+ {
7
+ custom: 'data',
8
+ status: 200,
9
+ method: 'GET',
10
+ path: '/',
11
+ controller: 'welcome',
12
+ action: 'index'
13
+ }
14
+ end
15
+ subject { described_class.new.call(payload) }
16
+ it { should match(/"@source":"unknown"/) }
17
+ it { should match(/"@tags":\[\]/) }
18
+ it { should match(/"@fields":{/) }
19
+ it { should match(/"custom":"data"/) }
20
+ it { should match(/"status":200/) }
21
+ it { should match(/"method":"GET"/) }
22
+ it { should match(/"path":"\/"/) }
23
+ it { should match(/"controller":"welcome"/) }
24
+ it { should match(/"action":"index"/) }
25
+ end
@@ -0,0 +1,6 @@
1
+ require 'spec_helper'
2
+ require 'lograge'
3
+
4
+ describe Lograge::Formatters::Raw do
5
+ it { expect( subject.call({ custom: 'data' })).to eq({ custom: 'data' }) }
6
+ end
@@ -8,15 +8,8 @@ require 'logger'
8
8
  describe Lograge::RequestLogSubscriber do
9
9
  let(:log_output) {StringIO.new}
10
10
  let(:logger) {
11
- logger = Logger.new(log_output)
12
- logger.formatter = ->(_, _, _, msg) {
13
- msg
14
- }
15
- logger
11
+ Logger.new(log_output).tap {|logger| logger.formatter = ->(_, _, _, msg) { msg } }
16
12
  }
17
- before do
18
- Lograge::RequestLogSubscriber.logger = logger
19
- end
20
13
 
21
14
  let(:subscriber) {Lograge::RequestLogSubscriber.new}
22
15
  let(:event) {
@@ -28,16 +21,46 @@ describe Lograge::RequestLogSubscriber do
28
21
  }
29
22
  )
30
23
  }
31
-
32
24
  let(:redirect) {
33
25
  ActiveSupport::Notifications::Event.new(
34
26
  'redirect_to.action_controller', Time.now, Time.now, 1, location: 'http://example.com', status: 302
35
27
  )
36
28
  }
37
29
 
30
+ before { Lograge.logger = logger }
31
+
32
+ describe "with custom_options configured for cee output" do
33
+ before do
34
+ Lograge::formatter = ->(data) { "My test: #{data}" }
35
+ end
36
+
37
+ it "should combine the hash properly for the output" do
38
+ Lograge.custom_options = {:data => "value"}
39
+ subscriber.process_action(event)
40
+ log_output.string.should =~ /^My test: {.*:data=>"value"/
41
+ end
42
+ it "should combine the output of a lambda properly" do
43
+ Lograge.custom_options = lambda {|event| {:data => "value"}}
44
+ subscriber.process_action(event)
45
+ log_output.string.should =~ /^My test: {.*:data=>"value"/
46
+ end
47
+ it "should work if the method returns nil" do
48
+ Lograge.custom_options = lambda {|event| nil}
49
+ subscriber.process_action(event)
50
+ log_output.string.should be_present
51
+ end
52
+ end
53
+
54
+ describe "when processing a redirect" do
55
+ it "should store the location in a thread local variable" do
56
+ subscriber.redirect_to(redirect)
57
+ Thread.current[:lograge_location].should == "http://example.com"
58
+ end
59
+ end
60
+
38
61
  describe "when processing an action with lograge output" do
39
62
  before do
40
- Lograge::log_format = :lograge
63
+ Lograge.formatter = Lograge::Formatters::KeyValue.new
41
64
  end
42
65
 
43
66
  it "should include the URL in the log output" do
@@ -117,234 +140,101 @@ describe Lograge::RequestLogSubscriber do
117
140
  end
118
141
  end
119
142
 
120
- describe "when processing an action with logstash output" do
143
+ describe "with custom_options configured for lograge output" do
121
144
  before do
122
- require 'logstash-event'
123
- Lograge::log_format = :logstash
145
+ Lograge.formatter = Lograge::Formatters::KeyValue.new
124
146
  end
125
147
 
126
- it "should include the URL in the log output" do
127
- subscriber.process_action(event)
128
- log_output.string.should include('/home')
129
- end
130
-
131
- it "should start include the HTTP method" do
132
- subscriber.process_action(event)
133
- log_output.string.should include('"method":"GET"')
134
- end
135
-
136
- it "should include the status code" do
137
- subscriber.process_action(event)
138
- log_output.string.should include('"status":200')
139
- end
140
-
141
- it "should include the controller and action" do
142
- subscriber.process_action(event)
143
- log_output.string.should include('"controller":"home"')
144
- log_output.string.should include('"action":"index"')
145
- end
146
-
147
- it "should include the duration" do
148
- subscriber.process_action(event)
149
- log_output.string.should =~ /"duration":\d+\.\d{0,2}/
150
- end
151
-
152
- it "should include the view rendering time" do
153
- subscriber.process_action(event)
154
- log_output.string.should =~ /"view":0.01/
155
- end
156
-
157
- it "should include the database rendering time" do
158
- subscriber.process_action(event)
159
- log_output.string.should =~ /"db":0.02/
160
- end
161
-
162
- it "should add a 500 status when an exception occurred" do
163
- event.payload[:status] = nil
164
- event.payload[:exception] = ['AbstractController::ActionNotFound', 'Route not found']
148
+ it "should combine the hash properly for the output" do
149
+ Lograge.custom_options = {:data => "value"}
165
150
  subscriber.process_action(event)
166
- log_output.string.should =~ /"status":500/
167
- log_output.string.should =~ /"error":"AbstractController::ActionNotFound:Route not found"/
151
+ log_output.string.should =~ / data=value/
168
152
  end
169
-
170
- it "should return an unknown status when no status or exception is found" do
171
- event.payload[:status] = nil
172
- event.payload[:exception] = nil
153
+ it "should combine the output of a lambda properly" do
154
+ Lograge.custom_options = lambda {|event| {:data => "value"}}
173
155
  subscriber.process_action(event)
174
- log_output.string.should =~ /"status":0/
175
- end
176
-
177
- describe "with a redirect" do
178
- before do
179
- Thread.current[:lograge_location] = "http://www.example.com"
180
- end
181
-
182
- it "should add the location to the log line" do
183
- subscriber.process_action(event)
184
- log_output.string.should =~ %r{"location":"http://www.example.com"}
185
- end
186
-
187
- it "should remove the thread local variable" do
188
- subscriber.process_action(event)
189
- Thread.current[:lograge_location].should == nil
190
- end
156
+ log_output.string.should =~ / data=value/
191
157
  end
192
-
193
- it "should not include a location by default" do
158
+ it "should work if the method returns nil" do
159
+ Lograge.custom_options = lambda {|event| nil}
194
160
  subscriber.process_action(event)
195
- log_output.string.should_not =~ /"location":/
161
+ log_output.string.should be_present
196
162
  end
197
163
  end
198
164
 
199
- describe "when processing an action with graylog2 output" do
165
+ describe "with ignore configured" do
200
166
  before do
201
- Lograge::log_format = :graylog2
202
- end
203
-
204
- it "should include the URL in the log output" do
205
- subscriber.process_action(event)
206
- log_output.string.should include(':_path=>"/home"')
167
+ # Lograge::log_format = :lograge
168
+ Lograge::ignore_nothing # clear the old ignores before each test
207
169
  end
208
170
 
209
- it "should start include the HTTP method" do
171
+ it "should not log ignored controller actions given a single ignored action" do
172
+ Lograge.ignore_actions 'home#index'
210
173
  subscriber.process_action(event)
211
- log_output.string.should include(':_method=>"GET"')
174
+ log_output.string.should be_blank
212
175
  end
213
176
 
214
- it "should include the status code" do
215
- subscriber.process_action(event)
216
- log_output.string.should include(':_status=>200') end
217
-
218
- it "should include the controller and action" do
177
+ it "should not log ignored controller actions given a single ignored action after a custom ignore" do
178
+ Lograge.ignore(lambda {|event| false})
179
+ Lograge.ignore_actions 'home#index'
219
180
  subscriber.process_action(event)
220
- log_output.string.should include(':_controller=>"home"')
221
- log_output.string.should include(':_action=>"index"')
181
+ log_output.string.should be_blank
222
182
  end
223
183
 
224
- it "should include the duration" do
184
+ it "should log non-ignored controller actions given a single ignored action" do
185
+ Lograge.ignore_actions 'foo#bar'
225
186
  subscriber.process_action(event)
226
- log_output.string.should =~ /:_duration=>\d+\.\d{0,2}/
187
+ log_output.string.should_not be_blank
227
188
  end
228
189
 
229
- it "should include the view rendering time" do
190
+ it "should not log ignored controller actions given multiple ignored actions" do
191
+ Lograge.ignore_actions ['foo#bar', 'home#index', 'bar#foo']
230
192
  subscriber.process_action(event)
231
- log_output.string.should include(':_view=>0.01')
193
+ log_output.string.should be_blank
232
194
  end
233
195
 
234
- it "should include the database rendering time" do
196
+ it "should log non-ignored controller actions given multiple ignored actions" do
197
+ Lograge.ignore_actions ['foo#bar', 'bar#foo']
235
198
  subscriber.process_action(event)
236
- log_output.string.should include(':_db=>0.02')
199
+ log_output.string.should_not be_blank
237
200
  end
238
201
 
239
- it "should add a 500 status when an exception occurred" do
240
- event.payload[:status] = nil
241
- event.payload[:exception] = ['AbstractController::ActionNotFound', 'Route not found']
202
+ it "should not log ignored events" do
203
+ Lograge.ignore(lambda do |event|
204
+ 'GET' == event.payload[:method]
205
+ end)
242
206
  subscriber.process_action(event)
243
- log_output.string.should include(':_status=>500')
244
- log_output.string.should include(':_error=>"AbstractController::ActionNotFound:Route not found"')
245
- end
246
-
247
- it "should return an unknown status when no status or exception is found" do
248
- event.payload[:status] = nil
249
- event.payload[:exception] = nil
250
- subscriber.process_action(event)
251
- log_output.string.should include(':_status=>0')
252
- end
253
-
254
- describe "with a redirect" do
255
- before do
256
- Thread.current[:lograge_location] = "http://www.example.com"
257
- end
258
-
259
- it "should add the location to the log line" do
260
- subscriber.process_action(event)
261
- log_output.string.should include(':_location=>"http://www.example.com"')
262
- end
263
-
264
- it "should remove the thread local variable" do
265
- subscriber.process_action(event)
266
- Thread.current[:lograge_location].should == nil
267
- end
207
+ log_output.string.should be_blank
268
208
  end
269
209
 
270
- it "should not include a location by default" do
210
+ it "should log non-ignored events" do
211
+ Lograge.ignore(lambda do |event|
212
+ 'foo' == event.payload[:method]
213
+ end)
271
214
  subscriber.process_action(event)
272
- log_output.string.should_not =~ /"location":/
273
- end
274
- end
275
-
276
- describe "with custom_options configured for graylog2 output" do
277
- before do
278
- Lograge::log_format = :graylog2
215
+ log_output.string.should_not be_blank
279
216
  end
280
217
 
281
- it "should combine the hash properly for the output" do
282
- Lograge.custom_options = {:data => "value"}
218
+ it "should not choke on nil ignore_actions input" do
219
+ Lograge.ignore_actions nil
283
220
  subscriber.process_action(event)
284
- log_output.string.should include(':_data=>"value"')
221
+ log_output.string.should_not be_blank
285
222
  end
286
223
 
287
- it "should combine the output of a lambda properly" do
288
- Lograge.custom_options = lambda {|event| {:data => "value"}}
224
+ it "should not choke on nil ignore input" do
225
+ Lograge.ignore nil
289
226
  subscriber.process_action(event)
290
- log_output.string.should include(':_data=>"value"')
291
- end
292
-
293
- it "should work if the method returns nil" do
294
- Lograge.custom_options = lambda {|event| nil}
295
- subscriber.process_action(event)
296
- log_output.string.should be_present
227
+ log_output.string.should_not be_blank
297
228
  end
298
229
  end
299
230
 
300
- describe "with custom_options configured for lograge output" do
301
- before do
302
- Lograge::log_format = :lograge
303
- end
231
+ it "should fallback to ActiveSupport's logger if one isn't configured" do
232
+ Lograge.formatter = Lograge::Formatters::KeyValue.new
233
+ Lograge.logger = nil
234
+ ActiveSupport::LogSubscriber.logger = logger
304
235
 
305
- it "should combine the hash properly for the output" do
306
- Lograge.custom_options = {:data => "value"}
307
- subscriber.process_action(event)
308
- log_output.string.should =~ / data=value/
309
- end
310
- it "should combine the output of a lambda properly" do
311
- Lograge.custom_options = lambda {|event| {:data => "value"}}
312
- subscriber.process_action(event)
313
- log_output.string.should =~ / data=value/
314
- end
315
- it "should work if the method returns nil" do
316
- Lograge.custom_options = lambda {|event| nil}
317
- subscriber.process_action(event)
318
- log_output.string.should be_present
319
- end
320
- end
236
+ subscriber.process_action(event)
321
237
 
322
- describe "with custom_options configured for logstash output" do
323
- before do
324
- Lograge::log_format = :logstash
325
- end
326
-
327
- it "should combine the hash properly for the output" do
328
- Lograge.custom_options = {:data => "value"}
329
- subscriber.process_action(event)
330
- log_output.string.should =~ /"data":"value"/
331
- end
332
- it "should combine the output of a lambda properly" do
333
- Lograge.custom_options = lambda {|event| {:data => "value"}}
334
- subscriber.process_action(event)
335
- log_output.string.should =~ /"data":"value"/
336
- end
337
- it "should work if the method returns nil" do
338
- Lograge.custom_options = lambda {|event| nil}
339
- subscriber.process_action(event)
340
- log_output.string.should be_present
341
- end
342
- end
343
-
344
- describe "when processing a redirect" do
345
- it "should store the location in a thread local variable" do
346
- subscriber.redirect_to(redirect)
347
- Thread.current[:lograge_location].should == "http://example.com"
348
- end
238
+ log_output.string.should be_present
349
239
  end
350
240
  end
data/spec/lograge_spec.rb CHANGED
@@ -37,4 +37,48 @@ describe Lograge do
37
37
  listeners.size.should > 0
38
38
  end
39
39
  end
40
+
41
+ describe 'deprecated log_format interpreter' do
42
+ let(:app_config) do
43
+ double(config:
44
+ ActiveSupport::OrderedOptions.new.tap do |config|
45
+ config.action_dispatch = double(rack_cache: false)
46
+ config.lograge = ActiveSupport::OrderedOptions.new
47
+ config.lograge.log_format = format
48
+ end
49
+ )
50
+ end
51
+ before { ActiveSupport::Deprecation.silence { Lograge.setup(app_config) } }
52
+ subject { Lograge.formatter }
53
+
54
+ context ':cee' do
55
+ let(:format) { :cee }
56
+ it { should be_instance_of(Lograge::Formatters::Cee) }
57
+ end
58
+
59
+ context ':raw' do
60
+ let(:format) { :raw }
61
+ it { should be_instance_of(Lograge::Formatters::Raw) }
62
+ end
63
+
64
+ context ':logstash' do
65
+ let(:format) { :logstash }
66
+ it { should be_instance_of(Lograge::Formatters::Logstash) }
67
+ end
68
+
69
+ context ':graylog2' do
70
+ let(:format) { :graylog2 }
71
+ it { should be_instance_of(Lograge::Formatters::Graylog2) }
72
+ end
73
+
74
+ context ':lograge' do
75
+ let(:format) { :lograge }
76
+ it { should be_instance_of(Lograge::Formatters::KeyValue) }
77
+ end
78
+
79
+ context 'default' do
80
+ let(:format) { nil }
81
+ it { should be_instance_of(Lograge::Formatters::KeyValue) }
82
+ end
83
+ end
40
84
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lograge
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-02-08 00:00:00.000000000 Z
12
+ date: 2013-09-17 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
@@ -50,7 +50,7 @@ dependencies:
50
50
  requirements:
51
51
  - - ! '>='
52
52
  - !ruby/object:Gem::Version
53
- version: '0'
53
+ version: '3'
54
54
  type: :runtime
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
@@ -58,7 +58,7 @@ dependencies:
58
58
  requirements:
59
59
  - - ! '>='
60
60
  - !ruby/object:Gem::Version
61
- version: '0'
61
+ version: '3'
62
62
  - !ruby/object:Gem::Dependency
63
63
  name: actionpack
64
64
  requirement: !ruby/object:Gem::Requirement
@@ -66,7 +66,7 @@ dependencies:
66
66
  requirements:
67
67
  - - ! '>='
68
68
  - !ruby/object:Gem::Version
69
- version: '0'
69
+ version: '3'
70
70
  type: :runtime
71
71
  prerelease: false
72
72
  version_requirements: !ruby/object:Gem::Requirement
@@ -74,7 +74,23 @@ dependencies:
74
74
  requirements:
75
75
  - - ! '>='
76
76
  - !ruby/object:Gem::Version
77
- version: '0'
77
+ version: '3'
78
+ - !ruby/object:Gem::Dependency
79
+ name: railties
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '3'
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '3'
78
94
  description: Tame Rails' multi-line logging into a single line per request
79
95
  email:
80
96
  - meyer@paperplanes.de
@@ -90,11 +106,21 @@ files:
90
106
  - README.md
91
107
  - Rakefile
92
108
  - lib/lograge.rb
109
+ - lib/lograge/formatters/cee.rb
110
+ - lib/lograge/formatters/graylog2.rb
111
+ - lib/lograge/formatters/key_value.rb
112
+ - lib/lograge/formatters/logstash.rb
113
+ - lib/lograge/formatters/raw.rb
93
114
  - lib/lograge/log_subscriber.rb
94
115
  - lib/lograge/rails_ext/rack/logger.rb
95
116
  - lib/lograge/railtie.rb
96
117
  - lib/lograge/version.rb
97
118
  - lograge.gemspec
119
+ - spec/formatters/cee_spec.rb
120
+ - spec/formatters/graylog2_spec.rb
121
+ - spec/formatters/key_value_spec.rb
122
+ - spec/formatters/logstash_spec.rb
123
+ - spec/formatters/raw_spec.rb
98
124
  - spec/lograge_logsubscriber_spec.rb
99
125
  - spec/lograge_spec.rb
100
126
  - spec/spec_helper.rb
@@ -123,6 +149,11 @@ signing_key:
123
149
  specification_version: 3
124
150
  summary: Tame Rails' multi-line logging into a single line per request
125
151
  test_files:
152
+ - spec/formatters/cee_spec.rb
153
+ - spec/formatters/graylog2_spec.rb
154
+ - spec/formatters/key_value_spec.rb
155
+ - spec/formatters/logstash_spec.rb
156
+ - spec/formatters/raw_spec.rb
126
157
  - spec/lograge_logsubscriber_spec.rb
127
158
  - spec/lograge_spec.rb
128
159
  - spec/spec_helper.rb