Skip to content

Read metrics

Source · io.systemd.Metrics · systemd v260+ · Unprivileged

systemd v260 introduced io.systemd.Metrics: services publish metric families on sockets under /run/systemd/report/. This example discovers those sockets and streams every metric from each, which is the building block for exporters such as report2otel.

Run it

go run ./examples/metrics
go run ./examples/metrics /run/systemd/report/io.systemd.Network
Output (illustrative)
# io.systemd.Manager
io.systemd.Manager.unitsByTypeTotal 12
io.systemd.Manager.unitsByTypeTotal 41
io.systemd.Manager.unitActiveState{dev-hvc0.device} "active"
io.systemd.Manager.unitActiveState{ssh.service} "active"

The code

examples/metrics/main.go
// Command metrics reads the io.systemd.Metrics interface that systemd
// services publish under /run/systemd/report/ (systemd v260+), the
// building block for exporters such as report2otel.
//
//  go run ./examples/metrics
//  go run ./examples/metrics /run/systemd/report/io.systemd.Network
package main

import (
    "context"
    "fmt"
    "log"
    "os"
    "path/filepath"

    "github.com/rossedman/sdvarlink/systemd/v260/metrics"
    "github.com/rossedman/sdvarlink/varlink"
)

func main() {
    sockets := os.Args[1:]
    if len(sockets) == 0 {
        sockets, _ = filepath.Glob("/run/systemd/report/*")
    }
    if len(sockets) == 0 {
        log.Fatal("no metrics sockets under /run/systemd/report (systemd v260+)")
    }
    ctx := context.Background()
    for _, sock := range sockets {
        c, err := metrics.DialPath(ctx, sock)
        if err != nil {
            log.Printf("%s: %v", sock, err)
            continue
        }
        fmt.Printf("# %s\n", filepath.Base(sock))
        // List streams one reply per metric value.
        for m, err := range c.List(ctx) {
            if err != nil {
                log.Printf("%s: %v", sock, err)
                break
            }
            obj := varlink.Deref(m.Object)
            if obj != "" {
                obj = "{" + obj + "}"
            }
            fmt.Printf("%s%s %s\n", m.Name, obj, m.Value)
        }
        c.Close()
    }
}

How it works

  • No default socket. Many daemons implement io.systemd.Metrics, each on its own socket, so the package has DialPath but no Dial.
  • Requires-more. List streams one reply per metric; it takes no parameters, so the method is just List(ctx).
  • Untyped values. Value is IDL type any, so it's a json.RawMessage; Fields (?object) distinguishes metrics within a family (e.g. by unit type). Use Describe to learn each family's type (counter, gauge, string).

See also