Metric_info does not render nanoseconds

CMK version:
2.1.0
OS version:
ubuntu 20.04

I am using the checkmk built_in metrics_info to render time values in seconds and it correctly displays a time series graph in my custom plugin.
However, values smaller than 500 ns are rendered to 0 sec. The smallest value it displays in the graph is 1 microsecond.

I noticed in the built in NTP plugin checkmk renders nanosecond values. Does checkmk uses there a different method to render the values?

Here is an example of my my_metric.py file in

local/share/check_mk/web/plugins/metrics/

#!/usr/bin/env python3

from cmk.gui.i18n import _
from cmk.gui.plugins.metrics import (
    metric_info,
    graph_info,
)

metric_info["master_offset"] = {
    "title": _("Master Offset"),
    "unit": "s",
    "color": "#ff8020",
}

It does not seem so. The NTP Time check uses the metric names “offset” and “jitter” which also use “s” as unit in their metric_info.

As the value is stored as a float with the base unit seconds it could be that the precision of the RRD storing it is not high enough. But that’s just a guess.

Checking the render.py file, there are even smaller time units defined.
I am using the render.timespan() function.

/omd/sites/dev/lib/python3/cmk/base/api/agent_based/render.py


"""Render functions for check development
These are meant to be exposed in the API
"""

import math
import time
from typing import Iterable, Optional, Tuple

_DATE_FORMAT = "%b %d %Y"

_TIME_UNITS = [
    ("years", 31536000),
    ("days", 86400),
    ("hours", 3600),
    ("minutes", 60),
    ("seconds", 1),
    ("milliseconds", 1e-3),
    ("microseconds", 1e-6),
    ("nanoseconds", 1e-9),
    ("picoseconds", 1e-12),
    ("femtoseconds", 1e-15),
    # and while we're at it:
    ("attoseconds", 1e-18),
    ("zeptoseconds", 1e-21),
    ("yoctoseconds", 1e-24),
]



def _gen_timespan_chunks(seconds: float, nchunks: int) -> Iterable[str]:
    if seconds < 0:
        raise ValueError("Cannot render negative timespan")

    try:
        start = next(i for i, (_, v) in enumerate(_TIME_UNITS) if seconds >= v)
    except StopIteration:
        start = len(_TIME_UNITS) - 1

    for unit, scale in _TIME_UNITS[start : start + nchunks]:
        last_chunk = unit.endswith("seconds")
        value = (round if last_chunk else int)(seconds / scale)  # type: ignore[operator]
        yield "%.0f %s" % (value, unit if value != 1 else unit[:-1])
        if last_chunk:
            break
        seconds %= scale


def timespan(seconds: float) -> str:
    """Render a time span in seconds

    Example:
        >>> timespan(1606721)
        '18 days 14 hours'
        >>> timespan(0.0001)
        '100 microseconds'

    """
    ts = " ".join(_gen_timespan_chunks(float(seconds), nchunks=2))
    if ts == "0 %s" % _TIME_UNITS[-1][0]:
        ts = "0 seconds"
    return ts



Ok , the render.timespan() function seems to work as expected.

>>> import cmk.base.api.agent_based.render as render
>>> render.timespan(1e-9)
'1 nanosecond'
>>> render.timespan(1e-6)
'1 microsecond'
>>> render.timespan(1e-12)
'1 picosecond'
>>> render.timespan(1e-24)
'1 yoctosecond'
>>>