package main import ( "context" "log/slog" "net/http" "os" "os/signal" "syscall" "time" "code.t-juice.club/torjus/nixos-exporter/collector" "code.t-juice.club/torjus/nixos-exporter/config" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" ) const version = "0.4.0" func main() { cfg, err := config.Parse() if err != nil { slog.Error("Failed to parse config", "error", err) os.Exit(1) } // Register generation collector genCollector := collector.NewGenerationCollector() prometheus.MustRegister(genCollector) slog.Info("Registered generation collector") // Register flake collector if enabled var flakeCollector *collector.FlakeCollector if cfg.FlakeCollector { var err error flakeCollector, err = collector.NewFlakeCollectorWithNATS(collector.FlakeCollectorConfig{ FlakeURL: cfg.FlakeURL, CheckInterval: cfg.FlakeCheckInterval, NATSEnabled: cfg.FlakeNATSEnable, NATSURL: cfg.FlakeNATSURL, NATSSubject: cfg.FlakeNATSSubject, NATSCredentialsFile: cfg.FlakeNATSCredentialsFile, NATSNkeySeedFile: cfg.FlakeNATSNkeySeedFile, }) if err != nil { slog.Error("Failed to create flake collector", "error", err) os.Exit(1) } prometheus.MustRegister(flakeCollector) slog.Info("Registered flake collector", "url", cfg.FlakeURL, "check_interval", cfg.FlakeCheckInterval, "nats_enabled", cfg.FlakeNATSEnable) } mux := http.NewServeMux() mux.Handle("/metrics", promhttp.Handler()) mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte(` NixOS Exporter

NixOS Exporter

Metrics

`)) }) server := &http.Server{ Addr: cfg.ListenAddr, Handler: mux, ReadTimeout: 10 * time.Second, WriteTimeout: 10 * time.Second, IdleTimeout: 60 * time.Second, } // Handle shutdown gracefully ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) defer stop() go func() { slog.Info("Starting server", "version", version, "addr", cfg.ListenAddr) if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { slog.Error("Server error", "error", err) os.Exit(1) } }() <-ctx.Done() slog.Info("Shutting down server") // Close flake collector (NATS connection) if flakeCollector != nil { if err := flakeCollector.Close(); err != nil { slog.Error("Failed to close flake collector", "error", err) } } shutdownCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := server.Shutdown(shutdownCtx); err != nil { slog.Error("Failed to shutdown server", "error", err) } }