Skip to content

Introspect a service

Source ยท Depends on the socket

varlinkctl info plus varlinkctl introspect, using only the core varlink package and the idl parser: no generated bindings. Point it at any Varlink socket, systemd's or your own.

Run it

go run ./examples/introspect /run/systemd/journal/io.systemd.journal
Output (real, systemd-journald v255)
systemd (systemd-journald) 255 (255.4-1ubuntu8.17) (The systemd Project)

io.systemd  (0 methods, 0 types, 4 errors)

io.systemd.Journal  (4 methods, 0 types, 1 errors)
    Synchronize() -> ()
    Rotate() -> ()
    FlushToVar() -> ()
    RelinquishVar() -> ()

org.varlink.service  (2 methods, 0 types, 6 errors)
    GetInfo() -> (vendor: string, product: string, version: string, url: string, interfaces: []string)
    GetInterfaceDescription(interface: string) -> (description: string)

The code

examples/introspect/main.go
// Command introspect lists the interfaces and methods a Varlink service
// offers, like `varlinkctl info` plus `varlinkctl introspect`, using the
// core varlink package and the idl parser.
//
//  go run ./examples/introspect /run/systemd/io.systemd.Manager
package main

import (
    "context"
    "fmt"
    "log"
    "os"

    "github.com/rossedman/sdvarlink/idl"
    "github.com/rossedman/sdvarlink/varlink"
)

func main() {
    if len(os.Args) != 2 {
        log.Fatal("usage: introspect SOCKET")
    }
    ctx := context.Background()
    conn, err := varlink.Dial(ctx, os.Args[1])
    if err != nil {
        log.Fatal(err)
    }
    defer conn.Close()

    info, err := varlink.GetInfo(ctx, conn)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%s %s (%s)\n\n", info.Product, info.Version, info.Vendor)

    for _, name := range info.Interfaces {
        desc, err := varlink.GetInterfaceDescription(ctx, conn, name)
        if err != nil {
            log.Fatal(err)
        }
        iface, err := idl.Parse(desc)
        if err != nil {
            log.Fatalf("%s: %v", name, err)
        }
        fmt.Printf("%s  (%d methods, %d types, %d errors)\n", iface.Name, len(iface.Methods), len(iface.Types), len(iface.Errors))
        for _, m := range iface.Methods {
            stream := ""
            if m.More != idl.MoreNone {
                stream = "  [" + m.More.String() + "]"
            }
            fmt.Printf("    %s%s -> %s%s\n", m.Name, m.In, m.Out, stream)
        }
        fmt.Println()
    }
}

How it works

  • varlink.GetInfo calls org.varlink.service.GetInfo: vendor, product, version and the interface list.
  • varlink.GetInterfaceDescription returns each interface's IDL text.
  • idl.Parse turns it into an *idl.Interface. idl.Type values print themselves in IDL syntax, and Method.More reports streaming annotations.
  • Both helpers take a varlink.Caller, so they work with a Conn, a Pool, or a generated client's Caller().

See also