mirror of
https://github.com/puma/puma.git
synced 2022-11-09 13:48:40 -05:00
537bc21593
Because frameworks like rails dependent on rack, if puma truly wants to be able to reload new code and thus new versions of rails, it has to be able to reload rack as well. Having a dependency on rack held by puma prevented that from happening and so that dependency has been removed.
107 lines
3.3 KiB
Ruby
107 lines
3.3 KiB
Ruby
module Puma
|
|
# Rack::CommonLogger forwards every request to the given +app+, and
|
|
# logs a line in the
|
|
# {Apache common log format}[http://httpd.apache.org/docs/1.3/logs.html#common]
|
|
# to the +logger+.
|
|
#
|
|
# If +logger+ is nil, CommonLogger will fall back +rack.errors+, which is
|
|
# an instance of Rack::NullLogger.
|
|
#
|
|
# +logger+ can be any class, including the standard library Logger, and is
|
|
# expected to have either +write+ or +<<+ method, which accepts the CommonLogger::FORMAT.
|
|
# According to the SPEC, the error stream must also respond to +puts+
|
|
# (which takes a single argument that responds to +to_s+), and +flush+
|
|
# (which is called without arguments in order to make the error appear for
|
|
# sure)
|
|
class CommonLogger
|
|
# Common Log Format: http://httpd.apache.org/docs/1.3/logs.html#common
|
|
#
|
|
# lilith.local - - [07/Aug/2006 23:58:02 -0400] "GET / HTTP/1.1" 500 -
|
|
#
|
|
# %{%s - %s [%s] "%s %s%s %s" %d %s\n} %
|
|
FORMAT = %{%s - %s [%s] "%s %s%s %s" %d %s %0.4f\n}
|
|
|
|
def initialize(app, logger=nil)
|
|
@app = app
|
|
@logger = logger
|
|
end
|
|
|
|
def call(env)
|
|
began_at = Time.now
|
|
status, header, body = @app.call(env)
|
|
header = Util::HeaderHash.new(header)
|
|
|
|
# If we've been hijacked, then output a special line
|
|
if env['rack.hijack_io']
|
|
log_hijacking(env, 'HIJACK', header, began_at)
|
|
else
|
|
ary = env['rack.after_reply']
|
|
ary << lambda { log(env, status, header, began_at) }
|
|
end
|
|
|
|
[status, header, body]
|
|
end
|
|
|
|
HIJACK_FORMAT = %{%s - %s [%s] "%s %s%s %s" HIJACKED -1 %0.4f\n}
|
|
|
|
private
|
|
|
|
def log_hijacking(env, status, header, began_at)
|
|
now = Time.now
|
|
|
|
logger = @logger || env['rack.errors']
|
|
logger.write HIJACK_FORMAT % [
|
|
env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
|
|
env["REMOTE_USER"] || "-",
|
|
now.strftime("%d/%b/%Y %H:%M:%S"),
|
|
env["REQUEST_METHOD"],
|
|
env["PATH_INFO"],
|
|
env["QUERY_STRING"].empty? ? "" : "?"+env["QUERY_STRING"],
|
|
env["HTTP_VERSION"],
|
|
now - began_at ]
|
|
end
|
|
|
|
PATH_INFO = 'PATH_INFO'.freeze
|
|
REQUEST_METHOD = 'REQUEST_METHOD'.freeze
|
|
SCRIPT_NAME = 'SCRIPT_NAME'.freeze
|
|
QUERY_STRING = 'QUERY_STRING'.freeze
|
|
CACHE_CONTROL = 'Cache-Control'.freeze
|
|
CONTENT_LENGTH = 'Content-Length'.freeze
|
|
CONTENT_TYPE = 'Content-Type'.freeze
|
|
|
|
GET = 'GET'.freeze
|
|
HEAD = 'HEAD'.freeze
|
|
|
|
|
|
def log(env, status, header, began_at)
|
|
now = Time.now
|
|
length = extract_content_length(header)
|
|
|
|
msg = FORMAT % [
|
|
env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
|
|
env["REMOTE_USER"] || "-",
|
|
now.strftime("%d/%b/%Y:%H:%M:%S %z"),
|
|
env[REQUEST_METHOD],
|
|
env[PATH_INFO],
|
|
env[QUERY_STRING].empty? ? "" : "?"+env[QUERY_STRING],
|
|
env["HTTP_VERSION"],
|
|
status.to_s[0..3],
|
|
length,
|
|
now - began_at ]
|
|
|
|
logger = @logger || env['rack.errors']
|
|
# Standard library logger doesn't support write but it supports << which actually
|
|
# calls to write on the log device without formatting
|
|
if logger.respond_to?(:write)
|
|
logger.write(msg)
|
|
else
|
|
logger << msg
|
|
end
|
|
end
|
|
|
|
def extract_content_length(headers)
|
|
value = headers[CONTENT_LENGTH] or return '-'
|
|
value.to_s == '0' ? '-' : value
|
|
end
|
|
end
|
|
end
|