123456789_123456789_123456789_123456789_123456789_

Class: Rack::CommonLogger

Relationships & Source Files
Inherits: Object
Defined in: lib/rack/common_logger.rb

Overview

CommonLogger forwards every request to the given app, and logs a line in the Apache common log format to the configured logger.

Constant Summary

Class Method Summary

Instance Method Summary

Constructor Details

.new(app, logger = nil) ⇒ CommonLogger

logger can be any object that supports the write or << methods, which includes the standard library Logger. These methods are called with a single string argument, the log message. If logger is nil, CommonLogger will fall back env['rack.errors'].

[ GitHub ]

  
# File 'lib/rack/common_logger.rb', line 29

def initialize(app, logger = nil)
  @app = app
  @logger = logger
end

Instance Method Details

#call(env)

Log all requests in common_log format after a response has been returned. Note that if the app raises an exception, the request will not be logged, so if exception handling middleware are used, they should be loaded after this middleware. Additionally, because the logging happens after the request body has been fully sent, any exceptions raised during the sending of the response body will cause the request not to be logged.

[ GitHub ]

  
# File 'lib/rack/common_logger.rb', line 41

def call(env)
  began_at = Utils.clock_time
  status, headers, body = response = @app.call(env)

  response[2] = BodyProxy.new(body) { log(env, status, headers, began_at) }
  response
end

#extract_content_length(headers) (private)

Attempt to determine the content length for the response to include it in the logged data.

[ GitHub ]

  
# File 'lib/rack/common_logger.rb', line 83

def extract_content_length(headers)
  value = headers[CONTENT_LENGTH]
  !value || value.to_s == '0' ? '-' : value
end

#log(env, status, response_headers, began_at) (private)

Log the request to the configured logger.

[ GitHub ]

  
# File 'lib/rack/common_logger.rb', line 52

def log(env, status, response_headers, began_at)
  request = Rack::Request.new(env)
  length = extract_content_length(response_headers)

  msg = sprintf(FORMAT,
    request.ip || "-",
    request.get_header("REMOTE_USER") || "-",
    Time.now.strftime("%d/%b/%Y:%H:%M:%S %z"),
    request.request_method,
    request.script_name,
    request.path_info,
    request.query_string.empty? ? "" : "?#{request.query_string}",
    request.get_header(SERVER_PROTOCOL),
    status.to_s[0..3],
    length,
    Utils.clock_time - began_at)

  msg.gsub!(/[^[:print:]\n]/) { |c| sprintf("\\x%x", c.ord) }

  logger = @logger || request.get_header(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