From 6a4c0a16118d0b545c3c5f6a08ecad432940c1cf Mon Sep 17 00:00:00 2001 From: Mel Date: Thu, 20 Aug 2026 21:45:20 +0200 Subject: Clean logging for modules Signed-off-by: Mel --- config.go | 4 +- main.go | 119 ++++++++++++++++++++++++++++++++++++--------------- provider/dummy.go | 7 +-- provider/provider.go | 10 ++++- source/file.go | 2 - source/source.go | 10 ++++- source/static.go | 1 - source/url.go | 2 - 8 files changed, 106 insertions(+), 49 deletions(-) diff --git a/config.go b/config.go index 9cd614d..eaf9d50 100644 --- a/config.go +++ b/config.go @@ -43,10 +43,10 @@ func LoadConfig(path string) (*Config, error) { return nil, fmt.Errorf("record %d: type must be A or AAAA", i) } if _, ok := cfg.Providers[r.Provider]; !ok { - return nil, fmt.Errorf("record %d: unknown provider %q", i, r.Provider) + return nil, fmt.Errorf("record %d: unknown provider '%s'", i, r.Provider) } if _, ok := cfg.Sources[r.Source]; !ok { - return nil, fmt.Errorf("record %d: unknown source %q", i, r.Source) + return nil, fmt.Errorf("record %d: unknown source '%s'", i, r.Source) } } return &cfg, nil diff --git a/main.go b/main.go index cc99e9e..96a3ae7 100644 --- a/main.go +++ b/main.go @@ -27,50 +27,55 @@ func main() { return } - slog.Info("ddnnss!", slog.String("version", version)) + baseLog := slog.New(slog.NewTextHandler(os.Stderr, nil)) + baseLog.Info("ddnnss!", slog.String("version", version)) cfg, err := LoadConfig(*configPath) if err != nil { - slog.Error("could not load config", slog.String("error", err.Error())) + baseLog.Error("could not load config", slog.String("error", err.Error())) os.Exit(1) } - providers := map[string]provider.Provider{} - sources := map[string]source.Source{} + providers, sources := createModules(baseLog, cfg) - slog.Info("starting new cycle", slog.Int("records", len(cfg.Records))) + baseLog.Info("starting new cycle", slog.Int("records", len(cfg.Records))) failed := false for _, r := range cfg.Records { fqdn := r.Name + "." + r.Zone - log := slog.With("record", fqdn, "type", r.Type) + log := baseLog.With( + slog.Group("record", + slog.String("fqdn", fqdn), + slog.String("type", string(r.Type)), + ), + ) + + sourceName, providerName := r.Source, r.Provider log.Info( "ensuring record", - slog.String("provider", r.Provider), - slog.String("source", r.Source), + slog.String("provider", providerName), + slog.String("source", sourceName), ) - p, ok := providers[r.Provider] - if !ok { - p, err = provider.New(log, cfg.Providers[r.Provider]) - if err != nil { - log.Error("provider setup failed", "provider", r.Provider, "error", err) - failed = true - continue - } - providers[r.Provider] = p + s, ok := sources[sourceName] + if !ok || s == nil { + log.Error( + "skipping record, failed creating source", + slog.String("source", sourceName), + ) + failed = true + continue } - s, ok := sources[r.Source] - if !ok { - s, err = source.New(log, cfg.Sources[r.Source]) - if err != nil { - log.Error("source setup failed", "source", r.Source, "error", err) - failed = true - continue - } - sources[r.Source] = s + p, ok := providers[providerName] + if !ok || p == nil { + log.Error( + "skipping record, failed creating provider", + slog.String("provider", providerName), + ) + failed = true + continue } family := source.IPv4 @@ -78,15 +83,22 @@ func main() { family = source.IPv6 } if !s.Supports(family) { - log.Error("source cannot provide the needed address family", - "source", r.Source, "family", family) + log.Error( + "skipping record, source cannot provide the needed address family", + slog.String("source", sourceName), + slog.String("family", string(family)), + ) failed = true continue } addr, err := s.Lookup(family) if err != nil { - log.Error("address lookup failed", "source", r.Source, "error", err) + log.Error( + "failed record, address lookup failed", + slog.String("source", sourceName), + slog.String("error", err.Error()), + ) failed = true continue } @@ -94,25 +106,62 @@ func main() { prev, changed, err := p.Ensure(r.Zone, r.Name, r.Type, addr) switch { case err != nil: - log.Error("update failed", "error", err) + log.Error("record update failed", slog.String("error", err.Error())) failed = true case changed && prev == "": - log.Info("record created", "addr", addr) + log.Info("record created", slog.String("addr", addr.String())) case changed: - log.Info("record updated", "from", prev, "to", addr) + log.Info("record updated", slog.String("from", prev), slog.String("to", addr.String())) default: log.Info("record unchanged", "addr", addr) } } - slog.Info( - "cycle finished", + baseLog.Info( + "cycle finished!", slog.Int("records", len(cfg.Records)), slog.Bool("failed", failed), ) if failed { - slog.Error("not all records were ensured successfully") + baseLog.Error("not all records were ensured successfully") os.Exit(1) } } + +func createModules(log *slog.Logger, cfg *Config) (map[string]provider.Provider, map[string]source.Source) { + sources := map[string]source.Source{} + providers := map[string]provider.Provider{} + + for name, c := range cfg.Sources { + s, err := source.New(log, name, c) + if err != nil { + log.Error( + "failed creating source", + slog.String("name", name), + slog.String("kind", string(c.Kind)), + slog.String("error", err.Error()), + ) + sources[name] = nil + continue + } + sources[name] = s + } + + for name, c := range cfg.Providers { + p, err := provider.New(log, name, c) + if err != nil { + log.Error( + "failed creating provider", + slog.String("name", name), + slog.String("kind", string(c.Kind)), + slog.String("error", err.Error()), + ) + providers[name] = nil + continue + } + providers[name] = p + } + + return providers, sources +} diff --git a/provider/dummy.go b/provider/dummy.go index bec5907..1f64f6f 100644 --- a/provider/dummy.go +++ b/provider/dummy.go @@ -17,15 +17,12 @@ type dummy struct { var _ Provider = (*dummy)(nil) func newDummy(log *slog.Logger) (*dummy, error) { - return &dummy{log: log.With(slog.String("provider", "dummy"))}, nil + return &dummy{log: log}, nil } -func (d *dummy) Ensure(zone, name string, rtype RecordType, addr netip.Addr) (string, bool, error) { +func (d *dummy) Ensure(_ string, _ string, _ RecordType, addr netip.Addr) (string, bool, error) { d.log.Info( "asked to ensure record, but nothing happened", - slog.String("zone", zone), - slog.String("name", name), - slog.String("record", string(rtype)), slog.String("addr", addr.String()), ) return "", true, nil diff --git a/provider/provider.go b/provider/provider.go index ee31ba8..ce4a715 100644 --- a/provider/provider.go +++ b/provider/provider.go @@ -63,7 +63,15 @@ type Provider interface { Ensure(zone, name string, rtype RecordType, addr netip.Addr) (string, bool, error) } -func New(log *slog.Logger, cfg Config) (Provider, error) { +func New(log *slog.Logger, name string, cfg Config) (Provider, error) { + log = log.With( + slog.Group( + "provider", + slog.String("name", name), + slog.String("kind", string(cfg.Kind)), + ), + ) + switch cfg.Kind { case KindDummy: return newDummy(log) diff --git a/source/file.go b/source/file.go index 4ef0e7c..004868f 100644 --- a/source/file.go +++ b/source/file.go @@ -20,8 +20,6 @@ type fileSource struct { var _ Source = (*fileSource)(nil) func newFile(log *slog.Logger, cfg Config) (*fileSource, error) { - log = log.With(slog.String("source", "file")) - if _, err := os.Stat(cfg.Path); errors.Is(err, os.ErrNotExist) { return nil, fmt.Errorf("cannot access file for source: %w", err) } diff --git a/source/source.go b/source/source.go index 6fe139c..ffa380a 100644 --- a/source/source.go +++ b/source/source.go @@ -40,7 +40,15 @@ type Source interface { Lookup(Family) (netip.Addr, error) } -func New(log *slog.Logger, cfg Config) (Source, error) { +func New(log *slog.Logger, name string, cfg Config) (Source, error) { + log = log.With( + slog.Group( + "source", + slog.String("name", name), + slog.String("kind", string(cfg.Kind)), + ), + ) + if cfg.Family != IPv4 && cfg.Family != IPv6 { return nil, fmt.Errorf("%s source needs family set to ipv4 or ipv6", cfg.Kind) } diff --git a/source/static.go b/source/static.go index d2645d6..4b27e5a 100644 --- a/source/static.go +++ b/source/static.go @@ -17,7 +17,6 @@ type staticSource struct { var _ Source = (*staticSource)(nil) func newStatic(log *slog.Logger, cfg Config) (*staticSource, error) { - log = log.With("source", "static") addr, err := parse(cfg.Value, cfg.Family) if err != nil { log.Error( diff --git a/source/url.go b/source/url.go index 067d48b..41452be 100644 --- a/source/url.go +++ b/source/url.go @@ -21,8 +21,6 @@ type urlSource struct { var _ Source = (*urlSource)(nil) func newURL(log *slog.Logger, cfg Config) (*urlSource, error) { - log = log.With("source", "url") - url, err := nurl.ParseRequestURI(cfg.URL) if err != nil { return nil, fmt.Errorf("invalid url for source: %w", err) -- cgit v1.3.1