moon-prometheus-sdk

    Prometheus metrics model, registry, and OpenMetrics text exporter for MoonBit.

    prometheus
    openmetrics
    metrics
    observability
    Download zip
    Author
    Version
    0.1.0
    License
    Apache-2.0
    Last updated
    2 months ago
    Downloads
    34

    #moon-prometheus-sdk

    MoonBit Prometheus/OpenMetrics 指标库。为长期运行的 MoonBit 服务提供标准指标模型、 注册表、文本导出和 HTTP 暴露能力,可接入 Prometheus、Grafana 及告警体系。

    #功能

    • Counter / Gauge / Histogram:输入校验、detached snapshot、_total 后缀规范
    • Vector 系列:CounterVec、GaugeVec、HistogramVec,label 去重和 cardinality 上限
    • Registry:显式注册/注销、自定义 Collector、稳定 gather、可选进程级默认实例
    • Build info:BuildInfoCollector 暴露 version、revision 和 target,值恒为 1
    • 文本导出:Prometheus text 0.0.4 与 OpenMetrics 1.0,含转义、特殊浮点和直方图编码
    • HTTP 暴露:框架无关的 Accept 协商和 /metrics handler
    • 多 target:Wasm、Wasm-GC、JavaScript、native;native 内部使用 pthread mutex 保护计数

    #安装

    0.1.0 发布到 mooncakes.io 后,在消费者项目中安装固定版本:

    moon add guiqi695/moon-prometheus-sdk@0.1.0

    推荐固定版本,避免依赖解析结果随未来发布变化。源码检出场景先执行 moon update, 再运行构建或测试。

    #快速开始

    ///|
    fn main raise {
    let registry = @prometheus.Registry::new()
    let requests = @prometheus.Counter::new(
    "http_requests_total",
    help="Total HTTP requests",
    )
    let in_flight = @prometheus.Gauge::new(
    "in_flight_requests",
    help="Requests currently being served",
    )
    let latency = @prometheus.Histogram::new(
    "http_request_duration_seconds",
    [0.01, 0.05, 0.1, 0.5, 1.0],
    help="HTTP request latency",
    unit="seconds",
    )

    registry.register_counter(requests)
    registry.register_gauge(in_flight)
    registry.register_histogram(latency)

    in_flight.inc()
    requests.inc()
    latency.observe(0.042)
    in_flight.dec()

    println(@prometheus.encode(registry))
    }

    运行内置示例:

    moon run examples/basic

    #API 概览

    #Counter / Gauge / Histogram

    let c = @prometheus.Counter::new("http_requests_total", help="Total HTTP requests")
    c.inc()
    c.add(5.0)

    let g = @prometheus.Gauge::new("in_flight_requests", help="In-flight requests")
    g.inc()
    g.dec()
    g.set(42.0)

    let h = @prometheus.Histogram::new(
    "http_request_duration_seconds",
    [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0],
    help="Request duration",
    unit="seconds",
    )
    h.observe(0.047)

    #带标签的 Vector

    let descriptor = @prometheus.Descriptor::new(
    "http_responses_total",
    CounterKind,
    help="Responses by outcome and status",
    variable_label_names=["outcome", "code"],
    )
    let responses = @prometheus.CounterVec::new(descriptor, cardinality_limit=32)
    responses.with_labels({ "outcome": "ok", "code": "200" }).inc()
    responses.with_label_values(["error", "500"]).add(2.0)
    registry.register_counter_vec(responses)

    不要把 user ID、request ID、URL 等无界取值放进 label。

    #Registry

    // 显式 Registry(推荐用于库和多租户场景)
    let registry = @prometheus.Registry::new()
    let handle = registry.register_counter(my_counter)
    ignore(registry.unregister(handle))

    // 进程级默认 Registry(小型单 owner 应用)
    let reg = @prometheus.default_registry()
    let h = reg.register_counter_with_handle(my_counter)

    #BuildInfoCollector

    BuildInfoCollector 生成 Gauge family moonbit_build_info,携带 version、 revision 和 target 三个常量 label,样本值恒为 1。它可通过根 facade 使用:

    let build = @prometheus.BuildInfoCollector::new(
    "0.1.0",
    revision="abc123",
    target="native",
    )
    ignore(registry.register_collector(build.collector()))

    部署时建议从构建系统注入真实 revision 和 target;未传入时使用 API 默认值, 不要把时间戳等每次启动都会变化的数据作为 label。

    #暴露 /metrics

    let response = @prometheus.handle_metrics(
    registry,
    accept="application/openmetrics-text; version=1.0.0",
    )
    // 将 response.status、response.headers、response.body 写入 HTTP 框架

    native demo:

    moon run cmd/metrics_demo --target native curl -i http://127.0.0.1:9464/metrics

    #从源码构建与测试

    moon update moon check --target all moon build --target all moon test --target native moon run examples/basic

    完整验收(需 Node.js、curl、Go、promtool):

    MOON_BIN=moon GO_BIN=go PROMTOOL_BIN=promtool bash scripts/acceptance.sh

    验收脚本覆盖 all-target check/build/test、示例与 native /metrics smoke、benchmark、 Go/promtool 互操作以及格式化和生成接口漂移检查。发布到 mooncakes.io 后,还应从一个 全新的消费者模块验证 registry 安装和根 facade:

    PACKAGE_VERSION=0.1.0 bash scripts/published_package_smoke.sh

    该 smoke 会通过 moon add 安装已发布版本,因此不能替代发布前的源码验收,也不应在 包尚未发布时作为主分支 CI 的必过步骤。

    #平台兼容性

    targetLinuxmacOSWindows
    Wasm / Wasm-GC / JavaScript支持支持支持
    native支持(POSIX/pthread)支持(POSIX/pthread)当前不支持

    CI 的完整质量门禁在 Linux 上运行,并以 macOS、Windows matrix 验证可移植 target; Windows job 不构建 native,避免把当前 POSIX/pthread 实现误报为 Windows 支持。

    #发布验收

    维护者发布 0.1.0 时按以下顺序执行,任一步失败都不应创建 tag 或 GitHub Release:

    bash scripts/acceptance.sh moon publish --dry-run moon publish PACKAGE_VERSION=0.1.0 bash scripts/published_package_smoke.sh

    外部消费者 smoke 通过后,再创建并推送 v0.1.0 tag 与对应 GitHub Release。 Release 触发的独立 smoke workflow 会再次从 mooncakes.io 安装该版本;仓库中的 0.1.0 版本号、发布包版本、tag 和 Release 必须一致。

    #并发模型

    核心模型、Registry 与 exporter 支持 Wasm、Wasm-GC、JavaScript 和 native 四种 target。 native 的数值存储使用 C-owned pthread_mutex 保护,Vec/Registry 的 table 操作使用短 临界区并在 gather 时 copy-and-release。

    公共对象采用 单 owner / event-loop 模型 —— 不要把同一 MoonBit 对象跨 OS thread 共享。该约束是 0.1.0 的已知设计边界。

    #文档

    #许可证

    本项目是参考 Prometheus/OpenMetrics 公开规范的原创 MoonBit 实现,不包含任何第三方 客户端库源码。

    BuildInfoCollector

    Ready-to-register collectors for common application metadata.

    CollectorAdapter

    Registry collection API. Explicit instances remain the preferred default.

    CollectorError

    Registry collection API. Explicit instances remain the preferred default.

    Counter

    Stable public metric model API.

    CounterVec

    Label-vector API. Child storage remains an implementation detail.

    Descriptor

    Stable public metric model API.

    DescriptorIdentity

    Stable public metric model API.

    EncodedExposition

    Prometheus/OpenMetrics exposition API.

    EncodingError

    Prometheus/OpenMetrics exposition API.

    ExpositionFormat

    Prometheus/OpenMetrics exposition API.

    FamilySnapshot

    Registry collection API. Explicit instances remain the preferred default.

    FamilyType

    Registry collection API. Explicit instances remain the preferred default.

    GatherError

    Registry collection API. Explicit instances remain the preferred default.

    GatherSnapshot

    Registry collection API. Explicit instances remain the preferred default.

    Gauge

    Stable public metric model API.

    GaugeVec

    Label-vector API. Child storage remains an implementation detail.

    Framework-neutral HTTP response and content negotiation API.

    Histogram

    Stable public metric model API.

    HistogramSampleSnapshot

    Registry collection API. Explicit instances remain the preferred default.

    HistogramSnapshot

    Stable public metric model API.

    HistogramVec

    Label-vector API. Child storage remains an implementation detail.

    HttpMetricsError

    Framework-neutral HTTP response and content negotiation API.

    Label

    Stable public metric model API.

    LabelSchema

    Label-vector API. Child storage remains an implementation detail.

    MetricError

    Stable public metric model API.

    MetricKind

    Stable public metric model API.

    MetricsResponse

    Framework-neutral HTTP response and content negotiation API.

    Registration

    Registry collection API. Explicit instances remain the preferred default.

    Registry

    Registry collection API. Explicit instances remain the preferred default.

    RegistryError

    Registry collection API. Explicit instances remain the preferred default.

    ScalarMetricSnapshot

    Stable public metric model API.

    ScalarSampleSnapshot

    Registry collection API. Explicit instances remain the preferred default.

    VectorError

    Label-vector API. Child storage remains an implementation detail.

    bad_request_response

    Return the stable response used for malformed or oversized Accept headers.

    default_registry

    Return the process-wide convenience registry.

    Values registered here remain present until they are explicitly unregistered. Callers that need cleanup should use a register_*_with_handle method and retain the returned Registration.

    encode

    Convenience OpenMetrics entry point for a complete registry snapshot.

    Unlike the scalar-only M0 compatibility function encode_registry, this gathers every registered collector, including vectors and custom adapters. New HTTP/exporter code should select an explicit format and use encode_snapshot(registry.gather(), format) so gather and encoding errors can be handled separately.

    encode_registry

    Transitional encoder for the M0 registry object.

    P0 callers should use encode_snapshot(registry.gather(), format) once Registry::gather is available. This compatibility path remains useful to existing M0 consumers and shares the same escaping, number, and format semantics.

    encode_snapshot

    Encode an immutable gather snapshot in the requested text exposition format.

    Family and sample order is canonicalized here, so equivalent snapshots produce identical bytes regardless of collection order. Prometheus text 0.0.4 omits UNIT and # EOF; OpenMetrics 1.0 includes both.

    handle_metrics

    Gather, negotiate and encode one complete /metrics response.

    This is the main framework-neutral integration entry point. It never returns a successful response containing a partial exposition: malformed negotiation is 400, unsupported formats are 406, and gather/encoding failures are 500 with a non-sensitive body.

    internal_error_response

    Return the stable response used after gather or encoding fails.

    The body intentionally does not contain internal collector errors, label values, or a partial exposition.

    metrics_response

    Wrap a fully encoded exposition without depending on an HTTP framework.

    metrics_response_from_exposition

    Wrap an encoder result while preserving its format/content-type contract.

    negotiate

    Select a supported exposition format from an HTTP Accept header.

    Missing or blank Accept defaults to Prometheus text 0.0.4 for legacy scraper compatibility. For equal quality and equally specific explicit formats, OpenMetrics wins; a wildcard-only tie remains Prometheus.

    negotiated_metrics_response

    fn negotiated_metrics_response(accept : String?, prometheus_body : String, openmetrics_body : String) ->
    MetricsResponse

    Select one already-complete body for a framework-neutral metrics response.

    This is intentionally a pure function. A concrete server first calls negotiate, gathers and encodes exactly the selected format, then maps an encoder error to internal_error_response. Passing both bodies here keeps the content-negotiation contract directly testable without a web runtime.

    not_acceptable_response

    Return the stable response used when neither supported format is acceptable.

    validate_help

    fn validate_help(help : String) -> Unit raise
    MetricError

    validate_histogram_boundaries

    fn validate_histogram_boundaries(boundaries : Array[Double]) -> Unit raise
    MetricError

    validate_label_name

    fn validate_label_name(name : String) -> Unit raise
    MetricError

    validate_metric_name

    fn validate_metric_name(name : String) -> Unit raise
    MetricError

    validate_unit

    fn validate_unit(unit : String) -> Unit raise
    MetricError