package main
import (
- "context"
+ "flag"
"os"
"os/signal"
"syscall"
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"
)
ldapAddr = "ldapAddr"
ldapUser = "ldapUser"
ldapPass = "ldapPass"
- mtlsId = "mtlsId"
interval = "interval"
metrics = "metrPath"
jsonLog = "jsonLog"
)
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),
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),
}
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
"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)
type Server struct {
server *http.Server
flagConfig *web.FlagConfig
- logger log.FieldLogger
+ logger log.Logger
}
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),
}
}
}
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
}
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
-}