# class Rack::CommonLogger

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

### Constants

FORMAT

  Common Log Format: 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} %

  The actual format is slightly different than the above due to the separation of SCRIPT_NAME and PATH_INFO, and because the elapsed time in seconds is included at the end.

### Public Class Methods

new(app, logger = nil) click to toggle source

`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']`.

    # File lib/rack/common_logger.rb, line 24
    def initialize(app, logger = nil)
      @app = app
      @logger = logger
    end

### Public Instance Methods

call(env) click to toggle source

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.

    # File lib/rack/common_logger.rb, line 36
    def call(env)
      began_at = Utils.clock_time
      status, headers, body = @app.call(env)
      headers = Utils::HeaderHash[headers]
      body = BodyProxy.new(body) { log(env, status, headers, began_at) }
      [status, headers, body]
    end

### Private Instance Methods

extract_content_length(headers) click to toggle source

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

    # File lib/rack/common_logger.rb, line 79
    def extract_content_length(headers)
      value = headers[CONTENT_LENGTH]
      !value || value.to_s == '0' ? '-' : value
    end

log(env, status, header, began_at) click to toggle source

Log the request to the configured logger.

    # File lib/rack/common_logger.rb, line 47
    def log(env, status, header, began_at)
      length = extract_content_length(header)

      msg = FORMAT % [
        env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
        env["REMOTE_USER"] || "-",
        Time.now.strftime("%d/%b/%Y:%H:%M:%S %z"),
        env[REQUEST_METHOD],
        env[SCRIPT_NAME],
        env[PATH_INFO],
        env[QUERY_STRING].empty? ? "" : "?#{env[QUERY_STRING]}",
        env[SERVER_PROTOCOL],
        status.to_s[0..3],
        length,
        Utils.clock_time - began_at ]

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

      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