berkeley_library-logging 0.2.4 → 0.2.6.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/.idea/inspectionProfiles/Project_Default.xml +6 -1
- data/.idea/logging.iml +81 -126
- data/.rubocop.yml +100 -136
- data/CHANGES.md +13 -0
- data/Rakefile +3 -1
- data/berkeley_library-logging.gemspec +9 -4
- data/lib/berkeley_library/logging/configurator.rb +6 -2
- data/lib/berkeley_library/logging/env.rb +1 -1
- data/lib/berkeley_library/logging/events.rb +58 -36
- data/lib/berkeley_library/logging/exception_serializer.rb +15 -0
- data/lib/berkeley_library/logging/formatters.rb +8 -18
- data/lib/berkeley_library/logging/logger.rb +8 -0
- data/lib/berkeley_library/logging/module_info.rb +1 -1
- data/lib/berkeley_library/logging/safe_serializer.rb +77 -0
- data/spec/.rubocop.yml +88 -7
- data/spec/rails/ucblit/logging/configurator_spec.rb +99 -47
- data/spec/rails/ucblit/logging/env_spec.rb +2 -2
- data/spec/rails/ucblit/logging/formatters_spec.rb +3 -1
- data/spec/rails/ucblit/logging/loggers_spec.rb +6 -5
- data/spec/rails/ucblit/logging/railtie_spec.rb +2 -2
- data/spec/rails/ucblit/logging/safe_serializer_spec.rb +23 -0
- data/spec/rails/ucblit/logging_spec.rb +3 -3
- data/spec/spec_helper.rb +1 -1
- data/spec/standalone/ucblit/logging/configurator_spec.rb +2 -2
- data/spec/standalone/ucblit/logging/formatters_spec.rb +3 -1
- data/spec/standalone/ucblit/logging/loggers_spec.rb +7 -7
- data/spec/standalone/ucblit/logging/safe_serializer_spec.rb +137 -0
- data/spec/standalone/ucblit/logging_spec.rb +3 -3
- data/spec/standalone_helper.rb +1 -1
- metadata +36 -14
@@ -20,12 +20,14 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.homepage = BerkeleyLibrary::Logging::ModuleInfo::HOMEPAGE
|
21
21
|
|
22
22
|
spec.files = `git ls-files -z`.split("\x0")
|
23
|
-
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
23
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features|artifacts)/})
|
24
24
|
spec.require_paths = ['lib']
|
25
25
|
|
26
26
|
spec.required_ruby_version = ">= #{ruby_version}"
|
27
27
|
|
28
|
-
|
28
|
+
rails_version = '>= 6'
|
29
|
+
|
30
|
+
spec.add_dependency 'activesupport', rails_version
|
29
31
|
spec.add_dependency 'amazing_print', '~> 1.1'
|
30
32
|
spec.add_dependency 'colorize', '~> 0.8.1'
|
31
33
|
spec.add_dependency 'lograge', '~> 0.11'
|
@@ -37,11 +39,14 @@ Gem::Specification.new do |spec|
|
|
37
39
|
spec.add_development_dependency 'dotenv', '~> 2.7'
|
38
40
|
spec.add_development_dependency 'irb', '~> 1.2' # workaroundfor https://github.com/bundler/bundler/issues/6929
|
39
41
|
spec.add_development_dependency 'listen', '>= 3.0.5', '< 3.2'
|
40
|
-
spec.add_development_dependency 'rails',
|
42
|
+
spec.add_development_dependency 'rails', rails_version
|
41
43
|
spec.add_development_dependency 'rake', '~> 13.0'
|
42
44
|
spec.add_development_dependency 'rspec-support', '~> 3.9'
|
43
|
-
spec.add_development_dependency 'rubocop', '~>
|
45
|
+
spec.add_development_dependency 'rubocop', '~> 1.26.0'
|
46
|
+
spec.add_development_dependency 'rubocop-rspec', '~> 2.4.0'
|
44
47
|
spec.add_development_dependency 'simplecov', '~> 0.21.1'
|
45
48
|
spec.add_development_dependency 'simplecov-console', '~> 0.9.1'
|
46
49
|
spec.add_development_dependency 'simplecov-rcov', '~> 0.2'
|
50
|
+
|
51
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
47
52
|
end
|
@@ -22,9 +22,13 @@ module BerkeleyLibrary
|
|
22
22
|
def configure_lograge(config)
|
23
23
|
return unless config.respond_to?(:lograge)
|
24
24
|
|
25
|
-
config.lograge
|
25
|
+
lograge_config = config.lograge
|
26
|
+
|
27
|
+
custom_options = Events.extract_data_for_lograge(lograge_config)
|
28
|
+
|
29
|
+
lograge_config.tap do |lograge|
|
26
30
|
lograge.enabled = true
|
27
|
-
lograge.custom_options =
|
31
|
+
lograge.custom_options = custom_options
|
28
32
|
lograge.formatter = Formatters.lograge_formatter
|
29
33
|
end
|
30
34
|
end
|
@@ -11,7 +11,7 @@ module BerkeleyLibrary
|
|
11
11
|
return Rails.env if defined?(Rails)
|
12
12
|
|
13
13
|
@env ||= begin
|
14
|
-
#
|
14
|
+
# NOTE: can't just self.env= b/c it returns the wrong value -- see
|
15
15
|
# https://stackoverflow.com/q/65226532/27358
|
16
16
|
env = (ENV['RAILS_ENV'] || ENV['RACK_ENV'] || FALLBACK_ENV)
|
17
17
|
ensure_rails_env_like(env)
|
@@ -1,41 +1,46 @@
|
|
1
|
+
require 'berkeley_library/logging/safe_serializer'
|
2
|
+
|
1
3
|
module BerkeleyLibrary
|
2
4
|
module Logging
|
3
5
|
module Events
|
6
|
+
LOGGED_REQUEST_ATTRIBUTES = %i[origin base_url x_csrf_token].freeze
|
7
|
+
LOGGED_SESSION_ATTRIBUTES = %i[session_id _csrf_token].freeze
|
8
|
+
LOGGED_PARAMETERS = [:authenticity_token].freeze
|
9
|
+
LOGGED_HEADERS = {
|
10
|
+
# yes, RFC 2616 uses a variant spelling for 'referrer', it's a known issue
|
11
|
+
# https://tools.ietf.org/html/rfc2616#section-14.36
|
12
|
+
referer: 'HTTP_REFERER',
|
13
|
+
request_id: 'action_dispatch.request_id',
|
14
|
+
remote_ip: 'action_dispatch.remote_ip',
|
15
|
+
remote_addr: 'REMOTE_ADDR',
|
16
|
+
x_forwarded_for: 'HTTP_X_FORWARDED_FOR',
|
17
|
+
forwarded: 'HTTP_FORWARDED' # RFC 7239
|
18
|
+
}.freeze
|
19
|
+
|
4
20
|
class << self
|
5
|
-
LOGGED_REQUEST_ATTRIBUTES = %i[origin base_url x_csrf_token].freeze
|
6
|
-
LOGGED_PARAMETERS = [:authenticity_token].freeze
|
7
|
-
LOGGED_HEADERS = {
|
8
|
-
# yes, RFC 2616 uses a variant spelling for 'referrer', it's a known issue
|
9
|
-
# https://tools.ietf.org/html/rfc2616#section-14.36
|
10
|
-
referer: 'HTTP_REFERER',
|
11
|
-
request_id: 'action_dispatch.request_id',
|
12
|
-
remote_ip: 'action_dispatch.remote_ip',
|
13
|
-
remote_addr: 'REMOTE_ADDR',
|
14
|
-
x_forwarded_for: 'HTTP_X_FORWARDED_FOR',
|
15
|
-
forwarded: 'HTTP_FORWARDED' # RFC 7239
|
16
|
-
}.freeze
|
17
|
-
|
18
|
-
def extract_data_for_lograge
|
19
|
-
->(event) { extract_event_data(event) }
|
20
|
-
end
|
21
21
|
|
22
|
-
|
22
|
+
def extract_data_for_lograge(lograge_config)
|
23
|
+
verbose_session_logging = lograge_config.verbose_session_logging
|
23
24
|
|
24
|
-
|
25
|
-
|
26
|
-
headers = extract_headers(event)
|
27
|
-
event_data.merge!(headers)
|
25
|
+
->(event) { extract_event_data(event.payload, verbose_session_logging) }
|
26
|
+
end
|
28
27
|
|
29
|
-
|
30
|
-
event_data.merge!(request_attributes)
|
28
|
+
private
|
31
29
|
|
32
|
-
|
33
|
-
|
30
|
+
def extract_event_data(payload, verbose_session_logging)
|
31
|
+
[
|
32
|
+
extract_headers(payload),
|
33
|
+
extract_request_attributes(payload),
|
34
|
+
extract_param_values(payload),
|
35
|
+
extract_session(payload, verbose_session_logging)
|
36
|
+
].inject({ time: Time.now }) do |data, values|
|
37
|
+
clean_values = SafeSerializer.serialize(values)
|
38
|
+
data.merge(clean_values)
|
34
39
|
end
|
35
40
|
end
|
36
41
|
|
37
|
-
def extract_param_values(
|
38
|
-
return {} unless (params =
|
42
|
+
def extract_param_values(payload)
|
43
|
+
return {} unless (params = payload[:params])
|
39
44
|
|
40
45
|
LOGGED_PARAMETERS.each_with_object({}) do |param, values|
|
41
46
|
next unless (param_val = params[param])
|
@@ -44,29 +49,46 @@ module BerkeleyLibrary
|
|
44
49
|
end
|
45
50
|
end
|
46
51
|
|
47
|
-
def extract_request_attributes(
|
48
|
-
return {} unless (request =
|
52
|
+
def extract_request_attributes(payload)
|
53
|
+
return {} unless (request = payload[:request])
|
49
54
|
|
50
55
|
LOGGED_REQUEST_ATTRIBUTES.each_with_object({}) do |attr, values|
|
51
56
|
next unless request.respond_to?(attr)
|
52
|
-
next
|
57
|
+
next if (attr_val = request.send(attr)).nil?
|
53
58
|
|
54
59
|
values[attr] = attr_val
|
55
60
|
end
|
56
61
|
end
|
57
62
|
|
58
|
-
def extract_headers(
|
59
|
-
return {} unless (headers =
|
63
|
+
def extract_headers(payload)
|
64
|
+
return {} unless (headers = payload[:headers])
|
60
65
|
|
61
66
|
LOGGED_HEADERS.each_with_object({}) do |(key, header), values|
|
62
67
|
next unless (header_val = headers[header])
|
63
68
|
|
64
|
-
|
65
|
-
# that cause SystemStackErrors in JSON serialization,
|
66
|
-
# so we convert them all to strings
|
67
|
-
values[key] = header_val.to_s
|
69
|
+
values[key] = header_val
|
68
70
|
end
|
69
71
|
end
|
72
|
+
|
73
|
+
def extract_session(payload, verbose_session_logging)
|
74
|
+
return {} unless (request = payload[:request])
|
75
|
+
return {} unless (session = request.session)
|
76
|
+
return {} unless session.respond_to?(:to_hash)
|
77
|
+
|
78
|
+
session_hash = session_hash(session, verbose_session_logging)
|
79
|
+
|
80
|
+
{ session: session_hash }
|
81
|
+
end
|
82
|
+
|
83
|
+
def session_hash(session, verbose)
|
84
|
+
raw_session_hash = session.to_hash
|
85
|
+
return raw_session_hash if verbose
|
86
|
+
|
87
|
+
LOGGED_SESSION_ATTRIBUTES.filter_map do |attr|
|
88
|
+
attr_str = attr.to_s
|
89
|
+
[attr, raw_session_hash[attr_str]] if raw_session_hash.key?(attr_str)
|
90
|
+
end.to_h
|
91
|
+
end
|
70
92
|
end
|
71
93
|
end
|
72
94
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module BerkeleyLibrary
|
2
|
+
module Logging
|
3
|
+
module ExceptionSerializer
|
4
|
+
def serialize_exc(ex, serialized = Set.new)
|
5
|
+
raw_result = { name: ex.class.name, message: ex.message, stack: ex.backtrace }
|
6
|
+
raw_result.tap do |result|
|
7
|
+
next unless (cause = ex.cause)
|
8
|
+
next if (serialized << ex).include?(cause) # prevent circular references
|
9
|
+
|
10
|
+
result[:cause] = serialize_exc(cause, serialized)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'ougai'
|
2
|
+
require 'berkeley_library/logging/exception_serializer'
|
2
3
|
|
3
4
|
module BerkeleyLibrary
|
4
5
|
module Logging
|
@@ -41,21 +42,8 @@ module BerkeleyLibrary
|
|
41
42
|
# ------------------------------------------------------------
|
42
43
|
# Private helper classes
|
43
44
|
|
44
|
-
module ErrorCauseSerializer
|
45
|
-
def serialize_exc(ex, serialized = Set.new)
|
46
|
-
super(ex).tap do |result|
|
47
|
-
next unless (cause = ex.cause)
|
48
|
-
next if (serialized << ex).include?(cause) # prevent circular references
|
49
|
-
|
50
|
-
result[:cause] = serialize_exc(cause, serialized)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
private_constant :ErrorCauseSerializer
|
56
|
-
|
57
45
|
class Readable < Ougai::Formatters::Readable
|
58
|
-
include
|
46
|
+
include ExceptionSerializer
|
59
47
|
|
60
48
|
protected
|
61
49
|
|
@@ -71,9 +59,11 @@ module BerkeleyLibrary
|
|
71
59
|
" #{err_hash[:name]} (#{err_hash[:message]}):".tap do |msg|
|
72
60
|
next unless (stack = err_hash[:stack])
|
73
61
|
|
74
|
-
|
75
|
-
|
76
|
-
|
62
|
+
trace_indent = (' ' * @trace_indent)
|
63
|
+
trace_separator = "\n#{trace_indent}"
|
64
|
+
|
65
|
+
msg << trace_separator
|
66
|
+
msg << stack.join(trace_separator)
|
77
67
|
|
78
68
|
next unless (cause_hash = err_hash[:cause])
|
79
69
|
|
@@ -87,7 +77,7 @@ module BerkeleyLibrary
|
|
87
77
|
|
88
78
|
class Bunyan < Ougai::Formatters::Bunyan
|
89
79
|
include Ougai::Logging::Severity
|
90
|
-
include
|
80
|
+
include ExceptionSerializer
|
91
81
|
|
92
82
|
def _call(severity, time, progname, data)
|
93
83
|
original_data = Formatters.ensure_hash(data)
|
@@ -1,3 +1,11 @@
|
|
1
|
+
begin
|
2
|
+
# Rails 7.x LoggerThreadSafeLevel needs IsolatedExecutionState,
|
3
|
+
# but doesn't explicitly require it
|
4
|
+
require 'active_support/isolated_execution_state'
|
5
|
+
rescue LoadError
|
6
|
+
# Rails 6.x doesn't
|
7
|
+
end
|
8
|
+
|
1
9
|
require 'active_support/logger'
|
2
10
|
require 'ougai'
|
3
11
|
require 'berkeley_library/logging/tagged_logging_extensions'
|
@@ -7,7 +7,7 @@ module BerkeleyLibrary
|
|
7
7
|
SUMMARY = 'Opinionated Ruby/Rails logging for UC Berkeley Library'.freeze
|
8
8
|
DESCRIPTION = 'A gem providing shared logging code for UC Berkeley Library gems and Rails applications'.freeze
|
9
9
|
LICENSE = 'MIT'.freeze
|
10
|
-
VERSION = '0.2.
|
10
|
+
VERSION = '0.2.6.1'.freeze
|
11
11
|
HOMEPAGE = 'https://github.com/BerkeleyLibrary/logging'.freeze
|
12
12
|
|
13
13
|
private_class_method :new
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'time'
|
2
|
+
require 'berkeley_library/logging/exception_serializer'
|
3
|
+
|
4
|
+
module BerkeleyLibrary
|
5
|
+
module Logging
|
6
|
+
# Some of values include recursive structures
|
7
|
+
# that cause SystemStackErrors in JSON serialization,
|
8
|
+
# so we convert them all to strings
|
9
|
+
class SafeSerializer
|
10
|
+
include ExceptionSerializer
|
11
|
+
|
12
|
+
RAW_TYPES = [NilClass, FalseClass, TrueClass, Numeric, String, Symbol, Date, Time].freeze
|
13
|
+
|
14
|
+
def initialize(value)
|
15
|
+
@value = value
|
16
|
+
end
|
17
|
+
|
18
|
+
class << self
|
19
|
+
def serialize(value)
|
20
|
+
SafeSerializer.new(value).serialized_value
|
21
|
+
end
|
22
|
+
|
23
|
+
def placeholder_for(value)
|
24
|
+
"#<#{value.class}:#{value.object_id}> (recursive reference)"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def serialized_value
|
29
|
+
@serialized_value ||= serialize(@value)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
35
|
+
def serialize(value)
|
36
|
+
return value if safe_raw_value?(value)
|
37
|
+
return SafeSerializer.placeholder_for(value) if serialized_values.include?(value)
|
38
|
+
|
39
|
+
serialized_values << value
|
40
|
+
|
41
|
+
return serialize_hash(value) if value.is_a?(Hash)
|
42
|
+
return serialize_hash(value.to_hash) if value.respond_to?(:to_hash)
|
43
|
+
return serialize_array(value) if value.is_a?(Array)
|
44
|
+
return serialize_array(value.to_ary) if value.respond_to?(:to_ary)
|
45
|
+
return serialize_exc(value, serialized_values) if value.is_a?(Exception)
|
46
|
+
|
47
|
+
value.to_s
|
48
|
+
end
|
49
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
50
|
+
|
51
|
+
def safe_raw_value?(value)
|
52
|
+
return true if rails_time_with_zone?(value)
|
53
|
+
|
54
|
+
RAW_TYPES.any? { |t| value.is_a?(t) }
|
55
|
+
end
|
56
|
+
|
57
|
+
def rails_time_with_zone?(value)
|
58
|
+
defined?(ActiveSupport::TimeWithZone) && value.is_a?(ActiveSupport::TimeWithZone)
|
59
|
+
end
|
60
|
+
|
61
|
+
def serialize_array(value)
|
62
|
+
value.map { |v| serialize(v) }
|
63
|
+
end
|
64
|
+
|
65
|
+
def serialize_hash(value)
|
66
|
+
value.each_with_object({}) do |(k, v), h|
|
67
|
+
k1, v1 = [k, v].map { |x| serialize(x) }
|
68
|
+
h[k1] = v1
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def serialized_values
|
73
|
+
@serialized_values ||= Set.new
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
data/spec/.rubocop.yml
CHANGED
@@ -1,15 +1,18 @@
|
|
1
1
|
inherit_from: ../.rubocop.yml
|
2
2
|
|
3
|
+
require:
|
4
|
+
- rubocop-rspec
|
5
|
+
|
3
6
|
Style/ClassAndModuleChildren:
|
4
7
|
Enabled: false
|
5
8
|
|
6
|
-
|
9
|
+
Style/OpenStructUse:
|
7
10
|
Enabled: false
|
8
11
|
|
9
|
-
Metrics/
|
12
|
+
Metrics/AbcSize:
|
10
13
|
Enabled: false
|
11
14
|
|
12
|
-
Metrics/
|
15
|
+
Metrics/BlockLength:
|
13
16
|
Enabled: false
|
14
17
|
|
15
18
|
Metrics/ModuleLength:
|
@@ -19,9 +22,87 @@ Metrics/MethodLength:
|
|
19
22
|
Enabled: false
|
20
23
|
|
21
24
|
############################################################
|
22
|
-
#
|
25
|
+
# rubocop-rspec
|
26
|
+
|
27
|
+
# believe me, it wasn't by choice
|
28
|
+
RSpec/AnyInstance:
|
29
|
+
Enabled: false
|
30
|
+
|
31
|
+
# we meant to do that
|
32
|
+
RSpec/BeforeAfterAll:
|
33
|
+
Enabled: false
|
34
|
+
|
35
|
+
# more words != more readable
|
36
|
+
RSpec/ContextWording:
|
37
|
+
Enabled: false
|
38
|
+
|
39
|
+
# explicit >>> implicit
|
40
|
+
RSpec/DescribedClass:
|
41
|
+
Enabled: false
|
42
|
+
|
43
|
+
# more punctuation != more readable
|
44
|
+
RSpec/DescribeSymbol:
|
45
|
+
Enabled: false
|
46
|
+
|
47
|
+
# too late now
|
48
|
+
RSpec/ExampleLength:
|
49
|
+
Enabled: false
|
50
|
+
|
51
|
+
# we meant to do that
|
52
|
+
RSpec/ExpectInHook:
|
53
|
+
Enabled: false
|
54
|
+
|
55
|
+
# if only it were that simple
|
56
|
+
RSpec/ExpectOutput:
|
57
|
+
Enabled: false
|
58
|
+
|
59
|
+
# your naming scheme is not in possession of all the facts
|
60
|
+
RSpec/FilePath:
|
61
|
+
Enabled: false
|
23
62
|
|
24
|
-
#
|
25
|
-
|
63
|
+
# explicit >>> implicit
|
64
|
+
RSpec/InstanceVariable:
|
26
65
|
Enabled: false
|
27
|
-
|
66
|
+
|
67
|
+
# maybe when 'all' has a corresponding 'none' matcher
|
68
|
+
RSpec/IteratedExpectation:
|
69
|
+
Enabled: false
|
70
|
+
|
71
|
+
# TODO: clean these up & de-disable this
|
72
|
+
RSpec/LeakyConstantDeclaration:
|
73
|
+
Enabled: false
|
74
|
+
|
75
|
+
# too late now
|
76
|
+
RSpec/MultipleMemoizedHelpers:
|
77
|
+
Enabled: false
|
78
|
+
|
79
|
+
# setup cost / time >>> failure granularity
|
80
|
+
RSpec/MultipleExpectations:
|
81
|
+
Enabled: false
|
82
|
+
|
83
|
+
# cure is worse than the disease
|
84
|
+
RSpec/NestedGroups:
|
85
|
+
Enabled: false
|
86
|
+
|
87
|
+
# more quotation marks != more readable
|
88
|
+
RSpec/SharedExamples:
|
89
|
+
Enabled: false
|
90
|
+
|
91
|
+
# we meant to do that
|
92
|
+
RSpec/StubbedMock:
|
93
|
+
Enabled: false
|
94
|
+
|
95
|
+
# we meant to do that
|
96
|
+
RSpec/VerifiedDoubles:
|
97
|
+
Enabled: false
|
98
|
+
|
99
|
+
############################################################
|
100
|
+
# rubocop-rspec
|
101
|
+
|
102
|
+
# enable newer rubocop-rspec cops
|
103
|
+
|
104
|
+
RSpec/IdenticalEqualityAssertion: # new in 2.4
|
105
|
+
Enabled: true
|
106
|
+
|
107
|
+
RSpec/Rails/AvoidSetupHook: # new in 2.4
|
108
|
+
Enabled: true
|
@@ -10,7 +10,7 @@ module BerkeleyLibrary
|
|
10
10
|
|
11
11
|
attr_reader :config
|
12
12
|
|
13
|
-
before
|
13
|
+
before do
|
14
14
|
app = Class.new(Rails::Application).new
|
15
15
|
allow(Rails).to receive(:application).and_return(app)
|
16
16
|
@config = app.config
|
@@ -30,53 +30,105 @@ module BerkeleyLibrary
|
|
30
30
|
expect(lograge.enabled).to eq(true)
|
31
31
|
end
|
32
32
|
|
33
|
-
|
34
|
-
|
35
|
-
|
33
|
+
context 'events' do
|
34
|
+
let(:params) { { authenticity_token: '8675309' } }
|
35
|
+
|
36
|
+
let(:session_hash) do
|
37
|
+
{
|
38
|
+
'session_id' => '17cd06b1b7cb9744e8fa626ef5f37c67',
|
39
|
+
'user' => {
|
40
|
+
'id' => 71,
|
41
|
+
'user_name' => 'Ms. Magoo',
|
42
|
+
'created_at' => '2021-10-14T09:24:42.730-07:00',
|
43
|
+
'updated_at' => '2021-10-14T09:24:42.729-07:00',
|
44
|
+
'user_role' => 'Administrator',
|
45
|
+
'user_active' => true,
|
46
|
+
'uid' => 1_684_944,
|
47
|
+
'updated_by' => 'Dr. Pibb'
|
48
|
+
},
|
49
|
+
'expires_at' => '2021-11-03T12:30:01.281-07:00',
|
50
|
+
'_csrf_token' => 'HiN1xUxFcOvWvoe2nwoBSGlmGSN6x0jprpSqDrzquxA='
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
let(:request_headers) do
|
55
|
+
{
|
56
|
+
'HTTP_REFERER' => 'value from HTTP_REFERER',
|
57
|
+
'action_dispatch.request_id' => 'value from action_dispatch.request_id',
|
58
|
+
'action_dispatch.remote_ip' => 'value from action_dispatch.remote_ip',
|
59
|
+
'REMOTE_ADDR' => 'value from REMOTE_ADDR',
|
60
|
+
'HTTP_X_FORWARDED_FOR' => 'value from HTTP_X_FORWARDED_FOR',
|
61
|
+
'HTTP_FORWARDED' => 'value from HTTP_FORWARDED'
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
let(:expected_header_map) do
|
66
|
+
{
|
67
|
+
referer: 'HTTP_REFERER',
|
68
|
+
request_id: 'action_dispatch.request_id',
|
69
|
+
remote_ip: 'action_dispatch.remote_ip',
|
70
|
+
remote_addr: 'REMOTE_ADDR',
|
71
|
+
x_forwarded_for: 'HTTP_X_FORWARDED_FOR',
|
72
|
+
forwarded: 'HTTP_FORWARDED'
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
attr_reader :session, :request, :payload, :event
|
77
|
+
|
78
|
+
before do
|
79
|
+
@session = instance_double(ActionDispatch::Request::Session)
|
80
|
+
allow(session).to receive(:to_hash).and_return(session_hash)
|
81
|
+
|
82
|
+
@request = instance_double(ActionDispatch::Request)
|
83
|
+
allow(request).to receive(:origin).and_return('http://example.org:3000')
|
84
|
+
allow(request).to receive(:base_url).and_return('https://example.org:3443')
|
85
|
+
allow(request).to receive(:x_csrf_token).and_return('5551212')
|
86
|
+
allow(request).to receive(:session).and_return(session)
|
87
|
+
|
88
|
+
@payload = {
|
89
|
+
params: params,
|
90
|
+
request: request,
|
91
|
+
headers: request_headers
|
92
|
+
}
|
93
|
+
|
94
|
+
@event = instance_double(ActiveSupport::Notifications::Event)
|
95
|
+
allow(event).to receive(:payload).and_return(payload)
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'extracts request info from log events' do
|
99
|
+
Configurator.configure(config)
|
100
|
+
data = config.lograge.custom_options.call(event)
|
101
|
+
|
102
|
+
expect(data).to be_a(Hash)
|
103
|
+
expect(data[:time]).to be_a(Time)
|
104
|
+
expect(data[:time].to_i).to be_within(60).of(Time.now.to_i)
|
105
|
+
|
106
|
+
expected_header_map.each { |xh, rh| expect(data[xh]).to eq(request_headers[rh]) }
|
107
|
+
|
108
|
+
expect(data[:authenticity_token]).to eq(params[:authenticity_token])
|
109
|
+
|
110
|
+
Events::LOGGED_REQUEST_ATTRIBUTES.each do |attr|
|
111
|
+
expect(data[attr]).to eq(request.send(attr))
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'includes the entire session if `verbose_session_logging` is true' do
|
116
|
+
config.lograge.verbose_session_logging = true
|
117
|
+
Configurator.configure(config)
|
118
|
+
data = config.lograge.custom_options.call(event)
|
119
|
+
|
120
|
+
expect(data[:session]).to eq(session_hash)
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'includes only the session ID by default' do
|
124
|
+
Configurator.configure(config)
|
125
|
+
data = config.lograge.custom_options.call(event)
|
126
|
+
|
127
|
+
expected_hash = Events::LOGGED_SESSION_ATTRIBUTES.each_with_object({}) do |attr, h|
|
128
|
+
h[attr] = session_hash[attr.to_s]
|
129
|
+
end
|
36
130
|
|
37
|
-
|
38
|
-
request = OpenStruct.new(
|
39
|
-
origin: 'http://example.org:3000',
|
40
|
-
base_url: 'https://example.org:3443',
|
41
|
-
x_csrf_token: '5551212'
|
42
|
-
)
|
43
|
-
|
44
|
-
request_headers = {
|
45
|
-
'HTTP_REFERER' => 'value from HTTP_REFERER',
|
46
|
-
'action_dispatch.request_id' => 'value from action_dispatch.request_id',
|
47
|
-
'action_dispatch.remote_ip' => 'value from action_dispatch.remote_ip',
|
48
|
-
'REMOTE_ADDR' => 'value from REMOTE_ADDR',
|
49
|
-
'HTTP_X_FORWARDED_FOR' => 'value from HTTP_X_FORWARDED_FOR',
|
50
|
-
'HTTP_FORWARDED' => 'value from HTTP_FORWARDED'
|
51
|
-
}
|
52
|
-
|
53
|
-
expected_header_map = {
|
54
|
-
referer: 'HTTP_REFERER',
|
55
|
-
request_id: 'action_dispatch.request_id',
|
56
|
-
remote_ip: 'action_dispatch.remote_ip',
|
57
|
-
remote_addr: 'REMOTE_ADDR',
|
58
|
-
x_forwarded_for: 'HTTP_X_FORWARDED_FOR',
|
59
|
-
forwarded: 'HTTP_FORWARDED'
|
60
|
-
}
|
61
|
-
|
62
|
-
payload = {
|
63
|
-
params: params,
|
64
|
-
request: request,
|
65
|
-
headers: request_headers
|
66
|
-
}
|
67
|
-
|
68
|
-
event = instance_double(ActiveSupport::Notifications::Event)
|
69
|
-
allow(event).to receive(:payload).and_return(payload)
|
70
|
-
|
71
|
-
custom_options = lograge.custom_options
|
72
|
-
data = custom_options.call(event)
|
73
|
-
expect(data).to be_a(Hash)
|
74
|
-
expect(data[:time]).to be_a(Time)
|
75
|
-
expect(data[:time].to_i).to be_within(60).of(Time.now.to_i)
|
76
|
-
expected_header_map.each { |xh, rh| expect(data[xh]).to eq(request_headers[rh]) }
|
77
|
-
expect(data[:authenticity_token]).to eq(params[:authenticity_token])
|
78
|
-
%i[origin base_url x_csrf_token].each do |attr|
|
79
|
-
expect(data[attr]).to eq(request.send(attr))
|
131
|
+
expect(data[:session]).to eq(expected_hash)
|
80
132
|
end
|
81
133
|
end
|
82
134
|
|
@@ -9,7 +9,7 @@ module BerkeleyLibrary
|
|
9
9
|
describe :new_json_formatter do
|
10
10
|
attr_reader :out, :logger
|
11
11
|
|
12
|
-
before
|
12
|
+
before do
|
13
13
|
@out = StringIO.new
|
14
14
|
@logger = Logger.new(out)
|
15
15
|
logger.formatter = Formatters.new_json_formatter
|
@@ -68,6 +68,7 @@ module BerkeleyLibrary
|
|
68
68
|
expect(additional_data['more_strings']).to eq([expected_string, expected_string])
|
69
69
|
end
|
70
70
|
|
71
|
+
# rubocop:disable Layout/LineLength
|
71
72
|
it 'removes ANSI formatting from ActiveRecord logs' do
|
72
73
|
original = " \e[1m\e[36mLendingItem Load (2.0ms)\e[0m \e[1m\e[34mSELECT \"lending_items\".* FROM \"lending_items\" WHERE \"lending_items\".\"directory\" = $1 LIMIT $2\e[0m [[\"directory\", \"b135297126_C068087930\"], [\"LIMIT\", 1]]"
|
73
74
|
expected = ' LendingItem Load (2.0ms) SELECT "lending_items".* FROM "lending_items" WHERE "lending_items"."directory" = $1 LIMIT $2 [["directory", "b135297126_C068087930"], ["LIMIT", 1]]'
|
@@ -76,6 +77,7 @@ module BerkeleyLibrary
|
|
76
77
|
msg = logged_json['msg']
|
77
78
|
expect(msg).to eq(expected)
|
78
79
|
end
|
80
|
+
# rubocop:enable Layout/LineLength
|
79
81
|
end
|
80
82
|
|
81
83
|
describe :ensure_hash do
|