From: Dan Fuhry Date: Mon, 19 Oct 2026 20:41:05 +0000 (-0400) Subject: [ldap] port ldap_health_exporter to builtin log and urfave/cli X-Git-Url: https://go.fuhry.dev/?a=commitdiff_plain;h=c5e3b86164f2ad2afb0b7aba442ef68b978a5339;p=runtime.git [ldap] port ldap_health_exporter to builtin log and urfave/cli --- diff --git a/cmd/ldap_health_exporter/BUILD.bazel b/cmd/ldap_health_exporter/BUILD.bazel index 519c1dd..b558816 100644 --- a/cmd/ldap_health_exporter/BUILD.bazel +++ b/cmd/ldap_health_exporter/BUILD.bazel @@ -9,9 +9,10 @@ go_multi_library( deps = [ "//ldap", "//mtls", + "//utils/context", + "//utils/log", "@com_github_sirupsen_logrus//:logrus", - "@com_github_urfave_cli_v2//:cli", - "@com_github_urfave_cli_v2//altsrc", + "@com_github_urfave_cli_v3//:cli", "@org_golang_x_sync//errgroup", ], ) diff --git a/cmd/ldap_health_exporter/main.go b/cmd/ldap_health_exporter/main.go index 4d3da0f..5d152c5 100644 --- a/cmd/ldap_health_exporter/main.go +++ b/cmd/ldap_health_exporter/main.go @@ -1,7 +1,7 @@ package main import ( - "context" + "flag" "os" "os/signal" "syscall" @@ -9,10 +9,13 @@ import ( exporter "go.fuhry.dev/runtime/ldap" "go.fuhry.dev/runtime/mtls" + "go.fuhry.dev/runtime/utils/context" + "go.fuhry.dev/runtime/utils/log" - log "github.com/sirupsen/logrus" - "github.com/urfave/cli/v2" - "github.com/urfave/cli/v2/altsrc" + "github.com/sirupsen/logrus" + + // "github.com/urfave/cli-altsrc/v3" + "github.com/urfave/cli/v3" "golang.org/x/sync/errgroup" ) @@ -22,7 +25,6 @@ const ( ldapAddr = "ldapAddr" ldapUser = "ldapUser" ldapPass = "ldapPass" - mtlsId = "mtlsId" interval = "interval" metrics = "metrPath" jsonLog = "jsonLog" @@ -32,104 +34,123 @@ const ( ) func main() { + ctx, cancel := context.Interruptible() + defer cancel() + flags := []cli.Flag{ - altsrc.NewStringFlag(&cli.StringFlag{ + &cli.StringFlag{ Name: promAddr, Value: ":9330", Usage: "Bind address for Prometheus HTTP metrics server", - EnvVars: []string{"PROM_ADDR"}, - }), - altsrc.NewStringFlag(&cli.StringFlag{ + Sources: cli.EnvVars("PROM_ADDR"), + }, + &cli.StringFlag{ Name: metrics, Value: "/metrics", Usage: "Path on which to expose Prometheus metrics", - EnvVars: []string{"METRICS_PATH"}, - }), - altsrc.NewStringFlag(&cli.StringFlag{ + Sources: cli.EnvVars("METRICS_PATH"), + }, + &cli.StringFlag{ Name: ldapNet, Value: "tcp", Usage: "Network of OpenLDAP server", - EnvVars: []string{"LDAP_NET"}, - }), - altsrc.NewStringFlag(&cli.StringFlag{ + Sources: cli.EnvVars("LDAP_NET"), + }, + &cli.StringFlag{ Name: ldapAddr, Value: "localhost:389", Usage: "Address and port of OpenLDAP server", - EnvVars: []string{"LDAP_ADDR"}, - }), - altsrc.NewStringFlag(&cli.StringFlag{ + Sources: cli.EnvVars("LDAP_ADDR"), + }, + &cli.StringFlag{ Name: ldapUser, Usage: "OpenLDAP bind username (optional)", - EnvVars: []string{"LDAP_USER"}, - }), - altsrc.NewStringFlag(&cli.StringFlag{ + Sources: cli.EnvVars("LDAP_USER"), + }, + &cli.StringFlag{ Name: ldapPass, Usage: "OpenLDAP bind password (optional)", - EnvVars: []string{"LDAP_PASS"}, - }), - altsrc.NewStringFlag(&cli.StringFlag{ - Name: mtlsId, - Usage: "mTLS identity from /etc/ssl/mtls", - EnvVars: []string{"MTLS_ID"}, - }), - altsrc.NewDurationFlag(&cli.DurationFlag{ + Sources: cli.EnvVars("LDAP_PASS"), + }, + &cli.DurationFlag{ Name: interval, Value: 30 * time.Second, Usage: "Scrape interval", - EnvVars: []string{"INTERVAL"}, - }), - altsrc.NewStringFlag(&cli.StringFlag{ + Sources: cli.EnvVars("INTERVAL"), + }, + &cli.StringFlag{ Name: webCfgFile, Usage: "Prometheus metrics web config `FILE` (optional)", - EnvVars: []string{"WEB_CFG_FILE"}, - }), - altsrc.NewBoolFlag(&cli.BoolFlag{ + Sources: cli.EnvVars("WEB_CFG_FILE"), + }, + &cli.BoolFlag{ Name: jsonLog, Value: false, Usage: "Output logs in JSON format", - EnvVars: []string{"JSON_LOG"}, - }), - altsrc.NewStringSliceFlag(&cli.StringSliceFlag{ + Sources: cli.EnvVars("JSON_LOG"), + }, + &cli.StringSliceFlag{ Name: replicationObject, Usage: "Object to watch replication upon", - }), - &cli.StringFlag{ - Name: config, - Usage: "Optional configuration from a `YAML_FILE`", }, + // &cli.StringFlag{ + // Name: config, + // Usage: "Optional configuration from a `YAML_FILE`", + // }, } - app := &cli.App{ - Name: "openldap_exporter", - Usage: "Export OpenLDAP metrics to Prometheus", - Before: altsrc.InitInputSourceWithContext(flags, optionalYamlSourceFunc(config)), + app := &cli.Command{ + Name: "openldap_exporter", + Usage: "Export OpenLDAP metrics to Prometheus", + // Before: altsrc.InitInputSourceWithContext(flags, optionalYamlSourceFunc(config)), Version: exporter.GetVersion(), HideHelpCommand: true, Flags: flags, Action: runMain, } - if err := app.Run(os.Args); err != nil { - log.WithError(err).Fatal("service failed") - } - log.Info("service stopped") -} - -func optionalYamlSourceFunc(flagFileName string) func(context *cli.Context) (altsrc.InputSourceContext, error) { - return func(c *cli.Context) (altsrc.InputSourceContext, error) { - filePath := c.String(flagFileName) - if filePath != "" { - return altsrc.NewYamlSourceFromFile(filePath) + flag.CommandLine.Parse([]string{}) + flag.CommandLine.VisitAll(func(f *flag.Flag) { + val, ok := f.Value.(cli.Value) + if !ok { + log.Default().Errorf("cannot convert flag %q (%s) of type %T to cli.Value", f.Name, f.Usage, f.Value) + app.Flags = append(app.Flags, &cli.StringFlag{ + Name: f.Name, + Usage: f.Usage, + Value: "", + Action: func(ctx context.Context, c *cli.Command, s string) error { + return f.Value.Set(s) + }, + }) + return } - return &altsrc.MapInputSource{}, nil + app.Flags = append(app.Flags, &cli.GenericFlag{ + Name: f.Name, + Usage: f.Usage, + Value: val, + }) + }) + if err := app.Run(ctx, os.Args); err != nil { + logrus.WithError(err).Fatal("service failed") } + logrus.Info("service stopped") } -func runMain(c *cli.Context) error { +// func optionalYamlSourceFunc(flagFileName string) func(context *cli.Context) (altsrc.InputSourceContext, error) { +// return func(c *cli.Context) (altsrc.InputSourceContext, error) { +// filePath := c.String(flagFileName) +// if filePath != "" { +// return altsrc.NewYamlSourceFromFile(filePath) +// } +// return &altsrc.MapInputSource{}, nil +// } +// } + +func runMain(ctx context.Context, c *cli.Command) error { if c.Bool(jsonLog) { - log.SetFormatter(&log.JSONFormatter{}) + logrus.SetFormatter(&logrus.JSONFormatter{}) } else { - log.SetFormatter(&log.TextFormatter{}) + logrus.SetFormatter(&logrus.TextFormatter{}) } - log.Info("service starting") + logrus.Info("service starting") server := exporter.NewMetricsServer( c.String(promAddr), @@ -142,7 +163,7 @@ func runMain(c *cli.Context) error { Addr: c.String(ldapAddr), User: c.String(ldapUser), Pass: c.String(ldapPass), - Mtls: mtls.NewServiceIdentity(c.String(mtlsId)), + Mtls: mtls.NewServiceIdentity(c.String("mtls.id")), Tick: c.Duration(interval), Sync: c.StringSlice(replicationObject), } @@ -167,7 +188,7 @@ func runMain(c *cli.Context) error { signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM) select { case <-signalChan: - log.Info("shutdown received") + logrus.Info("shutdown received") return nil case <-ctx.Done(): return nil diff --git a/ldap/BUILD.bazel b/ldap/BUILD.bazel index 8b46183..42c767c 100644 --- a/ldap/BUILD.bazel +++ b/ldap/BUILD.bazel @@ -11,7 +11,7 @@ go_multi_library( deps = [ "//mtls", "//mtls/certutil", - "@com_github_go_kit_log//:log", + "//utils/log", "@com_github_go_ldap_ldap_v3//:ldap", "@com_github_prometheus_client_golang//prometheus", "@com_github_prometheus_client_golang//prometheus/promhttp", diff --git a/ldap/server.go b/ldap/server.go index 1b8c467..5eb5edc 100644 --- a/ldap/server.go +++ b/ldap/server.go @@ -4,17 +4,20 @@ import ( "context" "errors" "fmt" + "log/slog" "net/http" "time" - kitlog "github.com/go-kit/log" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/prometheus/exporter-toolkit/web" - log "github.com/sirupsen/logrus" + + "go.fuhry.dev/runtime/utils/log" ) -var commit string -var tag string +var ( + commit string + tag string +) func GetVersion() string { return fmt.Sprintf("%s (%s)", tag, commit) @@ -23,7 +26,7 @@ func GetVersion() string { type Server struct { server *http.Server flagConfig *web.FlagConfig - logger log.FieldLogger + logger log.Logger } func NewMetricsServer(bindAddr, metricsPath, tlsConfigPath string) *Server { @@ -38,7 +41,7 @@ func NewMetricsServer(bindAddr, metricsPath, tlsConfigPath string) *Server { WebSystemdSocket: &systemdSocket, WebConfigFile: &tlsConfigPath, }, - logger: log.WithField("component", "server"), + logger: log.Default().WithAttrs([]slog.Attr{{"component", slog.StringValue("server")}}).(log.Logger), } } @@ -52,8 +55,9 @@ func showVersion(w http.ResponseWriter, r *http.Request) { } func (s *Server) Start() error { - s.logger.WithField("addr", s.server.Addr).Info("starting http listener") - err := web.ListenAndServe(s.server, s.flagConfig, kitlog.LoggerFunc(s.adaptor)) + logger := s.logger.WithAttrs([]slog.Attr{{"addr", slog.StringValue(s.server.Addr)}}).(log.Logger) + logger.Info("starting http listener") + err := web.ListenAndServe(s.server, s.flagConfig, slog.New(s.logger)) if errors.Is(err, http.ErrServerClosed) { return nil } @@ -65,39 +69,3 @@ func (s *Server) Stop() { s.server.Shutdown(ctx) cancel() } - -func (s *Server) adaptor(kvs ...interface{}) error { - if len(kvs) == 0 { - return nil - } - if len(kvs)%2 != 0 { - kvs = append(kvs, nil) - } - fields := log.Fields{} - for i := 0; i < len(kvs); i += 2 { - key := fmt.Sprint(kvs[i]) - fields[key] = kvs[i+1] - } - var msg string - if val, ok := fields["msg"]; ok { - delete(fields, "msg") - msg = fmt.Sprint(val) - } - var level string - if val, ok := fields["level"]; ok { - delete(fields, "level") - level = fmt.Sprint(val) - } - ll := s.logger.WithFields(fields) - switch level { - case "error": - ll.Error(msg) - case "warn": - ll.Warn(msg) - case "debug": - ll.Debug(msg) - default: - ll.Info(msg) - } - return nil -}