commonlogger.rb 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. require 'rack/body_proxy'
  2. module Rack
  3. # Rack::CommonLogger forwards every request to an +app+ given, and
  4. # logs a line in the Apache common log format to the +logger+, or
  5. # rack.errors by default.
  6. class CommonLogger
  7. # Common Log Format: http://httpd.apache.org/docs/1.3/logs.html#common
  8. # lilith.local - - [07/Aug/2006 23:58:02] "GET / HTTP/1.1" 500 -
  9. # %{%s - %s [%s] "%s %s%s %s" %d %s\n} %
  10. FORMAT = %{%s - %s [%s] "%s %s%s %s" %d %s %0.4f\n}
  11. def initialize(app, logger=nil)
  12. @app = app
  13. @logger = logger
  14. end
  15. def call(env)
  16. began_at = Time.now
  17. status, header, body = @app.call(env)
  18. header = Utils::HeaderHash.new(header)
  19. body = BodyProxy.new(body) { log(env, status, header, began_at) }
  20. [status, header, body]
  21. end
  22. private
  23. def log(env, status, header, began_at)
  24. now = Time.now
  25. length = extract_content_length(header)
  26. logger = @logger || env['rack.errors']
  27. logger.write FORMAT % [
  28. env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
  29. env["REMOTE_USER"] || "-",
  30. now.strftime("%d/%b/%Y %H:%M:%S"),
  31. env["REQUEST_METHOD"],
  32. env["PATH_INFO"],
  33. env["QUERY_STRING"].empty? ? "" : "?"+env["QUERY_STRING"],
  34. env["HTTP_VERSION"],
  35. status.to_s[0..3],
  36. length,
  37. now - began_at ]
  38. end
  39. def extract_content_length(headers)
  40. value = headers['Content-Length'] or return '-'
  41. value.to_s == '0' ? '-' : value
  42. end
  43. end
  44. end