1
0
mirror of https://github.com/ceph/ceph synced 2025-03-30 23:40:09 +00:00

mgr/dashboard: HTTP request logging

Signed-off-by: Ricardo Dias <rdias@suse.com>
This commit is contained in:
Ricardo Dias 2018-03-08 12:27:08 +00:00
parent 21146f9e4d
commit 2becfb78ce
No known key found for this signature in database
GPG Key ID: 74390C579BD37B68
2 changed files with 80 additions and 2 deletions
src/pybind/mgr/dashboard_v2

View File

@ -23,7 +23,7 @@ if 'COVERAGE_ENABLED' in os.environ:
from . import logger, mgr
from .controllers.auth import Auth
from .tools import load_controllers, json_error_page, SessionExpireAtBrowserCloseTool, \
NotificationQueue
NotificationQueue, RequestLoggingTool
from .settings import options_command_list, handle_option_command
@ -93,13 +93,15 @@ class Module(MgrModule):
# Initialize custom handlers.
cherrypy.tools.authenticate = cherrypy.Tool('before_handler', Auth.check_auth)
cherrypy.tools.session_expire_at_browser_close = SessionExpireAtBrowserCloseTool()
cherrypy.tools.request_logging = RequestLoggingTool()
# Apply the 'global' CherryPy configuration.
config = {
'engine.autoreload.on': False,
'server.socket_host': server_addr,
'server.socket_port': int(server_port),
'error_page.default': json_error_page
'error_page.default': json_error_page,
'tools.request_logging.on': True
}
cherrypy.config.update(config)

View File

@ -90,6 +90,82 @@ class BaseController(object):
}
class RequestLoggingTool(cherrypy.Tool):
def __init__(self):
cherrypy.Tool.__init__(self, 'before_handler', self.request_begin,
priority=95)
def _setup(self):
cherrypy.Tool._setup(self)
cherrypy.request.hooks.attach('on_end_request', self.request_end,
priority=5)
cherrypy.request.hooks.attach('after_error_response', self.request_error,
priority=5)
def _get_user(self):
if hasattr(cherrypy.serving, 'session'):
return cherrypy.session.get(Session.USERNAME)
return None
def request_begin(self):
req = cherrypy.request
user = self._get_user()
if user:
logger.debug("[%s:%s] [%s] [%s] %s", req.remote.ip,
req.remote.port, req.method, user, req.path_info)
else:
logger.debug("[%s:%s] [%s] %s", req.remote.ip,
req.remote.port, req.method, req.path_info)
def request_error(self):
self._request_log(logger.error)
logger.error(cherrypy.response.body)
def request_end(self):
status = cherrypy.response.status[:3]
if status in ["401"]:
# log unauthorized accesses
self._request_log(logger.warning)
else:
self._request_log(logger.info)
def _format_bytes(self, num):
units = ['B', 'K', 'M', 'G']
format_str = "{:.0f}{}"
for i, unit in enumerate(units):
div = 2**(10*i)
if num < 2**(10*(i+1)):
if num % div == 0:
format_str = "{}{}"
else:
div = float(div)
format_str = "{:.1f}{}"
return format_str.format(num/div, unit[0])
# content-length bigger than 1T!! return value in bytes
return "{}B".format(num)
def _request_log(self, logger_fn):
req = cherrypy.request
res = cherrypy.response
lat = time.time() - res.time
user = self._get_user()
status = res.status[:3] if isinstance(res.status, str) else res.status
if 'Content-Length' in res.headers:
length = self._format_bytes(res.headers['Content-Length'])
else:
length = self._format_bytes(0)
if user:
logger_fn("[%s:%s] [%s] [%s] [%s] [%s] [%s] %s", req.remote.ip,
req.remote.port, req.method, status,
"{0:.3f}s".format(lat), user, length, req.path_info)
else:
logger_fn("[%s:%s] [%s] [%s] [%s] [%s] %s", req.remote.ip,
req.remote.port, req.method, status,
"{0:.3f}s".format(lat), length, req.path_info)
# pylint: disable=too-many-instance-attributes
class ViewCache(object):
VALUE_OK = 0