class_docstr: Add-on to :class:`ContextMeter` that helps in the case where:
  
  - The code to be metered is not easily expressed as a self-contained code block
    e.g. you want to measure latency in the asyncio event loop before and after
    running a task
  - You want to alter the metrics depending on how the code ends; e.g. you want to
    post them differently in case of failure.
  
  Examples
  --------
  >>> ledger = DelayedMetricsLedger()  # Metering starts here
  >>> async def wrapper():
  ...     with ledger.record():
  ...         return await metered_function()
  >>> task = asyncio.create_task(wrapper())
  >>> # (later, elsewhere)
  >>> try:
  ...     await task
  ...     coarse_time = False
  ... except Exception:
  ...     coarse_time = "failed"
  ...     raise
  ... finally:
  ...     # Metering stops here
  ...     for label, value, unit in ledger.finalize(coarse_time):
  ...         # actually log metrics
class_docstr_tok: ["Add-on","to",":","class",":","`","ContextMeter","`","that","helps","in","the","case","where",":","-","The","code","to","be","metered","is","not","easily","expressed","as","a","self-contained","code","block","e.g",".","you","want","to","measure","latency","in","the","asyncio","event","loop","before","and","after","running","a","task","-","You","want","to","alter","the","metrics","depending","on","how","the","code","ends",";","e.g",".","you","want","to","post","them","differently","in","case","of","failure",".","Examples","--","--","--","--",">",">",">","ledger","=","DelayedMetricsLedger","(",")","#","Metering","starts","here",">",">",">","async","def","wrapper","(",")",":","...","with","ledger.record","(",")",":","...","return","await","metered_function","(",")",">",">",">","task","=","asyncio.create_task","(","wrapper","(",")",")",">",">",">","#","(","later",",","elsewhere",")",">",">",">","try",":","...","await","task","...","coarse_time","=","False","...","except","Exception",":","...","coarse_time","=","``","failed","''","...","raise","...","finally",":","...","#","Metering","stops","here","...","for","label",",","value",",","unit","in","ledger.finalize","(","coarse_time",")",":","...","#","actually","log","metrics"]
docstr: The metered code is terminated, and we now know how to log it.
  
  Parameters
  ----------
  coarse_time: str | False, optional
      False
          Yield all acquired metrics, plus an extra time metric, labelled "other",
          which is the time between creating the DelayedMetricsLedger and
          calling this method, minus any time logged in the metrics.
      label
          Yield all acquired non-time metrics.
          Yield a single metric, labelled <coarse_time>, which is the time
          between creating the DelayedMetricsLedger and calling this method.
  floor: float | False, optional
      Floor either the "other" or the <coarse_time> metric to this value
       (default: 0). Set to False to disable.
docstr_tok: ["The","metered","code","is","terminated",",","and","we","now","know","how","to","log","it",".","Parameters","--","--","--","--","--","coarse_time",":","str","|","False",",","optional","False","Yield","all","acquired","metrics",",","plus","an","extra","time","metric",",","labelled","``","other","''",",","which","is","the","time","between","creating","the","DelayedMetricsLedger","and","calling","this","method",",","minus","any","time","logged","in","the","metrics",".","label","Yield","all","acquired","non-time","metrics",".","Yield","a","single","metric",",","labelled","<","coarse_time",">",",","which","is","the","time","between","creating","the","DelayedMetricsLedger","and","calling","this","method",".","floor",":","float","|","False",",","optional","Floor","either","the","``","other","''","or","the","<","coarse_time",">","metric","to","this","value","(","default",":","0",")",".","Set","to","False","to","disable","."]
code: def finalize(
      self,
      coarse_time: str | Literal[False] = False,
      floor: float | Literal[False] = 0.0,
  ) -> Iterator[tuple[Hashable, float, str]]:
      """The metered code is terminated, and we now know how to log it.
  
      Parameters
      ----------
      coarse_time: str | False, optional
          False
              Yield all acquired metrics, plus an extra time metric, labelled "other",
              which is the time between creating the DelayedMetricsLedger and
              calling this method, minus any time logged in the metrics.
          label
              Yield all acquired non-time metrics.
              Yield a single metric, labelled <coarse_time>, which is the time
              between creating the DelayedMetricsLedger and calling this method.
      floor: float | False, optional
          Floor either the "other" or the <coarse_time> metric to this value
           (default: 0). Set to False to disable.
      """
      stop = self.func()
      delta = stop - self.start
  
      for label, value, unit in self.metrics:
          if unit != "seconds" or not coarse_time:
              yield label, value, unit
          if unit == "seconds" and not coarse_time:
              delta -= value
  
      if floor is not False:
          delta = max(floor, delta)
      yield coarse_time or "other", delta, "seconds"
  
imports: from __future__ import annotations
  import asyncio
  import collections
  import threading
  import time
  from collections.abc import Callable, Hashable, Iterator
  from contextlib import contextmanager
  from contextvars import ContextVar
  from dataclasses import dataclass
  from functools import wraps
  from math import nan
  from typing import Literal
  import psutil
  from distributed.compatibility import WINDOWS
label_desc: Use image node_id 4 for calling the DelayedMetricsLedger obj's underlying member method code with example usage: obj.finalize(coarse_time, floor) without return types