Decorator to show a description of the running function

    By default, it outputs the first line of the docstring.
    If the docstring is empty, it displays the name of the function.
    Alternatively, if a ``name`` is specified, it will display that only.

    It can be called as ``@log`` or as
    ``@log(name='abc, timing=True, timestamp=True)``.

def log(func=None, name=None, timing=True, timestamp=False):
    """ Decorator to show a description of the running function

    By default, it outputs the first line of the docstring.
    If the docstring is empty, it displays the name of the function.
    Alternatively, if a ``name`` is specified, it will display that only.

    It can be called as ``@log`` or as
    ``@log(name='abc, timing=True, timestamp=True)``.

    """
    # support to be called as @log or as @log(name='')
    if func is None:
        return functools.partial(log, name=name, timing=timing,
                                 timestamp=timestamp)

    @functools.wraps(func)
    def decorated(*args, **kwargs):
        assert len(args) > 0 and hasattr(args[0], 'log'), \
            "The first argument of the decorated function must be a Context"
        ctx = args[0]
        message = name
        if message is None:
            if func.__doc__:
                message = func.__doc__.splitlines()[0].strip()
        if message is None:
            message = func.__name__
        with ctx.log(message, timing=timing, timestamp=timestamp):
            return func(*args, **kwargs)
    return decorated