puma 5.6.4 → 6.4.2

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.

Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +372 -6
  3. data/LICENSE +0 -0
  4. data/README.md +79 -29
  5. data/bin/puma-wild +1 -1
  6. data/docs/architecture.md +0 -0
  7. data/docs/compile_options.md +34 -0
  8. data/docs/deployment.md +0 -0
  9. data/docs/fork_worker.md +1 -3
  10. data/docs/images/puma-connection-flow-no-reactor.png +0 -0
  11. data/docs/images/puma-connection-flow.png +0 -0
  12. data/docs/images/puma-general-arch.png +0 -0
  13. data/docs/jungle/README.md +0 -0
  14. data/docs/jungle/rc.d/README.md +0 -0
  15. data/docs/jungle/rc.d/puma.conf +0 -0
  16. data/docs/kubernetes.md +12 -0
  17. data/docs/nginx.md +1 -1
  18. data/docs/plugins.md +0 -0
  19. data/docs/rails_dev_mode.md +0 -0
  20. data/docs/restart.md +1 -0
  21. data/docs/signals.md +0 -0
  22. data/docs/stats.md +0 -0
  23. data/docs/systemd.md +3 -6
  24. data/docs/testing_benchmarks_local_files.md +150 -0
  25. data/docs/testing_test_rackup_ci_files.md +36 -0
  26. data/ext/puma_http11/PumaHttp11Service.java +0 -0
  27. data/ext/puma_http11/ext_help.h +0 -0
  28. data/ext/puma_http11/extconf.rb +22 -10
  29. data/ext/puma_http11/http11_parser.c +1 -1
  30. data/ext/puma_http11/http11_parser.h +1 -1
  31. data/ext/puma_http11/http11_parser.java.rl +2 -2
  32. data/ext/puma_http11/http11_parser.rl +2 -2
  33. data/ext/puma_http11/http11_parser_common.rl +2 -2
  34. data/ext/puma_http11/mini_ssl.c +153 -27
  35. data/ext/puma_http11/no_ssl/PumaHttp11Service.java +0 -0
  36. data/ext/puma_http11/org/jruby/puma/Http11.java +3 -3
  37. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +1 -1
  38. data/ext/puma_http11/org/jruby/puma/MiniSSL.java +167 -65
  39. data/ext/puma_http11/puma_http11.c +17 -9
  40. data/lib/puma/app/status.rb +7 -4
  41. data/lib/puma/binder.rb +51 -54
  42. data/lib/puma/cli.rb +16 -18
  43. data/lib/puma/client.rb +100 -26
  44. data/lib/puma/cluster/worker.rb +18 -11
  45. data/lib/puma/cluster/worker_handle.rb +4 -1
  46. data/lib/puma/cluster.rb +102 -40
  47. data/lib/puma/commonlogger.rb +21 -14
  48. data/lib/puma/configuration.rb +77 -59
  49. data/lib/puma/const.rb +129 -92
  50. data/lib/puma/control_cli.rb +33 -23
  51. data/lib/puma/detect.rb +7 -4
  52. data/lib/puma/dsl.rb +251 -53
  53. data/lib/puma/error_logger.rb +18 -9
  54. data/lib/puma/events.rb +6 -126
  55. data/lib/puma/io_buffer.rb +39 -4
  56. data/lib/puma/jruby_restart.rb +2 -1
  57. data/lib/puma/json_serialization.rb +0 -0
  58. data/lib/puma/launcher/bundle_pruner.rb +104 -0
  59. data/lib/puma/launcher.rb +113 -175
  60. data/lib/puma/log_writer.rb +147 -0
  61. data/lib/puma/minissl/context_builder.rb +26 -12
  62. data/lib/puma/minissl.rb +113 -15
  63. data/lib/puma/null_io.rb +21 -2
  64. data/lib/puma/plugin/systemd.rb +90 -0
  65. data/lib/puma/plugin/tmp_restart.rb +1 -1
  66. data/lib/puma/plugin.rb +0 -0
  67. data/lib/puma/rack/builder.rb +6 -6
  68. data/lib/puma/rack/urlmap.rb +1 -1
  69. data/lib/puma/rack_default.rb +19 -4
  70. data/lib/puma/reactor.rb +19 -10
  71. data/lib/puma/request.rb +365 -166
  72. data/lib/puma/runner.rb +56 -20
  73. data/lib/puma/sd_notify.rb +149 -0
  74. data/lib/puma/server.rb +137 -87
  75. data/lib/puma/single.rb +13 -11
  76. data/lib/puma/state_file.rb +4 -6
  77. data/lib/puma/thread_pool.rb +57 -19
  78. data/lib/puma/util.rb +12 -14
  79. data/lib/puma.rb +12 -11
  80. data/lib/rack/handler/puma.rb +113 -86
  81. data/tools/Dockerfile +2 -2
  82. data/tools/trickletest.rb +0 -0
  83. metadata +11 -6
  84. data/lib/puma/queue_close.rb +0 -26
  85. data/lib/puma/systemd.rb +0 -46
@@ -2,27 +2,29 @@
2
2
 
3
3
  module Puma
4
4
  class Cluster < Puma::Runner
5
+ #—————————————————————— DO NOT USE — this class is for internal use only ———
6
+
7
+
5
8
  # This class is instantiated by the `Puma::Cluster` and represents a single
6
9
  # worker process.
7
10
  #
8
11
  # At the core of this class is running an instance of `Puma::Server` which
9
12
  # gets created via the `start_server` method from the `Puma::Runner` class
10
13
  # that this inherits from.
11
- class Worker < Puma::Runner
14
+ class Worker < Puma::Runner # :nodoc:
12
15
  attr_reader :index, :master
13
16
 
14
17
  def initialize(index:, master:, launcher:, pipes:, server: nil)
15
- super launcher, launcher.events
18
+ super(launcher)
16
19
 
17
20
  @index = index
18
21
  @master = master
19
- @launcher = launcher
20
- @options = launcher.options
21
22
  @check_pipe = pipes[:check_pipe]
22
23
  @worker_write = pipes[:worker_write]
23
24
  @fork_pipe = pipes[:fork_pipe]
24
25
  @wakeup = pipes[:wakeup]
25
26
  @server = server
27
+ @hook_data = {}
26
28
  end
27
29
 
28
30
  def run
@@ -52,13 +54,14 @@ module Puma
52
54
 
53
55
  # Invoke any worker boot hooks so they can get
54
56
  # things in shape before booting the app.
55
- @launcher.config.run_hooks :before_worker_boot, index, @launcher.events
57
+ @config.run_hooks(:before_worker_boot, index, @log_writer, @hook_data)
56
58
 
57
59
  begin
58
60
  server = @server ||= start_server
59
61
  rescue Exception => e
60
62
  log "! Unable to start worker"
61
- log e.backtrace[0]
63
+ log e
64
+ log e.backtrace.join("\n ")
62
65
  exit 1
63
66
  end
64
67
 
@@ -83,8 +86,7 @@ module Puma
83
86
  if restart_server.length > 0
84
87
  restart_server.clear
85
88
  server.begin_restart(true)
86
- @launcher.config.run_hooks :before_refork, nil, @launcher.events
87
- Puma::Util.nakayoshi_gc @events if @options[:nakayoshi_fork]
89
+ @config.run_hooks(:before_refork, nil, @log_writer, @hook_data)
88
90
  end
89
91
  elsif idx == 0 # restart server
90
92
  restart_server << true << false
@@ -113,6 +115,11 @@ module Puma
113
115
 
114
116
  while restart_server.pop
115
117
  server_thread = server.run
118
+
119
+ if @log_writer.debug? && index == 0
120
+ debug_loaded_extensions "Loaded Extensions - worker 0:"
121
+ end
122
+
116
123
  stat_thread ||= Thread.new(@worker_write) do |io|
117
124
  Puma.set_thread_name "stat pld"
118
125
  base_payload = "p#{Process.pid}"
@@ -138,7 +145,7 @@ module Puma
138
145
 
139
146
  # Invoke any worker shutdown hooks so they can prevent the worker
140
147
  # exiting until any background operations are completed
141
- @launcher.config.run_hooks :before_worker_shutdown, index, @launcher.events
148
+ @config.run_hooks(:before_worker_shutdown, index, @log_writer, @hook_data)
142
149
  ensure
143
150
  @worker_write << "t#{Process.pid}\n" rescue nil
144
151
  @worker_write.close
@@ -147,7 +154,7 @@ module Puma
147
154
  private
148
155
 
149
156
  def spawn_worker(idx)
150
- @launcher.config.run_hooks :before_worker_fork, idx, @launcher.events
157
+ @config.run_hooks(:before_worker_fork, idx, @log_writer, @hook_data)
151
158
 
152
159
  pid = fork do
153
160
  new_worker = Worker.new index: idx,
@@ -165,7 +172,7 @@ module Puma
165
172
  exit! 1
166
173
  end
167
174
 
168
- @launcher.config.run_hooks :after_worker_fork, idx, @launcher.events
175
+ @config.run_hooks(:after_worker_fork, idx, @log_writer, @hook_data)
169
176
  pid
170
177
  end
171
178
  end
@@ -2,12 +2,15 @@
2
2
 
3
3
  module Puma
4
4
  class Cluster < Runner
5
+ #—————————————————————— DO NOT USE — this class is for internal use only ———
6
+
7
+
5
8
  # This class represents a worker process from the perspective of the puma
6
9
  # master process. It contains information about the process and its health
7
10
  # and it exposes methods to control the process via IPC. It does not
8
11
  # include the actual logic executed by the worker process itself. For that,
9
12
  # see Puma::Cluster::Worker.
10
- class WorkerHandle
13
+ class WorkerHandle # :nodoc:
11
14
  def initialize(idx, pid, phase, options)
12
15
  @index = idx
13
16
  @pid = pid
data/lib/puma/cluster.rb CHANGED
@@ -1,12 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'puma/runner'
4
- require 'puma/util'
5
- require 'puma/plugin'
6
- require 'puma/cluster/worker_handle'
7
- require 'puma/cluster/worker'
8
-
9
- require 'time'
3
+ require_relative 'runner'
4
+ require_relative 'util'
5
+ require_relative 'plugin'
6
+ require_relative 'cluster/worker_handle'
7
+ require_relative 'cluster/worker'
10
8
 
11
9
  module Puma
12
10
  # This class is instantiated by the `Puma::Launcher` and used
@@ -17,8 +15,8 @@ module Puma
17
15
  # via the `spawn_workers` method call. Each worker will have it's own
18
16
  # instance of a `Puma::Server`.
19
17
  class Cluster < Runner
20
- def initialize(cli, events)
21
- super cli, events
18
+ def initialize(launcher)
19
+ super(launcher)
22
20
 
23
21
  @phase = 0
24
22
  @workers = []
@@ -27,6 +25,10 @@ module Puma
27
25
  @phased_restart = false
28
26
  end
29
27
 
28
+ # Returns the list of cluster worker handles.
29
+ # @return [Array<Puma::Cluster::WorkerHandle>]
30
+ attr_reader :workers
31
+
30
32
  def stop_workers
31
33
  log "- Gracefully shutting down workers..."
32
34
  @workers.each { |x| x.term }
@@ -83,16 +85,14 @@ module Puma
83
85
  @workers << WorkerHandle.new(idx, pid, @phase, @options)
84
86
  end
85
87
 
86
- if @options[:fork_worker] &&
87
- @workers.all? {|x| x.phase == @phase}
88
-
88
+ if @options[:fork_worker] && all_workers_in_phase?
89
89
  @fork_writer << "0\n"
90
90
  end
91
91
  end
92
92
 
93
93
  # @version 5.0.0
94
94
  def spawn_worker(idx, master)
95
- @launcher.config.run_hooks :before_worker_fork, idx, @launcher.events
95
+ @config.run_hooks(:before_worker_fork, idx, @log_writer)
96
96
 
97
97
  pid = fork { worker(idx, master) }
98
98
  if !pid
@@ -101,7 +101,7 @@ module Puma
101
101
  exit! 1
102
102
  end
103
103
 
104
- @launcher.config.run_hooks :after_worker_fork, idx, @launcher.events
104
+ @config.run_hooks(:after_worker_fork, idx, @log_writer)
105
105
  pid
106
106
  end
107
107
 
@@ -146,10 +146,22 @@ module Puma
146
146
  idx
147
147
  end
148
148
 
149
+ def worker_at(idx)
150
+ @workers.find { |w| w.index == idx }
151
+ end
152
+
149
153
  def all_workers_booted?
150
154
  @workers.count { |w| !w.booted? } == 0
151
155
  end
152
156
 
157
+ def all_workers_in_phase?
158
+ @workers.all? { |w| w.phase == @phase }
159
+ end
160
+
161
+ def all_workers_idle_timed_out?
162
+ (@workers.map(&:pid) - idle_timed_out_worker_pids).empty?
163
+ end
164
+
153
165
  def check_workers
154
166
  return if @next_check >= Time.now
155
167
 
@@ -176,10 +188,10 @@ module Puma
176
188
  end
177
189
  end
178
190
 
179
- @next_check = [
180
- @workers.reject(&:term?).map(&:ping_timeout).min,
181
- @next_check
182
- ].compact.min
191
+ t = @workers.reject(&:term?)
192
+ t.map!(&:ping_timeout)
193
+
194
+ @next_check = [t.min, @next_check].compact.min
183
195
  end
184
196
 
185
197
  def worker(index, master)
@@ -209,8 +221,8 @@ module Puma
209
221
  stop
210
222
  end
211
223
 
212
- def phased_restart
213
- return false if @options[:preload_app]
224
+ def phased_restart(refork = false)
225
+ return false if @options[:preload_app] && !refork
214
226
 
215
227
  @phased_restart = true
216
228
  wakeup!
@@ -226,7 +238,7 @@ module Puma
226
238
  def stop_blocked
227
239
  @status = :stop if @status == :run
228
240
  wakeup!
229
- @control.stop(true) if @control
241
+ @control&.stop true
230
242
  Process.waitall
231
243
  end
232
244
 
@@ -248,24 +260,24 @@ module Puma
248
260
  old_worker_count = @workers.count { |w| w.phase != @phase }
249
261
  worker_status = @workers.map do |w|
250
262
  {
251
- started_at: w.started_at.utc.iso8601,
263
+ started_at: utc_iso8601(w.started_at),
252
264
  pid: w.pid,
253
265
  index: w.index,
254
266
  phase: w.phase,
255
267
  booted: w.booted?,
256
- last_checkin: w.last_checkin.utc.iso8601,
268
+ last_checkin: utc_iso8601(w.last_checkin),
257
269
  last_status: w.last_status,
258
270
  }
259
271
  end
260
272
 
261
273
  {
262
- started_at: @started_at.utc.iso8601,
274
+ started_at: utc_iso8601(@started_at),
263
275
  workers: @workers.size,
264
276
  phase: @phase,
265
277
  booted_workers: worker_status.count { |w| w[:booted] },
266
278
  old_workers: old_worker_count,
267
279
  worker_status: worker_status,
268
- }
280
+ }.merge(super)
269
281
  end
270
282
 
271
283
  def preload?
@@ -274,10 +286,10 @@ module Puma
274
286
 
275
287
  # @version 5.0.0
276
288
  def fork_worker!
277
- if (worker = @workers.find { |w| w.index == 0 })
289
+ if (worker = worker_at 0)
278
290
  worker.phase += 1
279
291
  end
280
- phased_restart
292
+ phased_restart(true)
281
293
  end
282
294
 
283
295
  # We do this in a separate method to keep the lambda scope
@@ -290,7 +302,7 @@ module Puma
290
302
 
291
303
  # Auto-fork after the specified number of requests.
292
304
  if (fork_requests = @options[:fork_worker].to_i) > 0
293
- @launcher.events.register(:ping!) do |w|
305
+ @events.register(:ping!) do |w|
294
306
  fork_worker! if w.index == 0 &&
295
307
  w.phase == 0 &&
296
308
  w.last_status[:requests_count] >= fork_requests
@@ -336,6 +348,8 @@ module Puma
336
348
  def run
337
349
  @status = :run
338
350
 
351
+ @idle_workers = {}
352
+
339
353
  output_header "cluster"
340
354
 
341
355
  # This is aligned with the output from Runner, see Runner#output_header
@@ -372,12 +386,12 @@ module Puma
372
386
  else
373
387
  log "* Restarts: (\u2714) hot (\u2714) phased"
374
388
 
375
- unless @launcher.config.app_configured?
389
+ unless @config.app_configured?
376
390
  error "No application configured, nothing to run"
377
391
  exit 1
378
392
  end
379
393
 
380
- @launcher.binder.parse @options[:binds], self
394
+ @launcher.binder.parse @options[:binds]
381
395
  end
382
396
 
383
397
  read, @wakeup = Puma::Util.pipe
@@ -409,8 +423,9 @@ module Puma
409
423
 
410
424
  @master_read, @worker_write = read, @wakeup
411
425
 
412
- @launcher.config.run_hooks :before_fork, nil, @launcher.events
413
- Puma::Util.nakayoshi_gc @events if @options[:nakayoshi_fork]
426
+ @options[:worker_write] = @worker_write
427
+
428
+ @config.run_hooks(:before_fork, nil, @log_writer)
414
429
 
415
430
  spawn_workers
416
431
 
@@ -425,6 +440,11 @@ module Puma
425
440
 
426
441
  while @status == :run
427
442
  begin
443
+ if all_workers_idle_timed_out?
444
+ log "- All workers reached idle timeout"
445
+ break
446
+ end
447
+
428
448
  if @phased_restart
429
449
  start_phased_restart
430
450
  @phased_restart = false
@@ -445,7 +465,7 @@ module Puma
445
465
 
446
466
  if req == "b" || req == "f"
447
467
  pid, idx = result.split(':').map(&:to_i)
448
- w = @workers.find {|x| x.index == idx}
468
+ w = worker_at idx
449
469
  w.pid = pid if w.pid.nil?
450
470
  end
451
471
 
@@ -462,22 +482,37 @@ module Puma
462
482
  when "t"
463
483
  w.term unless w.term?
464
484
  when "p"
465
- w.ping!(result.sub(/^\d+/,'').chomp)
466
- @launcher.events.fire(:ping!, w)
485
+ status = result.sub(/^\d+/,'').chomp
486
+ w.ping!(status)
487
+ @events.fire(:ping!, w)
488
+
489
+ if in_phased_restart && workers_not_booted.positive? && w0 = worker_at(0)
490
+ w0.ping!(status)
491
+ @events.fire(:ping!, w0)
492
+ end
493
+
467
494
  if !booted && @workers.none? {|worker| worker.last_status.empty?}
468
- @launcher.events.fire_on_booted!
495
+ @events.fire_on_booted!
496
+ debug_loaded_extensions("Loaded Extensions - master:") if @log_writer.debug?
469
497
  booted = true
470
498
  end
499
+ when "i"
500
+ if @idle_workers[pid]
501
+ @idle_workers.delete pid
502
+ else
503
+ @idle_workers[pid] = true
504
+ end
471
505
  end
472
506
  else
473
507
  log "! Out-of-sync worker list, no #{pid} worker"
474
508
  end
475
509
  end
510
+
476
511
  if in_phased_restart && workers_not_booted.zero?
477
512
  @events.fire_on_booted!
513
+ debug_loaded_extensions("Loaded Extensions - master:") if @log_writer.debug?
478
514
  in_phased_restart = false
479
515
  end
480
-
481
516
  rescue Interrupt
482
517
  @status = :stop
483
518
  end
@@ -506,10 +541,28 @@ module Puma
506
541
  # loops thru @workers, removing workers that exited, and calling
507
542
  # `#term` if needed
508
543
  def wait_workers
544
+ # Reap all children, known workers or otherwise.
545
+ # If puma has PID 1, as it's common in containerized environments,
546
+ # then it's responsible for reaping orphaned processes, so we must reap
547
+ # all our dead children, regardless of whether they are workers we spawned
548
+ # or some reattached processes.
549
+ reaped_children = {}
550
+ loop do
551
+ begin
552
+ pid, status = Process.wait2(-1, Process::WNOHANG)
553
+ break unless pid
554
+ reaped_children[pid] = status
555
+ rescue Errno::ECHILD
556
+ break
557
+ end
558
+ end
559
+
509
560
  @workers.reject! do |w|
510
561
  next false if w.pid.nil?
511
562
  begin
512
- if Process.wait(w.pid, Process::WNOHANG)
563
+ # When `fork_worker` is enabled, some worker may not be direct children, but grand children.
564
+ # Because of this they won't be reaped by `Process.wait2(-1)`, so we need to check them individually)
565
+ if reaped_children.delete(w.pid) || (@options[:fork_worker] && Process.wait(w.pid, Process::WNOHANG))
513
566
  true
514
567
  else
515
568
  w.term if w.term?
@@ -526,6 +579,11 @@ module Puma
526
579
  end
527
580
  end
528
581
  end
582
+
583
+ # Log unknown children
584
+ reaped_children.each do |pid, status|
585
+ log "! reaped unknown child process pid=#{pid} status=#{status}"
586
+ end
529
587
  end
530
588
 
531
589
  # @version 5.0.0
@@ -533,14 +591,18 @@ module Puma
533
591
  @workers.each do |w|
534
592
  if !w.term? && w.ping_timeout <= Time.now
535
593
  details = if w.booted?
536
- "(worker failed to check in within #{@options[:worker_timeout]} seconds)"
594
+ "(Worker #{w.index} failed to check in within #{@options[:worker_timeout]} seconds)"
537
595
  else
538
- "(worker failed to boot within #{@options[:worker_boot_timeout]} seconds)"
596
+ "(Worker #{w.index} failed to boot within #{@options[:worker_boot_timeout]} seconds)"
539
597
  end
540
598
  log "! Terminating timed out worker #{details}: #{w.pid}"
541
599
  w.kill
542
600
  end
543
601
  end
544
602
  end
603
+
604
+ def idle_timed_out_worker_pids
605
+ @idle_workers.keys
606
+ end
545
607
  end
546
608
  end
@@ -3,7 +3,7 @@
3
3
  module Puma
4
4
  # Rack::CommonLogger forwards every request to the given +app+, and
5
5
  # logs a line in the
6
- # {Apache common log format}[https://httpd.apache.org/docs/1.3/logs.html#common]
6
+ # {Apache common log format}[https://httpd.apache.org/docs/2.4/logs.html#common]
7
7
  # to the +logger+.
8
8
  #
9
9
  # If +logger+ is nil, CommonLogger will fall back +rack.errors+, which is
@@ -16,7 +16,7 @@ module Puma
16
16
  # (which is called without arguments in order to make the error appear for
17
17
  # sure)
18
18
  class CommonLogger
19
- # Common Log Format: https://httpd.apache.org/docs/1.3/logs.html#common
19
+ # Common Log Format: https://httpd.apache.org/docs/2.4/logs.html#common
20
20
  #
21
21
  # lilith.local - - [07/Aug/2006 23:58:02 -0400] "GET / HTTP/1.1" 500 -
22
22
  #
@@ -25,10 +25,17 @@ module Puma
25
25
 
26
26
  HIJACK_FORMAT = %{%s - %s [%s] "%s %s%s %s" HIJACKED -1 %0.4f\n}
27
27
 
28
- CONTENT_LENGTH = 'Content-Length'.freeze
29
- PATH_INFO = 'PATH_INFO'.freeze
30
- QUERY_STRING = 'QUERY_STRING'.freeze
31
- REQUEST_METHOD = 'REQUEST_METHOD'.freeze
28
+ LOG_TIME_FORMAT = '%d/%b/%Y:%H:%M:%S %z'
29
+
30
+ CONTENT_LENGTH = 'Content-Length' # should be lower case from app,
31
+ # Util::HeaderHash allows mixed
32
+ HTTP_VERSION = Const::HTTP_VERSION
33
+ HTTP_X_FORWARDED_FOR = Const::HTTP_X_FORWARDED_FOR
34
+ PATH_INFO = Const::PATH_INFO
35
+ QUERY_STRING = Const::QUERY_STRING
36
+ REMOTE_ADDR = Const::REMOTE_ADDR
37
+ REMOTE_USER = 'REMOTE_USER'
38
+ REQUEST_METHOD = Const::REQUEST_METHOD
32
39
 
33
40
  def initialize(app, logger=nil)
34
41
  @app = app
@@ -57,13 +64,13 @@ module Puma
57
64
  now = Time.now
58
65
 
59
66
  msg = HIJACK_FORMAT % [
60
- env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
61
- env["REMOTE_USER"] || "-",
62
- now.strftime("%d/%b/%Y %H:%M:%S"),
67
+ env[HTTP_X_FORWARDED_FOR] || env[REMOTE_ADDR] || "-",
68
+ env[REMOTE_USER] || "-",
69
+ now.strftime(LOG_TIME_FORMAT),
63
70
  env[REQUEST_METHOD],
64
71
  env[PATH_INFO],
65
72
  env[QUERY_STRING].empty? ? "" : "?#{env[QUERY_STRING]}",
66
- env["HTTP_VERSION"],
73
+ env[HTTP_VERSION],
67
74
  now - began_at ]
68
75
 
69
76
  write(msg)
@@ -74,13 +81,13 @@ module Puma
74
81
  length = extract_content_length(header)
75
82
 
76
83
  msg = FORMAT % [
77
- env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
78
- env["REMOTE_USER"] || "-",
79
- now.strftime("%d/%b/%Y:%H:%M:%S %z"),
84
+ env[HTTP_X_FORWARDED_FOR] || env[REMOTE_ADDR] || "-",
85
+ env[REMOTE_USER] || "-",
86
+ now.strftime(LOG_TIME_FORMAT),
80
87
  env[REQUEST_METHOD],
81
88
  env[PATH_INFO],
82
89
  env[QUERY_STRING].empty? ? "" : "?#{env[QUERY_STRING]}",
83
- env["HTTP_VERSION"],
90
+ env[HTTP_VERSION],
84
91
  status.to_s[0..3],
85
92
  length,
86
93
  now - began_at ]