epilog 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rspec +2 -0
- data/.rubocop.yml +28 -0
- data/.travis.yml +40 -0
- data/.yardopts +4 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +201 -0
- data/README.md +70 -0
- data/Rakefile +13 -0
- data/bin/check-version +6 -0
- data/bin/console +16 -0
- data/bin/rake +18 -0
- data/bin/rspec +18 -0
- data/bin/rubocop +18 -0
- data/bin/yard +18 -0
- data/bin/yardoc +18 -0
- data/bin/yri +18 -0
- data/epilog.gemspec +34 -0
- data/lib/epilog.rb +10 -0
- data/lib/epilog/filter.rb +4 -0
- data/lib/epilog/filter/blacklist.rb +30 -0
- data/lib/epilog/filter/hash_key.rb +41 -0
- data/lib/epilog/log_formatter.rb +67 -0
- data/lib/epilog/logger.rb +22 -0
- data/lib/epilog/mock_logger.rb +59 -0
- data/lib/epilog/rails.rb +23 -0
- data/lib/epilog/rails/action_controller_subscriber.rb +153 -0
- data/lib/epilog/rails/action_mailer_subscriber.rb +48 -0
- data/lib/epilog/rails/action_view_subscriber.rb +40 -0
- data/lib/epilog/rails/active_job_subscriber.rb +58 -0
- data/lib/epilog/rails/active_record_subscriber.rb +63 -0
- data/lib/epilog/rails/epilog_ext.rb +11 -0
- data/lib/epilog/rails/ext/action_controller.rb +45 -0
- data/lib/epilog/rails/ext/active_support_logger.rb +16 -0
- data/lib/epilog/rails/ext/debug_exceptions.rb +18 -0
- data/lib/epilog/rails/ext/event_delegate.rb +16 -0
- data/lib/epilog/rails/ext/rack_logger.rb +13 -0
- data/lib/epilog/rails/log_subscriber.rb +14 -0
- data/lib/epilog/rails/railtie.rb +71 -0
- data/lib/epilog/version.rb +5 -0
- metadata +258 -0
data/bin/rspec
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# This file was generated by Bundler.
|
|
6
|
+
#
|
|
7
|
+
# The application 'rspec' is installed as part of a gem, and
|
|
8
|
+
# this file is here to facilitate running it.
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
require 'pathname'
|
|
12
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
|
|
13
|
+
Pathname.new(__FILE__).realpath)
|
|
14
|
+
|
|
15
|
+
require 'rubygems'
|
|
16
|
+
require 'bundler/setup'
|
|
17
|
+
|
|
18
|
+
load Gem.bin_path('rspec-core', 'rspec')
|
data/bin/rubocop
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# This file was generated by Bundler.
|
|
6
|
+
#
|
|
7
|
+
# The application 'rubocop' is installed as part of a gem, and
|
|
8
|
+
# this file is here to facilitate running it.
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
require 'pathname'
|
|
12
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
|
|
13
|
+
Pathname.new(__FILE__).realpath)
|
|
14
|
+
|
|
15
|
+
require 'rubygems'
|
|
16
|
+
require 'bundler/setup'
|
|
17
|
+
|
|
18
|
+
load Gem.bin_path('rubocop', 'rubocop')
|
data/bin/yard
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# This file was generated by Bundler.
|
|
6
|
+
#
|
|
7
|
+
# The application 'yard' is installed as part of a gem, and
|
|
8
|
+
# this file is here to facilitate running it.
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
require 'pathname'
|
|
12
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
|
|
13
|
+
Pathname.new(__FILE__).realpath)
|
|
14
|
+
|
|
15
|
+
require 'rubygems'
|
|
16
|
+
require 'bundler/setup'
|
|
17
|
+
|
|
18
|
+
load Gem.bin_path('yard', 'yard')
|
data/bin/yardoc
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# This file was generated by Bundler.
|
|
6
|
+
#
|
|
7
|
+
# The application 'yardoc' is installed as part of a gem, and
|
|
8
|
+
# this file is here to facilitate running it.
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
require 'pathname'
|
|
12
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
|
|
13
|
+
Pathname.new(__FILE__).realpath)
|
|
14
|
+
|
|
15
|
+
require 'rubygems'
|
|
16
|
+
require 'bundler/setup'
|
|
17
|
+
|
|
18
|
+
load Gem.bin_path('yard', 'yardoc')
|
data/bin/yri
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
#
|
|
5
|
+
# This file was generated by Bundler.
|
|
6
|
+
#
|
|
7
|
+
# The application 'yri' is installed as part of a gem, and
|
|
8
|
+
# this file is here to facilitate running it.
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
require 'pathname'
|
|
12
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
|
|
13
|
+
Pathname.new(__FILE__).realpath)
|
|
14
|
+
|
|
15
|
+
require 'rubygems'
|
|
16
|
+
require 'bundler/setup'
|
|
17
|
+
|
|
18
|
+
load Gem.bin_path('yard', 'yri')
|
data/epilog.gemspec
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
5
|
+
require 'epilog/version'
|
|
6
|
+
|
|
7
|
+
Gem::Specification.new do |spec|
|
|
8
|
+
spec.name = 'epilog'
|
|
9
|
+
spec.version = Epilog::VERSION
|
|
10
|
+
spec.authors = ['Justin Howard']
|
|
11
|
+
spec.email = ['jmhoward0@gmail.com']
|
|
12
|
+
spec.license = 'Apache-2.0'
|
|
13
|
+
|
|
14
|
+
spec.summary = 'A JSON logger with Rails support'
|
|
15
|
+
spec.homepage = 'https://github.com/machinima/epilog'
|
|
16
|
+
|
|
17
|
+
spec.files = `git ls-files -z`
|
|
18
|
+
.split("\x0")
|
|
19
|
+
.reject { |f| f.match(%r{^spec/}) }
|
|
20
|
+
spec.require_paths = ['lib']
|
|
21
|
+
|
|
22
|
+
spec.add_development_dependency 'bundler', '~> 1.12'
|
|
23
|
+
spec.add_development_dependency 'byebug', '~> 9.0'
|
|
24
|
+
spec.add_development_dependency 'combustion', '~> 1.0.0'
|
|
25
|
+
spec.add_development_dependency 'rails', '>= 4.2', '< 6'
|
|
26
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
|
27
|
+
spec.add_development_dependency 'redcarpet', '~> 3.4'
|
|
28
|
+
spec.add_development_dependency 'rspec', '~> 3.4'
|
|
29
|
+
spec.add_development_dependency 'rspec-rails', '~> 3.8.1'
|
|
30
|
+
spec.add_development_dependency 'rubocop', '~> 0.61'
|
|
31
|
+
spec.add_development_dependency 'simplecov', '~> 0.12'
|
|
32
|
+
spec.add_development_dependency 'sqlite3', '~> 1.3'
|
|
33
|
+
spec.add_development_dependency 'yard', '~> 0.9.11'
|
|
34
|
+
end
|
data/lib/epilog.rb
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Epilog
|
|
4
|
+
module Filter
|
|
5
|
+
class Blacklist < HashKey
|
|
6
|
+
DEFAULT_BLACKLIST = %w[
|
|
7
|
+
password
|
|
8
|
+
pass
|
|
9
|
+
pw
|
|
10
|
+
secret
|
|
11
|
+
].freeze
|
|
12
|
+
|
|
13
|
+
attr_reader :blacklist
|
|
14
|
+
|
|
15
|
+
def initialize(blacklist = DEFAULT_BLACKLIST)
|
|
16
|
+
@blacklist = Hash[blacklist.map { |b| [b.to_s.downcase, nil] }]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def key?(key)
|
|
22
|
+
@blacklist.key?(key.to_s.downcase)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def filter(value)
|
|
26
|
+
"[filtered #{value.class.name}]"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Epilog
|
|
4
|
+
module Filter
|
|
5
|
+
class HashKey
|
|
6
|
+
def call(log)
|
|
7
|
+
fix(log)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
def fix(value)
|
|
13
|
+
if value.is_a?(Hash)
|
|
14
|
+
fix_hash(value)
|
|
15
|
+
elsif value.is_a?(Array)
|
|
16
|
+
value.map { |i| fix(i) }
|
|
17
|
+
else
|
|
18
|
+
value
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def fix_hash(hash)
|
|
23
|
+
hash.each_with_object({}) do |(key, value), obj|
|
|
24
|
+
obj[key] = if key?(key)
|
|
25
|
+
filter(value)
|
|
26
|
+
else
|
|
27
|
+
fix(value)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def key?(_key)
|
|
33
|
+
true
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def filter(value)
|
|
37
|
+
"[filtered #{value.class.name}]"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Epilog
|
|
4
|
+
class Formatter
|
|
5
|
+
SEVERITY_MAP = {
|
|
6
|
+
'FATAL' => 'ALERT',
|
|
7
|
+
'WARN' => 'WARNING'
|
|
8
|
+
}.freeze
|
|
9
|
+
|
|
10
|
+
DEFAULT_TIME_FORMAT = '%Y-%m-%dT%H:%M:%S%z'
|
|
11
|
+
|
|
12
|
+
attr_reader :filter
|
|
13
|
+
attr_writer :datetime_format
|
|
14
|
+
|
|
15
|
+
def initialize(options = {})
|
|
16
|
+
@filter = options[:filter] || Filter::Blacklist.new
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def call(severity, time, progname, msg)
|
|
20
|
+
log = base_log(severity, time, progname)
|
|
21
|
+
log.merge!(message(msg))
|
|
22
|
+
|
|
23
|
+
if log[:exception].is_a?(Exception)
|
|
24
|
+
log[:exception] = format_error(log[:exception])
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
log = before_write(log)
|
|
28
|
+
"#{JSON.dump(log)}\n"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def datetime_format
|
|
32
|
+
@datetime_format || DEFAULT_TIME_FORMAT
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def base_log(severity, time, progname)
|
|
38
|
+
{
|
|
39
|
+
timestamp: time.strftime(datetime_format),
|
|
40
|
+
severity: SEVERITY_MAP[severity] || severity,
|
|
41
|
+
source: progname
|
|
42
|
+
}
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def message(msg)
|
|
46
|
+
return { message: msg.message, exception: msg } if msg.is_a?(Exception)
|
|
47
|
+
return msg.to_h if msg.respond_to?(:to_h)
|
|
48
|
+
|
|
49
|
+
{ message: msg.to_s }
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def format_error(error)
|
|
53
|
+
hash = {
|
|
54
|
+
name: error.class.name,
|
|
55
|
+
message: error.message,
|
|
56
|
+
trace: error.backtrace
|
|
57
|
+
}
|
|
58
|
+
cause = error.cause
|
|
59
|
+
hash[:parent] = format_error(cause) unless cause.nil?
|
|
60
|
+
hash
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def before_write(log)
|
|
64
|
+
@filter ? @filter.call(log) : log
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Epilog
|
|
4
|
+
class Logger < ::Logger
|
|
5
|
+
def initialize(*args, **options)
|
|
6
|
+
super
|
|
7
|
+
self.formatter = Formatter.new
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def datetime_format
|
|
11
|
+
return unless formatter
|
|
12
|
+
|
|
13
|
+
formatter.datetime_format
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def datetime_format=(format)
|
|
17
|
+
return unless formatter
|
|
18
|
+
|
|
19
|
+
formatter.datetime_format = format
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Epilog
|
|
4
|
+
class MockLogger < ::Logger
|
|
5
|
+
def initialize
|
|
6
|
+
super(nil)
|
|
7
|
+
reset
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# rubocop:disable MethodLength
|
|
11
|
+
def add(severity, message = nil, progname = nil)
|
|
12
|
+
severity ||= Logger::UNKNOWN
|
|
13
|
+
return true if severity < level
|
|
14
|
+
|
|
15
|
+
prog ||= progname
|
|
16
|
+
if message.nil?
|
|
17
|
+
if block_given?
|
|
18
|
+
message = yield
|
|
19
|
+
else
|
|
20
|
+
message = prog
|
|
21
|
+
prog = progname
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
write(format_severity(severity), current_time, prog, message)
|
|
26
|
+
end
|
|
27
|
+
# rubocop:enable MethodLength
|
|
28
|
+
alias log add
|
|
29
|
+
|
|
30
|
+
def reopen(_logdev = nil)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def [](index)
|
|
34
|
+
@logs[index].dup || []
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def to_a
|
|
38
|
+
(0...@logs.size).map { |i| self[i] }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def freeze_time(time)
|
|
42
|
+
@time = time
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def reset
|
|
46
|
+
@logs = []
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def current_time
|
|
52
|
+
@time || Time.now
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def write(severity, time, prog, message)
|
|
56
|
+
@logs << [severity, time, prog, message]
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
data/lib/epilog/rails.rb
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'action_controller/log_subscriber'
|
|
4
|
+
require 'action_dispatch/middleware/debug_exceptions'
|
|
5
|
+
require 'action_mailer/log_subscriber'
|
|
6
|
+
require 'action_view/log_subscriber'
|
|
7
|
+
require 'active_record/log_subscriber'
|
|
8
|
+
require 'active_job/logging'
|
|
9
|
+
|
|
10
|
+
require 'epilog/rails/ext/event_delegate'
|
|
11
|
+
require 'epilog/rails/ext/active_support_logger'
|
|
12
|
+
require 'epilog/rails/ext/rack_logger'
|
|
13
|
+
require 'epilog/rails/ext/action_controller'
|
|
14
|
+
require 'epilog/rails/ext/debug_exceptions'
|
|
15
|
+
|
|
16
|
+
require 'epilog/rails/epilog_ext'
|
|
17
|
+
require 'epilog/rails/log_subscriber'
|
|
18
|
+
require 'epilog/rails/action_controller_subscriber'
|
|
19
|
+
require 'epilog/rails/action_mailer_subscriber'
|
|
20
|
+
require 'epilog/rails/action_view_subscriber'
|
|
21
|
+
require 'epilog/rails/active_record_subscriber'
|
|
22
|
+
require 'epilog/rails/active_job_subscriber'
|
|
23
|
+
require 'epilog/rails/railtie'
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# rubocop:disable ClassLength
|
|
4
|
+
module Epilog
|
|
5
|
+
module Rails
|
|
6
|
+
class ActionControllerSubscriber < LogSubscriber
|
|
7
|
+
RAILS_PARAMS = %i[controller action format _method only_path].freeze
|
|
8
|
+
|
|
9
|
+
def request_received(event)
|
|
10
|
+
info do
|
|
11
|
+
{
|
|
12
|
+
message: "#{request_string(event)} started",
|
|
13
|
+
request: request_hash(event)
|
|
14
|
+
}
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def process_request(event)
|
|
19
|
+
info do
|
|
20
|
+
{
|
|
21
|
+
message: response_string(event),
|
|
22
|
+
request: short_request_hash(event),
|
|
23
|
+
response: response_hash(event),
|
|
24
|
+
metrics: process_metrics(event.payload[:metrics]
|
|
25
|
+
.merge(request_runtime: event.duration.round(2)))
|
|
26
|
+
}
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def start_processing(*)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def process_action(*)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def send_data(event)
|
|
37
|
+
info { basic_message(event, "Sent data #{event.payload[:filename]}") }
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def send_file(event)
|
|
41
|
+
info { basic_message(event, "Sent file #{event.payload[:path]}") }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def redirect_to(event)
|
|
45
|
+
info { basic_message(event, "Redirect > #{event.payload[:location]}") }
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def halted_callback(event)
|
|
49
|
+
info do
|
|
50
|
+
basic_message(event, 'Filter chain halted as ' \
|
|
51
|
+
"#{event.payload[:filter].inspect} rendered or redirected")
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def unpermitted_parameters(event)
|
|
56
|
+
debug do
|
|
57
|
+
basic_message(event, 'Unpermitted parameters: ' \
|
|
58
|
+
"#{event.payload[:keys].join(', ')}")
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
%i[
|
|
63
|
+
write_fragment
|
|
64
|
+
read_fragment
|
|
65
|
+
exist_fragment?
|
|
66
|
+
expire_fragment
|
|
67
|
+
expire_page
|
|
68
|
+
write_page
|
|
69
|
+
].each do |method|
|
|
70
|
+
define_method(method) do |event|
|
|
71
|
+
return unless logger.info?
|
|
72
|
+
|
|
73
|
+
path = Array(event.payload[:key] || event.payload[:path]).join('/')
|
|
74
|
+
debug(basic_message(event, "#{method} #{path}"))
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
private
|
|
79
|
+
|
|
80
|
+
def request_hash(event) # rubocop:disable AbcSize, MethodLength
|
|
81
|
+
request = event.payload[:request]
|
|
82
|
+
{
|
|
83
|
+
id: request.uuid,
|
|
84
|
+
ip: request.remote_ip,
|
|
85
|
+
host: request.host,
|
|
86
|
+
protocol: request.protocol.to_s.gsub('://', ''),
|
|
87
|
+
method: request.request_method,
|
|
88
|
+
port: request.port,
|
|
89
|
+
path: request.fullpath,
|
|
90
|
+
query: request.query_parameters,
|
|
91
|
+
cookies: request.cookies,
|
|
92
|
+
headers: request.headers.to_h.keep_if do |key, _value|
|
|
93
|
+
key =~ ActionDispatch::Http::Headers::HTTP_HEADER
|
|
94
|
+
end,
|
|
95
|
+
params: request.filtered_parameters.except(*RAILS_PARAMS),
|
|
96
|
+
format: request.format.try(:ref),
|
|
97
|
+
controller: event.payload[:controller],
|
|
98
|
+
action: event.payload[:action]
|
|
99
|
+
}
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def short_request_hash(event)
|
|
103
|
+
request = event.payload[:request]
|
|
104
|
+
{
|
|
105
|
+
id: request.uuid,
|
|
106
|
+
method: request.method,
|
|
107
|
+
path: request.fullpath
|
|
108
|
+
}
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def request_string(event)
|
|
112
|
+
request = event.payload[:request]
|
|
113
|
+
"#{request.request_method} #{request.fullpath}"
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def response_hash(event)
|
|
117
|
+
{ status: normalize_status(event) }
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def response_string(event)
|
|
121
|
+
status = normalize_status(event)
|
|
122
|
+
status_string = Rack::Utils::HTTP_STATUS_CODES[status]
|
|
123
|
+
"#{request_string(event)} > #{status} #{status_string}"
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def normalize_status(event)
|
|
127
|
+
payload = event.payload
|
|
128
|
+
status = payload[:response].status
|
|
129
|
+
if status.nil? && payload[:exception].present?
|
|
130
|
+
status = ActionDispatch::ExceptionWrapper
|
|
131
|
+
.status_code_for_exception(payload[:exception].first)
|
|
132
|
+
end
|
|
133
|
+
status
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def basic_message(event, message)
|
|
137
|
+
{
|
|
138
|
+
message: message,
|
|
139
|
+
metrics: process_metrics(duration: event.duration)
|
|
140
|
+
}
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def process_metrics(metrics)
|
|
144
|
+
metrics.each_with_object({}) do |(key, value), obj|
|
|
145
|
+
next if value.nil?
|
|
146
|
+
|
|
147
|
+
obj[key] = value.round(2) if value.is_a?(Numeric)
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
# rubocop:enable ClassLength
|