buckets: Array[Double]
The default bucket bounds the official Prometheus clients share: 0.005 through 10, fourteen finite bounds plus the implicit +Inf bucket every histogram has.
Generated from the interfaces MoonBit prints for this module, so nothing public is missing and no signature was typed twice. The prose is the documentation comment beside the code.
moonbitstack/moonp8s/metric
The model: kinds, the seven metric types, families, a registry, and the snapshot an exposition is written from. Nothing here reads a clock, opens a socket or writes a byte.
buckets: Array[Double]
The default bucket bounds the official Prometheus clients share: 0.005 through 10, fourteen finite bounds plus the implicit +Inf bucket every histogram has.
exemplar_label_limit: Int32
OpenMetrics caps an exemplar's combined label names and values at 128 characters; a longer set makes the exemplar unrepresentable.
exponential(Double, Double, Int32) -> Array[Double] raise Refused
count bounds starting at start and multiplying by factor.
is_valid_label_name(String) -> Bool
Whether name is a label name under the OpenMetrics character rules: [a-zA-Z_][a-zA-Z0-9_]*.
is_valid_metric_name(String) -> Bool
Whether name is a metric name under the OpenMetrics character rules: [a-zA-Z_:][a-zA-Z0-9_:]*.
is_valid_unit(String) -> Bool
Whether unit may be appended to a metric name. A unit starts with a letter and continues with letters, digits, or underscores.
linear(Double, Double, Int32) -> Array[Double] raise Refused
count bounds starting at start and growing by width.
point_of(Value) -> Point
A point with no labels and no metadata, the shape a bare metric collects into before its registry or family adds labels.
Refused
The one error this library raises: a request it will not honour, with the reason in the message. Messages carry the offending value and, where a position is meaningful, an at offset counted from zero.
Refused(String)
Refused::message(Self) -> String
The reason a request was refused.
Counter
A monotonically increasing count. inc refuses a negative step because a counter that goes down is a gauge.
Counter::get(Self) -> Double
The current count.
Counter::inc(Self, by? : Double, exemplar? : Exemplar) -> Unit raise Refused
Increase the counter by by, keeping exemplar as the latest exemplar.
Counter::new(created? : Double) -> Self
A counter at zero. created records when the series came into existence, for the _created series OpenMetrics exposes.
Counter::reset(Self, created? : Double) -> Unit
Restart the counter at zero, optionally dating the reset as a new creation time. Use this when a logical process restarts without restarting the program.
A reset is a new series, so the creation time is the reset's: passing none clears it rather than leaving the old one in place, which would claim the restarted counter started when the old one did.
Counter::shard(Self) -> LocalCounter
A shard of this counter. Many shards may feed one counter; each flushes its own accumulations.
Also on the type: kind · points — derived, or required by an implementation above.
Exemplar
An exemplar ties a sample to the request that produced it: the request's labels, the observed value, and optionally when it was observed (Unix seconds).
Exemplar::new(Array[(String, String)], Double, timestamp? : Double) -> Self raise Refused
Build an exemplar, refusing a label set over the OpenMetrics limit.
Gauge
An instantaneous value that may go up or down. set takes the timestamp to record, because this library never reads a clock; pass timestamp~ when the sample is worth dating.
Gauge::dec(Self, by? : Double) -> Unit
Decrease the gauge by by.
Gauge::get(Self) -> Double
The current value.
Gauge::inc(Self, by? : Double) -> Unit
Increase the gauge by by.
Gauge::new(initial? : Double) -> Self
A gauge at initial (zero unless given).
Gauge::set(Self, Double, timestamp? : Double) -> Unit
Set the gauge to v, optionally dating the sample.
Gauge::set_function(Self, () -> Double) -> Unit
Take the value from f instead of a stored number. While a function is set, set, inc, and dec do nothing, matching the Python client.
Also on the type: kind · points — derived, or required by an implementation above.
GaugeHistogram
A gauge histogram: the same buckets as a histogram, but the sum and count are a gauge's, and the wire format spells them _gsum and _gcount.
GaugeHistogram::new(buckets? : Array[Double], created? : Double) -> Self raise Refused
A gauge histogram over buckets (the shared defaults unless given).
GaugeHistogram::observe(Self, Double, exemplar? : Exemplar) -> Unit
Record one observation.
GaugeHistogram::snapshot(Self) -> Point
The snapshot of this gauge histogram.
Also on the type: kind · points — derived, or required by an implementation above.
Histogram
A histogram with cumulative buckets. Counts are kept per bucket and made cumulative on snapshot, which is what the wire format carries.
Histogram::new(buckets? : Array[Double], created? : Double) -> Self raise Refused
A histogram over buckets (the shared defaults unless given).
Histogram::observe(Self, Double, exemplar? : Exemplar) -> Unit
Record one observation in the first bucket whose bound it does not exceed, or in the +Inf bucket when it exceeds every bound.
Histogram::snapshot(Self) -> Point
The snapshot of this histogram: cumulative bucket counts, the sum, and the total count, with the retained exemplars.
Histogram::sum_value(Self) -> Double
The sum of the observations.
Histogram::total(Self) -> Int64
The number of observations.
Also on the type: kind · points — derived, or required by an implementation above.
Info
An info metric: a fixed set of labels whose value is always 1. It carries build and version metadata, which is why it never changes after creation.
Info::labels(Self) -> Array[(String, String)]
The labels this info metric carries.
Info::new(Array[(String, String)]) -> Self raise Refused
An info metric with these labels.
Also on the type: kind · points — derived, or required by an implementation above.
Kind
The kind of a metric, as spelled in the # TYPE line of an exposition.
Counter
Gauge
Histogram
GaugeHistogram
Summary
Info
StateSet
Unknown
Kind::code(Self) -> String
The wire spelling of this kind: counter, gauge, histogram, gaugehistogram, summary, info, stateset, or unknown.
Kind::of(String) -> Self
The kind a wire spelling names. untyped is the legacy spelling of unknown, and an unrecognised spelling is unknown rather than an error so that a newer peer's exposition still parses.
LocalCounter
A non-atomic shard of a counter. Increments land in the shard and are added to the shared counter on flush, which is the local accumulation the Rust client offers; it keeps a hot path off the shared value without requiring thread-local storage.
LocalCounter::flush(Self) -> Unit
Add the shard's value to the shared counter and clear the shard.
LocalCounter::get(Self) -> Double
The shard's unflushed value.
LocalCounter::inc(Self, by? : Double) -> Unit raise Refused
Increase the shard by by.
LocalCounter::reset(Self) -> Unit
Drop the unflushed value.
Also on the type: kind · points — derived, or required by an implementation above.
MetricFamily
A family of series sharing one name, help text, kind, and optional unit. This is what an exposition is written from and what a parser produces.
Point
One series of a family: its labels, its value, and the optional metadata OpenMetrics carries alongside it. created is when the series was created (Unix seconds); exemplars are the retained exemplars, matched to histogram buckets by the value that produced them.
ProcessCollector
The seven process_* series the Rust client's process collector exposes: CPU time, open and maximum file descriptors, virtual and resident memory, start time, and thread count.
ProcessCollector::new(ProcessStats, prefix? : String) -> Self
A process collector over stats. namespace prefixes every name, as the Rust client's namespace does.
Also on the type: collect — derived, or required by an implementation above.
ProcessStats
The process numbers a ProcessCollector exports. The caller reads them — this library performs no I/O — which keeps the collector portable across every target.
Registry
The set of metrics one exposition exposes, with an optional name prefix and optional constant labels applied to everything registered. A registry refuses a metric name that is not a valid OpenMetrics name, a label name that is not a valid label name, a unit that is not a valid unit, and a name registered twice.
Registry::add(Self, &Collector) -> Unit
Add a custom collector. Its families are exposed after the registered metrics, with this registry's prefix and labels applied.
Registry::counter(Self, String, String, unit? : String) -> Counter raise Refused
Create a counter, register it, and return it.
Registry::gauge(Self, String, String, unit? : String) -> Gauge raise Refused
Create a gauge, register it, and return it.
Registry::histogram(Self, String, String, buckets? : Array[Double], unit? : String) -> Histogram raise Refused
Create a histogram, register it, and return it.
Registry::new(prefix? : String, labels? : Array[(String, String)]) -> Self raise Refused
An empty registry. prefix is prepended to every registered name, and labels is added to every series.
Registry::register(Self, String, String, &Metric, unit? : String) -> Unit raise Refused
Register metric under name, with help and an optional unit. The unit is appended to the name on the wire.
Registry::sub(Self, prefix~ : String, labels? : Array[(String, String)]) -> Self raise Refused
A sub-registry whose names carry prefix after this registry's own prefix, and whose series carry this registry's labels plus labels.
Also on the type: collect — derived, or required by an implementation above.
StateSet
A set of named states, each true or false. A state set with exactly one true state is the Enum of the Python client.
StateSet::exclusive(Array[String]) -> Self
A state set with exactly one state true: the first, which is the Python client's default.
StateSet::get(Self, String) -> Bool
Whether state is true.
StateSet::new(Array[String]) -> Self
A state set whose states all start false, in the order given.
StateSet::set(Self, String) -> Unit
Set one state true, leaving the others as they are.
StateSet::set_many(Self, Map[String, Bool]) -> Unit
Apply a whole map of states at once.
StateSet::unset(Self, String) -> Unit
Set one state false.
Also on the type: kind · points — derived, or required by an implementation above.
Summary
A summary: the count and sum of the observations, plus approximate quantiles when the constructor is given target quantiles and their permitted rank error.
Summary::new(quantiles? : Array[(Double, Double)], created? : Double) -> Self raise Refused
A summary. With quantiles (pairs of target quantile and permitted error), observations also feed a sketch so that snapshot can report those quantiles; without them the summary carries only count and sum, as the official clients do by default.
Summary::observe(Self, Double) -> Unit
Record one observation.
Summary::snapshot(Self) -> Point
The snapshot of this summary: the configured quantiles (empty when none were configured), the sum, and the count.
Summary::total(Self) -> Int64
The number of observations.
Also on the type: kind · points — derived, or required by an implementation above.
Value
The value of one series. A histogram carries its cumulative buckets, sum, and count together so that one series stays one Point; a summary carries its quantiles, sum, and count the same way; a state set carries every state with its flag.
Number(Double)
Buckets(buckets~ : Array[(Double, Int64)], sum~ : Double, count~ : Int64)
Quantiles(quantiles~ : Array[(Double, Double)], sum~ : Double, count~ : Int64)
State(states~ : Array[(String, Bool)])
Collector
A custom source of metric families. Implement this to contribute series whose shape the built-in metric types do not cover; the registry applies its prefix and constant labels to whatever collect returns.
Collector::collect(Self) -> Array[MetricFamily]
LabelSet
A record that can name its own label pairs. Implementing this for a struct and using TypedFamily gives a family keyed by a typed label set instead of an array of strings.
LabelSet::pairs(Self) -> Array[(String, String)]
Metric
Anything a registry can collect: a metric, a family of metrics, or a custom collector's contribution. Implement this to plug a new metric shape into a registry without changing the registry.
Metric::kind(Self) -> Kind
Metric::points(Self) -> Array[Point]
moonbitstack/moonp8s/expo
The two text formats, their negotiation from an
Accept header, and a parser for both. The float and
escape rules are the ones a scraper already implements.
escape_help(String, Bool) -> String
Escape help text. The compatibility format escapes backslash and newline; OpenMetrics also escapes the double quote, so help text survives a round trip inside a line-oriented document.
escape_label_value(String) -> String
Escape a label value: backslash, double quote, and newline are backslash-escaped, every other character passes through as UTF-8.
format_float(Double) -> String
Format a float the way the official clients do: +Inf, -Inf, and NaN by name; otherwise the shortest decimal that round-trips, with a .0 on integers and Go's switch to a two-digit exponent once the integer part is longer than six digits (so 1000000.0 is 1e+06, matching what a Prometheus scrape expects to read).
negotiate(String) -> Format
Pick a format from an HTTP Accept header. application/openmetrics-text wins when it names a version this library speaks (or names no version); otherwise a scrape gets the compatibility format, which is also the default when the header is absent or unrecognised.
openmetrics(Array[@metric.MetricFamily]) -> String
Write families in the OpenMetrics text format, version 1.0.0, ending with the # EOF marker the format requires.
parse(String, format? : Format) -> Array[@metric.MetricFamily] raise @metric.Refused
Parse an exposition back into families. The compatibility format is lossy for info and state sets, which it spells as gauges; OpenMetrics keeps them. The format argument selects which spelling conventions to expect, and the same parser accepts both because the syntax is a superset.
protobuf(Array[@metric.MetricFamily]) -> Bytes
Write families in the Prometheus protobuf format: a length-delimited stream of io.prometheus.client.MetricFamily messages, the bytes a scraper reads when it answers application/vnd.google.protobuf. It shares the text formats' snapshot, so one scrape is every format. A family is named as the text format declares it, so a counter is <name>_total with its value in the counter field and an info is <name>_info; a histogram keeps its cumulative buckets, sum, and count, its +Inf bucket being the count; a summary keeps its count, sum, and quantiles; a state set is a gauge per state.
protobuf_content_type: String
The Content-Type an HTTP response should carry for the protobuf format: the metric family the stream holds and the framing of the messages.
text(Array[@metric.MetricFamily]) -> String
Write families in the Prometheus text exposition format, version 0.0.4. Counters gain a _total suffix, info becomes a gauge ending in _info, state sets become gauges, and _created, _gcount, and _gsum series are emitted as separate gauge families, as the compatibility format requires.
wants_protobuf(String) -> Bool
Whether an Accept header asks for the protobuf format. It does when any part is the media type the protobuf exposition carries; the two text formats are picked out of the header by negotiate, which never returns a protobuf.
Format
The exposition formats this library writes and reads.
Text004
Prometheus text exposition format, version 0.0.4.
OpenMetrics100
OpenMetrics text format, version 1.0.0.
Format::content_type(Self) -> String
The Content-Type an HTTP response should carry for this format.
moonbitstack/moonp8s/push
Push gateway requests — method, path, headers and body — built and handed back. Sending them is the caller's, which is why this package needs no HTTP client.
delete(String, String, grouping_key? : Array[(String, String)]) -> PushRequest
Build a DELETE that removes every series under job and grouping_key.
push(String, String, Array[@metric.MetricFamily], grouping_key? : Array[(String, String)], format? : @expo.Format) -> PushRequest
Build a PUT that replaces every series under job and grouping_key with the exposition of families.
push_add(String, String, Array[@metric.MetricFamily], grouping_key? : Array[(String, String)], format? : @expo.Format) -> PushRequest
Build a POST that replaces only the series named in families, leaving other series under the same job and grouping key alone.
PushRequest
A push gateway request: the method, the absolute URL path, the headers, and the body. The caller sends it with whatever HTTP client it has; this package never touches a socket.
moonbitstack/moonp8s/asgi
The /metrics handler and the request-counting
middleware, built on moonbitstack/moonasgi.
app(@metric.Registry) -> (@http.Request) -> @http.Response
A /metrics handler for a registry. GET negotiates the format from the Accept header, OPTIONS advertises the allowed methods, anything else is refused with 405, and /favicon.ico is answered empty so a browser probing the endpoint stays quiet.
middleware(@metric.Registry, now? : () -> Double) -> (((@http.Request) -> @http.Response) -> ((@http.Request) -> @http.Response)) raise @metric.Refused
A middleware that counts handled requests (http_requests, labelled by method, route, and status) and observes their duration in seconds (http_request_duration_seconds, labelled by method and route). The clock is a parameter so a test can drive time; it defaults to wall-clock seconds.
moonbitstack/moonp8s/compat
The surface an older caller already has: a counter vector keyed by one label, the server metric set, and the remote report writer — rebuilt on the registry model so it can be replaced one import at a time.
default_latency_buckets: Array[Double]
The latency buckets the legacy metric package used, in milliseconds.
CounterVec
A counter partitioned by one label string, the shape the legacy metric package exposed. New code should use Family[@metric.Counter]; this exists so an existing call site can move over without being rewritten.
CounterVec::add(Self, String, Int64) -> Unit raise @metric.Refused
Add delta to the series named by label, creating it on first sight.
CounterVec::inc(Self, String) -> Unit raise @metric.Refused
Increment the series named by label by one.
CounterVec::kind(Self) -> @metric.Kind
CounterVec::labels(Self) -> Array[String]
The series names seen so far.
CounterVec::new(label? : String) -> Self
An empty counter vector whose series are labelled label.
CounterVec::points(Self) -> Array[@metric.Point]
CounterVec::total(Self) -> Int64
The sum of every series.
CounterVec::value(Self, String) -> Int64
The current count of the series named by label.
RemoteRequest
A report request, ready for the caller to send: a POST of JSON to the reporting endpoint.
RemoteWriter
A remote writer bound to one reporting endpoint.
RemoteWriter::new(String) -> Self
A writer for endpoint.
RemoteWriter::request(Self, StatReport) -> RemoteRequest
Build the POST a remote writer sends for report.
ServerMetrics
The request counter and latency histogram the legacy server metric set exposed: request counts labelled by request signature, and a millisecond latency histogram.
ServerMetrics::latency(Self) -> @metric.Histogram
The latency histogram, in milliseconds.
ServerMetrics::new() -> Self raise @metric.Refused
A fresh server metric set.
ServerMetrics::register(Self, @metric.Registry, prefix? : String) -> Unit raise @metric.Refused
Register both series under the legacy names, optionally prefixed.
ServerMetrics::requests(Self) -> CounterVec
The request counter.
StatReport
The periodic stat report the legacy remote writer posted as JSON.
moonbitstack/moonp8s/multiproc
How several processes' values become one series: the gauge modes, the record a worker's file holds, its bytes, and the merge. Pure data, so it runs on every target.
merge(Array[Part]) -> Array[@metric.MetricFamily] raise @metric.Refused
Fold the parts into one set of families.
Counters and summaries add up across processes; histograms add up per bucket and are made cumulative again; a gauge follows its mode. Families come out in the order their first part mentions them, and series in the order they were first seen, so two runs over the same directory write the same bytes.
A family that two files disagree about — a name that is a counter in one process and a histogram in another, or a gauge written under two modes — is refused. The numbers would be meaningless, and a scrape that says so is better than one that quietly picks a side.
Entry
One value in one worker's file: the family it belongs to, the name the sample is written under, its labels, the family's help text, the value, and the time the value was recorded (zero when it was not recorded with one).
The pair of metric and sample is what lets a counter be filed under orders and written as orders_total, and a histogram bucket under orders_seconds and orders_seconds_bucket.
Entry::new(String, String, Array[(String, String)], String, Double, timestamp? : Double) -> Self
One value for a worker's file.
Mode
How the values of one gauge from several processes become one series.
A gauge has no natural merge — a counter can be added up, a bucket can be added up, but "requests in flight" from three workers is a policy decision. All and LiveAll keep the processes apart, one series each, labelled pid; the other four collapse them: the smallest, the largest, the sum, or the value set most recently.
The Live spellings mean the same thing at a scrape. They decide what happens when a process exits: mark_dead removes the files of a live mode, and leaves the others, which is what makes a handful of gauges forget a dead worker instead of keeping its last value forever.
All
LiveAll
Min
LiveMin
Max
LiveMax
Sum
LiveSum
MostRecent
LiveMostRecent
Mode::code(Self) -> String
The spelling a file name carries: all, liveall, min, livemin, max, livemax, sum, livesum, mostrecent, livemostrecent.
Mode::is_live(Self) -> Bool
Whether this mode forgets a process when it exits. mark_dead removes the files of these modes only.
Mode::is_most_recent(Self) -> Bool
Whether this mode keeps the value set most recently instead of combining values, which is why a most-recent gauge cannot be stepped with inc.
Mode::is_separate(Self) -> Bool
Whether this mode keeps the processes apart, one series per pid.
Mode::of(String) -> Self raise @metric.Refused
The mode a file name spells. An unknown spelling is refused: it would change what the numbers mean, which is worse than a failed scrape.
Part
One worker's file, decoded: whose it is, what kind of metric it holds, the gauge mode it was written for, and its values.
The process the file belongs to, as the pid label carries it.
The gauge mode, for a file of gauges; None for every other kind.
Part::decode(String, Bytes) -> Self raise @metric.Refused
Decode one worker's file. A file shorter than its header claims is refused rather than half-read: a torn file means a writer that does not write whole files, and guessing at the remainder would report numbers nobody wrote.
Part::encode(Self) -> Bytes
The bytes of this part: a four-byte used count, four bytes of padding, then one record per entry — a key length, the key, padding to an eight-byte boundary, the value, and the timestamp, each value a little-endian double.
This is the layout the official clients' multiprocess mode uses, which is the point: a directory of these files is readable by them and by this library alike.
Part::file_name(Self) -> String
The name this part is stored under: <kind>_<pid>.db, or gauge_<mode>_<pid>.db for gauges, which is the layout the official clients read and write.
Part::name_of(String) -> (String, @metric.Kind, Mode?) raise @metric.Refused
The part a file name announces. A gauge file carries its mode in the name because the mode is a property of how the worker wrote the value, and the scrape has no other way to learn it.
Part::new(String, @metric.Kind, Mode?, Array[Entry]) -> Self
One worker's file.
moonbitstack/moonp8s/multiproc/directory
The directory the worker files live in. Native only: writing a process's file, reading them all at a scrape, and forgetting the gauges of a process that has exited.
Written
What one flush left behind: how many files it wrote, how many series they hold, and the families it could not share between processes.
Families of a kind that has no cross-process meaning — an info metric, a state set, a gauge histogram — left out by name rather than dropped quietly.