timber 1.1.14 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -2
  3. data/.travis.yml +47 -0
  4. data/Gemfile +1 -28
  5. data/README.md +83 -298
  6. data/bin/timber +13 -0
  7. data/gemfiles/rails-3.0.gemfile +5 -0
  8. data/gemfiles/rails-3.1.gemfile +5 -0
  9. data/gemfiles/rails-3.2.gemfile +5 -0
  10. data/gemfiles/rails-4.0.gemfile +9 -0
  11. data/gemfiles/rails-4.1.gemfile +9 -0
  12. data/gemfiles/rails-4.2.gemfile +9 -0
  13. data/gemfiles/rails-5.0.gemfile +9 -0
  14. data/gemfiles/rails-edge.gemfile +7 -0
  15. data/lib/timber.rb +7 -7
  16. data/lib/timber/cli.rb +72 -0
  17. data/lib/timber/cli/api.rb +104 -0
  18. data/lib/timber/cli/application.rb +28 -0
  19. data/lib/timber/cli/install.rb +186 -0
  20. data/lib/timber/cli/io_helper.rb +58 -0
  21. data/lib/timber/cli/messages.rb +170 -0
  22. data/lib/timber/config.rb +47 -6
  23. data/lib/timber/contexts/http.rb +2 -2
  24. data/lib/timber/current_context.rb +1 -1
  25. data/lib/timber/event.rb +8 -0
  26. data/lib/timber/events.rb +2 -0
  27. data/lib/timber/events/controller_call.rb +12 -3
  28. data/lib/timber/events/exception.rb +4 -3
  29. data/lib/timber/events/http_client_request.rb +61 -0
  30. data/lib/timber/events/http_client_response.rb +47 -0
  31. data/lib/timber/events/http_server_request.rb +15 -23
  32. data/lib/timber/events/http_server_response.rb +9 -9
  33. data/lib/timber/events/sql_query.rb +2 -2
  34. data/lib/timber/events/template_render.rb +2 -2
  35. data/lib/timber/frameworks/rails.rb +31 -6
  36. data/lib/timber/integrations.rb +22 -0
  37. data/lib/timber/integrations/action_controller/log_subscriber.rb +25 -0
  38. data/lib/timber/integrations/action_controller/log_subscriber/timber_log_subscriber.rb +40 -0
  39. data/lib/timber/integrations/action_dispatch/debug_exceptions.rb +51 -0
  40. data/lib/timber/integrations/action_view/log_subscriber.rb +25 -0
  41. data/lib/timber/integrations/action_view/log_subscriber/timber_log_subscriber.rb +73 -0
  42. data/lib/timber/integrations/active_record/log_subscriber.rb +25 -0
  43. data/lib/timber/integrations/active_record/log_subscriber/timber_log_subscriber.rb +39 -0
  44. data/lib/timber/integrations/active_support/tagged_logging.rb +71 -0
  45. data/lib/timber/integrations/rack.rb +16 -0
  46. data/lib/timber/integrations/rack/exception_event.rb +28 -0
  47. data/lib/timber/integrations/rack/http_context.rb +25 -0
  48. data/lib/timber/integrations/rack/http_events.rb +46 -0
  49. data/lib/timber/integrations/rack/user_context.rb +59 -0
  50. data/lib/timber/integrations/rails/rack_logger.rb +49 -0
  51. data/lib/timber/integrator.rb +24 -0
  52. data/lib/timber/log_devices/http.rb +14 -21
  53. data/lib/timber/log_entry.rb +1 -1
  54. data/lib/timber/logger.rb +38 -12
  55. data/lib/timber/overrides.rb +9 -0
  56. data/lib/timber/overrides/lograge.rb +14 -0
  57. data/lib/timber/overrides/rails_server.rb +10 -0
  58. data/lib/timber/util.rb +2 -0
  59. data/lib/timber/util/active_support_log_subscriber.rb +13 -9
  60. data/lib/timber/util/http_event.rb +54 -0
  61. data/lib/timber/util/request.rb +44 -0
  62. data/lib/timber/version.rb +1 -1
  63. data/spec/README.md +5 -9
  64. data/spec/spec_helper.rb +1 -4
  65. data/spec/support/action_controller.rb +7 -3
  66. data/spec/support/active_record.rb +23 -19
  67. data/spec/support/rails.rb +56 -32
  68. data/spec/support/timber.rb +2 -3
  69. data/spec/support/webmock.rb +1 -0
  70. data/spec/timber/integrations/action_controller/log_subscriber_spec.rb +55 -0
  71. data/spec/timber/integrations/action_dispatch/debug_exceptions_spec.rb +53 -0
  72. data/spec/timber/integrations/action_view/log_subscriber_spec.rb +115 -0
  73. data/spec/timber/integrations/active_record/log_subscriber_spec.rb +46 -0
  74. data/spec/timber/integrations/rack/http_context_spec.rb +60 -0
  75. data/spec/timber/integrations/rails/rack_logger_spec.rb +58 -0
  76. data/spec/timber/logger_spec.rb +45 -9
  77. data/timber.gemspec +29 -3
  78. metadata +143 -46
  79. data/Appraisals +0 -41
  80. data/circle.yml +0 -33
  81. data/lib/timber/overrides/logger_add.rb +0 -38
  82. data/lib/timber/probe.rb +0 -23
  83. data/lib/timber/probes.rb +0 -23
  84. data/lib/timber/probes/action_controller_log_subscriber.rb +0 -20
  85. data/lib/timber/probes/action_controller_log_subscriber/log_subscriber.rb +0 -64
  86. data/lib/timber/probes/action_controller_user_context.rb +0 -52
  87. data/lib/timber/probes/action_dispatch_debug_exceptions.rb +0 -80
  88. data/lib/timber/probes/action_view_log_subscriber.rb +0 -20
  89. data/lib/timber/probes/action_view_log_subscriber/log_subscriber.rb +0 -69
  90. data/lib/timber/probes/active_record_log_subscriber.rb +0 -20
  91. data/lib/timber/probes/active_record_log_subscriber/log_subscriber.rb +0 -31
  92. data/lib/timber/probes/active_support_tagged_logging.rb +0 -63
  93. data/lib/timber/probes/rails_rack_logger.rb +0 -77
  94. data/lib/timber/rack_middlewares.rb +0 -12
  95. data/lib/timber/rack_middlewares/http_context.rb +0 -30
  96. data/spec/support/action_view.rb +0 -4
  97. data/spec/support/coveralls.rb +0 -2
  98. data/spec/support/simplecov.rb +0 -9
  99. data/spec/timber/overrides/logger_add_spec.rb +0 -26
  100. data/spec/timber/probes/action_controller_log_subscriber_spec.rb +0 -65
  101. data/spec/timber/probes/action_controller_user_context_spec.rb +0 -53
  102. data/spec/timber/probes/action_dispatch_debug_exceptions_spec.rb +0 -48
  103. data/spec/timber/probes/action_view_log_subscriber_spec.rb +0 -107
  104. data/spec/timber/probes/active_record_log_subscriber_spec.rb +0 -47
  105. data/spec/timber/probes/rails_rack_logger_spec.rb +0 -46
  106. data/spec/timber/rack_middlewares/http_context_spec.rb +0 -47
@@ -3,7 +3,7 @@ module Timber
3
3
  # `Logger` and the log device that you set it up with.
4
4
  class LogEntry #:nodoc:
5
5
  DT_PRECISION = 6.freeze
6
- SCHEMA = "https://raw.githubusercontent.com/timberio/log-event-json-schema/1.2.6/schema.json".freeze
6
+ SCHEMA = "https://raw.githubusercontent.com/timberio/log-event-json-schema/1.2.20/schema.json".freeze
7
7
 
8
8
  attr_reader :context_snapshot, :event, :level, :message, :progname, :tags, :time, :time_ms
9
9
 
@@ -16,7 +16,7 @@ module Timber
16
16
  # @example Using a Hash
17
17
  # # The :message key is required, the other additional key is your event type and data
18
18
  # # :type is the namespace used in timber for the :data
19
- # logger.info message: "Payment rejected", payment_rejected: {customer_id: customer_id, amount: 100}
19
+ # logger.info "Payment rejected", payment_rejected: {customer_id: customer_id, amount: 100}
20
20
  #
21
21
  # @example Using a Struct (a simple, more structured way, to define events)
22
22
  # PaymentRejectedEvent = Struct.new(:customer_id, :amount, :reason) do
@@ -69,7 +69,7 @@ module Timber
69
69
  "INFO" => :info,
70
70
  "WARN" => :warn,
71
71
  "ERROR" => :error,
72
- "FATAL" => :datal,
72
+ "FATAL" => :fatal,
73
73
  "UNKNOWN" => :unknown
74
74
  }
75
75
 
@@ -81,9 +81,12 @@ module Timber
81
81
  tags = extract_active_support_tagged_logging_tags
82
82
  time_ms = nil
83
83
  if msg.is_a?(Hash)
84
- tags << msg.delete(:tag) if msg.key?(:tag)
85
- tags += msg.delete(:tags) if msg.key?(:tags)
86
- tags.uniq!
84
+ if msg.key?(:tag) || msg.key?(:tags)
85
+ tags = tags.clone
86
+ tags << msg.delete(:tag) if msg.key?(:tag)
87
+ tags += msg.delete(:tags) if msg.key?(:tags)
88
+ tags.uniq!
89
+ end
87
90
  time_ms = msg.delete(:time_ms) if msg.key?(:time_ms)
88
91
 
89
92
  msg = msg[:message] if msg.length == 1
@@ -106,6 +109,16 @@ module Timber
106
109
  end
107
110
  end
108
111
 
112
+ # For use in development and test environments where you do not want metadata
113
+ # included in the log lines.
114
+ class SimpleFormatter < Formatter
115
+
116
+ # This method is invoked when a log event occurs
117
+ def call(severity, timestamp, progname, msg)
118
+ "#{String === msg ? msg : msg.inspect}\n"
119
+ end
120
+ end
121
+
109
122
  # Structures your log messages into Timber's hybrid format, which makes
110
123
  # it easy to read while also appending the appropriate metadata.
111
124
  #
@@ -153,6 +166,11 @@ module Timber
153
166
  end
154
167
  end
155
168
 
169
+ class << self
170
+ def new_from_config
171
+ end
172
+ end
173
+
156
174
  # Creates a new Timber::Logger instances. Accepts the same arguments as `::Logger.new`.
157
175
  # The only difference is that it default the formatter to {HybridFormatter}. Using
158
176
  # a different formatter is easy. For example, if you prefer your logs in JSON.
@@ -175,26 +193,34 @@ module Timber
175
193
  end
176
194
 
177
195
  self.level = environment_level
196
+
197
+ @initialized = true
178
198
  end
179
199
 
180
200
  def formatter=(value)
181
- if @dev.is_a?(Timber::LogDevices::HTTP)
201
+ if @initialized && @logdev && @logdev.dev.is_a?(Timber::LogDevices::HTTP) && !value.is_a?(PassThroughFormatter)
182
202
  raise ArgumentError.new("The formatter cannot be changed when using the " +
183
203
  "Timber::LogDevices::HTTP log device. The PassThroughFormatter must be used for proper " +
184
204
  "delivery.")
185
205
  end
186
206
 
187
- if !value.is_a?(Timber::Logger::Formatter)
188
- # silently discard this value since rails calls this during initialization :/
189
- nil
190
- else
191
- super
192
- end
207
+ super
193
208
  end
194
209
 
195
210
  # Backwards compatibility with older ActiveSupport::Logger versions
196
211
  Logger::Severity.constants.each do |severity|
197
212
  class_eval(<<-EOT, __FILE__, __LINE__ + 1)
213
+ def #{severity.downcase}(*args, &block)
214
+ progname = args.first
215
+ options = args.last
216
+
217
+ if args.length == 2 and options.is_a?(Hash) && options != {}
218
+ progname = options.merge(message: progname)
219
+ end
220
+
221
+ add(#{severity}, nil, progname, &block)
222
+ end
223
+
198
224
  def #{severity.downcase}? # def debug?
199
225
  Logger::#{severity} >= level # DEBUG >= level
200
226
  end # end
@@ -0,0 +1,9 @@
1
+ require "timber/overrides/lograge"
2
+ require "timber/overrides/rails_server"
3
+ require "timber/overrides/rails_stdout_logging"
4
+
5
+ module Timber
6
+ # @private
7
+ module Overrides
8
+ end
9
+ end
@@ -0,0 +1,14 @@
1
+ # Timber and lograge are not compatible installed together. Using lograge
2
+ # with the Timber.io *service* is perfectly fine, but not with the Timber *gem*.
3
+ begin
4
+ require "lograge"
5
+
6
+ module Lograge
7
+ module_function
8
+
9
+ def setup(app)
10
+ return true
11
+ end
12
+ end
13
+ rescue Exception
14
+ end
@@ -0,0 +1,10 @@
1
+ begin
2
+ require "rails/commands/server"
3
+
4
+ class ::Rails::Server < ::Rack::Server
5
+ private
6
+ def log_to_stdout
7
+ end
8
+ end
9
+ rescue Exception
10
+ end
@@ -1,6 +1,8 @@
1
1
  require "timber/util/active_support_log_subscriber"
2
2
  require "timber/util/hash"
3
+ require "timber/util/http_event"
3
4
  require "timber/util/object"
5
+ require "timber/util/request"
4
6
  require "timber/util/struct"
5
7
 
6
8
  module Timber
@@ -5,7 +5,7 @@ module Timber
5
5
  extend self
6
6
 
7
7
  def find(component, type)
8
- ActiveSupport::LogSubscriber.log_subscribers.find do |subscriber|
8
+ ::ActiveSupport::LogSubscriber.log_subscribers.find do |subscriber|
9
9
  subscriber.class == type
10
10
  end
11
11
  end
@@ -14,16 +14,20 @@ module Timber
14
14
  !find(component, type).nil?
15
15
  end
16
16
 
17
- def unsubscribe(component, type)
17
+ # I don't know why this has to be so complicated, but it is. This code was taken from
18
+ # lograge :/
19
+ def unsubscribe!(component, type)
18
20
  subscriber = find(component, type)
19
21
 
20
- if subscriber
21
- events = subscriber.public_methods(false).reject { |method| method.to_s == 'call' }
22
- events.each do |event|
23
- ActiveSupport::Notifications.notifier.listeners_for("#{event}.#{component}").each do |listener|
24
- if listener.instance_variable_get('@delegate') == subscriber
25
- ActiveSupport::Notifications.unsubscribe listener
26
- end
22
+ if !subscriber
23
+ raise "We could not find a log subscriber for #{component.inspect} of type #{type.inspect}"
24
+ end
25
+
26
+ events = subscriber.public_methods(false).reject { |method| method.to_s == 'call' }
27
+ events.each do |event|
28
+ ::ActiveSupport::Notifications.notifier.listeners_for("#{event}.#{component}").each do |listener|
29
+ if listener.instance_variable_get('@delegate') == subscriber
30
+ ::ActiveSupport::Notifications.unsubscribe listener
27
31
  end
28
32
  end
29
33
  end
@@ -0,0 +1,54 @@
1
+ module Timber
2
+ module Util
3
+ module HTTPEvent
4
+ BODY_LIMIT = 5_000.freeze
5
+ QUERY_STRING_LIMIT = 5_000.freeze
6
+
7
+ extend self
8
+
9
+ def full_path(path, query_string)
10
+ if query_string
11
+ "#{path}?#{query_string}"
12
+ else
13
+ path
14
+ end
15
+ end
16
+
17
+ def normalize_body(content_type, body)
18
+ if Config.instance.capture_http_body_content_types.include?(content_type)
19
+ if body.respond_to?(:body)
20
+ body = body.body.to_s
21
+ end
22
+
23
+ body[0..(BODY_LIMIT - 1)]
24
+ else
25
+ # Drop the body if it is not a format we want to capture.
26
+ # This gives users more control to avoid loggin files, etc.
27
+ nil
28
+ end
29
+ end
30
+
31
+ def normalize_headers(headers)
32
+ if headers.is_a?(::Hash)
33
+ headers.each_with_object({}) do |(k, v), h|
34
+ h[k.to_s.downcase] = v
35
+ end
36
+ else
37
+ headers
38
+ end
39
+ end
40
+
41
+ def normalize_method(method)
42
+ method.is_a?(::String) ? method.upcase : method
43
+ end
44
+
45
+ def normalize_query_string(query_string)
46
+ if !query_string.nil?
47
+ query_string = query_string.to_s
48
+ end
49
+
50
+ query_string[0..(QUERY_STRING_LIMIT - 1)]
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,44 @@
1
+ begin
2
+ require "rack"
3
+ rescue LoadError
4
+ end
5
+
6
+ if defined?(::Rack::Request)
7
+ module Timber
8
+ module Util
9
+ class Request < ::Rack::Request
10
+ def body_content
11
+ content = body.read
12
+ body.rewind
13
+ content
14
+ end
15
+
16
+ def headers
17
+ @headers ||= ::Hash[*@env.select {|k,v| k.start_with? 'HTTP_'}
18
+ .collect {|k,v| [k.sub(/^HTTP_/, ''), v]}
19
+ .collect {|k,v| [k.split('_').collect(&:capitalize).join('-'), v]}
20
+ .sort
21
+ .flatten]
22
+ end
23
+
24
+ def ip
25
+ @ip ||= if @env["action_dispatch.remote_ip"]
26
+ @env["action_dispatch.remote_ip"].to_s || super
27
+ else
28
+ super
29
+ end
30
+ end
31
+
32
+ def referer
33
+ # Rails 3.X returns "/" for some reason
34
+ @referer ||= super == "/" ? nil : super
35
+ end
36
+
37
+ def request_id
38
+ @request_id ||= @env["action_dispatch.request_id"] || @env["X-Request-ID"] ||
39
+ @env["X-Request-Id"]
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -1,3 +1,3 @@
1
1
  module Timber
2
- VERSION = "1.1.14"
2
+ VERSION = "2.0.0"
3
3
  end
@@ -1,23 +1,19 @@
1
1
  # Testing
2
2
 
3
- Testing Timber uses [`appraisal`](https://github.com/thoughtbot/appraisal). This allows us to
4
- test across multiple versions and combinations of libraries.
5
-
6
3
  To get started:
7
4
 
8
5
  ```shell
9
6
  bundle install
10
- bundle exec appraisal install
11
7
  ```
12
8
 
13
- To see all appraisal commands:
9
+ Be sure to install specific Gemfile dependencies:
14
10
 
15
- ```shell
16
- appraisal --help
11
+ ```
12
+ BUNDLE_GEMFILE=gemfiles/rails-4.2.gemfile bundle install
17
13
  ```
18
14
 
19
- You can run tests with:
15
+ You can run tests like this:
20
16
 
21
17
  ```shell
22
- appraisal rails-3.2.X rspec
18
+ BUNDLE_GEMFILE=gemfiles/rails-4.2.gemfile bundle exec rspec
23
19
  ```
@@ -3,23 +3,20 @@ require 'rubygems'
3
3
  require 'bundler/setup'
4
4
 
5
5
  # Testing
6
- require 'pry'
7
6
  require 'rspec'
8
7
  require 'rspec/its'
9
8
  require 'rspec/mocks'
10
9
 
11
10
  # Support files, order is relevant
12
- require File.join(File.dirname(__FILE__), 'support', 'coveralls')
13
11
  require File.join(File.dirname(__FILE__), 'support', 'socket_hostname')
14
- require File.join(File.dirname(__FILE__), 'support', 'simplecov')
15
12
  require File.join(File.dirname(__FILE__), 'support', 'timecop')
16
13
  require File.join(File.dirname(__FILE__), 'support', 'webmock')
17
14
  require File.join(File.dirname(__FILE__), 'support', 'timber')
18
15
 
16
+ # Load framework files after we've setup everything
19
17
  if !ENV["RAILS_23"]
20
18
  require File.join(File.dirname(__FILE__), 'support', 'rails')
21
19
  require File.join(File.dirname(__FILE__), 'support', 'action_controller')
22
- require File.join(File.dirname(__FILE__), 'support', 'action_view')
23
20
  require File.join(File.dirname(__FILE__), 'support', 'active_record')
24
21
  end
25
22
 
@@ -1,4 +1,8 @@
1
- require "action_controller"
1
+ begin
2
+ require "action_controller"
3
+ rescue LoadError
4
+ end
2
5
 
3
- ActionController::Base.prepend_view_path("#{File.dirname(__FILE__)}/rails/templates")
4
- ActionController::Base.logger = Rails.logger
6
+ if defined?(::ActionController::Base)
7
+ ::ActionController::Base.prepend_view_path("#{File.dirname(__FILE__)}/rails/templates")
8
+ end
@@ -1,28 +1,32 @@
1
- require 'active_record'
1
+ begin
2
+ require 'active_record'
3
+ rescue LoadError
4
+ end
2
5
 
3
- ActiveRecord::Base.logger = Rails.logger
4
- ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:"
5
- ActiveRecord::Schema.define do
6
- self.verbose = false
6
+ if defined?(::ActiveRecord::Base)
7
+ ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:"
8
+ ActiveRecord::Schema.define do
9
+ self.verbose = false
7
10
 
8
- create_table :organizations, :force => true do |t|
9
- t.string :name
11
+ create_table :organizations, :force => true do |t|
12
+ t.string :name
10
13
 
11
- t.timestamps :null => false
12
- end
14
+ t.timestamps :null => false
15
+ end
13
16
 
14
- create_table :users, :force => true do |t|
15
- t.integer :age
16
- t.string :email
17
- t.string :first_name
17
+ create_table :users, :force => true do |t|
18
+ t.integer :age
19
+ t.string :email
20
+ t.string :first_name
18
21
 
19
- t.timestamps :null => false
20
- end
22
+ t.timestamps :null => false
23
+ end
21
24
 
22
- end
25
+ end
23
26
 
24
- class Organization < ::ActiveRecord::Base
25
- end
27
+ class Organization < ::ActiveRecord::Base
28
+ end
26
29
 
27
- class User < ::ActiveRecord::Base
30
+ class User < ::ActiveRecord::Base
31
+ end
28
32
  end
@@ -1,37 +1,61 @@
1
- require "rails"
2
-
3
- # Defualt the rails logger to nothing, each test shoould be
4
- # responsible for setting up the logger
5
- logger = ::Logger.new(STDOUT) # change to STDOUT to see rails logs
6
- Rails.logger = logger
7
-
8
- class RailsApp < Rails::Application
9
- if ::Rails.version =~ /^3\./
10
- config.secret_token = '1e05af2b349457936a41427e63450937'
11
- else
12
- config.secret_key_base = '1e05af2b349457936a41427e63450937'
13
- end
14
- config.active_support.deprecation = :stderr
15
- config.eager_load = false
1
+ begin
2
+ require "rails"
3
+ rescue LoadError
16
4
  end
17
5
 
18
- RailsApp.initialize!
19
-
20
- module Support
21
- module Rails
22
- def dispatch_rails_request(path, additional_env_options = {})
23
- application = ::Rails.application
24
- env = application.respond_to?(:env_config) ? application.env_config.clone : application.env_defaults.clone
25
- env["rack.request.cookie_hash"] = {}.with_indifferent_access
26
- env["REMOTE_ADDR"] = "123.456.789.10"
27
- env["X-Request-Id"] = "unique-request-id-1234"
28
- env["action_dispatch.request_id"] = env["X-Request-Id"]
29
- env = env.merge(additional_env_options)
30
- ::Rack::MockRequest.new(application).get(path, env)
6
+ if defined?(::Rails)
7
+ # Defualt the rails logger to nothing, each test shoould be
8
+ # responsible for setting up the logger
9
+ logger = Timber::Logger.new(nil) # change to STDOUT to see rails logs
10
+ Rails.logger = logger
11
+
12
+ class RailsApp < Rails::Application
13
+ if ::Rails.version =~ /^3\./
14
+ config.secret_token = '1e05af2b349457936a41427e63450937'
15
+ else
16
+ config.secret_key_base = '1e05af2b349457936a41427e63450937'
31
17
  end
18
+
19
+ # This ensures our tests fail, otherwise exceptions get swallowed by ActionDispatch::DebugExceptions
20
+ config.action_dispatch.show_exceptions = false
21
+ config.active_support.deprecation = :stderr
22
+ config.eager_load = false
32
23
  end
33
- end
34
24
 
35
- RSpec.configure do |config|
36
- config.include Support::Rails
37
- end
25
+ RailsApp.initialize!
26
+
27
+ module Support
28
+ module Rails
29
+ def dispatch_rails_request(path, additional_env_options = {})
30
+ application = ::Rails.application
31
+ env = application.respond_to?(:env_config) ? application.env_config.clone : application.env_defaults.clone
32
+ env["rack.request.cookie_hash"] = {}.with_indifferent_access
33
+ env["REMOTE_ADDR"] = "123.456.789.10"
34
+ env["HTTP_X_REQUEST_ID"] = "unique-request-id-1234"
35
+ env["action_dispatch.request_id"] = env["HTTP_X_REQUEST_ID"]
36
+ env = env.merge(additional_env_options)
37
+ ::Rack::MockRequest.new(application).get(path, env)
38
+ end
39
+
40
+ def with_rails_logger(logger)
41
+ old_logger = ::Rails.logger
42
+
43
+ # We have to set these again because rails set's these after initialization.
44
+ # Since we've already booted the rails app we need to update them all as we
45
+ # change the logger.
46
+ #
47
+ # You can see here that they use simple class attribute, hence the reason we need
48
+ # to update all of them: https://github.com/rails/rails/blob/700ec897f97c60016ad748236bf3a49ef15a20de/actionview/lib/action_view/base.rb#L157
49
+ Timber::Frameworks::Rails.set_logger(logger)
50
+
51
+ yield
52
+
53
+ ::Rails.logger = old_logger
54
+ end
55
+ end
56
+ end
57
+
58
+ RSpec.configure do |config|
59
+ config.include Support::Rails
60
+ end
61
+ end