loggerator 0.0.2 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 147fb6d7ba2b85f8916e9b8e5e96ac088baa8fa2
4
- data.tar.gz: 699170130066ddbc05ba5ba8f33e1bfccfc2ddda
3
+ metadata.gz: 9e9a65b92ed9e08a20614a02d8b8abf5ea970ef1
4
+ data.tar.gz: 783ea749f4dfe30ffa92af44b8f9f95e09d79e70
5
5
  SHA512:
6
- metadata.gz: e85021a1d1bc361b85a764e8ec65c9ec097eeee232f77ff05cc7ad1f3850afef012dee300b16b2cbae99e9a1aca90edeb03c810b424dd0e27ddea785cd298daf
7
- data.tar.gz: 61852b4aada68c3c5c931876d310a777092ee3809fcc424ae7f555667345e8149065548d2fe1f358e0daf0f3d8170af7320c56f346a8e5d2340ab7da05776bc6
6
+ metadata.gz: 4b5565c2404a379837a6c9a429c167cc66f42179272b2af74f555a75e1c989e2c575a15227cc3b8b2e34b305557e79b87eacef59495112c780550834c4585f70
7
+ data.tar.gz: 897661dec2f7d5ba388aee5002585ddf17481ce0cf230934bcbb726d793b9cf78cb5e35de117a63e3945728e912abab1f9ab75092994f17cbbb525587206daad
@@ -1,4 +1,34 @@
1
- Loggerator::Log.default_context = { app: "<%= app_name %>" }
1
+ Loggerator.config do |config|
2
+ # Set loggerator's default context. These are the key/value pairs
3
+ # defining your application, which are prepended to every log line.
4
+ config.default_context = { app: "<%= app_name %>" }
2
5
  <% if defined?(Loggerator::Metrics) -%>
3
- Loggerator::Metrics.name = "<%= app_name %>"
6
+
7
+ # Set loggerator's metrics name. This is the name to be included as
8
+ # part of the metric key when emitting metrics.
9
+ config.metrics_app_name = "<%= app_name %>"
4
10
  <% end -%>
11
+ <% if defined?(Loggerator::Railtie) -%>
12
+
13
+ # Requiring 'loggerator/rails' automatically overrides Rails' log subscribers
14
+ # for controller handling with it's own log subscriber.
15
+ #
16
+ # In case you may need to disable this functionality, the following is
17
+ # a simple method for turning this off, causing the default logging to be
18
+ # modified.
19
+ #
20
+ # Additionally, the line below could be added only to config/environments/development.rb
21
+ # to disable Loggerator's controller logging in development only.
22
+ #
23
+ #config.rails_default_subscribers = true
24
+ <% end -%>
25
+ end
26
+
27
+ # Beyond the above configuration method, you can also set loggerator's config via
28
+ # a hash.
29
+ #
30
+ #Loggerator.config = { default_context: { app: "<%= app_name %>" } }
31
+ #
32
+ # Or parsed from a yaml file.
33
+ #
34
+ #Loggerator.config = YAML.load_file(File.expand_path("../../loggerator.yml", __FILE__))
@@ -0,0 +1,22 @@
1
+ module Loggerator
2
+ class Configuration
3
+ attr_accessor :default_context, :metrics_app_name, :rails_default_subscribers, :stdout, :stderr
4
+
5
+ def initialize(h = {})
6
+ @default_context = h[:default_context] || {}
7
+ @rails_default_subscribers = h[:rails_default_subscribers] || false
8
+ @metrics_app_name = h[:metrics_app_name] || "loggerator"
9
+
10
+ @stdout = h[:stdout] || $stdout
11
+ @stderr = h[:stderr] || $stderr
12
+ end
13
+
14
+ def to_h
15
+ {
16
+ default_context: default_context,
17
+ metrics_app_name: metrics_app_name,
18
+ rails_default_subscribers: rails_default_subscribers
19
+ }
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,94 @@
1
+ module Loggerator
2
+ # Don't expose internals into included modules so name-collisions are reduced
3
+ module Log
4
+ extend self
5
+
6
+ def local_context
7
+ RequestStore.store[:local_context] ||= {}
8
+ end
9
+
10
+ def local_context=(h)
11
+ RequestStore.store[:local_context] = h
12
+ end
13
+
14
+ def stdout=(stream)
15
+ Loggerator.config.stdout = stream
16
+ end
17
+
18
+ def stdout
19
+ Loggerator.config.stdout
20
+ end
21
+
22
+ def stderr=(stream)
23
+ Loggerator.config.stderr = stream
24
+ end
25
+
26
+ def stderr
27
+ Loggerator.config.stderr
28
+ end
29
+
30
+ def contexts(data)
31
+ Loggerator.config.default_context.merge(request_context.merge(local_context.merge(data)))
32
+ end
33
+
34
+ def to_stream(stream, data, &block)
35
+ unless block
36
+ str = unparse(data)
37
+ stream.print(str + "\n")
38
+ else
39
+ data = data.dup
40
+ start = Time.now
41
+ to_stream(stream, data.merge(at: 'start'))
42
+ begin
43
+ res = yield
44
+
45
+ to_stream(stream, data.merge(
46
+ at: 'finish', elapsed: (Time.now - start).to_f))
47
+ res
48
+ rescue
49
+ to_stream(stream, data.merge(
50
+ at: 'exception', elapsed: (Time.now - start).to_f))
51
+ raise $!
52
+ end
53
+ end
54
+ end
55
+
56
+ private
57
+ def request_context
58
+ RequestStore.store[:request_context] || {}
59
+ end
60
+
61
+ def unparse(attrs)
62
+ attrs.map { |k, v| unparse_pair(k, v) }.compact.join(" ")
63
+ end
64
+
65
+ def unparse_pair(k, v)
66
+ v = v.call if v.is_a?(Proc)
67
+ # only quote strings if they include whitespace
68
+ if v == nil
69
+ nil
70
+ elsif v == true
71
+ k
72
+ elsif v.is_a?(Float)
73
+ "#{k}=#{format("%.3f", v)}"
74
+ elsif v.is_a?(String) && v =~ /\s/
75
+ quote_string(k, v)
76
+ elsif v.is_a?(Time)
77
+ "#{k}=#{v.iso8601}"
78
+ else
79
+ "#{k}=#{v}"
80
+ end
81
+ end
82
+
83
+ def quote_string(k, v)
84
+ # try to find a quote style that fits
85
+ if !v.include?('"')
86
+ %{#{k}="#{v}"}
87
+ elsif !v.include?("'")
88
+ %{#{k}='#{v}'}
89
+ else
90
+ %{#{k}="#{v.gsub(/"/, '\\"')}"}
91
+ end
92
+ end
93
+ end
94
+ end
@@ -1,22 +1,35 @@
1
- require_relative 'request_store'
2
- require_relative 'middleware'
1
+ require "loggerator/log"
2
+ require "loggerator/configuration"
3
+ require "loggerator/request_store"
4
+ require "loggerator/middleware"
3
5
 
4
6
  module Loggerator
5
-
6
7
  def self.included(mod)
7
8
  mod.extend self
8
9
  end
9
10
 
11
+ def self.config
12
+ @config ||= Configuration.new
13
+
14
+ return @config unless block_given?
15
+
16
+ yield(@config)
17
+ end
18
+
19
+ def self.config=(cfg)
20
+ @config = Configuration.new(cfg)
21
+ end
22
+
10
23
  def log(data, &block)
11
24
  Log.to_stream(Log.stdout, Log.contexts(data), &block)
12
25
  end
13
26
 
14
- def log_error(e=$!, data = {})
15
- exception_id = e.object_id
27
+ def log_error(error, data = {})
28
+ exception_id = error.object_id
16
29
 
17
30
  # Log backtrace in reverse order for easier digestion.
18
- if e.backtrace
19
- e.backtrace.reverse.each do |backtrace|
31
+ if error.backtrace
32
+ error.backtrace.reverse.each do |backtrace|
20
33
  Log.to_stream(Log.stderr, Log.contexts(
21
34
  exception_id: exception_id,
22
35
  backtrace: backtrace
@@ -28,12 +41,12 @@ module Loggerator
28
41
  # a log trace as possible
29
42
  data.merge!(
30
43
  exception: true,
31
- class: e.class.name,
32
- message: e.message,
44
+ class: error.class.name,
45
+ message: error.message,
33
46
  exception_id: exception_id
34
47
  )
35
48
 
36
- data[:status] = e.status if e.respond_to?(:status)
49
+ data[:status] = error.status if error.respond_to?(:status)
37
50
 
38
51
  Log.to_stream(Log.stderr, Log.contexts(data))
39
52
  end
@@ -46,105 +59,4 @@ module Loggerator
46
59
  Log.local_context = old
47
60
  res
48
61
  end
49
-
50
- # Don't expose internals into included modules so name-collisions are reduced
51
- module Log
52
- extend self
53
-
54
- def default_context=(default_context)
55
- @@default_context = default_context
56
- end
57
-
58
- def default_context
59
- @@default_context ||= {}
60
- end
61
-
62
- def local_context
63
- RequestStore.store[:local_context] ||= {}
64
- end
65
-
66
- def local_context=(h)
67
- RequestStore.store[:local_context] = h
68
- end
69
-
70
- def stdout=(stream)
71
- @@stdout = stream
72
- end
73
-
74
- def stdout
75
- @@stdout ||= $stdout
76
- end
77
-
78
- def stderr=(stream)
79
- @@stderr = stream
80
- end
81
-
82
- def stderr
83
- @@stderr ||= $stderr
84
- end
85
-
86
- def contexts(data)
87
- default_context.merge(request_context.merge(local_context.merge(data)))
88
- end
89
-
90
- def to_stream(stream, data, &block)
91
- unless block
92
- str = unparse(data)
93
- stream.print(str + "\n")
94
- else
95
- data = data.dup
96
- start = Time.now
97
- to_stream(stream, data.merge(at: 'start'))
98
- begin
99
- res = yield
100
-
101
- to_stream(stream, data.merge(
102
- at: 'finish', elapsed: (Time.now - start).to_f))
103
- res
104
- rescue
105
- to_stream(stream, data.merge(
106
- at: 'exception', elapsed: (Time.now - start).to_f))
107
- raise $!
108
- end
109
- end
110
- end
111
-
112
- private
113
- def request_context
114
- RequestStore.store[:request_context] || {}
115
- end
116
-
117
- def unparse(attrs)
118
- attrs.map { |k, v| unparse_pair(k, v) }.compact.join(" ")
119
- end
120
-
121
- def unparse_pair(k, v)
122
- v = v.call if v.is_a?(Proc)
123
- # only quote strings if they include whitespace
124
- if v == nil
125
- nil
126
- elsif v == true
127
- k
128
- elsif v.is_a?(Float)
129
- "#{k}=#{format("%.3f", v)}"
130
- elsif v.is_a?(String) && v =~ /\s/
131
- quote_string(k, v)
132
- elsif v.is_a?(Time)
133
- "#{k}=#{v.iso8601}"
134
- else
135
- "#{k}=#{v}"
136
- end
137
- end
138
-
139
- def quote_string(k, v)
140
- # try to find a quote style that fits
141
- if !v.include?('"')
142
- %{#{k}="#{v}"}
143
- elsif !v.include?("'")
144
- %{#{k}='#{v}'}
145
- else
146
- %{#{k}="#{v.gsub(/"/, '\\"')}"}
147
- end
148
- end
149
- end
150
62
  end
@@ -1,34 +1,24 @@
1
- require_relative 'loggerator'
1
+ require "loggerator"
2
2
 
3
3
  module Loggerator
4
4
  module Metrics
5
5
  include Loggerator
6
6
  extend self
7
7
 
8
- @@metrics_name = 'loggerator'
9
-
10
- def name=(name)
11
- @@metrics_name = name
12
- end
13
-
14
- def name
15
- @@metrics_name
16
- end
17
-
18
8
  def count(key, value=1)
19
- log("count##{name}.#{key}" => value)
9
+ log("count##{Loggerator.config.metrics_app_name}.#{key}" => value)
20
10
  end
21
11
 
22
12
  def sample(key, value)
23
- log("sample##{name}.#{key}" => value)
13
+ log("sample##{Loggerator.config.metrics_app_name}.#{key}" => value)
24
14
  end
25
15
 
26
16
  def unique(key, value)
27
- log("unique##{name}.#{key}" => value)
17
+ log("unique##{Loggerator.config.metrics_app_name}.#{key}" => value)
28
18
  end
29
19
 
30
- def measure(key, value, units='s')
31
- log("measure##{name}.#{key}" => "#{value}#{units}")
20
+ def measure(key, value, units="s")
21
+ log("measure##{Loggerator.config.metrics_app_name}.#{key}" => "#{value}#{units}")
32
22
  end
33
23
  end
34
24
 
@@ -1,5 +1,5 @@
1
- require_relative 'middleware/request_store'
2
- require_relative 'middleware/request_id'
1
+ require "loggerator/middleware/request_store"
2
+ require "loggerator/middleware/request_id"
3
3
 
4
4
  module Loggerator
5
5
  module Middleware; end
@@ -1,4 +1,4 @@
1
- require_relative 'loggerator'
1
+ require "loggerator"
2
2
 
3
3
  module Loggerator
4
4
  module Namespace
@@ -1,22 +1,8 @@
1
- require_relative "loggerator"
1
+ require "loggerator"
2
+ require "loggerator/railtie/log_subscriber"
3
+ require "loggerator/railtie/helper"
4
+ require "loggerator/railtie/adapter"
2
5
 
3
6
  module Loggerator
4
- class Railtie < Rails::Railtie
5
-
6
- config.before_configuration do
7
- Rails.application.middleware.insert_after ActionDispatch::RequestId, Loggerator::Middleware::RequestStore
8
- Rails.application.middleware.swap ActionDispatch::RequestId, Loggerator::Middleware::RequestID
9
- end
10
-
11
- config.before_initialize do
12
- [ ActionView::Base,
13
- ActiveRecord::Base,
14
- ActionMailer::Base,
15
- ActionController::Base ].each do |c|
16
-
17
- c.include Loggerator
18
- end
19
- end
20
-
21
- end
7
+ module Railtie; end
22
8
  end
@@ -0,0 +1,24 @@
1
+ module Loggerator
2
+ module Railtie
3
+ class Adapter < ::Rails::Railtie
4
+ config.before_configuration do
5
+ Rails.application.middleware.insert_after ActionDispatch::RequestId, Loggerator::Middleware::RequestStore
6
+ Rails.application.middleware.swap ActionDispatch::RequestId, Loggerator::Middleware::RequestID
7
+ end
8
+
9
+ config.before_initialize do
10
+ [ ActionView::Base,
11
+ ActiveRecord::Base,
12
+ ActionMailer::Base,
13
+ ActionController::Base ].each do |c|
14
+
15
+ c.include Loggerator
16
+ end
17
+ end
18
+
19
+ config.after_initialize do
20
+ Loggerator::Railtie::Helper.setup(Rails.application)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,48 @@
1
+ module Loggerator
2
+ module Railtie
3
+ module Helper
4
+ # Implementation respectfully borrowed from:
5
+ # https://github.com/minefold/scrolls-rails
6
+ extend self
7
+
8
+ def setup(_app)
9
+ return unless subscribe?
10
+
11
+ detach_existing_subscribers
12
+ Loggerator::Railtie::LogSubscriber.attach_to(:action_controller)
13
+ end
14
+
15
+ def detach_existing_subscribers
16
+ ActiveSupport::LogSubscriber.log_subscribers.each do |subscriber|
17
+ case subscriber
18
+ when ActionView::LogSubscriber
19
+ unsubscribe(:action_view, subscriber)
20
+ when ActionController::LogSubscriber
21
+ unsubscribe(:action_controller, subscriber)
22
+ end
23
+ end
24
+ end
25
+
26
+ def subscribe?
27
+ !Loggerator.config.rails_default_subscribers
28
+ end
29
+
30
+ def unsubscribe(component, subscriber)
31
+ events = events_for_subscriber(subscriber)
32
+
33
+ events.each do |event|
34
+ notifier = ActiveSupport::Notifications.notifier
35
+ notifier.listeners_for("#{event}.#{component}").each do |listener|
36
+ if listener.instance_variable_get('@delegate') == subscriber
37
+ ActiveSupport::Notifications.unsubscribe(listener)
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ def events_for_subscriber(subscriber)
44
+ subscriber.public_methods(false).reject {|method| method.to_s == 'call' }
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,85 @@
1
+ # Implementation respectfully borrowed from:
2
+ # https://github.com/minefold/scrolls-rails
3
+ require "loggerator"
4
+ require "active_support/core_ext/class/attribute"
5
+ require "active_support/log_subscriber"
6
+
7
+ module Loggerator
8
+ module Railtie
9
+ class LogSubscriber < ActiveSupport::LogSubscriber
10
+ include Loggerator
11
+
12
+ FIELDS = [:method, :path, :format, :controller, :action, :status,
13
+ :error, :duration, :view, :db, :location].freeze
14
+
15
+ def process_action(event)
16
+ exception = event.payload[:exception]
17
+ if exception.present?
18
+ # In Rails 3.2.9 event.payload[:exception] was changed from an
19
+ # Exception object to an Array containing the e.class.name and
20
+ # e.message. Adding handling for this case here.
21
+ if exception.is_a?(Array)
22
+ exception_class_name, exception_message = exception
23
+ exception = exception_class_name.constantize.new(exception_message)
24
+ end
25
+
26
+ self.log_error(exception, status: 500)
27
+ else
28
+ self.log(extract_request_data_from_event(event))
29
+ end
30
+ end
31
+
32
+ def redirect_to(event)
33
+ Thread.current[:scrolls_rails_location] = event.payload[:location]
34
+ end
35
+
36
+ private
37
+
38
+ def extract_request_data_from_event(event)
39
+ data = extract_request(event.payload)
40
+ data[:status] = extract_status(event.payload)
41
+
42
+ data.merge!(runtimes(event))
43
+ data.merge!(location(event))
44
+ end
45
+
46
+ def extract_request(payload)
47
+ {
48
+ method: payload[:method],
49
+ path: payload[:path],
50
+ format: payload[:format],
51
+ controller: payload[:params]["controller"],
52
+ action: payload[:params]["action"]
53
+ }
54
+ end
55
+
56
+ def extract_status(payload)
57
+ if payload[:status]
58
+ payload[:status].to_i
59
+ else
60
+ 0
61
+ end
62
+ end
63
+
64
+ def runtimes(event)
65
+ { duration: event.duration,
66
+ view: event.payload[:view_runtime],
67
+ db: event.payload[:db_runtime]
68
+ }.inject({}) do |runtimes, (name, runtime)|
69
+ runtimes[name] = runtime.to_f.round(2) if runtime
70
+ runtimes
71
+ end
72
+ end
73
+
74
+ def location(_event)
75
+ if location = Thread.current[:scrolls_rails_location]
76
+ Thread.current[:scrolls_rails_location] = nil
77
+
78
+ { location: location }
79
+ else
80
+ {}
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,3 @@
1
+ test:
2
+ adapter: sqlite3
3
+ database: db/combustion_test.sqlite
@@ -0,0 +1,3 @@
1
+ Rails.application.routes.draw do
2
+ #
3
+ end
@@ -0,0 +1,3 @@
1
+ ActiveRecord::Schema.define do
2
+ #
3
+ end
@@ -0,0 +1 @@
1
+ *.log
File without changes
@@ -0,0 +1,64 @@
1
+ require_relative "../test_helper"
2
+ require "loggerator/metrics"
3
+
4
+ class TestLoggeratorMetrics < Minitest::Test
5
+ include Loggerator
6
+ include Loggerator::Metrics
7
+
8
+ def config
9
+ Loggerator.config
10
+ end
11
+
12
+ def test_name_equals
13
+ config.metrics_app_name = "test_name_equals"
14
+
15
+ assert_equal "test_name_equals", config.metrics_app_name
16
+ end
17
+
18
+ def test_name
19
+ config.metrics_app_name = "test_name"
20
+
21
+ assert_equal "test_name", self.name
22
+ end
23
+
24
+ def test_count
25
+ config.metrics_app_name = "test_count"
26
+ out, err = capture_subprocess_io do
27
+ self.count(:foo, 99)
28
+ end
29
+
30
+ assert_empty err
31
+ assert_match(/count#test_count\.foo=99/, out)
32
+ end
33
+
34
+ def test_sample
35
+ config.metrics_app_name = "test_sample"
36
+ out, err = capture_subprocess_io do
37
+ self.sample(:foo, :bar)
38
+ end
39
+
40
+ assert_empty err
41
+ assert_match(/sample#test_sample\.foo=bar/, out)
42
+ end
43
+
44
+ def test_unique
45
+ config.metrics_app_name = "test_unique"
46
+ out, err = capture_subprocess_io do
47
+ self.unique(:foo, :bar)
48
+ end
49
+
50
+ assert_empty err
51
+ assert_match(/unique#test_unique\.foo=bar/, out)
52
+ end
53
+
54
+ def test_measure
55
+ config.metrics_app_name = "test_measure"
56
+ out, err = capture_subprocess_io do
57
+ self.measure(:foo, 60, "ms")
58
+ end
59
+
60
+ assert_empty err
61
+ assert_match(/measure#test_measure\.foo=60ms/, out)
62
+ end
63
+ end
64
+
@@ -1,9 +1,4 @@
1
- require 'rack/test'
2
- require 'minitest/mock'
3
- require 'minitest/autorun'
4
- require 'logger'
5
-
6
- require_relative '../../../lib/loggerator'
1
+ require_relative "../../test_helper"
7
2
 
8
3
  class Loggerator::Middleware::TestRequestID < Minitest::Test
9
4
  include Rack::Test::Methods
@@ -13,21 +8,21 @@ class Loggerator::Middleware::TestRequestID < Minitest::Test
13
8
  use Rack::Lint
14
9
  use Loggerator::Middleware::RequestID
15
10
 
16
- run ->(env) { [ 200, { }, [ 'hi' ] ] }
11
+ run ->(env) { [ 200, { }, [ "hi" ] ] }
17
12
  end
18
13
  end
19
14
 
20
15
  def test_sets_request_id
21
- get '/'
16
+ get "/"
22
17
 
23
18
  assert_match ::Loggerator::Middleware::RequestID::UUID_PATTERN,
24
- last_request.env['REQUEST_ID']
19
+ last_request.env["REQUEST_ID"]
25
20
  end
26
21
 
27
22
  def test_sets_request_ids
28
- get '/'
23
+ get "/"
29
24
 
30
25
  assert_match ::Loggerator::Middleware::RequestID::UUID_PATTERN,
31
- last_request.env['REQUEST_IDS'].first
26
+ last_request.env["REQUEST_IDS"].first
32
27
  end
33
28
  end
@@ -1,9 +1,4 @@
1
- require 'rack/test'
2
- require 'minitest/mock'
3
- require 'minitest/autorun'
4
- require 'logger'
5
-
6
- require_relative '../../../lib/loggerator'
1
+ require_relative "../../test_helper"
7
2
 
8
3
  class Loggerator::Middleware::TestRequestStore < Minitest::Test
9
4
  include Rack::Test::Methods
@@ -13,14 +8,14 @@ class Loggerator::Middleware::TestRequestStore < Minitest::Test
13
8
  use Rack::Lint
14
9
  use Loggerator::Middleware::RequestStore
15
10
 
16
- run ->(env) { [ 200, { }, [ 'hi' ] ] }
11
+ run ->(env) { [ 200, { }, [ "hi" ] ] }
17
12
  end
18
13
  end
19
14
 
20
15
  def test_clears_the_store
21
- Thread.current[:request_store] = { something_added_before: 'bar' }
16
+ Thread.current[:request_store] = { something_added_before: "bar" }
22
17
 
23
- get '/'
18
+ get "/"
24
19
 
25
20
  assert_nil Thread.current[:request_store][:something_added_before]
26
21
  end
@@ -28,7 +23,7 @@ class Loggerator::Middleware::TestRequestStore < Minitest::Test
28
23
  def test_seeds_the_store
29
24
  Thread.current[:request_store] = {}
30
25
 
31
- get '/'
26
+ get "/"
32
27
 
33
28
  assert_equal Thread.current[:request_store], {
34
29
  request_id: nil,
@@ -0,0 +1,60 @@
1
+ require_relative "../test_helper"
2
+
3
+ class TestLoggeratorRails < Minitest::Test
4
+ def test_middleware_modifications
5
+ # This ensures that the middlewares list includes our middlewares and that
6
+ # the default request id handler has been replaced.
7
+ middlewares = Rails.application.middleware
8
+
9
+ assert middlewares.include?(Loggerator::Middleware::RequestStore)
10
+ assert middlewares.include?(Loggerator::Middleware::RequestID)
11
+ refute middlewares.include?(ActionDispatch::RequestId)
12
+ end
13
+
14
+ def test_loggerator_included
15
+ # This ensures that Loggerator has been included in each of the classes below
16
+ # by checking to ensure that it's included in each classes "ancestors" list.
17
+ [ ActionView::Base,
18
+ ActiveRecord::Base,
19
+ ActionMailer::Base,
20
+ ActionController::Base
21
+ ].each do |c|
22
+ assert c.ancestors.include?(Loggerator)
23
+ end
24
+ end
25
+
26
+ def test_log_subscriber_attached
27
+ # This sets subscribers to a unique list of all log subscribers. Our
28
+ # LogSubscriber class should be included in this list.
29
+ subscribers = \
30
+ ActiveSupport::Notifications.notifier
31
+ .instance_variable_get("@subscribers")
32
+ .map { |subscriber|
33
+ subscriber.instance_variable_get("@delegate").class
34
+ }.uniq
35
+
36
+ assert subscribers.include?(Loggerator::Railtie::LogSubscriber)
37
+ end
38
+
39
+ def test_detach_existing_subscribers
40
+ # This sets subscribed_classes to the unique list of classes contstants
41
+ # which are currently subscribed to either "process_action.action_controller"
42
+ # or "redirect_to.action_controller". Given that only our LogSubscriber
43
+ # should be subscribed to these two events, only our LogSubscriber should
44
+ # be in the resulting list.
45
+ subscribed_classes = \
46
+ ActiveSupport::Notifications.notifier
47
+ .instance_variable_get("@subscribers")
48
+ .map { |subscriber|
49
+ subscriber.instance_variable_get("@delegate")
50
+ }.select { |delegate|
51
+ patterns = delegate.instance_variable_get("@patterns")
52
+ patterns && (
53
+ patterns.include?("process_action.action_controller") ||
54
+ patterns.include?("redirect_to.action_controller")
55
+ )
56
+ }.map(&:class).uniq
57
+
58
+ assert_equal subscribed_classes, [Loggerator::Railtie::LogSubscriber]
59
+ end
60
+ end
@@ -0,0 +1,44 @@
1
+ require_relative "../../test_helper"
2
+
3
+ class FakeEvent
4
+ attr_accessor :payload
5
+ end
6
+
7
+ class LoggeratorRailtieLogSubscriber < Minitest::Test
8
+ def setup
9
+ @sub = Loggerator::Railtie::LogSubscriber.new
10
+ @evt = FakeEvent.new
11
+ end
12
+
13
+ def test_process_action_with_array
14
+ out, err = capture_subprocess_io do
15
+ @evt.payload = {
16
+ exception: ["Exception", "Test array"]
17
+ }
18
+
19
+ @sub.process_action(@evt)
20
+ end
21
+
22
+ assert_empty(out)
23
+ assert_match(
24
+ /status=500 exception class=Exception message=\"Test array\" exception_id=\d+\n$/,
25
+ err
26
+ )
27
+ end
28
+
29
+ def test_process_action_with_exception
30
+ out, err = capture_subprocess_io do
31
+ @evt.payload = {
32
+ exception: Exception.new("Test exception")
33
+ }
34
+
35
+ @sub.process_action(@evt)
36
+ end
37
+
38
+ assert_empty(out)
39
+ assert_match(
40
+ /status=500 exception class=Exception message=\"Test exception\" exception_id=\d+\n$/,
41
+ err
42
+ )
43
+ end
44
+ end
@@ -1,7 +1,4 @@
1
- require 'minitest/autorun'
2
- require 'logger'
3
-
4
- require_relative '../../lib/loggerator'
1
+ require_relative "../test_helper"
5
2
 
6
3
  class Loggerator::TestRequestStore < Minitest::Test
7
4
  def setup
@@ -9,21 +6,21 @@ class Loggerator::TestRequestStore < Minitest::Test
9
6
  Thread.current[:request_store] = {}
10
7
 
11
8
  @env = {
12
- 'REQUEST_ID' => 'abc',
13
- 'REQUEST_IDS' => %w[ abc def ]
9
+ "REQUEST_ID" => "abc",
10
+ "REQUEST_IDS" => %w[ abc def ]
14
11
  }
15
12
  end
16
13
 
17
14
  def test_seeds_request_id
18
15
  Loggerator::RequestStore.seed(@env)
19
16
 
20
- assert_equal 'abc,def', Loggerator::RequestStore.store[:request_id]
17
+ assert_equal "abc,def", Loggerator::RequestStore.store[:request_id]
21
18
  end
22
19
 
23
20
  def test_seeds_request_context
24
21
  Loggerator::RequestStore.seed(@env)
25
22
 
26
- assert_equal 'abc,def', Loggerator::RequestStore.store[:request_context][:request_id]
23
+ assert_equal "abc,def", Loggerator::RequestStore.store[:request_context][:request_id]
27
24
  end
28
25
 
29
26
  def test_is_cleared_by_clear!
@@ -1,16 +1,44 @@
1
- require 'minitest/autorun'
2
- require 'logger'
3
-
4
- require_relative '../lib/loggerator'
1
+ require_relative "test_helper"
5
2
 
6
3
  class TestLoggerator < Minitest::Test
7
4
  include Loggerator
5
+ include Loggerator::Log
8
6
 
9
7
  def setup
10
8
  # flush request store
11
9
  Thread.current[:request_store] = {}
12
10
 
13
- self.default_context = {}
11
+ Loggerator.config.default_context = {}
12
+ end
13
+
14
+ def test_config_from_block
15
+ Loggerator.config do |c|
16
+ c.default_context = { foo: :bar }
17
+ c.metrics_app_name = "foo_bar"
18
+ c.rails_default_subscribers = true
19
+ end
20
+
21
+ expected = {
22
+ default_context: { foo: :bar },
23
+ metrics_app_name: "foo_bar",
24
+ rails_default_subscribers: true
25
+ }
26
+
27
+ assert_equal expected, Loggerator.config.to_h
28
+ end
29
+
30
+ def test_config_from_hash
31
+ expected = {
32
+ default_context: { foo: :bar },
33
+ metrics_app_name: "foo_bar",
34
+ rails_default_subscribers: true
35
+ }
36
+
37
+ refute_equal expected, Loggerator.config.to_h
38
+
39
+ Loggerator.config = expected
40
+
41
+ assert_equal expected, Loggerator.config.to_h
14
42
  end
15
43
 
16
44
  def test_logs_in_structured_format
@@ -41,7 +69,7 @@ class TestLoggerator < Minitest::Test
41
69
 
42
70
  def test_merges_default_context_with_eq
43
71
  # testing both methods
44
- self.default_context = { app: 'my_app' }
72
+ Loggerator.config.default_context = { app: "my_app" }
45
73
 
46
74
  out, _ = capture_subprocess_io do
47
75
  log(foo: 'bar')
@@ -62,7 +90,7 @@ class TestLoggerator < Minitest::Test
62
90
 
63
91
  def test_log_context_merged_with_default_context
64
92
  out, _ = capture_subprocess_io do
65
- self.default_context = { app: 'my_app' }
93
+ Loggerator.config.default_context = { app: 'my_app' }
66
94
  self.log_context(foo: 'bar') do
67
95
  log(bah: 'boo')
68
96
  end
@@ -70,4 +98,29 @@ class TestLoggerator < Minitest::Test
70
98
 
71
99
  assert_equal out, "app=my_app foo=bar bah=boo\n"
72
100
  end
101
+
102
+ def test_log_error
103
+ _, err = capture_subprocess_io do
104
+ begin
105
+ raise "an error"
106
+ rescue => ex
107
+ self.log_error(ex, foo: :bar_bah_boo)
108
+ end
109
+ end
110
+
111
+ assert_match(/message="an error"/, err)
112
+ assert_match(/foo=bar_bah_boo/, err)
113
+ end
114
+
115
+ def test_log_error_without_data
116
+ _, err = capture_subprocess_io do
117
+ begin
118
+ raise "another error"
119
+ rescue => ex
120
+ self.log_error(ex)
121
+ end
122
+ end
123
+
124
+ assert_match(/message="another error"/, err)
125
+ end
73
126
  end
@@ -0,0 +1,21 @@
1
+ # like running `ruby -W0`
2
+ $VERBOSE = nil
3
+
4
+ require "rack/test"
5
+ require "minitest/mock"
6
+ require "minitest/autorun"
7
+ require "pry"
8
+ require "pp"
9
+
10
+ require "logger"
11
+
12
+ require "combustion"
13
+ Combustion.path = "test/internal"
14
+ Combustion.initialize! :all
15
+
16
+ # Unfreeze rails middleware
17
+ Rails.application.middleware.instance_variable_set(:@middlewares,
18
+ Rails.application.middleware.instance_variable_get(:@middlewares).dup)
19
+
20
+ require "loggerator"
21
+ require "loggerator/rails"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: loggerator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua Mervine
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-10-12 00:00:00.000000000 Z
12
+ date: 2017-03-03 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Simple web application extension for logging, following the 12factor
15
15
  pattern.
@@ -23,6 +23,8 @@ files:
23
23
  - lib/generators/loggerator/log_generator.rb
24
24
  - lib/generators/templates/log.rb.erb
25
25
  - lib/loggerator.rb
26
+ - lib/loggerator/configuration.rb
27
+ - lib/loggerator/log.rb
26
28
  - lib/loggerator/loggerator.rb
27
29
  - lib/loggerator/metrics.rb
28
30
  - lib/loggerator/middleware.rb
@@ -30,12 +32,24 @@ files:
30
32
  - lib/loggerator/middleware/request_store.rb
31
33
  - lib/loggerator/namespace.rb
32
34
  - lib/loggerator/rails.rb
35
+ - lib/loggerator/railtie/adapter.rb
36
+ - lib/loggerator/railtie/helper.rb
37
+ - lib/loggerator/railtie/log_subscriber.rb
33
38
  - lib/loggerator/request_store.rb
34
39
  - lib/loggerator/test.rb
40
+ - test/internal/config/database.yml
41
+ - test/internal/config/routes.rb
42
+ - test/internal/db/schema.rb
43
+ - test/internal/log/.gitignore
44
+ - test/internal/public/favicon.ico
45
+ - test/loggerator/metrics_test.rb
35
46
  - test/loggerator/middleware/request_id_test.rb
36
47
  - test/loggerator/middleware/request_store_test.rb
48
+ - test/loggerator/rails_test.rb
49
+ - test/loggerator/railtie/log_subscriber_test.rb
37
50
  - test/loggerator/request_store_test.rb
38
51
  - test/loggerator_test.rb
52
+ - test/test_helper.rb
39
53
  homepage: https://github.com/heroku/loggerator
40
54
  licenses:
41
55
  - MIT
@@ -61,7 +75,16 @@ signing_key:
61
75
  specification_version: 4
62
76
  summary: 'loggerator: A Log Helper'
63
77
  test_files:
78
+ - test/internal/config/database.yml
79
+ - test/internal/config/routes.rb
80
+ - test/internal/db/schema.rb
81
+ - test/internal/log/.gitignore
82
+ - test/internal/public/favicon.ico
83
+ - test/loggerator/metrics_test.rb
64
84
  - test/loggerator/middleware/request_id_test.rb
65
85
  - test/loggerator/middleware/request_store_test.rb
86
+ - test/loggerator/rails_test.rb
87
+ - test/loggerator/railtie/log_subscriber_test.rb
66
88
  - test/loggerator/request_store_test.rb
67
89
  - test/loggerator_test.rb
90
+ - test/test_helper.rb