loggerator 0.0.2 → 0.1.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.
- checksums.yaml +4 -4
- data/lib/generators/templates/log.rb.erb +32 -2
- data/lib/loggerator/configuration.rb +22 -0
- data/lib/loggerator/log.rb +94 -0
- data/lib/loggerator/loggerator.rb +23 -111
- data/lib/loggerator/metrics.rb +6 -16
- data/lib/loggerator/middleware.rb +2 -2
- data/lib/loggerator/namespace.rb +1 -1
- data/lib/loggerator/rails.rb +5 -19
- data/lib/loggerator/railtie/adapter.rb +24 -0
- data/lib/loggerator/railtie/helper.rb +48 -0
- data/lib/loggerator/railtie/log_subscriber.rb +85 -0
- data/test/internal/config/database.yml +3 -0
- data/test/internal/config/routes.rb +3 -0
- data/test/internal/db/schema.rb +3 -0
- data/test/internal/log/.gitignore +1 -0
- data/test/internal/public/favicon.ico +0 -0
- data/test/loggerator/metrics_test.rb +64 -0
- data/test/loggerator/middleware/request_id_test.rb +6 -11
- data/test/loggerator/middleware/request_store_test.rb +5 -10
- data/test/loggerator/rails_test.rb +60 -0
- data/test/loggerator/railtie/log_subscriber_test.rb +44 -0
- data/test/loggerator/request_store_test.rb +5 -8
- data/test/loggerator_test.rb +60 -7
- data/test/test_helper.rb +21 -0
- metadata +25 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9e9a65b92ed9e08a20614a02d8b8abf5ea970ef1
|
4
|
+
data.tar.gz: 783ea749f4dfe30ffa92af44b8f9f95e09d79e70
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4b5565c2404a379837a6c9a429c167cc66f42179272b2af74f555a75e1c989e2c575a15227cc3b8b2e34b305557e79b87eacef59495112c780550834c4585f70
|
7
|
+
data.tar.gz: 897661dec2f7d5ba388aee5002585ddf17481ce0cf230934bcbb726d793b9cf78cb5e35de117a63e3945728e912abab1f9ab75092994f17cbbb525587206daad
|
@@ -1,4 +1,34 @@
|
|
1
|
-
Loggerator
|
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
|
-
|
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
|
-
|
2
|
-
|
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(
|
15
|
-
exception_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
|
19
|
-
|
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:
|
32
|
-
message:
|
44
|
+
class: error.class.name,
|
45
|
+
message: error.message,
|
33
46
|
exception_id: exception_id
|
34
47
|
)
|
35
48
|
|
36
|
-
data[: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
|
data/lib/loggerator/metrics.rb
CHANGED
@@ -1,34 +1,24 @@
|
|
1
|
-
|
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##{
|
9
|
+
log("count##{Loggerator.config.metrics_app_name}.#{key}" => value)
|
20
10
|
end
|
21
11
|
|
22
12
|
def sample(key, value)
|
23
|
-
log("sample##{
|
13
|
+
log("sample##{Loggerator.config.metrics_app_name}.#{key}" => value)
|
24
14
|
end
|
25
15
|
|
26
16
|
def unique(key, value)
|
27
|
-
log("unique##{
|
17
|
+
log("unique##{Loggerator.config.metrics_app_name}.#{key}" => value)
|
28
18
|
end
|
29
19
|
|
30
|
-
def measure(key, value, units=
|
31
|
-
log("measure##{
|
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
|
|
data/lib/loggerator/namespace.rb
CHANGED
data/lib/loggerator/rails.rb
CHANGED
@@ -1,22 +1,8 @@
|
|
1
|
-
|
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
|
-
|
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 @@
|
|
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
|
-
|
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, { }, [
|
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[
|
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[
|
26
|
+
last_request.env["REQUEST_IDS"].first
|
32
27
|
end
|
33
28
|
end
|
@@ -1,9 +1,4 @@
|
|
1
|
-
|
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, { }, [
|
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:
|
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
|
-
|
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
|
-
|
13
|
-
|
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
|
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
|
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!
|
data/test/loggerator_test.rb
CHANGED
@@ -1,16 +1,44 @@
|
|
1
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
data/test/test_helper.rb
ADDED
@@ -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.
|
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:
|
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
|