# frozen_string_literal: truemodulePuma# Rack::CommonLogger forwards every request to the given +app+, and# logs a line in the# {Apache common log format}[https://httpd.apache.org/docs/2.4/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)classCommonLogger# Common Log Format: https://httpd.apache.org/docs/2.4/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}HIJACK_FORMAT=%{%s - %s [%s] "%s %s%s %s" HIJACKED -1 %0.4f\n}LOG_TIME_FORMAT='%d/%b/%Y:%H:%M:%S %z'CONTENT_LENGTH='Content-Length'# should be lower case from app,# Util::HeaderHash allows mixedHTTP_VERSION=Const::HTTP_VERSIONHTTP_X_FORWARDED_FOR=Const::HTTP_X_FORWARDED_FORPATH_INFO=Const::PATH_INFOQUERY_STRING=Const::QUERY_STRINGREMOTE_ADDR=Const::REMOTE_ADDRREMOTE_USER='REMOTE_USER'REQUEST_METHOD=Const::REQUEST_METHODdefinitialize(app,logger=nil)@app=app@logger=loggerenddefcall(env)began_at=Time.nowstatus,header,body=@app.call(env)header=Util::HeaderHash.new(header)# If we've been hijacked, then output a special lineifenv['rack.hijack_io']log_hijacking(env,'HIJACK',header,began_at)elseary=env['rack.after_reply']ary<<lambda{log(env,status,header,began_at)}end[status,header,body]endprivatedeflog_hijacking(env,status,header,began_at)now=Time.nowmsg=HIJACK_FORMAT%[env[HTTP_X_FORWARDED_FOR]||env[REMOTE_ADDR]||"-",env[REMOTE_USER]||"-",now.strftime(LOG_TIME_FORMAT),env[REQUEST_METHOD],env[PATH_INFO],env[QUERY_STRING].empty??"":"?#{env[QUERY_STRING]}",env[HTTP_VERSION],now-began_at]write(msg)enddeflog(env,status,header,began_at)now=Time.nowlength=extract_content_length(header)msg=FORMAT%[env[HTTP_X_FORWARDED_FOR]||env[REMOTE_ADDR]||"-",env[REMOTE_USER]||"-",now.strftime(LOG_TIME_FORMAT),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]write(msg)enddefwrite(msg)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 formattingiflogger.respond_to?(:write)logger.write(msg)elselogger<<msgendenddefextract_content_length(headers)value=headers[CONTENT_LENGTH]orreturn'-'value.to_s=='0'?'-':valueendendend