puma 5.0.0-java → 5.1.0-java
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of puma might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/History.md +1190 -574
- data/README.md +28 -20
- data/bin/puma-wild +3 -9
- data/docs/compile_options.md +19 -0
- data/docs/deployment.md +5 -6
- data/docs/fork_worker.md +2 -0
- data/docs/jungle/README.md +0 -4
- data/docs/jungle/rc.d/puma +2 -2
- data/docs/nginx.md +1 -1
- data/docs/restart.md +46 -23
- data/docs/systemd.md +25 -3
- data/ext/puma_http11/ext_help.h +1 -1
- data/ext/puma_http11/extconf.rb +4 -5
- data/ext/puma_http11/http11_parser.c +64 -64
- data/ext/puma_http11/mini_ssl.c +39 -37
- data/ext/puma_http11/puma_http11.c +25 -12
- data/lib/puma.rb +7 -4
- data/lib/puma/app/status.rb +44 -46
- data/lib/puma/binder.rb +48 -1
- data/lib/puma/cli.rb +4 -0
- data/lib/puma/client.rb +31 -80
- data/lib/puma/cluster.rb +39 -202
- data/lib/puma/cluster/worker.rb +176 -0
- data/lib/puma/cluster/worker_handle.rb +86 -0
- data/lib/puma/configuration.rb +20 -8
- data/lib/puma/const.rb +11 -3
- data/lib/puma/control_cli.rb +71 -70
- data/lib/puma/dsl.rb +67 -19
- data/lib/puma/error_logger.rb +2 -2
- data/lib/puma/events.rb +21 -3
- data/lib/puma/json.rb +96 -0
- data/lib/puma/launcher.rb +61 -12
- data/lib/puma/minissl.rb +8 -0
- data/lib/puma/puma_http11.jar +0 -0
- data/lib/puma/queue_close.rb +26 -0
- data/lib/puma/reactor.rb +79 -373
- data/lib/puma/request.rb +451 -0
- data/lib/puma/runner.rb +15 -21
- data/lib/puma/server.rb +193 -508
- data/lib/puma/single.rb +3 -2
- data/lib/puma/state_file.rb +5 -3
- data/lib/puma/systemd.rb +46 -0
- data/lib/puma/thread_pool.rb +22 -2
- data/lib/puma/util.rb +12 -0
- metadata +9 -6
- data/docs/jungle/upstart/README.md +0 -61
- data/docs/jungle/upstart/puma-manager.conf +0 -31
- data/docs/jungle/upstart/puma.conf +0 -69
- data/lib/puma/accept_nonblock.rb +0 -29
data/lib/puma/dsl.rb
CHANGED
@@ -34,6 +34,34 @@ module Puma
|
|
34
34
|
class DSL
|
35
35
|
include ConfigDefault
|
36
36
|
|
37
|
+
# convenience method so logic can be used in CI
|
38
|
+
# @see ssl_bind
|
39
|
+
#
|
40
|
+
def self.ssl_bind_str(host, port, opts)
|
41
|
+
verify = opts.fetch(:verify_mode, 'none').to_s
|
42
|
+
|
43
|
+
tls_str =
|
44
|
+
if opts[:no_tlsv1_1] then '&no_tlsv1_1=true'
|
45
|
+
elsif opts[:no_tlsv1] then '&no_tlsv1=true'
|
46
|
+
else ''
|
47
|
+
end
|
48
|
+
|
49
|
+
ca_additions = "&ca=#{opts[:ca]}" if ['peer', 'force_peer'].include?(verify)
|
50
|
+
|
51
|
+
if defined?(JRUBY_VERSION)
|
52
|
+
ssl_cipher_list = opts[:ssl_cipher_list] ?
|
53
|
+
"&ssl_cipher_list=#{opts[:ssl_cipher_list]}" : nil
|
54
|
+
keystore_additions = "keystore=#{opts[:keystore]}&keystore-pass=#{opts[:keystore_pass]}"
|
55
|
+
"ssl://#{host}:#{port}?#{keystore_additions}#{ssl_cipher_list}" \
|
56
|
+
"&verify_mode=#{verify}#{tls_str}#{ca_additions}"
|
57
|
+
else
|
58
|
+
ssl_cipher_filter = opts[:ssl_cipher_filter] ?
|
59
|
+
"&ssl_cipher_filter=#{opts[:ssl_cipher_filter]}" : nil
|
60
|
+
"ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}" \
|
61
|
+
"#{ssl_cipher_filter}&verify_mode=#{verify}#{tls_str}#{ca_additions}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
37
65
|
def initialize(options, config)
|
38
66
|
@config = config
|
39
67
|
@options = options
|
@@ -191,6 +219,32 @@ module Puma
|
|
191
219
|
@options[:binds] = []
|
192
220
|
end
|
193
221
|
|
222
|
+
# Bind to (systemd) activated sockets, regardless of configured binds.
|
223
|
+
#
|
224
|
+
# Systemd can present sockets as file descriptors that are already opened.
|
225
|
+
# By default Puma will use these but only if it was explicitly told to bind
|
226
|
+
# to the socket. If not, it will close the activated sockets. This means
|
227
|
+
# all configuration is duplicated.
|
228
|
+
#
|
229
|
+
# Binds can contain additional configuration, but only SSL config is really
|
230
|
+
# relevant since the unix and TCP socket options are ignored.
|
231
|
+
#
|
232
|
+
# This means there is a lot of duplicated configuration for no additional
|
233
|
+
# value in most setups. This method tells the launcher to bind to all
|
234
|
+
# activated sockets, regardless of existing bind.
|
235
|
+
#
|
236
|
+
# To clear configured binds, the value only can be passed. This will clear
|
237
|
+
# out any binds that may have been configured.
|
238
|
+
#
|
239
|
+
# @example Use any systemd activated sockets as well as configured binds
|
240
|
+
# bind_to_activated_sockets
|
241
|
+
#
|
242
|
+
# @example Only bind to systemd activated sockets, ignoring other binds
|
243
|
+
# bind_to_activated_sockets 'only'
|
244
|
+
def bind_to_activated_sockets(bind=true)
|
245
|
+
@options[:bind_to_activated_sockets] = bind
|
246
|
+
end
|
247
|
+
|
194
248
|
# Define the TCP port to bind to. Use +bind+ for more advanced options.
|
195
249
|
#
|
196
250
|
# @example
|
@@ -376,28 +430,15 @@ module Puma
|
|
376
430
|
# ssl_cipher_filter: cipher_filter, # optional
|
377
431
|
# verify_mode: verify_mode, # default 'none'
|
378
432
|
# }
|
379
|
-
# @example For JRuby
|
433
|
+
# @example For JRuby, two keys are required: keystore & keystore_pass.
|
380
434
|
# ssl_bind '127.0.0.1', '9292', {
|
381
|
-
# cert: path_to_cert,
|
382
|
-
# key: path_to_key,
|
383
|
-
# ssl_cipher_filter: cipher_filter, # optional
|
384
|
-
# verify_mode: verify_mode, # default 'none'
|
385
435
|
# keystore: path_to_keystore,
|
386
|
-
# keystore_pass: password
|
436
|
+
# keystore_pass: password,
|
437
|
+
# ssl_cipher_list: cipher_list, # optional
|
438
|
+
# verify_mode: verify_mode # default 'none'
|
387
439
|
# }
|
388
440
|
def ssl_bind(host, port, opts)
|
389
|
-
|
390
|
-
no_tlsv1 = opts.fetch(:no_tlsv1, 'false')
|
391
|
-
no_tlsv1_1 = opts.fetch(:no_tlsv1_1, 'false')
|
392
|
-
ca_additions = "&ca=#{opts[:ca]}" if ['peer', 'force_peer'].include?(verify)
|
393
|
-
|
394
|
-
if defined?(JRUBY_VERSION)
|
395
|
-
keystore_additions = "keystore=#{opts[:keystore]}&keystore-pass=#{opts[:keystore_pass]}"
|
396
|
-
bind "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}&#{keystore_additions}&verify_mode=#{verify}&no_tlsv1=#{no_tlsv1}&no_tlsv1_1=#{no_tlsv1_1}#{ca_additions}"
|
397
|
-
else
|
398
|
-
ssl_cipher_filter = "&ssl_cipher_filter=#{opts[:ssl_cipher_filter]}" if opts[:ssl_cipher_filter]
|
399
|
-
bind "ssl://#{host}:#{port}?cert=#{opts[:cert]}&key=#{opts[:key]}#{ssl_cipher_filter}&verify_mode=#{verify}&no_tlsv1=#{no_tlsv1}&no_tlsv1_1=#{no_tlsv1_1}#{ca_additions}"
|
400
|
-
end
|
441
|
+
bind self.class.ssl_bind_str(host, port, opts)
|
401
442
|
end
|
402
443
|
|
403
444
|
# Use +path+ as the file to store the server info state. This is
|
@@ -561,7 +602,7 @@ module Puma
|
|
561
602
|
end
|
562
603
|
|
563
604
|
# Preload the application before starting the workers; this conflicts with
|
564
|
-
# phased restart feature.
|
605
|
+
# phased restart feature. On by default if your app uses more than 1 worker.
|
565
606
|
#
|
566
607
|
# @note Cluster mode only.
|
567
608
|
# @example
|
@@ -810,5 +851,12 @@ module Puma
|
|
810
851
|
def nakayoshi_fork(enabled=true)
|
811
852
|
@options[:nakayoshi_fork] = enabled
|
812
853
|
end
|
854
|
+
|
855
|
+
# The number of requests to attempt inline before sending a client back to
|
856
|
+
# the reactor to be subject to normal ordering.
|
857
|
+
#
|
858
|
+
def max_fast_inline(num_of_requests)
|
859
|
+
@options[:max_fast_inline] = Float(num_of_requests)
|
860
|
+
end
|
813
861
|
end
|
814
862
|
end
|
data/lib/puma/error_logger.rb
CHANGED
@@ -51,8 +51,8 @@ module Puma
|
|
51
51
|
|
52
52
|
string_block = []
|
53
53
|
string_block << title(options)
|
54
|
-
string_block << request_dump(req) if req
|
55
|
-
string_block <<
|
54
|
+
string_block << request_dump(req) if request_parsed?(req)
|
55
|
+
string_block << error.backtrace if error
|
56
56
|
|
57
57
|
ioerr.puts string_block.join("\n")
|
58
58
|
end
|
data/lib/puma/events.rb
CHANGED
@@ -106,10 +106,12 @@ module Puma
|
|
106
106
|
end
|
107
107
|
|
108
108
|
# An SSL error has occurred.
|
109
|
-
#
|
110
|
-
#
|
109
|
+
# @param error <Puma::MiniSSL::SSLError>
|
110
|
+
# @param ssl_socket <Puma::MiniSSL::Socket>
|
111
111
|
#
|
112
|
-
def ssl_error(error,
|
112
|
+
def ssl_error(error, ssl_socket)
|
113
|
+
peeraddr = ssl_socket.peeraddr.last rescue "<unknown>"
|
114
|
+
peercert = ssl_socket.peercert
|
113
115
|
subject = peercert ? peercert.subject : nil
|
114
116
|
@error_logger.info(error: error, text: "SSL error, peer: #{peeraddr}, peer cert: #{subject}")
|
115
117
|
end
|
@@ -135,10 +137,26 @@ module Puma
|
|
135
137
|
register(:on_booted, &block)
|
136
138
|
end
|
137
139
|
|
140
|
+
def on_restart(&block)
|
141
|
+
register(:on_restart, &block)
|
142
|
+
end
|
143
|
+
|
144
|
+
def on_stopped(&block)
|
145
|
+
register(:on_stopped, &block)
|
146
|
+
end
|
147
|
+
|
138
148
|
def fire_on_booted!
|
139
149
|
fire(:on_booted)
|
140
150
|
end
|
141
151
|
|
152
|
+
def fire_on_restart!
|
153
|
+
fire(:on_restart)
|
154
|
+
end
|
155
|
+
|
156
|
+
def fire_on_stopped!
|
157
|
+
fire(:on_stopped)
|
158
|
+
end
|
159
|
+
|
142
160
|
DEFAULT = new(STDOUT, STDERR)
|
143
161
|
|
144
162
|
# Returns an Events object which writes its status to 2 StringIO
|
data/lib/puma/json.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'stringio'
|
3
|
+
|
4
|
+
module Puma
|
5
|
+
|
6
|
+
# Puma deliberately avoids the use of the json gem and instead performs JSON
|
7
|
+
# serialization without any external dependencies. In a puma cluster, loading
|
8
|
+
# any gem into the puma master process means that operators cannot use a
|
9
|
+
# phased restart to upgrade their application if the new version of that
|
10
|
+
# application uses a different version of that gem. The json gem in
|
11
|
+
# particular is additionally problematic because it leverages native
|
12
|
+
# extensions. If the puma master process relies on a gem with native
|
13
|
+
# extensions and operators remove gems from disk related to old releases,
|
14
|
+
# subsequent phased restarts can fail.
|
15
|
+
#
|
16
|
+
# The implementation of JSON serialization in this module is not designed to
|
17
|
+
# be particularly full-featured or fast. It just has to handle the few places
|
18
|
+
# where Puma relies on JSON serialization internally.
|
19
|
+
|
20
|
+
module JSON
|
21
|
+
QUOTE = /"/
|
22
|
+
BACKSLASH = /\\/
|
23
|
+
CONTROL_CHAR_TO_ESCAPE = /[\x00-\x1F]/ # As required by ECMA-404
|
24
|
+
CHAR_TO_ESCAPE = Regexp.union QUOTE, BACKSLASH, CONTROL_CHAR_TO_ESCAPE
|
25
|
+
|
26
|
+
class SerializationError < StandardError; end
|
27
|
+
|
28
|
+
class << self
|
29
|
+
def generate(value)
|
30
|
+
StringIO.open do |io|
|
31
|
+
serialize_value io, value
|
32
|
+
io.string
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def serialize_value(output, value)
|
39
|
+
case value
|
40
|
+
when Hash
|
41
|
+
output << '{'
|
42
|
+
value.each_with_index do |(k, v), index|
|
43
|
+
output << ',' if index != 0
|
44
|
+
serialize_object_key output, k
|
45
|
+
output << ':'
|
46
|
+
serialize_value output, v
|
47
|
+
end
|
48
|
+
output << '}'
|
49
|
+
when Array
|
50
|
+
output << '['
|
51
|
+
value.each_with_index do |member, index|
|
52
|
+
output << ',' if index != 0
|
53
|
+
serialize_value output, member
|
54
|
+
end
|
55
|
+
output << ']'
|
56
|
+
when Integer, Float
|
57
|
+
output << value.to_s
|
58
|
+
when String
|
59
|
+
serialize_string output, value
|
60
|
+
when true
|
61
|
+
output << 'true'
|
62
|
+
when false
|
63
|
+
output << 'false'
|
64
|
+
when nil
|
65
|
+
output << 'null'
|
66
|
+
else
|
67
|
+
raise SerializationError, "Unexpected value of type #{value.class}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def serialize_string(output, value)
|
72
|
+
output << '"'
|
73
|
+
output << value.gsub(CHAR_TO_ESCAPE) do |character|
|
74
|
+
case character
|
75
|
+
when BACKSLASH
|
76
|
+
'\\\\'
|
77
|
+
when QUOTE
|
78
|
+
'\\"'
|
79
|
+
when CONTROL_CHAR_TO_ESCAPE
|
80
|
+
'\u%.4X' % character.ord
|
81
|
+
end
|
82
|
+
end
|
83
|
+
output << '"'
|
84
|
+
end
|
85
|
+
|
86
|
+
def serialize_object_key(output, value)
|
87
|
+
case value
|
88
|
+
when Symbol, String
|
89
|
+
serialize_string output, value.to_s
|
90
|
+
else
|
91
|
+
raise SerializationError, "Could not serialize object of type #{value.class} as object key"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
data/lib/puma/launcher.rb
CHANGED
@@ -58,6 +58,13 @@ module Puma
|
|
58
58
|
|
59
59
|
@config.load
|
60
60
|
|
61
|
+
if @config.options[:bind_to_activated_sockets]
|
62
|
+
@config.options[:binds] = @binder.synthesize_binds_from_activated_fs(
|
63
|
+
@config.options[:binds],
|
64
|
+
@config.options[:bind_to_activated_sockets] == 'only'
|
65
|
+
)
|
66
|
+
end
|
67
|
+
|
61
68
|
@options = @config.options
|
62
69
|
@config.clamp
|
63
70
|
|
@@ -87,6 +94,8 @@ module Puma
|
|
87
94
|
Puma.stats_object = @runner
|
88
95
|
|
89
96
|
@status = :run
|
97
|
+
|
98
|
+
log_config if ENV['PUMA_LOG_CONFIG']
|
90
99
|
end
|
91
100
|
|
92
101
|
attr_reader :binder, :events, :config, :options, :restart_dir
|
@@ -130,6 +139,7 @@ module Puma
|
|
130
139
|
|
131
140
|
# Begin async shutdown of the server gracefully
|
132
141
|
def stop
|
142
|
+
@events.fire_on_stopped!
|
133
143
|
@status = :stop
|
134
144
|
@runner.stop
|
135
145
|
end
|
@@ -168,6 +178,7 @@ module Puma
|
|
168
178
|
|
169
179
|
setup_signals
|
170
180
|
set_process_title
|
181
|
+
integrate_with_systemd
|
171
182
|
@runner.run
|
172
183
|
|
173
184
|
case @status
|
@@ -188,11 +199,13 @@ module Puma
|
|
188
199
|
end
|
189
200
|
|
190
201
|
# Return all tcp ports the launcher may be using, TCP or SSL
|
202
|
+
# @!attribute [r] connected_ports
|
191
203
|
# @version 5.0.0
|
192
204
|
def connected_ports
|
193
205
|
@binder.connected_ports
|
194
206
|
end
|
195
207
|
|
208
|
+
# @!attribute [r] restart_args
|
196
209
|
def restart_args
|
197
210
|
cmd = @options[:restart_cmd]
|
198
211
|
if cmd
|
@@ -207,6 +220,7 @@ module Puma
|
|
207
220
|
@binder.close_listeners
|
208
221
|
end
|
209
222
|
|
223
|
+
# @!attribute [r] thread_status
|
210
224
|
# @version 5.0.0
|
211
225
|
def thread_status
|
212
226
|
Thread.list.each do |thread|
|
@@ -226,11 +240,10 @@ module Puma
|
|
226
240
|
def write_pid
|
227
241
|
path = @options[:pidfile]
|
228
242
|
return unless path
|
229
|
-
|
230
|
-
File.
|
231
|
-
cur = Process.pid
|
243
|
+
cur_pid = Process.pid
|
244
|
+
File.write path, cur_pid, mode: 'wb:UTF-8'
|
232
245
|
at_exit do
|
233
|
-
delete_pidfile if
|
246
|
+
delete_pidfile if cur_pid == Process.pid
|
234
247
|
end
|
235
248
|
end
|
236
249
|
|
@@ -239,6 +252,7 @@ module Puma
|
|
239
252
|
end
|
240
253
|
|
241
254
|
def restart!
|
255
|
+
@events.fire_on_restart!
|
242
256
|
@config.run_hooks :on_restart, self, @events
|
243
257
|
|
244
258
|
if Puma.jruby?
|
@@ -261,16 +275,14 @@ module Puma
|
|
261
275
|
end
|
262
276
|
end
|
263
277
|
|
264
|
-
|
278
|
+
# @!attribute [r] files_to_require_after_prune
|
279
|
+
def files_to_require_after_prune
|
265
280
|
puma = spec_for_gem("puma")
|
266
281
|
|
267
|
-
|
268
|
-
"#{d.name}:#{spec_for_gem(d.name).version}"
|
269
|
-
end
|
270
|
-
|
271
|
-
[deps, require_paths_for_gem(puma) + extra_runtime_deps_directories]
|
282
|
+
require_paths_for_gem(puma) + extra_runtime_deps_directories
|
272
283
|
end
|
273
284
|
|
285
|
+
# @!attribute [r] extra_runtime_deps_directories
|
274
286
|
def extra_runtime_deps_directories
|
275
287
|
Array(@options[:extra_runtime_dependencies]).map do |d_name|
|
276
288
|
if (spec = spec_for_gem(d_name))
|
@@ -282,6 +294,7 @@ module Puma
|
|
282
294
|
end.flatten.compact
|
283
295
|
end
|
284
296
|
|
297
|
+
# @!attribute [r] puma_wild_location
|
285
298
|
def puma_wild_location
|
286
299
|
puma = spec_for_gem("puma")
|
287
300
|
dirs = require_paths_for_gem(puma)
|
@@ -298,7 +311,7 @@ module Puma
|
|
298
311
|
return
|
299
312
|
end
|
300
313
|
|
301
|
-
|
314
|
+
dirs = files_to_require_after_prune
|
302
315
|
|
303
316
|
log '* Pruning Bundler environment'
|
304
317
|
home = ENV['GEM_HOME']
|
@@ -307,13 +320,37 @@ module Puma
|
|
307
320
|
ENV['GEM_HOME'] = home
|
308
321
|
ENV['BUNDLE_GEMFILE'] = bundle_gemfile
|
309
322
|
ENV['PUMA_BUNDLER_PRUNED'] = '1'
|
310
|
-
args = [Gem.ruby, puma_wild_location, '-I', dirs.join(':')
|
323
|
+
args = [Gem.ruby, puma_wild_location, '-I', dirs.join(':')] + @original_argv
|
311
324
|
# Ruby 2.0+ defaults to true which breaks socket activation
|
312
325
|
args += [{:close_others => false}]
|
313
326
|
Kernel.exec(*args)
|
314
327
|
end
|
315
328
|
end
|
316
329
|
|
330
|
+
#
|
331
|
+
# Puma's systemd integration allows Puma to inform systemd:
|
332
|
+
# 1. when it has successfully started
|
333
|
+
# 2. when it is starting shutdown
|
334
|
+
# 3. periodically for a liveness check with a watchdog thread
|
335
|
+
#
|
336
|
+
|
337
|
+
def integrate_with_systemd
|
338
|
+
return unless ENV["NOTIFY_SOCKET"]
|
339
|
+
|
340
|
+
begin
|
341
|
+
require 'puma/systemd'
|
342
|
+
rescue LoadError
|
343
|
+
log "Systemd integration failed. It looks like you're trying to use systemd notify but don't have sd_notify gem installed"
|
344
|
+
return
|
345
|
+
end
|
346
|
+
|
347
|
+
log "* Enabling systemd notification integration"
|
348
|
+
|
349
|
+
systemd = Systemd.new(@events)
|
350
|
+
systemd.hook_events
|
351
|
+
systemd.start_watchdog
|
352
|
+
end
|
353
|
+
|
317
354
|
def spec_for_gem(gem_name)
|
318
355
|
Bundler.rubygems.loaded_specs(gem_name)
|
319
356
|
end
|
@@ -336,6 +373,7 @@ module Puma
|
|
336
373
|
end
|
337
374
|
|
338
375
|
def graceful_stop
|
376
|
+
@events.fire_on_stopped!
|
339
377
|
@runner.stop_blocked
|
340
378
|
log "=== puma shutdown: #{Time.now} ==="
|
341
379
|
log "- Goodbye!"
|
@@ -345,6 +383,7 @@ module Puma
|
|
345
383
|
Process.respond_to?(:setproctitle) ? Process.setproctitle(title) : $0 = title
|
346
384
|
end
|
347
385
|
|
386
|
+
# @!attribute [r] title
|
348
387
|
def title
|
349
388
|
buffer = "puma #{Puma::Const::VERSION} (#{@options[:binds].join(',')})"
|
350
389
|
buffer += " [#{@options[:tag]}]" if @options[:tag] && !@options[:tag].empty?
|
@@ -356,6 +395,7 @@ module Puma
|
|
356
395
|
ENV['RACK_ENV'] = environment
|
357
396
|
end
|
358
397
|
|
398
|
+
# @!attribute [r] environment
|
359
399
|
def environment
|
360
400
|
@environment
|
361
401
|
end
|
@@ -489,5 +529,14 @@ module Puma
|
|
489
529
|
Bundler.with_unbundled_env { yield }
|
490
530
|
end
|
491
531
|
end
|
532
|
+
|
533
|
+
def log_config
|
534
|
+
log "Configuration:"
|
535
|
+
|
536
|
+
@config.final_options
|
537
|
+
.each { |config_key, value| log "- #{config_key}: #{value}" }
|
538
|
+
|
539
|
+
log "\n"
|
540
|
+
end
|
492
541
|
end
|
493
542
|
end
|