package main import ( "context" "errors" "fmt" "log" "net/http" "os" "os/signal" "sync" "syscall" "time" _ "github.com/duckdb/duckdb-go/v2" "gopkg.in/ini.v1" "datasource/collector" "datasource/config" "datasource/controller" "datasource/store" ) func main() { // todo (david): init logger var wg sync.WaitGroup defer wg.Wait() ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) defer stop() cfg, err := ini.Load("./config.ini") if err != nil { log.Fatal(err) } dataSourceConfig, err := config.LoadDataSourceConfig(cfg) if err != nil { log.Fatal(err) } store, err := store.NewStore(dataSourceConfig.DBPath) if err != nil { log.Fatal(err) } defer store.Close() redisConfig, err := config.LoadRedisConfig(cfg) if err != nil { log.Fatal(err) } redisCollector := collector.NewRedisCollector(redisConfig, store) defer redisCollector.Close() collectors := []collector.Collector{redisCollector} for _, collector := range collectors { wg.Add(1) go func() { defer wg.Done() ticker := time.NewTicker(5 * time.Second) defer ticker.Stop() for { select { case <-ctx.Done(): return case <-ticker.C: if err := collector.Collect(ctx); err != nil { log.Printf("failed to collect: %v", err) } } } }() } controller := controller.NewController(store) mux := http.NewServeMux() mux.HandleFunc("GET /api/v1/metrics", controller.GetMetrics) // todo (david) // mux.HandleFunc("DELETE /api/v1/metrics", controller.DeleteMetrics) srv := &http.Server{ Addr: fmt.Sprintf("0.0.0.0:%d", dataSourceConfig.Port), Handler: mux, } wg.Add(1) go func() { defer wg.Done() if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { log.Fatalf("http.ListenAndServe: %v\n", err) } }() <-ctx.Done() srv.Shutdown(context.Background()) srvShutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() if err := srv.Shutdown(srvShutdownCtx); err != nil { log.Fatalf("srv.Shutdown: %v", err) } }