berkeley_library-logging 0.2.4 → 0.2.6.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|