class Racknga::AccessLogParser

Supported formats:

* combined (nginx's default format)
* combined (Apache's predefined format)
* combined_with_time_nginx (custom format with runtime)
* combined_with_time_apache (custom format with runtime)

Configurations:

* combined
  * nginx
    log_format combined '$remote_addr - $remote_user [$time_local]  '
                        '"$request" $status $body_bytes_sent '
                        '"$http_referer" "$http_user_agent"';
    access_log log/access.log combined
  * Apache
    CustomLog ${APACHE_LOG_DIR}/access.log combined

* combined_with_time_nginx
  * nginx
    log_format combined_with_time '$remote_addr - $remote_user '
                                  '[$time_local, $upstream_http_x_runtime, $request_time]  '
                                  '"$request" $status $body_bytes_sent '
                                  '"$http_referer" "$http_user_agent"';
    access_log log/access.log combined_with_time

* combined_with_time_apache
  * Apache
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\" %{X-Runtime}o %D" combined_with_time
    CustomLog ${APACHE_LOG_DIR}/access.log combined_with_time

Constants

BODY_BYTES_SENT
COMBINED_FORMAT
HTTP_REFERER
HTTP_USER_AGENT
REMOTE_ADDRESS
REMOTE_USER
REQUEST
REQUEST_TIME
RUNTIME
STATUS
TIME_LOCAL

Public Class Methods

new(line_reader) click to toggle source
# File lib/racknga/access_log_parser.rb, line 57
def initialize(line_reader)
  @line_reader = line_reader
end

Public Instance Methods

each() { |parse_line(line)| ... } click to toggle source
# File lib/racknga/access_log_parser.rb, line 61
def each
  @line_reader.each do |line|
    line.force_encoding("UTF-8")
    yield(parse_line(line)) if line.valid_encoding?
  end
end

Private Instance Methods

parse_line(line) click to toggle source
# File lib/racknga/access_log_parser.rb, line 90
def parse_line(line)
  case line
  when COMBINED_FORMAT
    last_match = Regexp.last_match
    options = {}
    options[:remote_address] = last_match[1]
    options[:remote_user] = last_match[2]
    options[:time_local] = parse_local_time(last_match[3])
    if last_match[4]
      if /\A(#{RUNTIME}), (#{REQUEST_TIME})\z/ =~ last_match[4]
        time_match = Regexp.last_match
        options[:runtime] = time_match[1]
        options[:request_time] = time_match[2]
      else
        message = "expected 'RUNTIME, REQUEST_TIME' time format: " +
                  "<#{last_match[4]}>: <#{line}>"
        raise FormatError.new(message)
      end
    end
    options[:request] = last_match[5]
    options[:status] = last_match[6].to_i
    options[:body_bytes_sent] = last_match[7]
    options[:http_referer] = last_match[8]
    options[:http_user_agent] = last_match[9]
    if last_match[10]
      if /\A(#{RUNTIME}) (#{REQUEST_TIME})\z/ =~ last_match[10]
        time_match = Regexp.last_match
        runtime = time_match[1]
        request_time = time_match[2]
        request_time = request_time.to_i * 0.000_001 if request_time
        options[:runtime] = runtime
        options[:request_time] = request_time
      else
        message = "expected 'RUNTIME REQUEST_TIME' time format: " +
                  "<#{last_match[10]}>: <#{line}>"
        raise FormatError.new(message)
      end
    end
    LogEntry.new(options)
  else
    raise FormatError.new("unsupported format log entry: <#{line}>")
  end
end
parse_local_time(token) click to toggle source
# File lib/racknga/access_log_parser.rb, line 134
def parse_local_time(token)
  day, month, year, hour, minute, second, _time_zone = token.split(/[\/: ]/)
  _ = _time_zone # FIXME: suppress a warning. :<
  Time.local(year, month, day, hour, minute, second)
end