def log(prefix = ''):
    '''Add start and stop logging messages to the function.

    Parameters
    ----------

    :``prefix``: a prefix for the function name (optional)

    '''

    function = None

    if inspect.isfunction(prefix):
        prefix, function = '', prefix

    def _(function):
        @functools.wraps(function, assigned = functools.WRAPPER_ASSIGNMENTS + ( '__file__', ))
        def wrapper(*args, **kwargs):
            name, my_args = function.__name__, args

            if inspect.ismethod(function):
                name = function.__self__.__class__.__name__ + '.' + function.__name__
            elif len(args):
                members = dict(inspect.getmembers(args[0], predicate = lambda _: inspect.ismethod(_) and _.__name__ == function.__name__))
                logger.debug('members.keys(): %s', members.keys())

                if len(members):
                    name, my_args = args[0].__class__.__name__ + '.' + function.__name__, args[1:]

            format_args = (
                prefix + name,
                ', '.join(list(map(str, my_args)) + [ ' = '.join(map(str, item)) for item in kwargs.items() ]),
            )

            logger.info('STARTING: %s(%s)', *format_args)

            try:
                return function(*args, **kwargs)
            except:
                logger.exception('EXCEPTION: %s(%s)', *format_args)
                raise
            finally:
                logger.info('STOPPING: %s(%s)', *format_args)

        return wrapper

    if function is not None:
        _ = _(function)

    return _
Add start and stop logging messages to the function.

    Parameters
    ----------

    :``prefix``: a prefix for the function name (optional)