rage-rb 1.18.0 → 1.19.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/CHANGELOG.md +19 -0
- data/lib/rage/all.rb +1 -0
- data/lib/rage/application.rb +3 -25
- data/lib/rage/cable/cable.rb +30 -3
- data/lib/rage/configuration.rb +536 -195
- data/lib/rage/controller/api.rb +15 -3
- data/lib/rage/cookies.rb +89 -0
- data/lib/rage/deferred/context.rb +48 -0
- data/lib/rage/deferred/deferred.rb +1 -1
- data/lib/rage/deferred/queue.rb +8 -8
- data/lib/rage/deferred/task.rb +29 -25
- data/lib/rage/env.rb +15 -0
- data/lib/rage/hooks.rb +1 -0
- data/lib/rage/internal.rb +14 -0
- data/lib/rage/log_processor.rb +117 -0
- data/lib/rage/logger/json_formatter.rb +37 -18
- data/lib/rage/logger/logger.rb +130 -30
- data/lib/rage/logger/text_formatter.rb +21 -2
- data/lib/rage/middleware/fiber_wrapper.rb +8 -0
- data/lib/rage/middleware/reloader.rb +6 -11
- data/lib/rage/request.rb +18 -1
- data/lib/rage/response.rb +1 -1
- data/lib/rage/router/util.rb +8 -0
- data/lib/rage/session.rb +64 -3
- data/lib/rage/version.rb +1 -1
- data/lib/rage-rb.rb +45 -0
- metadata +4 -3
- data/lib/rage/deferred/metadata.rb +0 -43
data/lib/rage/configuration.rb
CHANGED
|
@@ -4,262 +4,371 @@ require "yaml"
|
|
|
4
4
|
require "erb"
|
|
5
5
|
|
|
6
6
|
##
|
|
7
|
-
#
|
|
7
|
+
# Configuration class for Rage framework.
|
|
8
8
|
#
|
|
9
|
+
# Use {Rage.configure Rage.configure} to access and modify the configuration.
|
|
10
|
+
#
|
|
11
|
+
# **Example:**
|
|
9
12
|
# ```ruby
|
|
10
13
|
# Rage.configure do
|
|
11
|
-
# config.
|
|
12
|
-
# config.server.
|
|
13
|
-
# end
|
|
14
|
-
# ```
|
|
15
|
-
#
|
|
16
|
-
# # General Configuration
|
|
17
|
-
#
|
|
18
|
-
# • _config.logger_
|
|
19
|
-
#
|
|
20
|
-
# > The logger that will be used for `Rage.logger` and any related `Rage` logging. Custom loggers should implement Ruby's {https://ruby-doc.org/3.2.2/stdlibs/logger/Logger.html#class-Logger-label-Entries Logger} interface.
|
|
21
|
-
#
|
|
22
|
-
# • _config.log_formatter_
|
|
23
|
-
#
|
|
24
|
-
# > The formatter of the Rage logger. Built in options include `Rage::TextFormatter` and `Rage::JSONFormatter`. Defaults to an instance of `Rage::TextFormatter`.
|
|
25
|
-
#
|
|
26
|
-
# • _config.log_level_
|
|
27
|
-
#
|
|
28
|
-
# > Defines the verbosity of the Rage logger. This option defaults to `:debug` for all environments except production, where it defaults to `:info`. The available log levels are: `:debug`, `:info`, `:warn`, `:error`, `:fatal`, and `:unknown`.
|
|
29
|
-
#
|
|
30
|
-
# • _config.secret_key_base_
|
|
31
|
-
#
|
|
32
|
-
# > The `secret_key_base` is used as the input secret to the application's key generator, which is used to encrypt cookies. Rage will fall back to the `SECRET_KEY_BASE` environment variable if this is not set.
|
|
33
|
-
#
|
|
34
|
-
# • _config.fallback_secret_key_base_
|
|
35
|
-
#
|
|
36
|
-
# > Defines one or several old secrets that need to be rotated. Can accept a single key or an array of keys. Rage will fall back to the `FALLBACK_SECRET_KEY_BASE` environment variable if this is not set.
|
|
37
|
-
#
|
|
38
|
-
# • _config.after_initialize_
|
|
39
|
-
#
|
|
40
|
-
# > Schedule a block of code to run after Rage has finished loading the application code. Use this to reference application-level constants during the initialization process.
|
|
41
|
-
# > ```
|
|
42
|
-
# Rage.config.after_initialize do
|
|
43
|
-
# SUPER_USER = User.find_by!(super: true)
|
|
44
|
-
# end
|
|
45
|
-
# > ```
|
|
46
|
-
#
|
|
47
|
-
# # Middleware Configuration
|
|
48
|
-
#
|
|
49
|
-
# • _config.middleware.use_
|
|
50
|
-
#
|
|
51
|
-
# > Adds a middleware to the top of the middleware stack. **This is the recommended way of adding a middleware.**
|
|
52
|
-
# > ```
|
|
53
|
-
# config.middleware.use Rack::Cors do
|
|
54
|
-
# allow do
|
|
55
|
-
# origins "*"
|
|
56
|
-
# resource "*", headers: :any
|
|
57
|
-
# end
|
|
58
|
-
# end
|
|
59
|
-
# > ```
|
|
60
|
-
#
|
|
61
|
-
# • _config.middleware.insert_before_
|
|
62
|
-
#
|
|
63
|
-
# > Adds middleware at a specified position before another middleware. The position can be either an index or another middleware.
|
|
64
|
-
#
|
|
65
|
-
# > **_❗️Heads up:_** By default, Rage always uses the `Rage::FiberWrapper` middleware, which wraps every request in a separate fiber. Make sure to always have this middleware in the top of the stack. Placing other middlewares in front may lead to undefined behavior.
|
|
66
|
-
#
|
|
67
|
-
# > ```
|
|
68
|
-
# config.middleware.insert_before Rack::Head, Magical::Unicorns
|
|
69
|
-
# config.middleware.insert_before 0, Magical::Unicorns
|
|
70
|
-
# > ```
|
|
71
|
-
#
|
|
72
|
-
# • _config.middleware.insert_after_
|
|
73
|
-
#
|
|
74
|
-
# > Adds middleware at a specified position after another middleware. The position can be either an index or another middleware.
|
|
75
|
-
#
|
|
76
|
-
# > ```
|
|
77
|
-
# config.middleware.insert_after Rack::Head, Magical::Unicorns
|
|
78
|
-
# > ```
|
|
79
|
-
#
|
|
80
|
-
# # Server Configuration
|
|
81
|
-
#
|
|
82
|
-
# _• config.server.max_clients_
|
|
83
|
-
#
|
|
84
|
-
# > Limits the number of simultaneous connections the server can accept. Defaults to the maximum number of open files.
|
|
85
|
-
#
|
|
86
|
-
# > **_❗️Heads up:_** Decreasing this number is almost never a good idea. Depending on your application specifics, you are encouraged to use other methods to limit the number of concurrent connections:
|
|
87
|
-
#
|
|
88
|
-
# > 1. If your application is exposed to the public, you may want to use a cloud rate limiter, like {https://developers.cloudflare.com/waf Cloudflare WAF} or {https://docs.fastly.com/en/ngwaf Fastly WAF}.
|
|
89
|
-
# > 2. Otherwise, consider using tools like {https://github.com/rack/rack-attack Rack::Attack} or {https://github.com/mperham/connection_pool connection_pool}.
|
|
90
|
-
#
|
|
91
|
-
# > ```
|
|
92
|
-
# # Limit the amount of connections your application can accept
|
|
93
|
-
# config.middleware.use Rack::Attack
|
|
94
|
-
# Rack::Attack.throttle("req/ip", limit: 300, period: 5.minutes) do |req|
|
|
95
|
-
# req.ip
|
|
96
|
-
# end
|
|
97
|
-
# #
|
|
98
|
-
# # Limit the amount of connections to a specific resource
|
|
99
|
-
# HTTP = ConnectionPool.new(size: 5, timeout: 5) { Net::HTTP }
|
|
100
|
-
# HTTP.with do |conn|
|
|
101
|
-
# conn.get("/my-resource")
|
|
102
|
-
# end
|
|
103
|
-
# > ```
|
|
104
|
-
#
|
|
105
|
-
# • _config.server.port_
|
|
106
|
-
#
|
|
107
|
-
# > Specifies what port the server will listen on.
|
|
108
|
-
#
|
|
109
|
-
# • _config.server.workers_count_
|
|
110
|
-
#
|
|
111
|
-
# > Specifies the number of server processes to run. Defaults to 1 in development and to the number of available CPU cores in other environments.
|
|
112
|
-
#
|
|
113
|
-
# • _config.server.timeout_
|
|
114
|
-
#
|
|
115
|
-
# > Specifies connection timeout.
|
|
116
|
-
#
|
|
117
|
-
# # Static file server
|
|
118
|
-
#
|
|
119
|
-
# • _config.public_file_server.enabled_
|
|
120
|
-
#
|
|
121
|
-
# > Configures whether Rage should serve static files from the public directory. Defaults to `false`.
|
|
122
|
-
#
|
|
123
|
-
# # Cable Configuration
|
|
124
|
-
#
|
|
125
|
-
# • _config.cable.protocol_
|
|
126
|
-
#
|
|
127
|
-
# > Specifies the protocol the server will use. Supported values include {Rage::Cable::Protocols::ActioncableV1Json :actioncable_v1_json} and {Rage::Cable::Protocols::RawWebSocketJson :raw_websocket_json}. Defaults to {Rage::Cable::Protocols::ActioncableV1Json :actioncable_v1_json}.
|
|
128
|
-
#
|
|
129
|
-
# • _config.cable.allowed_request_origins_
|
|
130
|
-
#
|
|
131
|
-
# > Restricts the server to only accept requests from specified origins. The origins can be instances of strings or regular expressions, against which a check for the match will be performed.
|
|
132
|
-
#
|
|
133
|
-
# • _config.cable.disable_request_forgery_protection_
|
|
134
|
-
#
|
|
135
|
-
# > Allows requests from any origin.
|
|
136
|
-
#
|
|
137
|
-
# # OpenAPI Configuration
|
|
138
|
-
# • _config.openapi.tag_resolver_
|
|
139
|
-
#
|
|
140
|
-
# > Specifies the proc to build tags for API operations. The proc accepts the controller class, the symbol name of the action, and the default tag built by Rage.
|
|
141
|
-
#
|
|
142
|
-
# > ```ruby
|
|
143
|
-
# config.openapi.tag_resolver = proc do |controller, action, default_tag|
|
|
144
|
-
# # ...
|
|
14
|
+
# config.log_level = :warn
|
|
15
|
+
# config.server.port = 8080
|
|
145
16
|
# end
|
|
146
|
-
# > ```
|
|
147
|
-
#
|
|
148
|
-
# # Deferred Configuration
|
|
149
|
-
# • _config.deferred.backend_
|
|
150
|
-
#
|
|
151
|
-
# > Specifies the backend for deferred tasks. Supported values are `:disk`, which uses disk storage, or `nil`, which disables persistence of deferred tasks.
|
|
152
|
-
# > The `:disk` backend accepts the following options:
|
|
153
|
-
# >
|
|
154
|
-
# > - `:path` - the path to the directory where deferred tasks will be stored. Defaults to `storage`.
|
|
155
|
-
# > - `:prefix` - the prefix for the deferred task files. Defaults to `deferred-`.
|
|
156
|
-
# > - `:fsync_frequency` - the frequency of `fsync` calls in seconds. Defaults to `0.5`.
|
|
157
|
-
#
|
|
158
|
-
# > ```ruby
|
|
159
|
-
# config.deferred.backend = :disk, { path: "storage" }
|
|
160
|
-
# > ```
|
|
161
|
-
#
|
|
162
|
-
# • _config.deferred.backpressure_
|
|
163
|
-
#
|
|
164
|
-
# > Enables the backpressure for deferred tasks. The backpressure is used to limit the number of pending tasks in the queue. It accepts a hash with the following options:
|
|
165
|
-
# >
|
|
166
|
-
# > - `:high_water_mark` - the maximum number of pending tasks in the queue. Defaults to `1000`.
|
|
167
|
-
# > - `:low_water_mark` - the minimum number of pending tasks in the queue before the backpressure is released. Defaults to `high_water_mark * 0.8`.
|
|
168
|
-
# > - `:timeout` - the timeout for the backpressure in seconds. Defaults to `2`.
|
|
169
|
-
#
|
|
170
|
-
# > ```ruby
|
|
171
|
-
# config.deferred.backpressure = { high_water_mark: 1000, low_water_mark: 800, timeout: 2 }
|
|
172
|
-
# > ```
|
|
173
|
-
#
|
|
174
|
-
# > Additionally, you can set the backpressure value to `true` to use the default values:
|
|
175
|
-
#
|
|
176
|
-
# > ```ruby
|
|
177
|
-
# config.deferred.backpressure = true
|
|
178
17
|
# ```
|
|
179
18
|
#
|
|
180
|
-
#
|
|
19
|
+
# ## Transient Settings
|
|
181
20
|
#
|
|
182
21
|
# The settings described in this section should be configured using **environment variables** and are either temporary or will become the default in the future.
|
|
183
22
|
#
|
|
184
|
-
#
|
|
185
|
-
#
|
|
186
|
-
#
|
|
187
|
-
#
|
|
188
|
-
# • _RAGE_DISABLE_AR_POOL_PATCH_
|
|
189
|
-
#
|
|
190
|
-
# > Disables the `ActiveRecord::ConnectionPool` patch and makes Rage use the original ActiveRecord implementation.
|
|
191
|
-
#
|
|
192
|
-
# • _RAGE_DISABLE_AR_WEAK_CONNECTIONS_
|
|
193
|
-
#
|
|
194
|
-
# > Instructs Rage to not reuse Active Record connections between different fibers.
|
|
23
|
+
# - _RAGE_DISABLE_IO_WRITE_ - disables the `io_write` hook to fix the ["zero-length iov"](https://bugs.ruby-lang.org/issues/19640) error on Ruby < 3.3.
|
|
24
|
+
# - _RAGE_DISABLE_AR_POOL_PATCH_ - disables the `ActiveRecord::ConnectionPool` patch and makes Rage use the original ActiveRecord implementation.
|
|
25
|
+
# - _RAGE_DISABLE_AR_WEAK_CONNECTIONS_ - instructs Rage to not reuse Active Record connections between different fibers. Only applies to Active Record < 7.2.
|
|
195
26
|
#
|
|
196
27
|
class Rage::Configuration
|
|
28
|
+
# @private
|
|
197
29
|
include Hooks
|
|
198
30
|
|
|
199
|
-
|
|
200
|
-
attr_reader :log_formatter, :log_level
|
|
201
|
-
attr_writer :secret_key_base, :fallback_secret_key_base
|
|
202
|
-
|
|
31
|
+
# @private
|
|
203
32
|
# used in DSL
|
|
204
33
|
def config = self
|
|
205
34
|
|
|
35
|
+
# @!group General Configuration
|
|
36
|
+
|
|
37
|
+
# Returns the logger used by Rage.
|
|
38
|
+
# @return [Rage::Logger, nil]
|
|
39
|
+
def logger
|
|
40
|
+
@logger
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Set the logger used by Rage.
|
|
44
|
+
# Accepts a logger object that implements the `#debug`, `#info`, `#warn`, `#error`, `#fatal`, and `#unknown` methods, or `nil`. If set to `nil`, logging will be disabled.
|
|
45
|
+
# `Rage.logger` always returns an instance of {Rage::Logger Rage::Logger}, but if you provide a custom object, it will be used internally by `Rage.logger`.
|
|
46
|
+
#
|
|
47
|
+
# @overload logger=(logger)
|
|
48
|
+
# Set a standard logger
|
|
49
|
+
# @param logger [#debug, #info, #warn, #error, #fatal, #unknown]
|
|
50
|
+
# @example
|
|
51
|
+
# config.logger = Rage::Logger.new(STDOUT)
|
|
52
|
+
# @overload logger=(callable)
|
|
53
|
+
# Set an external logger. This allows you to send Rage's raw structured logging data directly to external observability platforms without serializing it to text first.
|
|
54
|
+
#
|
|
55
|
+
# The external logger receives pre-parsed structured data (severity, tags, context) rather than formatted strings. This differs from `config.log_formatter` in that formatters control how logs are formatted (text vs JSON), while the external logger controls where logs are sent and how they integrate with external platforms.
|
|
56
|
+
# @param callable [ExternalLoggerInterface]
|
|
57
|
+
# @example
|
|
58
|
+
# config.logger = proc do |severity:, tags:, context:, message:, request_info:|
|
|
59
|
+
# # Custom logging logic here
|
|
60
|
+
# end
|
|
61
|
+
# @overload logger=(nil)
|
|
62
|
+
# Disable logging
|
|
63
|
+
# @example
|
|
64
|
+
# config.logger = nil
|
|
65
|
+
def logger=(logger)
|
|
66
|
+
@logger = if logger.nil? || logger.is_a?(Rage::Logger)
|
|
67
|
+
logger
|
|
68
|
+
elsif Rage::Logger::METHODS_MAP.keys.all? { |method| logger.respond_to?(method) }
|
|
69
|
+
Rage::Logger.new(Rage::Logger::External::Static[logger])
|
|
70
|
+
elsif logger.respond_to?(:call)
|
|
71
|
+
Rage::Logger.new(Rage::Logger::External::Dynamic[logger])
|
|
72
|
+
else
|
|
73
|
+
raise ArgumentError, "Invalid logger: must be an instance of `Rage::Logger`, respond to `#call`, or implement all standard Ruby Logger methods (`#debug`, `#info`, `#warn`, `#error`, `#fatal`, `#unknown`)"
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Returns the log formatter used by Rage.
|
|
78
|
+
# @return [#call, nil]
|
|
79
|
+
def log_formatter
|
|
80
|
+
@log_formatter
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Set the log formatter used by Rage.
|
|
84
|
+
# Built in options include {Rage::TextFormatter Rage::TextFormatter} and {Rage::JSONFormatter Rage::JSONFormatter}.
|
|
85
|
+
#
|
|
86
|
+
# @param formatter [#call] a callable object that formats log messages
|
|
87
|
+
# @example
|
|
88
|
+
# config.log_formatter = proc do |severity, datetime, progname, msg|
|
|
89
|
+
# "[#{datetime}] #{severity} -- #{progname}: #{msg}\n"
|
|
90
|
+
# end
|
|
206
91
|
def log_formatter=(formatter)
|
|
207
92
|
raise ArgumentError, "Custom log formatter should respond to `#call`" unless formatter.respond_to?(:call)
|
|
208
93
|
@log_formatter = formatter
|
|
209
94
|
end
|
|
210
95
|
|
|
96
|
+
# Returns the log level used by Rage.
|
|
97
|
+
# @return [Integer, nil]
|
|
98
|
+
def log_level
|
|
99
|
+
@log_level
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Set the log level used by Rage.
|
|
103
|
+
# @param level [:debug, :info, :warn, :error, :fatal, :unknown, Integer] the log level
|
|
104
|
+
# @example
|
|
105
|
+
# config.log_level = :info
|
|
211
106
|
def log_level=(level)
|
|
212
107
|
@log_level = level.is_a?(Symbol) ? Logger.const_get(level.to_s.upcase) : level
|
|
213
108
|
end
|
|
214
109
|
|
|
110
|
+
# The secret key base is used as the input secret to the application's key generator, which is used to encrypt cookies. Rage will fall back to the `SECRET_KEY_BASE` environment variable if this is not set.
|
|
111
|
+
# @param key [String] the secret key base
|
|
112
|
+
def secret_key_base=(key)
|
|
113
|
+
@secret_key_base = key
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Returns the secret key base used for encrypting cookies.
|
|
117
|
+
# @return [String, nil]
|
|
215
118
|
def secret_key_base
|
|
216
119
|
@secret_key_base || ENV["SECRET_KEY_BASE"]
|
|
217
120
|
end
|
|
218
121
|
|
|
122
|
+
# Set one or several old secrets that need to be rotated. Can accept a single key or an array of keys. Rage will fall back to the `FALLBACK_SECRET_KEY_BASE` environment variable if this is not set.
|
|
123
|
+
# @param key [String, Array<String>] the fallback secret key base(s)
|
|
124
|
+
def fallback_secret_key_base=(key)
|
|
125
|
+
@fallback_secret_key_base = key
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Returns the fallback secret key base(s) used for decrypting cookies encrypted with old secrets.
|
|
129
|
+
# @return [Array<String>]
|
|
219
130
|
def fallback_secret_key_base
|
|
220
131
|
Array(@fallback_secret_key_base || ENV["FALLBACK_SECRET_KEY_BASE"])
|
|
221
132
|
end
|
|
222
133
|
|
|
223
|
-
|
|
224
|
-
|
|
134
|
+
# Schedule a block of code to run after Rage has finished loading the application code. Use this to reference application-level constants during the initialization process.
|
|
135
|
+
# @example
|
|
136
|
+
# Rage.config.after_initialize do
|
|
137
|
+
# SUPER_USER = User.find_by!(super: true)
|
|
138
|
+
# end
|
|
139
|
+
def after_initialize(&block)
|
|
140
|
+
push_hook(block, :after_initialize)
|
|
225
141
|
end
|
|
142
|
+
# @!endgroup
|
|
226
143
|
|
|
144
|
+
# @!group Middleware Configuration
|
|
145
|
+
# Allows configuring the middleware stack used by Rage.
|
|
146
|
+
# @return [Rage::Configuration::Middleware]
|
|
227
147
|
def middleware
|
|
228
148
|
@middleware ||= Middleware.new
|
|
229
149
|
end
|
|
150
|
+
# @!endgroup
|
|
230
151
|
|
|
231
|
-
|
|
232
|
-
|
|
152
|
+
# @!group Server Configuration
|
|
153
|
+
# Allows configuring the built-in Rage server.
|
|
154
|
+
# @return [Rage::Configuration::Server]
|
|
155
|
+
def server
|
|
156
|
+
@server ||= Server.new
|
|
233
157
|
end
|
|
158
|
+
# @!endgroup
|
|
234
159
|
|
|
160
|
+
# @!group Static File Server
|
|
161
|
+
# Allows configuring the static file server used by Rage.
|
|
162
|
+
# @return [Rage::Configuration::PublicFileServer]
|
|
235
163
|
def public_file_server
|
|
236
164
|
@public_file_server ||= PublicFileServer.new
|
|
237
165
|
end
|
|
166
|
+
# @!endgroup
|
|
167
|
+
|
|
168
|
+
# @!group Cable Configuration
|
|
169
|
+
# Allows configuring Cable settings.
|
|
170
|
+
# @return [Rage::Configuration::Cable]
|
|
171
|
+
def cable
|
|
172
|
+
@cable ||= Cable.new
|
|
173
|
+
end
|
|
174
|
+
# @!endgroup
|
|
238
175
|
|
|
176
|
+
# @!group OpenAPI Configuration
|
|
177
|
+
# Allows configuring OpenAPI settings.
|
|
178
|
+
# @return [Rage::Configuration::OpenAPI]
|
|
239
179
|
def openapi
|
|
240
180
|
@openapi ||= OpenAPI.new
|
|
241
181
|
end
|
|
182
|
+
# @!endgroup
|
|
242
183
|
|
|
184
|
+
# @!group Deferred Configuration
|
|
185
|
+
# Allows configuring Deferred settings.
|
|
186
|
+
# @return [Rage::Configuration::Deferred]
|
|
243
187
|
def deferred
|
|
244
188
|
@deferred ||= Deferred.new
|
|
245
189
|
end
|
|
190
|
+
# @!endgroup
|
|
246
191
|
|
|
247
|
-
|
|
248
|
-
|
|
192
|
+
# @!group Logging Context and Tags Configuration
|
|
193
|
+
# Allows configuring custom log context objects that will be included in every log entry.
|
|
194
|
+
# @return [Rage::Configuration::LogContext]
|
|
195
|
+
def log_context
|
|
196
|
+
@log_context ||= LogContext.new
|
|
249
197
|
end
|
|
250
198
|
|
|
251
|
-
|
|
252
|
-
|
|
199
|
+
# Allows configuring custom log tags that will be included in every log entry.
|
|
200
|
+
# @return [Rage::Configuration::LogTags]
|
|
201
|
+
def log_tags
|
|
202
|
+
@log_tags ||= LogTags.new
|
|
253
203
|
end
|
|
204
|
+
# @!endgroup
|
|
254
205
|
|
|
206
|
+
# @!group Session Configuration
|
|
207
|
+
# Allows configuring session settings.
|
|
208
|
+
# @return [Rage::Configuration::Session]
|
|
209
|
+
def session
|
|
210
|
+
@session ||= Session.new
|
|
211
|
+
end
|
|
212
|
+
# @!endgroup
|
|
213
|
+
|
|
214
|
+
# @private
|
|
215
|
+
def internal
|
|
216
|
+
@internal ||= Internal.new
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
# @private
|
|
255
220
|
def run_after_initialize!
|
|
256
221
|
run_hooks_for!(:after_initialize, self)
|
|
257
222
|
end
|
|
258
223
|
|
|
224
|
+
class LogContext
|
|
225
|
+
# @private
|
|
226
|
+
def initialize
|
|
227
|
+
@objects = []
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
# @private
|
|
231
|
+
def objects
|
|
232
|
+
@objects.dup
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
# Add a new custom log context object. Each context object is evaluated independently and the results are merged into the final log entry.
|
|
236
|
+
# @overload <<(hash)
|
|
237
|
+
# Add a static log context entry.
|
|
238
|
+
# @param hash [Hash] a hash representing the log context
|
|
239
|
+
# @example
|
|
240
|
+
# Rage.configure do
|
|
241
|
+
# config.log_context << { version: ENV["APP_VERSION"] }
|
|
242
|
+
# end
|
|
243
|
+
# @overload <<(callable)
|
|
244
|
+
# Add a dynamic log context entry. Dynamic context entries are executed on every log call to capture dynamic state like changing span IDs during request processing.
|
|
245
|
+
# @param callable [#call] a callable object that returns a hash representing the log context or nil
|
|
246
|
+
# @example
|
|
247
|
+
# Rage.configure do
|
|
248
|
+
# config.log_context << proc { { trace_id: MyObservabilitySDK.trace_id } if MyObservabilitySDK.active? }
|
|
249
|
+
# end
|
|
250
|
+
# @note Exceptions from dynamic context callables will cause the entire request to fail. Make sure to handle exceptions inside the callable if necessary.
|
|
251
|
+
def <<(block_or_hash)
|
|
252
|
+
validate_input!(block_or_hash)
|
|
253
|
+
@objects << block_or_hash
|
|
254
|
+
@objects.tap(&:flatten!).tap(&:uniq!)
|
|
255
|
+
|
|
256
|
+
self
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
alias_method :push, :<<
|
|
260
|
+
|
|
261
|
+
# Remove a custom log context object.
|
|
262
|
+
# @param block_or_hash [Hash, #call] the context object to remove
|
|
263
|
+
# @example
|
|
264
|
+
# Rage.configure do
|
|
265
|
+
# config.log_context.delete(MyObservabilitySDK::LOG_CONTEXT)
|
|
266
|
+
# end
|
|
267
|
+
def delete(block_or_hash)
|
|
268
|
+
@objects.delete(block_or_hash)
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
private
|
|
272
|
+
|
|
273
|
+
def validate_input!(obj)
|
|
274
|
+
if obj.is_a?(Array)
|
|
275
|
+
obj.each { |item| validate_input!(item) }
|
|
276
|
+
elsif !obj.is_a?(Hash) && !obj.respond_to?(:call)
|
|
277
|
+
raise ArgumentError, "custom log context has to be a hash, an array of hashes, or respond to `#call`"
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
class LogTags < LogContext
|
|
283
|
+
# @!method <<(block_or_string)
|
|
284
|
+
# Add a new custom log tag. Each tag is evaluated independently and the results are merged into the final log entry.
|
|
285
|
+
# @overload <<(string)
|
|
286
|
+
# Add a static log tag.
|
|
287
|
+
# @param string [String] the log tag
|
|
288
|
+
# @example
|
|
289
|
+
# Rage.configure do
|
|
290
|
+
# config.log_tags << Rage.env
|
|
291
|
+
# end
|
|
292
|
+
# @overload <<(callable)
|
|
293
|
+
# Add a dynamic log tag. Dynamic tags are executed on every log call.
|
|
294
|
+
# @param callable [#call] a callable object that returns a string representing the log tag, an array of log tags, or nil
|
|
295
|
+
# @example
|
|
296
|
+
# Rage.configure do
|
|
297
|
+
# config.log_tags << proc { Current.tenant.slug }
|
|
298
|
+
# end
|
|
299
|
+
# @note Exceptions from dynamic tag callables will cause the entire request to fail. Make sure to handle exceptions inside the callable if necessary.
|
|
300
|
+
|
|
301
|
+
# @!method delete(block_or_string)
|
|
302
|
+
# Remove a custom log tag object.
|
|
303
|
+
# @param block_or_string [String, #call] the tag object to remove
|
|
304
|
+
# @example
|
|
305
|
+
# Rage.configure do
|
|
306
|
+
# config.log_tags.delete(MyObservabilitySDK::LOG_TAGS)
|
|
307
|
+
# end
|
|
308
|
+
|
|
309
|
+
# @private
|
|
310
|
+
private
|
|
311
|
+
|
|
312
|
+
def validate_input!(obj)
|
|
313
|
+
if obj.is_a?(Array)
|
|
314
|
+
obj.each { |item| validate_input!(item) }
|
|
315
|
+
elsif !obj.respond_to?(:to_str) && !obj.respond_to?(:call)
|
|
316
|
+
raise ArgumentError, "custom log tag has to be a string, an array of strings, or respond to `#call`"
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
|
|
259
321
|
class Server
|
|
322
|
+
# @!attribute port
|
|
323
|
+
# Specify the port the server will listen on.
|
|
324
|
+
# @return [Integer]
|
|
325
|
+
# @example Change the default port
|
|
326
|
+
# Rage.configure do
|
|
327
|
+
# config.server.port = 3001
|
|
328
|
+
# end
|
|
329
|
+
#
|
|
330
|
+
# @!attribute workers_count
|
|
331
|
+
# Specify the number of worker processes to spawn. Use `-1` to spawn one worker per CPU core.
|
|
332
|
+
# @return [Integer]
|
|
333
|
+
# @example Change the number of worker processes
|
|
334
|
+
# Rage.configure do
|
|
335
|
+
# config.server.workers_count = 4
|
|
336
|
+
# end
|
|
337
|
+
#
|
|
338
|
+
# @!attribute timeout
|
|
339
|
+
# Specify the connection timeout in seconds.
|
|
340
|
+
# @return [Integer]
|
|
341
|
+
# @example Change the connection timeout
|
|
342
|
+
# Rage.configure do
|
|
343
|
+
# config.server.timeout = 30
|
|
344
|
+
# end
|
|
345
|
+
#
|
|
346
|
+
# @!attribute max_clients
|
|
347
|
+
# Limit the number of simultaneous connections the server can accept. Defaults to the maximum number of open files.
|
|
348
|
+
# @return [Integer]
|
|
349
|
+
#
|
|
350
|
+
# @note Decreasing this number is almost never a good idea. Depending on your application specifics, you are encouraged to use other methods to limit the number of concurrent connections:
|
|
351
|
+
#
|
|
352
|
+
# - If your application is exposed to the public, you may want to use a cloud rate limiter, like {https://developers.cloudflare.com/waf Cloudflare WAF} or {https://docs.fastly.com/en/ngwaf Fastly WAF}.
|
|
353
|
+
# - Otherwise, consider using tools like {https://github.com/rack/rack-attack Rack::Attack} or {https://github.com/mperham/connection_pool connection_pool}.
|
|
354
|
+
# @example Limit the amount of connections your application can accept
|
|
355
|
+
# Rage.configure do
|
|
356
|
+
# config.middleware.use Rack::Attack
|
|
357
|
+
# Rack::Attack.throttle("req/ip", limit: 300, period: 5.minutes) do |req|
|
|
358
|
+
# req.ip
|
|
359
|
+
# end
|
|
360
|
+
# end
|
|
361
|
+
# @example Limit the amount of connections to a specific resource
|
|
362
|
+
# HTTP = ConnectionPool.new(size: 5, timeout: 5) { Net::HTTP }
|
|
363
|
+
# HTTP.with do |conn|
|
|
364
|
+
# conn.get("/my-resource")
|
|
365
|
+
# end
|
|
260
366
|
attr_accessor :port, :workers_count, :timeout, :max_clients
|
|
367
|
+
|
|
368
|
+
# @private
|
|
261
369
|
attr_reader :threads_count
|
|
262
370
|
|
|
371
|
+
# @private
|
|
263
372
|
def initialize
|
|
264
373
|
@threads_count = 1
|
|
265
374
|
@workers_count = Rage.env.development? ? 1 : -1
|
|
@@ -268,16 +377,47 @@ class Rage::Configuration
|
|
|
268
377
|
end
|
|
269
378
|
|
|
270
379
|
class Middleware
|
|
380
|
+
# @private
|
|
271
381
|
attr_reader :middlewares
|
|
272
382
|
|
|
383
|
+
# @private
|
|
273
384
|
def initialize
|
|
274
385
|
@middlewares = [[Rage::FiberWrapper]]
|
|
275
386
|
end
|
|
276
387
|
|
|
388
|
+
# Add a new middleware to the end of the stack.
|
|
389
|
+
# @note This is the recommended way of adding a middleware.
|
|
390
|
+
# @param new_middleware [Class] the middleware class
|
|
391
|
+
# @param args [Array] arguments passed to the middleware initializer
|
|
392
|
+
# @param block [Proc] an optional block passed to the middleware initializer
|
|
393
|
+
# @example
|
|
394
|
+
# Rage.configure do
|
|
395
|
+
# config.middleware.use Rack::Cors do
|
|
396
|
+
# allow do
|
|
397
|
+
# origins "*"
|
|
398
|
+
# resource "*", headers: :any
|
|
399
|
+
# end
|
|
400
|
+
# end
|
|
401
|
+
# end
|
|
277
402
|
def use(new_middleware, *args, &block)
|
|
278
403
|
insert_after(@middlewares.length - 1, new_middleware, *args, &block)
|
|
279
404
|
end
|
|
280
405
|
|
|
406
|
+
# Insert a new middleware before an existing middleware in the stack.
|
|
407
|
+
# @note Rage always uses the `Rage::FiberWrapper` middleware, which wraps every request in a separate fiber. Make sure to always have this middleware in the top of the stack. Placing other middlewares in front may lead to undefined behavior.
|
|
408
|
+
# @param existing_middleware [Class, Integer] the existing middleware class or its index in the stack
|
|
409
|
+
# @param new_middleware [Class] the new middleware class
|
|
410
|
+
# @param args [Array] arguments passed to the middleware initializer
|
|
411
|
+
# @param block [Proc] an optional block passed to the middleware initializer
|
|
412
|
+
# @example
|
|
413
|
+
# Rage.configure do
|
|
414
|
+
# config.middleware.insert_before Rack::Runtime, Rack::Cors do
|
|
415
|
+
# allow do
|
|
416
|
+
# origins "*"
|
|
417
|
+
# resource "*", headers: :any
|
|
418
|
+
# end
|
|
419
|
+
# end
|
|
420
|
+
# end
|
|
281
421
|
def insert_before(existing_middleware, new_middleware, *args, &block)
|
|
282
422
|
index = find_middleware_index(existing_middleware)
|
|
283
423
|
if index == 0 && @middlewares[0][0] == Rage::FiberWrapper
|
|
@@ -286,11 +426,28 @@ class Rage::Configuration
|
|
|
286
426
|
@middlewares = (@middlewares[0...index] + [[new_middleware, args, block]] + @middlewares[index..]).uniq(&:first)
|
|
287
427
|
end
|
|
288
428
|
|
|
429
|
+
# Insert a new middleware after an existing middleware in the stack.
|
|
430
|
+
# @param existing_middleware [Class, Integer] the existing middleware class or its index in the stack
|
|
431
|
+
# @param new_middleware [Class] the new middleware class
|
|
432
|
+
# @param args [Array] arguments passed to the middleware initializer
|
|
433
|
+
# @param block [Proc] an optional block passed to the middleware initializer
|
|
434
|
+
# @example
|
|
435
|
+
# Rage.configure do
|
|
436
|
+
# config.middleware.insert_after Rack::Runtime, Rack::Cors do
|
|
437
|
+
# allow do
|
|
438
|
+
# origins "*"
|
|
439
|
+
# resource "*", headers: :any
|
|
440
|
+
# end
|
|
441
|
+
# end
|
|
442
|
+
# end
|
|
289
443
|
def insert_after(existing_middleware, new_middleware, *args, &block)
|
|
290
444
|
index = find_middleware_index(existing_middleware)
|
|
291
445
|
@middlewares = (@middlewares[0..index] + [[new_middleware, args, block]] + @middlewares[index + 1..]).uniq(&:first)
|
|
292
446
|
end
|
|
293
447
|
|
|
448
|
+
# Check if a middleware is included in the stack.
|
|
449
|
+
# @param middleware [Class, Integer] the middleware class or its index in the stack
|
|
450
|
+
# @return [Boolean]
|
|
294
451
|
def include?(middleware)
|
|
295
452
|
!!find_middleware_index(middleware) rescue false
|
|
296
453
|
end
|
|
@@ -312,9 +469,24 @@ class Rage::Configuration
|
|
|
312
469
|
end
|
|
313
470
|
|
|
314
471
|
class Cable
|
|
472
|
+
# @!attribute allowed_request_origins
|
|
473
|
+
# Restrict the server to only accept requests from specified origins. The origins can be strings or regular expressions. Defaults to `/localhost/` in development and test environments.
|
|
474
|
+
# @return [Array<Regexp>, Regexp, Array<String>, String, nil]
|
|
475
|
+
# @example
|
|
476
|
+
# Rage.configure do
|
|
477
|
+
# config.cable.allowed_request_origins = [/example\.com/, "myapp.com"]
|
|
478
|
+
# end
|
|
479
|
+
#
|
|
480
|
+
# @!attribute disable_request_forgery_protection
|
|
481
|
+
# Disable request forgery protection for WebSocket connections to allow requests from any origin.
|
|
482
|
+
# @return [Boolean]
|
|
483
|
+
# @example
|
|
484
|
+
# Rage.configure do
|
|
485
|
+
# config.cable.disable_request_forgery_protection = true
|
|
486
|
+
# end
|
|
315
487
|
attr_accessor :allowed_request_origins, :disable_request_forgery_protection
|
|
316
|
-
attr_reader :protocol
|
|
317
488
|
|
|
489
|
+
# @private
|
|
318
490
|
def initialize
|
|
319
491
|
@protocol = Rage::Cable::Protocols::ActioncableV1Json
|
|
320
492
|
@allowed_request_origins = if Rage.env.development? || Rage.env.test?
|
|
@@ -322,6 +494,22 @@ class Rage::Configuration
|
|
|
322
494
|
end
|
|
323
495
|
end
|
|
324
496
|
|
|
497
|
+
# Returns the protocol the server will use.
|
|
498
|
+
# @return [Class] the protocol class
|
|
499
|
+
def protocol
|
|
500
|
+
@protocol
|
|
501
|
+
end
|
|
502
|
+
|
|
503
|
+
# Specify the protocol the server will use. Supported values include {Rage::Cable::Protocols::ActioncableV1Json :actioncable_v1_json} and {Rage::Cable::Protocols::RawWebSocketJson :raw_websocket_json}. Defaults to {Rage::Cable::Protocols::ActioncableV1Json :actioncable_v1_json}.
|
|
504
|
+
# @param protocol [:actioncable_v1_json, :raw_websocket_json] the protocol symbol
|
|
505
|
+
# @example Use the built-in ActionCable V1 JSON protocol
|
|
506
|
+
# Rage.configure do
|
|
507
|
+
# config.cable.protocol = :actioncable_v1_json
|
|
508
|
+
# end
|
|
509
|
+
# @example Use the built-in Raw WebSocket JSON protocol
|
|
510
|
+
# Rage.configure do
|
|
511
|
+
# config.cable.protocol = :raw_websocket_json
|
|
512
|
+
# end
|
|
325
513
|
def protocol=(protocol)
|
|
326
514
|
@protocol = case protocol
|
|
327
515
|
when Class
|
|
@@ -350,6 +538,7 @@ class Rage::Configuration
|
|
|
350
538
|
end
|
|
351
539
|
end
|
|
352
540
|
|
|
541
|
+
# @private
|
|
353
542
|
def config
|
|
354
543
|
@config ||= begin
|
|
355
544
|
config_file = Rage.root.join("config/cable.yml")
|
|
@@ -363,10 +552,12 @@ class Rage::Configuration
|
|
|
363
552
|
end
|
|
364
553
|
end
|
|
365
554
|
|
|
555
|
+
# @private
|
|
366
556
|
def adapter_config
|
|
367
557
|
config.except(:adapter)
|
|
368
558
|
end
|
|
369
559
|
|
|
560
|
+
# @private
|
|
370
561
|
def adapter
|
|
371
562
|
case config[:adapter]
|
|
372
563
|
when "redis"
|
|
@@ -376,20 +567,54 @@ class Rage::Configuration
|
|
|
376
567
|
end
|
|
377
568
|
|
|
378
569
|
class PublicFileServer
|
|
570
|
+
# @!attribute enabled
|
|
571
|
+
# Configure whether Rage should serve static files from the `public` directory. Defaults to `false`.
|
|
572
|
+
# @return [Boolean] whether the static file server is enabled
|
|
573
|
+
# @example
|
|
574
|
+
# Rage.configure do
|
|
575
|
+
# config.public_file_server.enabled = true
|
|
576
|
+
# end
|
|
379
577
|
attr_accessor :enabled
|
|
380
578
|
end
|
|
381
579
|
|
|
382
580
|
class OpenAPI
|
|
383
|
-
|
|
581
|
+
# Specify the rules to customize how OpenAPI tags are generated for API operations.
|
|
582
|
+
# The method accepts a callable object that receives the controller class, the action name (as a symbol), and the original tag generated by Rage.
|
|
583
|
+
# The callable should return a string or an array of strings representing the tags to use for the API operation.
|
|
584
|
+
# This enables grouping endpoints in the OpenAPI documentation according to your application's needs.
|
|
585
|
+
# @param tag_resolver [#call] a callable object that resolves OpenAPI tags
|
|
586
|
+
# @example
|
|
587
|
+
# Rage.configure do
|
|
588
|
+
# config.openapi.tag_resolver = proc do |controller_class, action_name, default_tag|
|
|
589
|
+
# if controller_class.name.start_with?("Admin::")
|
|
590
|
+
# [default_tag, "Admin"]
|
|
591
|
+
# else
|
|
592
|
+
# [default_tag, "Public"]
|
|
593
|
+
# end
|
|
594
|
+
# end
|
|
595
|
+
# end
|
|
596
|
+
def tag_resolver=(tag_resolver)
|
|
597
|
+
unless tag_resolver.respond_to?(:call)
|
|
598
|
+
raise ArgumentError, "Custom tag resolver should respond to `#call`"
|
|
599
|
+
end
|
|
600
|
+
|
|
601
|
+
@tag_resolver = tag_resolver
|
|
602
|
+
end
|
|
603
|
+
|
|
604
|
+
# Returns the OpenAPI tag resolver used by Rage.
|
|
605
|
+
# @return [#call, nil]
|
|
606
|
+
def tag_resolver
|
|
607
|
+
@tag_resolver
|
|
608
|
+
end
|
|
384
609
|
end
|
|
385
610
|
|
|
386
611
|
class Deferred
|
|
387
|
-
|
|
388
|
-
|
|
612
|
+
# @private
|
|
389
613
|
def initialize
|
|
390
614
|
@configured = false
|
|
391
615
|
end
|
|
392
616
|
|
|
617
|
+
# Returns the backend instance used by `Rage::Deferred`.
|
|
393
618
|
def backend
|
|
394
619
|
unless @backend_class
|
|
395
620
|
@backend_class = Rage::Deferred::Backends::Disk
|
|
@@ -399,6 +624,27 @@ class Rage::Configuration
|
|
|
399
624
|
@backend_class.new(**@backend_options)
|
|
400
625
|
end
|
|
401
626
|
|
|
627
|
+
# Specify the backend used to persist deferred tasks. Supported values are `:disk`, which uses disk storage, or `nil`, which disables persistence of deferred tasks.
|
|
628
|
+
# @overload backend=(disk, options = {})
|
|
629
|
+
# Use the disk backend.
|
|
630
|
+
# @param options [Hash] additional backend options
|
|
631
|
+
# @option options [Pathname, String] :path the directory where deferred tasks will be stored. Defaults to `storage/`
|
|
632
|
+
# @option options [String] :prefix the prefix used for deferred task files. Defaults to `deferred-`
|
|
633
|
+
# @option options [Integer] :fsync_frequency the frequency of `fsync` calls in seconds. Defaults to `0.5`
|
|
634
|
+
# @example Use the disk backend with default options
|
|
635
|
+
# Rage.configure do
|
|
636
|
+
# config.deferred.backend = :disk
|
|
637
|
+
# end
|
|
638
|
+
# @example Use the disk backend with custom options
|
|
639
|
+
# Rage.configure do
|
|
640
|
+
# config.deferred.backend = :disk, path: "my_storage", fsync_frequency: 1000
|
|
641
|
+
# end
|
|
642
|
+
# @overload backend=(nil)
|
|
643
|
+
# Disable persistence of deferred tasks.
|
|
644
|
+
# @example
|
|
645
|
+
# Rage.configure do
|
|
646
|
+
# config.deferred.backend = nil
|
|
647
|
+
# end
|
|
402
648
|
def backend=(config)
|
|
403
649
|
@configured = true
|
|
404
650
|
|
|
@@ -422,6 +668,7 @@ class Rage::Configuration
|
|
|
422
668
|
class Backpressure
|
|
423
669
|
attr_reader :high_water_mark, :low_water_mark, :timeout, :sleep_interval, :timeout_iterations
|
|
424
670
|
|
|
671
|
+
# @private
|
|
425
672
|
def initialize(high_water_mark = nil, low_water_mark = nil, timeout = nil)
|
|
426
673
|
@high_water_mark = high_water_mark || 1_000
|
|
427
674
|
@low_water_mark = low_water_mark || (@high_water_mark * 0.8).round
|
|
@@ -432,6 +679,38 @@ class Rage::Configuration
|
|
|
432
679
|
end
|
|
433
680
|
end
|
|
434
681
|
|
|
682
|
+
# Returns the backpressure configuration used by `Rage::Deferred`.
|
|
683
|
+
# @return [Backpressure, nil]
|
|
684
|
+
def backpressure
|
|
685
|
+
@backpressure
|
|
686
|
+
end
|
|
687
|
+
|
|
688
|
+
# Configure backpressure settings for `Rage::Deferred`. Backpressure is used to limit the number of pending tasks in the queue and is disabled by default.
|
|
689
|
+
#
|
|
690
|
+
# @overload backpressure=(true)
|
|
691
|
+
# Enable backpressure with default settings.
|
|
692
|
+
# @example
|
|
693
|
+
# Rage.configure do
|
|
694
|
+
# config.deferred.backpressure = true
|
|
695
|
+
# end
|
|
696
|
+
#
|
|
697
|
+
# @overload backpressure=(false)
|
|
698
|
+
# Disable backpressure.
|
|
699
|
+
# @example
|
|
700
|
+
# Rage.configure do
|
|
701
|
+
# config.deferred.backpressure = false
|
|
702
|
+
# end
|
|
703
|
+
#
|
|
704
|
+
# @overload backpressure=(config)
|
|
705
|
+
# Enable backpressure with custom settings.
|
|
706
|
+
# @param config [Hash] backpressure configuration
|
|
707
|
+
# @option config [Integer] :high_water_mark the maximum number of deferred tasks allowed in the queue before applying backpressure. Defaults to `1000`.
|
|
708
|
+
# @option config [Integer] :low_water_mark the minimum number of deferred tasks in the queue at which backpressure is lifted. Defaults to `80%` of `:high_water_mark`.
|
|
709
|
+
# @option config [Integer] :timeout the maximum time in seconds to wait for the queue size to drop below `:low_water_mark` before raising the {Rage::Deferred::PushTimeout Rage::Deferred::PushTimeout} exception. Defaults to 2 seconds.
|
|
710
|
+
# @example
|
|
711
|
+
# Rage.configure do
|
|
712
|
+
# config.deferred.backpressure = { high_water_mark: 2000, low_water_mark: 1500, timeout: 5 }
|
|
713
|
+
# end
|
|
435
714
|
def backpressure=(config)
|
|
436
715
|
@configured = true
|
|
437
716
|
|
|
@@ -451,18 +730,22 @@ class Rage::Configuration
|
|
|
451
730
|
@backpressure = Backpressure.new(high_water_mark, low_water_mark, timeout)
|
|
452
731
|
end
|
|
453
732
|
|
|
733
|
+
# @private
|
|
454
734
|
def default_disk_storage_path
|
|
455
735
|
Pathname.new("storage")
|
|
456
736
|
end
|
|
457
737
|
|
|
738
|
+
# @private
|
|
458
739
|
def default_disk_storage_prefix
|
|
459
740
|
"deferred-"
|
|
460
741
|
end
|
|
461
742
|
|
|
743
|
+
# @private
|
|
462
744
|
def has_default_disk_storage?
|
|
463
745
|
default_disk_storage_path.glob("#{default_disk_storage_prefix}*").any?
|
|
464
746
|
end
|
|
465
747
|
|
|
748
|
+
# @private
|
|
466
749
|
def configured?
|
|
467
750
|
@configured
|
|
468
751
|
end
|
|
@@ -498,6 +781,17 @@ class Rage::Configuration
|
|
|
498
781
|
end
|
|
499
782
|
end
|
|
500
783
|
|
|
784
|
+
class Session
|
|
785
|
+
# @!attribute key
|
|
786
|
+
# Specify the name of the session cookie.
|
|
787
|
+
# @return [String]
|
|
788
|
+
# @example Change the session cookie name
|
|
789
|
+
# Rage.configure do
|
|
790
|
+
# config.session.key = "_myapp_session"
|
|
791
|
+
# end
|
|
792
|
+
attr_accessor :key
|
|
793
|
+
end
|
|
794
|
+
|
|
501
795
|
# @private
|
|
502
796
|
class Internal
|
|
503
797
|
attr_accessor :rails_mode
|
|
@@ -539,5 +833,52 @@ class Rage::Configuration
|
|
|
539
833
|
else
|
|
540
834
|
@logger = Rage::Logger.new(nil)
|
|
541
835
|
end
|
|
836
|
+
|
|
837
|
+
if @log_formatter && @logger.external_logger.is_a?(Rage::Logger::External::Dynamic)
|
|
838
|
+
puts "WARNING: changing the log formatter via `config.log_formatter=` has no effect when using a custom external logger."
|
|
839
|
+
end
|
|
840
|
+
|
|
841
|
+
if @log_context
|
|
842
|
+
Rage.__log_processor.add_custom_context(@log_context.objects)
|
|
843
|
+
@logger.dynamic_context = Rage.__log_processor.dynamic_context
|
|
844
|
+
end
|
|
845
|
+
|
|
846
|
+
if @log_tags
|
|
847
|
+
Rage.__log_processor.add_custom_tags(@log_tags.objects)
|
|
848
|
+
@logger.dynamic_tags = Rage.__log_processor.dynamic_tags
|
|
849
|
+
end
|
|
542
850
|
end
|
|
543
851
|
end
|
|
852
|
+
|
|
853
|
+
# @!parse [ruby]
|
|
854
|
+
# # @note This class does not exist at runtime and is used for documentation purposes only. Do not inherit external loggers from it.
|
|
855
|
+
# class ExternalLoggerInterface
|
|
856
|
+
# # Called whenever a log entry is created.
|
|
857
|
+
# #
|
|
858
|
+
# # Rage automatically detects which parameters your external logger's `#call` method accepts, and only passes those parameters. You can omit any of the described parameters in your implementation.
|
|
859
|
+
# #
|
|
860
|
+
# # @param severity [:debug, :info, :warn, :error, :fatal, :unknown] the log severity
|
|
861
|
+
# # @param tags [Array] the log tags submitted via {Rage::Logger#tagged Rage::Logger#tagged}. The first tag is always the request ID
|
|
862
|
+
# # @param context [Hash] the log context submitted via {Rage::Logger#with_context Rage::Logger#with_context}
|
|
863
|
+
# # @param message [String, nil] the log message. For request logs generated by Rage, this is always `nil`
|
|
864
|
+
# # @param request_info [Hash, nil] request-specific information. The value is `nil` for non-request logs; for request logs, contains the following keys:
|
|
865
|
+
# # @option request_info [Hash] :env the Rack env object
|
|
866
|
+
# # @option request_info [Hash] :params the request parameters
|
|
867
|
+
# # @option request_info [Array] :response the Rack response object
|
|
868
|
+
# # @option request_info [Float] :duration the duration of the request in milliseconds
|
|
869
|
+
# # @example
|
|
870
|
+
# # Rage.configure do
|
|
871
|
+
# # config.logger = proc do |severity:, tags:, context:, message:, request_info:|
|
|
872
|
+
# # data = context.merge(tags:)
|
|
873
|
+
# #
|
|
874
|
+
# # if request_info
|
|
875
|
+
# # data[:path] = request_info[:env]["PATH_INFO"]
|
|
876
|
+
# # MyLoggingSDK.info("Request completed", data)
|
|
877
|
+
# # else
|
|
878
|
+
# # MyLoggingSDK.public_send(severity, message, data)
|
|
879
|
+
# # end
|
|
880
|
+
# # end
|
|
881
|
+
# # end
|
|
882
|
+
# def call(severity:, tags:, context:, message:, request_info:)
|
|
883
|
+
# end
|
|
884
|
+
# end
|