You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
143 lines
5.5 KiB
143 lines
5.5 KiB
#!/usr/bin/env python2
|
|
|
|
# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
import functools
|
|
import inspect
|
|
import logging
|
|
import traceback
|
|
|
|
def log_dbus_method(return_logger=logging.debug, raise_logger=logging.warning,
|
|
return_cb_arg=None, raise_cb_arg=None):
|
|
"""
|
|
Factory method for decorator to log dbus responses / errors.
|
|
|
|
This method should be used to decorate the most concerete implementation of
|
|
a dbus method.
|
|
|
|
@param return_logger: A function that accepts a string argument to log the
|
|
response from the decorated function.
|
|
@param raise_logger: A function accepts a string argument to log the
|
|
exception raised by the decorated function.
|
|
@param return_cb_arg: str name of the async callback argument for the return
|
|
value, if the function takes one.
|
|
@param raise_cb_arg: str name of the async callback argument for the error
|
|
return value, if the function takes one.
|
|
|
|
"""
|
|
def wrapper(func):
|
|
"""
|
|
The decorator returned by this factory.
|
|
|
|
@param func: The function to be decorated.
|
|
|
|
"""
|
|
@functools.wraps(func)
|
|
def wrapped_func(*args, **kwargs):
|
|
"""The modified function for the decorated function."""
|
|
modified_args = list(args)
|
|
modified_kwargs = kwargs
|
|
return_cb_index = getattr(wrapped_func, '_logging_return_cb_index')
|
|
if return_cb_index > -1:
|
|
if len(args) > return_cb_index:
|
|
modified_args[return_cb_index] = _wrap_async_return(
|
|
args[return_cb_index],
|
|
func.__name__,
|
|
return_logger)
|
|
elif return_cb_arg in kwargs:
|
|
modified_kwargs[return_cb_arg] = _wrap_async_return(
|
|
kwargs[return_cb_arg],
|
|
func.__name__,
|
|
return_logger)
|
|
else:
|
|
logging.debug('Not logging default return_cb')
|
|
|
|
raise_cb_index = getattr(wrapped_func, '_logging_raise_cb_index')
|
|
if raise_cb_index > -1:
|
|
if len(args) > raise_cb_index:
|
|
modified_args[raise_cb_index] = _wrap_async_raise(
|
|
args[raise_cb_index],
|
|
func.__name__,
|
|
raise_logger)
|
|
elif raise_cb_arg in kwargs:
|
|
modified_kwargs[raise_cb_arg] = _wrap_async_raise(
|
|
kwargs[raise_cb_arg],
|
|
func.__name__,
|
|
raise_logger)
|
|
else:
|
|
logging.debug('Not logging default raise_cb')
|
|
|
|
try:
|
|
retval = func(*modified_args, **modified_kwargs)
|
|
# No |return_cb_arg| ==> return value is the DBus response, so
|
|
# it needs to be logged.
|
|
if return_cb_index == -1:
|
|
return_logger('Response[%s] OK: |%s|' % (func.__name__,
|
|
repr(retval)))
|
|
except Exception as e:
|
|
raise_logger('Response[%s] ERROR: |%s|' % (func.__name__,
|
|
repr(e)))
|
|
raise_logger(traceback.format_exc())
|
|
raise
|
|
return retval
|
|
|
|
|
|
args, _, _, defaults = inspect.getargspec(func)
|
|
wrapped_func._logging_return_cb_index = -1
|
|
wrapped_func._logging_raise_cb_index = -1
|
|
if return_cb_arg:
|
|
if return_cb_arg not in args:
|
|
logging.warning(
|
|
'Did not find expected argument %s in argument list '
|
|
'of %s', return_cb_arg, func.__name__)
|
|
wrapped_func._logging_return_cb_index = args.index(return_cb_arg)
|
|
if raise_cb_arg:
|
|
if raise_cb_arg not in args:
|
|
logging.warning(
|
|
'Did not find expected argument %s in argument list '
|
|
'of %s', raise_cb_arg, func.__name__)
|
|
wrapped_func._logging_raise_cb_index = args.index(raise_cb_arg)
|
|
return wrapped_func
|
|
return wrapper
|
|
|
|
|
|
def _wrap_async_return(return_cb, fname, logger):
|
|
"""
|
|
Wrap return_cb to log the return value.
|
|
|
|
@param return_cb: The function to be wrapped.
|
|
@param fname: Name of the DBus function called.
|
|
@param logger: The logger to use for logging.
|
|
@returns: Wrapped |return_cb| that additionally logs its arguments.
|
|
|
|
"""
|
|
@functools.wraps(return_cb)
|
|
def wrapped_return_cb(*args, **kwargs):
|
|
""" Log arguments before calling return_cb. """
|
|
logger('AsyncResponse[%s] OK: |%s|' % (fname, str((args, kwargs))))
|
|
return_cb(*args, **kwargs)
|
|
|
|
return wrapped_return_cb
|
|
|
|
|
|
def _wrap_async_raise(raise_cb, fname, logger):
|
|
"""
|
|
Wrap raise_cb to log the raised error.
|
|
|
|
@param raise_cb: The function to be wrapped.
|
|
@param fname: Name of the DBus function called.
|
|
@param logger: The logger to use for logging.
|
|
@returns: Wrapped |raise_cb| that additionally logs its arguments.
|
|
|
|
"""
|
|
@functools.wraps(raise_cb)
|
|
def wrapped_raise_cb(*args, **kwargs):
|
|
""" Log arguments before calling raise_cb. """
|
|
logger('AsyncResponse[%s] ERROR: |%s|' % (fname, str((args, kwargs))))
|
|
logger(traceback.format_exc())
|
|
raise_cb(*args, **kwargs)
|
|
|
|
return wrapped_raise_cb
|