Reference / Metrics API for Python
Metrics API for Python
Every public class, function and type of the Metrics engine in tinystore, generated from its source. The Metrics guide explains how to use them, and the Bun and Node, Go and Rust pages list the same API.
Series
@dataclass(slots=True)
class Series:
name: str
kind: SeriesKind
labels: Mapping[str, LabelValue] = field(default_factory=dict[str, LabelValue])
samples: Sequence[tuple[Time, float]] | None = None
times: Sequence[Time] | None = None
values: Sequence[float] | None = None
keep: Duration | None = None # how long the name's samples stay: its own, kept in the file; unless given, what it keeps alreadyA series: what ingest writes, and what a read gives back.
Ingest takes its samples as (time, value) pairs, or as times and values
columns, a time an aware datetime or unix milliseconds. A read gives
times, unix milliseconds in an array('q'), and values, an
array('d') whose bytes keep every value's bits: -0 and a NaN's
payload survive.
AggregateBucket
@dataclass(frozen=True, slots=True)
class AggregateBucket:
at: datetime # where it begins
samples: int # how many samples it comes from; a timer's, how many durations
resets: int
partial: bool # its value comes from less than its span: the range, the clock or retention cut it
gap: bool # its first step began before the bucket before it: a whole bucket between had no samples
value: float | None = None
lower: float | None = None
upper: float | None = None # infinity past the last bound
estimate: float | None = NoneA bucket of an aggregate.
A bucket of count … last has its value; a percentile's is a gauge's sample at the rank, or a timer's bucket of its spread that holds it, from lower to upper, and with estimate asked a point between them.
Aggregate
@dataclass(frozen=True, slots=True)
class Aggregate:
name: str
labels: dict[str, str] # the labels by kept or without left
buckets: list[AggregateBucket] # a bucket without samples is left outPoint
@dataclass(frozen=True, slots=True)
class Point:
name: str
labels: dict[str, str]
at: datetime
value: floatA series' newest sample in the range.
Plan
@dataclass(frozen=True, slots=True)
class Plan:
series: int
bytes: int
decoded: int
exceeds: Exceeds | NoneWhat a read or an aggregate would spend of each bound, and the bound it would stop at.
NameInfo
@dataclass(frozen=True, slots=True)
class NameInfo:
name: str
kind: SeriesKind
series_count: int
unit: str
help: str
keep: str
retained_from: datetime # its oldest sample, or where its keep begins while it holds samples from before
newest: datetimeA name the store holds samples of.
NamePage
@dataclass(frozen=True, slots=True)
class NamePage:
names: list[NameInfo]
next: str | None # where the next page starts; none on the lastMetricsDamage
@dataclass(frozen=True, slots=True)
class MetricsDamage:
name: str
labels: dict[str, str]
error: strA series whose bytes no longer read, which delete removes.
Metrics
class Metrics:
...A store's metrics: series by name and labels, their reads and aggregates, and the program's instruments.
Metrics.ingest
async def ingest(series: Series | Sequence[Series]) -> None: ...Writes series and their samples, every one or none: a refused series names itself.
Metrics.read
async def read(**query: Unpack[SeriesQuery]) -> list[Series]: ...The samples of each series the query finds, in its range: whole, or a LimitError naming its bound.
Metrics.latest
async def latest(**query: Unpack[SeriesQuery]) -> list[Point]: ...The newest sample of each series the query finds, when it has one in the range.
Metrics.aggregate
async def aggregate(**query: Unpack[AggregateQuery]) -> list[Aggregate]: ...The buckets of each group of the series the query finds, each one exact value of op, rounded once.
Metrics.explain
async def explain(**query: Unpack[AggregateQuery]) -> Plan: ...What a read, or an aggregate when given its op, would spend of each bound; it decodes no sample.
Metrics.names
async def names(
*,
prefix: str | None = None,
limit: int | None = None,
after: str | None = None,
) -> NamePage: ...A page of the names the store holds samples of, in the byte order of their text.
Metrics.label_names
async def label_names(
name: str,
*,
prefix: str | None = None,
limit: int | None = None,
after: str | None = None,
) -> LabelPage: ...A page of a name's label names, but the store's own.
Metrics.label_values
async def label_values(
name: str,
label: str,
*,
prefix: str | None = None,
limit: int | None = None,
after: str | None = None,
) -> ValuePage: ...A page of the values a label of a name's series holds.
Metrics.describe
async def describe(name: str, *, unit: str = '', help: str = '') -> None: ...Sets a name's unit and help in place of what it had: what is not given is removed.
They belong to the name, so a delete of its series leaves them.
Metrics.description
async def description(name: str) -> Description: ...A name's unit and help; both empty when nothing described it.
Metrics.delete
async def delete(*, name: str, labels: Mapping[str, LabelValue]) -> bool: ...Removes the one series of exactly this name and these labels, whether its samples still read or not.
True when the store held it; labels={} is the series without labels.
Metrics.damaged
async def damaged() -> list[MetricsDamage]: ...The series whose bytes no longer read, 1000 at most, each with what broke; deleting them shows the next.
Metrics.flush
async def flush() -> None: ...Sends what every instrument changed and has the store write its totals now, as it does every 15 seconds.
Metrics.counter
def counter(
name: str,
*,
unit: str | None = None,
help: str | None = None,
keep: Duration | None = None,
) -> Counter: ...A total that only goes up, which the store keeps: processes counting into one series count into one total.
Metrics.gauge
def gauge(
name: str,
*,
unit: str | None = None,
help: str | None = None,
keep: Duration | None = None,
) -> Gauge: ...A value that goes up and down: a queue's length, a temperature.
Metrics.gauge_func
def gauge_func(
name: str,
read: Callable[[], float | Awaitable[float]],
*,
labels: Mapping[str, LabelValue] | None = None,
unit: str | None = None,
help: str | None = None,
keep: Duration | None = None,
) -> None: ...A gauge whose value read gives every 15 seconds, of the set of labels given.
Another set of the name takes a function of its own. It may be async, is never called again while a call of it runs, and an error or an answer that is not a number writes nothing that time, said once while it repeats:
store.metrics.gauge_func("queue_depth", emails.depth, labels={"queue": "emails"})Metrics.timer
def timer(
name: str,
*,
buckets: Sequence[float] | Literal['exponential'] | None = None,
help: str | None = None,
keep: Duration | None = None,
) -> Timer: ...How many things took how long: their count, sum and longest in milliseconds, and their spread.
Metrics.histogram
def histogram(
name: str,
*,
buckets: Sequence[float] | Literal['exponential'] | None = None,
unit: str | None = None,
help: str | None = None,
keep: Duration | None = None,
) -> Histogram: ...A timer of numbers that are not durations: a response's size in bytes.
exponential_buckets
def exponential_buckets(start: float, factor: float, count: int) -> list[float]: ...Upper bounds from start, each factor times the one before: exponential_buckets(1, 2, 14) is 1, 2, 4 … 8192.
Instruments
class Instruments:
...The instruments of a store's handle, and what sends their changes; store.metrics makes them.
Instruments.declare
def declare(
name: str,
form: Form,
*,
unit: str | None = None,
help_: str | None = None,
keep: Duration | None = None,
buckets: Sequence[float] | Literal['exponential'] | None = None,
read: bool = False,
) -> _Declared: ...An instrument of name, made the first time; another form or other options than it has are refused.
Instruments.reader
def reader(
name: str,
labels: dict[str, str],
read: Callable[[], float | Awaitable[float]],
**told: Any,
) -> None: ...A gauge of name whose set of labels read gives every 15 seconds; each set has a function of its own.
Instruments.set_of
def set_of(instrument: _Declared, labels: dict[str, str]) -> _Set: ...The set of labels of an instrument, made the first time; past the sets it holds, its __overflow.
Instruments.pending
def pending(set_: _Set) -> _Change | None: ...Instruments.change
def change(set_: _Set) -> _Change: ...What a call changes of a set, kept for the next batch.
Instruments.flush
async def flush() -> bool: ...Sends what changed now and has the store write its totals; says whether there was anything to send.
One the store cannot be reached for fails as a call does, and what it carried goes once the store can be. What the store refused since the flush before, and what a store that started again may have lost, fail it, each once.
Instruments.stop
async def stop() -> None: ...Stops the timers, sends what is left, and ends the stream; the store's close calls it.
Counter
class Counter:
...A total that only goes up, which the store keeps: processes counting into one series count into one total.
Counter.labels
def labels(**labels: LabelValue) -> Counter: ...The same counter with more labels, a series of its own; the same labels in any order are one.
Counter.inc
def inc() -> None: ...Counter.add
def add(n: float) -> None: ...Adds n, a finite number of 0 or more; add(0) makes the set of labels known with a total of zero.
Gauge
class Gauge:
...A value that goes up and down, written while this program is connected.
Gauge.labels
def labels(**labels: LabelValue) -> Gauge: ...Gauge.set
def set(value: float) -> None: ...Gauge.add
def add(n: float) -> None: ...Moves it by n, from zero when it was never set.
Gauge.inc
def inc() -> None: ...Gauge.dec
def dec() -> None: ...Timer
class Timer:
...How many things took how long: their count, sum and longest in milliseconds, and their spread.
Timer.labels
def labels(**labels: LabelValue) -> Timer: ...Timer.record
def record(duration: timedelta | Duration) -> None: ...Records a duration measured elsewhere: a timedelta, or text such as "250ms".
Timer.measure
def measure() -> Timing: ...Measures the block it runs: async with latency.measure():, recorded whether it returns or raises.
Timer.start
def start() -> Timing: ...A timing that records when it stops, for a span that is no one block.
Timing
class Timing:
...A span a timer measures from its start; stop records it, once.
Timing.stop
def stop() -> timedelta: ...Records how long since the timing started, the first time it is called, and gives it.
Histogram
class Histogram:
...A timer of numbers that are not durations: a response's size in bytes.
Histogram.labels
def labels(**labels: LabelValue) -> Histogram: ...Histogram.record
def record(value: float) -> None: ...Records a value of 0 or more.