// Command ffd-metrics is the long-running metrics daemon for the federated // forge indexer. // // It reads the same SQLite store the indexer writes to and exposes the state // of the index to Prometheus at /metrics. It is intended to be run as a // separate systemd service; it performs no scraping of its own. package main import ( "context" "errors" "flag" "fmt" "net/http" "os" "os/signal" "syscall" "time" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" "go.yaml.in/yaml/v4" "git.xengi.de/ffd/indexer/config" "git.xengi.de/ffd/indexer/internal/version" "git.xengi.de/ffd/indexer/metrics" "git.xengi.de/ffd/indexer/store" ) func main() { configPath := flag.String("config", "config.yaml", "path to the configuration file") showVersion := flag.Bool("version", false, "print version and commit, then exit") flag.Parse() if *showVersion { version.PrintFull() return } data, err := os.ReadFile(*configPath) if err != nil { panic(err) } var cfg config.Config if err := yaml.Unmarshal(data, &cfg); err != nil { panic(err) } // The daemon shares the indexer's database; both processes may be open on // it at once (the SQLite driver handles that with WAL-safe read queries). db, err := store.Open(cfg.DbPath) if err != nil { panic(err) } defer func() { _ = db.Close() }() registry := prometheus.NewRegistry() registry.MustRegister(metrics.NewCollector(db)) mux := http.NewServeMux() mux.Handle("/metrics", promhttp.HandlerFor(registry, promhttp.HandlerOpts{})) srv := &http.Server{ Addr: cfg.Metrics.Listen, Handler: mux, ReadHeaderTimeout: 5 * time.Second, } // Shut down cleanly on SIGTERM/SIGINT. ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM, os.Interrupt) defer stop() errCh := make(chan error, 1) go func() { fmt.Printf("ffd-metrics listening on %s\n", srv.Addr) errCh <- srv.ListenAndServe() }() select { case err := <-errCh: if err != nil && !errors.Is(err, http.ErrServerClosed) { fmt.Fprintf(os.Stderr, "metrics server: %v\n", err) os.Exit(1) } case <-ctx.Done(): fmt.Println("shutting down") shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := srv.Shutdown(shutdownCtx); err != nil { fmt.Fprintf(os.Stderr, "shutdown: %v\n", err) } } }