blob: 572ef63abd26b625cdeff378509c9f3092b0cccc [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership. The
# ASF licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
require_relative 'body_proxy'
# This module is based on Rack::CommonLogger[1]
# Copyright (C) 2007, 2008, 2009, 2010 Christian Neukirchen <purl.org/net/chneukirchen>
#
# [1] https://github.com/rack/rack/blob/master/lib/rack/commonlogger.rb
module Rack
# Rack::CommonLogger forwards every request to an +app+ given, and
# logs a line in the Apache common log format to the +logger+, or
# rack.errors by default.
class DeltacloudLogger
class << self
def log_path(path=nil)
@log_file ||= path
end
def verbose?
@verbose
end
def verbose(v=nil)
@verbose ||= v
end
def setup(path, be_verbose=false)
verbose(be_verbose)
return self if path.nil?
dir = ::File.dirname(path)
if ::File.exists?(dir) and ::File.writable?(dir)
log_path(path)
else
warn "Warning: The log directory (#{dir}) is not writeable."
end
self
end
def logger
@logger ||= ::Logger.new(log_path || $stdout)
end
[:error, :warn, :info].each do |method_name|
define_method method_name do |msg, &block|
logger.send(method_name, msg, &block)
end
end
end
# Common Log Format: http://httpd.apache.org/docs/1.3/logs.html#common
# lilith.local - - [07/Aug/2006 23:58:02] "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}
VERBOSE_FORMAT = %{%s - %s [%s] "%s %s%s%s %s" %s %s %d %s %0.4f\n}
# If Deltacloud is started with the -L/--log option then
# we set logger to this file, otherwise use the default
# Sinatra logger facility
#
def initialize(app, logger=nil)
@app = app
if self.class.log_path
@logger = self.class.logger
else
@logger = logger
end
end
def call(env)
began_at = Time.now
status, header, body = @app.call(env)
header = Utils::HeaderHash.new(header)
body = BodyProxy.new(body) do
self.class.verbose? ? verbose_log(env, status, header, began_at) : log(env, status, header, began_at)
end
[status, header, body]
end
private
def verbose_log(env, status, header, began_at)
now = Time.now
length = extract_content_length(header)
params = env['rack.request.form_hash'].nil? ? '' : ' '+env['rack.request.form_hash'].to_json
logger = @logger || env['rack.errors']
logger_method = logger.respond_to?(:info) ? :info : :puts
logger.send logger_method, VERBOSE_FORMAT % [
env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
env["REMOTE_USER"] || "-",
now.strftime("%d/%b/%Y %H:%M:%S"),
env["REQUEST_METHOD"],
env["PATH_INFO"],
env["QUERY_STRING"].empty? ? '' : "?"+env["QUERY_STRING"],
params,
env["HTTP_VERSION"],
env['HTTP_X_DELTACLOUD_DRIVER'] || ENV['API_DRIVER'] || 'mock',
env['HTTP_X_DELTACLOUD_PROVIDER'] || ENV['API_PROVIDER'] || '-',
status.to_s[0..3],
length,
now - began_at ]
end
def log(env, status, header, began_at)
now = Time.now
length = extract_content_length(header)
logger = @logger || env['rack.errors']
logger_method = logger.respond_to?(:info) ? :info : :puts
logger.send logger_method, FORMAT % [
env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
env["REMOTE_USER"] || "-",
now.strftime("%d/%b/%Y %H:%M:%S"),
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 ]
end
def extract_content_length(headers)
value = headers['Content-Length'] or return '-'
value.to_s == '0' ? '-' : value
end
end
end