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.
This commit is contained in:
Winni Neessen 2023-12-22 17:31:41 +01:00
parent 77ad132bc7
commit 0fae461408
Signed by: wneessen
GPG key ID: 5F3AF39B820C119D
3 changed files with 65 additions and 2 deletions

View file

@ -21,6 +21,7 @@ type Config struct {
// Server holds server specific configuration values // Server holds server specific configuration values
Server struct { 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 { Listener struct {
ListenerUnix struct { ListenerUnix struct {

48
rule.go Normal file
View file

@ -0,0 +1,48 @@
// SPDX-FileCopyrightText: 2023 Winni Neessen <wn@neessen.dev>
//
// 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
}

View file

@ -35,6 +35,8 @@ type Server struct {
log *slog.Logger log *slog.Logger
// parser is a parsesyslog.Parser // parser is a parsesyslog.Parser
parser parsesyslog.Parser parser parsesyslog.Parser
// ruleset is a pointer to the ruleset
ruleset *Ruleset
// wg is a sync.WaitGroup // wg is a sync.WaitGroup
wg sync.WaitGroup wg sync.WaitGroup
} }
@ -55,11 +57,22 @@ func (s *Server) Run() error {
if err != nil { if err != nil {
return err return err
} }
p, err := parsesyslog.New(s.conf.internal.ParserType) p, err := parsesyslog.New(s.conf.internal.ParserType)
if err != nil { if err != nil {
return fmt.Errorf("failed to initialize syslog parser: %w", err) return fmt.Errorf("failed to initialize syslog parser: %w", err)
} }
s.parser = p 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) return s.RunWithListener(l)
} }
@ -159,7 +172,8 @@ ReadLoop:
s.log.Debug("log message successfully received", s.log.Debug("log message successfully received",
slog.String("message", lm.Message.String()), slog.String("message", lm.Message.String()),
slog.String("facility", lm.Facility.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))
} }
} }