berkeley_library-logging 0.2.3 → 0.2.6

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