Decorator to measure a function that produces many items.

    The function should return an object that supports ``__len__`` (ie, a
    list). If the function returns an iterator, use :func:`all` instead.

    :arg function metric: f(name, count, total_time)
    :arg str name: name for the metric

def producer(*, name = None, metric = call_default):
    """Decorator to measure a function that produces many items.

    The function should return an object that supports ``__len__`` (ie, a
    list). If the function returns an iterator, use :func:`all` instead.

    :arg function metric: f(name, count, total_time)
    :arg str name: name for the metric
    """

    def wrapper(func):
        def instrumenter(name_, *args, **kwargs):
            t = time.time()
            try:
                ret = func(*args, **kwargs)
            except Exception:
                # record a metric for other exceptions, than raise
                metric(name_, 0, time.time() - t)
                raise
            else:
                # normal path, record metric & return
                metric(name_, len(ret), time.time() - t)
                return ret

        name_ = name if name is not None else func.__module__ + '.' +func.__name__
        class instrument_decorator(object): # must be a class for descriptor magic to work
            @wraps(func)
            def __call__(self, *args, **kwargs):
                return instrumenter(name_, *args, **kwargs)

            def __get__(self, instance, class_):
                name_ = name if name is not None else\
                    ".".join((class_.__module__, class_.__name__, func.__name__))
                @wraps(func)
                def wrapped_method(*args, **kwargs):
                    return instrumenter(name_, instance, *args, **kwargs)
                return wrapped_method

        return instrument_decorator()
    return wrapper