1# Copyright (C) 2013 eNovance SAS <licensing@enovance.com> 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); you may 4# not use this file except in compliance with the License. You may obtain 5# a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12# License for the specific language governing permissions and limitations 13# under the License. 14 15"""Log helper functions.""" 16 17import functools 18import inspect 19import logging 20 21 22def _get_full_class_name(cls): 23 return '%s.%s' % (cls.__module__, 24 getattr(cls, '__qualname__', cls.__name__)) 25 26 27def _is_method(obj, method): 28 """Returns True if a given method is obj's method. 29 30 You can not simply test a given method like: 31 32 return inspect.ismethod(method) 33 34 This is because functools.wraps converts the method to a function 35 in log_method_call function. 36 """ 37 return inspect.ismethod(getattr(obj, method.__name__, None)) 38 39 40def log_method_call(method): 41 """Decorator helping to log method calls. 42 43 :param method: Method to decorate to be logged. 44 :type method: method definition 45 """ 46 log = logging.getLogger(method.__module__) 47 48 @functools.wraps(method) 49 def wrapper(*args, **kwargs): 50 args_start_pos = 0 51 if args: 52 first_arg = args[0] 53 if _is_method(first_arg, method): 54 cls = (first_arg if isinstance(first_arg, type) 55 else first_arg.__class__) 56 caller = _get_full_class_name(cls) 57 args_start_pos = 1 58 else: 59 caller = 'static' 60 else: 61 caller = 'static' 62 data = {'caller': caller, 63 'method_name': method.__name__, 64 'args': args[args_start_pos:], 'kwargs': kwargs} 65 log.debug('%(caller)s method %(method_name)s ' 66 'called with arguments %(args)s %(kwargs)s', data) 67 return method(*args, **kwargs) 68 return wrapper 69