berkeley_library-logging 0.2.3 → 0.2.6

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.
Files changed (33) hide show
  1. checksums.yaml +4 -4
  2. data/.idea/inspectionProfiles/Project_Default.xml +6 -1
  3. data/.idea/logging.iml +98 -126
  4. data/.rubocop.yml +100 -136
  5. data/.simplecov +0 -12
  6. data/CHANGES.md +19 -0
  7. data/Rakefile +3 -1
  8. data/artifacts/.keep +0 -0
  9. data/berkeley_library-logging.gemspec +7 -4
  10. data/lib/berkeley_library/logging/configurator.rb +6 -2
  11. data/lib/berkeley_library/logging/env.rb +1 -1
  12. data/lib/berkeley_library/logging/events.rb +80 -24
  13. data/lib/berkeley_library/logging/exception_serializer.rb +15 -0
  14. data/lib/berkeley_library/logging/formatters.rb +8 -18
  15. data/lib/berkeley_library/logging/logger.rb +1 -0
  16. data/lib/berkeley_library/logging/module_info.rb +1 -1
  17. data/lib/berkeley_library/logging/safe_serializer.rb +77 -0
  18. data/spec/.rubocop.yml +88 -7
  19. data/spec/rails/ucblit/logging/configurator_spec.rb +100 -30
  20. data/spec/rails/ucblit/logging/env_spec.rb +2 -2
  21. data/spec/rails/ucblit/logging/formatters_spec.rb +3 -1
  22. data/spec/rails/ucblit/logging/loggers_spec.rb +6 -5
  23. data/spec/rails/ucblit/logging/railtie_spec.rb +2 -2
  24. data/spec/rails/ucblit/logging/safe_serializer_spec.rb +23 -0
  25. data/spec/rails/ucblit/logging_spec.rb +3 -3
  26. data/spec/spec_helper.rb +1 -1
  27. data/spec/standalone/ucblit/logging/configurator_spec.rb +2 -2
  28. data/spec/standalone/ucblit/logging/formatters_spec.rb +3 -1
  29. data/spec/standalone/ucblit/logging/loggers_spec.rb +12 -8
  30. data/spec/standalone/ucblit/logging/safe_serializer_spec.rb +137 -0
  31. data/spec/standalone/ucblit/logging_spec.rb +3 -3
  32. data/spec/standalone_helper.rb +1 -1
  33. metadata +33 -10
data/CHANGES.md CHANGED
@@ -1,3 +1,22 @@
1
+ # 0.2.6 (2022-03-14)
2
+
3
+ - Add support for Rails 7.
4
+
5
+ # 0.2.5 (2021-11-04)
6
+
7
+ - Rails event logs now include a subset of session attributes (`session_id` and `_csrf_token`).
8
+ Set `Rails.config.lograge.verbose_session_logging` to log the full session hash.
9
+
10
+ # 0.2.4 (2021-11-02)
11
+
12
+ - Rails event logs now include the following, in addition to the
13
+ headers already logged:
14
+
15
+ - `request.origin`
16
+ - `request.base_url`
17
+ - `request.x_csrf_token`
18
+ - `params[:authenticity_token]`
19
+
1
20
  # 0.2.3 (2021-09-02)
2
21
 
3
22
  - JSON formatter now strips all ANSI 7-bit C1 escapes from strings
data/Rakefile CHANGED
@@ -19,9 +19,11 @@ end
19
19
  # ------------------------------------------------------------
20
20
  # Custom tasks
21
21
 
22
- desc 'Remove artifacts directory'
22
+ desc 'Remove artifacts directory, except for .keep file'
23
23
  task :clean do
24
24
  FileUtils.rm_rf('artifacts')
25
+ FileUtils.mkdir('artifacts')
26
+ FileUtils.touch(File.join('artifacts', '.keep'))
25
27
  end
26
28
 
27
29
  desc 'Check test coverage, check code style, check gems for vulnerabilities'
data/artifacts/.keep ADDED
File without changes
@@ -20,12 +20,12 @@ 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
- spec.add_dependency 'activesupport', '~> 6.0'
28
+ spec.add_dependency 'activesupport', '>= 6.0'
29
29
  spec.add_dependency 'amazing_print', '~> 1.1'
30
30
  spec.add_dependency 'colorize', '~> 0.8.1'
31
31
  spec.add_dependency 'lograge', '~> 0.11'
@@ -37,11 +37,14 @@ Gem::Specification.new do |spec|
37
37
  spec.add_development_dependency 'dotenv', '~> 2.7'
38
38
  spec.add_development_dependency 'irb', '~> 1.2' # workaroundfor https://github.com/bundler/bundler/issues/6929
39
39
  spec.add_development_dependency 'listen', '>= 3.0.5', '< 3.2'
40
- spec.add_development_dependency 'rails', '~> 6.0'
40
+ spec.add_development_dependency 'rails', '>= 6.0'
41
41
  spec.add_development_dependency 'rake', '~> 13.0'
42
42
  spec.add_development_dependency 'rspec-support', '~> 3.9'
43
- spec.add_development_dependency 'rubocop', '~> 0.91.0'
43
+ spec.add_development_dependency 'rubocop', '~> 1.26.0'
44
+ spec.add_development_dependency 'rubocop-rspec', '~> 2.4.0'
44
45
  spec.add_development_dependency 'simplecov', '~> 0.21.1'
45
46
  spec.add_development_dependency 'simplecov-console', '~> 0.9.1'
46
47
  spec.add_development_dependency 'simplecov-rcov', '~> 0.2'
48
+
49
+ spec.metadata['rubygems_mfa_required'] = 'true'
47
50
  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.tap do |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 = Events.extract_data_for_lograge
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
- # Note: can't just self.env= b/c it returns the wrong value -- see
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,37 +1,93 @@
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
- def extract_data_for_lograge
6
- ->(event) { extract_event_data(event) }
21
+
22
+ def extract_data_for_lograge(lograge_config)
23
+ verbose_session_logging = lograge_config.verbose_session_logging
24
+
25
+ ->(event) { extract_event_data(event.payload, verbose_session_logging) }
7
26
  end
8
27
 
9
28
  private
10
29
 
11
- def extract_event_data(event)
12
- event_data = { time: Time.now }
13
- extracted_headers = extract_headers(event)
14
- event_data.merge(extracted_headers)
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)
39
+ end
15
40
  end
16
41
 
17
- def extract_headers(event)
18
- return {} unless (headers = event.payload[:headers])
19
-
20
- extracted_headers = {
21
- # yes, RFC 2616 uses a variant spelling for 'referrer', it's a known issue
22
- # https://tools.ietf.org/html/rfc2616#section-14.36
23
- referer: headers['HTTP_REFERER'],
24
- request_id: headers['action_dispatch.request_id'],
25
- remote_ip: headers['action_dispatch.remote_ip'],
26
- remote_addr: headers['REMOTE_ADDR'],
27
- x_forwarded_for: headers['HTTP_X_FORWARDED_FOR'],
28
- forwarded: headers['HTTP_FORWARDED'] # RFC 7239
29
- }
30
-
31
- # Some of these 'headers' include recursive structures
32
- # that cause SystemStackErrors in JSON serialization,
33
- # so we convert them all to strings
34
- extracted_headers.transform_values(&:to_s)
42
+ def extract_param_values(payload)
43
+ return {} unless (params = payload[:params])
44
+
45
+ LOGGED_PARAMETERS.each_with_object({}) do |param, values|
46
+ next unless (param_val = params[param])
47
+
48
+ values[param] = param_val
49
+ end
50
+ end
51
+
52
+ def extract_request_attributes(payload)
53
+ return {} unless (request = payload[:request])
54
+
55
+ LOGGED_REQUEST_ATTRIBUTES.each_with_object({}) do |attr, values|
56
+ next unless request.respond_to?(attr)
57
+ next if (attr_val = request.send(attr)).nil?
58
+
59
+ values[attr] = attr_val
60
+ end
61
+ end
62
+
63
+ def extract_headers(payload)
64
+ return {} unless (headers = payload[:headers])
65
+
66
+ LOGGED_HEADERS.each_with_object({}) do |(key, header), values|
67
+ next unless (header_val = headers[header])
68
+
69
+ values[key] = header_val
70
+ end
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
35
91
  end
36
92
  end
37
93
  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 ErrorCauseSerializer
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
- msg << "\n"
75
- msg << (' ' * @trace_indent)
76
- msg << stack
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 ErrorCauseSerializer
80
+ include ExceptionSerializer
91
81
 
92
82
  def _call(severity, time, progname, data)
93
83
  original_data = Formatters.ensure_hash(data)
@@ -1,3 +1,4 @@
1
+ require 'active_support/isolated_execution_state'
1
2
  require 'active_support/logger'
2
3
  require 'ougai'
3
4
  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.3'.freeze
10
+ VERSION = '0.2.6'.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
- Layout/LineLength:
9
+ Style/OpenStructUse:
7
10
  Enabled: false
8
11
 
9
- Metrics/BlockLength:
12
+ Metrics/AbcSize:
10
13
  Enabled: false
11
14
 
12
- Metrics/ClassLength:
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
- # Added in Rubocop 0.89
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
- # Sometimes we're testing the operator
25
- Lint/BinaryOperatorWithIdenticalOperands:
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(:each) do
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,36 +30,106 @@ module BerkeleyLibrary
30
30
  expect(lograge.enabled).to eq(true)
31
31
  end
32
32
 
33
- it 'extracts request info from log events' do
34
- Configurator.configure(config)
35
- lograge = config.lograge
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)
36
101
 
37
- request_headers = {
38
- 'HTTP_REFERER' => 'value from HTTP_REFERER',
39
- 'action_dispatch.request_id' => 'value from action_dispatch.request_id',
40
- 'action_dispatch.remote_ip' => 'value from action_dispatch.remote_ip',
41
- 'REMOTE_ADDR' => 'value from REMOTE_ADDR',
42
- 'HTTP_X_FORWARDED_FOR' => 'value from HTTP_X_FORWARDED_FOR',
43
- 'HTTP_FORWARDED' => 'value from HTTP_FORWARDED'
44
- }
45
-
46
- expected_header_map = {
47
- referer: 'HTTP_REFERER',
48
- request_id: 'action_dispatch.request_id',
49
- remote_ip: 'action_dispatch.remote_ip',
50
- remote_addr: 'REMOTE_ADDR',
51
- x_forwarded_for: 'HTTP_X_FORWARDED_FOR',
52
- forwarded: 'HTTP_FORWARDED'
53
- }
54
-
55
- event = instance_double(ActiveSupport::Notifications::Event)
56
- allow(event).to receive(:payload).and_return({ headers: request_headers })
57
-
58
- custom_options = lograge.custom_options
59
- data = custom_options.call(event)
60
- expect(data).to be_a(Hash)
61
- expect(data[:time]).to be_a(Time) # TODO: check for accuracy
62
- expected_header_map.each { |xh, rh| expect(data[xh]).to eq(request_headers[rh]) }
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
130
+
131
+ expect(data[:session]).to eq(expected_hash)
132
+ end
63
133
  end
64
134
 
65
135
  it 'formats Lograge data as a hash' do
@@ -5,11 +5,11 @@ module BerkeleyLibrary
5
5
 
6
6
  attr_reader :orig_rails_env
7
7
 
8
- before(:each) do
8
+ before do
9
9
  @orig_rails_env = Rails.env
10
10
  end
11
11
 
12
- after(:each) do
12
+ after do
13
13
  Rails.env = orig_rails_env
14
14
  end
15
15