From 0fae4614084adf020bb2ce61498b5fde438a5187 Mon Sep 17 00:00:00 2001 From: Winni Neessen Date: Fri, 22 Dec 2023 17:31:41 +0100 Subject: [PATCH] Implement Ruleset configuration in logranger Added a Ruleset configuration to the logranger application, along with associated error handling. The code now loads a ruleset file from configuration, checks for duplicate rules, and logs each rule as it is found. The ruleset is also integrated within the server setup. The PIDFile now includes a default RuleFile reference in config.go. --- config.go | 3 ++- rule.go | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ server.go | 16 +++++++++++++++- 3 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 rule.go diff --git a/config.go b/config.go index c5618de..1490233 100644 --- a/config.go +++ b/config.go @@ -20,7 +20,8 @@ import ( type Config struct { // Server holds server specific configuration values Server struct { - PIDFile string `fig:"pid_file" default:"/var/run/logranger.pid"` + PIDFile string `fig:"pid_file" default:"/var/run/logranger.pid"` + RuleFile string `fig:"rule_file" default:"etc/logranger.rules.toml"` } Listener struct { ListenerUnix struct { diff --git a/rule.go b/rule.go new file mode 100644 index 0000000..9e7c8a8 --- /dev/null +++ b/rule.go @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: 2023 Winni Neessen +// +// SPDX-License-Identifier: MIT + +package logranger + +import ( + "fmt" + "os" + "path/filepath" + "regexp" + "strings" + + "github.com/kkyr/fig" +) + +type Ruleset struct { + Rule []struct { + ID string `fig:"id" validate:"required"` + Regexp *regexp.Regexp `fig:"regexp" validate:"required"` + } `fig:"rule"` +} + +func NewRuleset(c *Config) (*Ruleset, error) { + rs := &Ruleset{} + p := filepath.Dir(c.Server.RuleFile) + f := filepath.Base(c.Server.RuleFile) + _, err := os.Stat(fmt.Sprintf("%s/%s", p, f)) + if err != nil { + return rs, fmt.Errorf("failed to read config: %w", err) + } + + if err = fig.Load(rs, fig.Dirs(p), fig.File(f), fig.UseStrict()); err != nil { + return rs, fmt.Errorf("failed to load ruleset: %w", err) + } + + rna := make([]string, 0) + for _, r := range rs.Rule { + for _, rn := range rna { + if strings.EqualFold(r.ID, rn) { + return nil, fmt.Errorf("duplicate rule found: %s", r.ID) + } + } + rna = append(rna, r.ID) + } + + return rs, nil +} diff --git a/server.go b/server.go index 73b3370..3c5949d 100644 --- a/server.go +++ b/server.go @@ -35,6 +35,8 @@ type Server struct { log *slog.Logger // parser is a parsesyslog.Parser parser parsesyslog.Parser + // ruleset is a pointer to the ruleset + ruleset *Ruleset // wg is a sync.WaitGroup wg sync.WaitGroup } @@ -55,11 +57,22 @@ func (s *Server) Run() error { if err != nil { return err } + p, err := parsesyslog.New(s.conf.internal.ParserType) if err != nil { return fmt.Errorf("failed to initialize syslog parser: %w", err) } s.parser = p + + rs, err := NewRuleset(s.conf) + if err != nil { + return fmt.Errorf("failed to read ruleset: %w", err) + } + s.ruleset = rs + for _, r := range rs.Rule { + s.log.Debug("found rule", slog.String("ID", r.ID)) + } + return s.RunWithListener(l) } @@ -159,7 +172,8 @@ ReadLoop: s.log.Debug("log message successfully received", slog.String("message", lm.Message.String()), slog.String("facility", lm.Facility.String()), - slog.String("severity", lm.Severity.String())) + slog.String("severity", lm.Severity.String()), + slog.Time("server_time", lm.Timestamp)) } }