code: def producer(*, name = None, metric = call_default):
      
  
      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
docs: 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