feat: implement drain3 based generic log-parser
This commit is contained in:
parent
1d1568e3ee
commit
5af49f926a
17 changed files with 612 additions and 220 deletions
|
|
@ -3,21 +3,28 @@ package parser
|
|||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"watch-tool/models"
|
||||
"watch-tool/patterns"
|
||||
|
||||
"codeberg.org/pata1704/drain3"
|
||||
)
|
||||
|
||||
type GenericParser struct {
|
||||
ServiceName string
|
||||
Hostname string
|
||||
Extractors []patterns.CompiledExtractor
|
||||
CommonExt []patterns.CompiledExtractor
|
||||
ServiceName string
|
||||
Hostname string
|
||||
Extractors []patterns.CompiledExtractor
|
||||
CommonExt []patterns.CompiledExtractor
|
||||
drainMiner *drain3.TemplateMiner
|
||||
drainEnabled bool
|
||||
drainStatePath string
|
||||
}
|
||||
|
||||
func NewGenericParser(serviceName, hostname string) *GenericParser {
|
||||
func NewGenericParser(serviceName, hostname string, drainCfg *drain3.Config, stateDir string) *GenericParser {
|
||||
repo := patterns.GetInstance()
|
||||
|
||||
var svcExt, commonExt []patterns.CompiledExtractor
|
||||
|
|
@ -28,12 +35,36 @@ func NewGenericParser(serviceName, hostname string) *GenericParser {
|
|||
slog.Error("CRITICAL: Pattern Repository is nil. Parser will not work correctly.")
|
||||
}
|
||||
|
||||
return &GenericParser{
|
||||
parser := &GenericParser{
|
||||
ServiceName: serviceName,
|
||||
Hostname: hostname,
|
||||
Extractors: svcExt,
|
||||
CommonExt: commonExt,
|
||||
}
|
||||
if drainCfg != nil && stateDir != "" {
|
||||
parser.drainEnabled = true
|
||||
|
||||
parser.drainStatePath = filepath.Join(stateDir, serviceName+".bin")
|
||||
|
||||
if err := os.MkdirAll(stateDir, 0755); err != nil {
|
||||
slog.Error("Failed to create drain3 state dir", "error", err)
|
||||
parser.drainEnabled = false
|
||||
return parser
|
||||
}
|
||||
|
||||
persister := drain3.NewFilePersistence(parser.drainStatePath, false)
|
||||
|
||||
state, err := persister.LoadState()
|
||||
if err == nil && state != nil {
|
||||
parser.drainMiner = drain3.NewTemplateMiner(drainCfg, persister)
|
||||
slog.Info("Drain3 state loaded", "service", serviceName, "clusters", len(state.Clusters))
|
||||
} else {
|
||||
parser.drainMiner = drain3.NewTemplateMiner(drainCfg, persister)
|
||||
slog.Info("Drain3 initialized fresh", "service", serviceName)
|
||||
}
|
||||
}
|
||||
|
||||
return parser
|
||||
}
|
||||
|
||||
func (p *GenericParser) Parse(line string) (models.LogMessage, error) {
|
||||
|
|
@ -51,6 +82,15 @@ func (p *GenericParser) Parse(line string) (models.LogMessage, error) {
|
|||
return entry, nil
|
||||
}
|
||||
|
||||
if p.drainEnabled && p.drainMiner != nil {
|
||||
cluster := p.drainMiner.AddLogMessage(trimmedLine)
|
||||
if cluster != nil {
|
||||
entry.Fields["drain_template_id"] = cluster.ClusterID
|
||||
entry.Fields["drain_template"] = cluster.TemplateMined
|
||||
// Optional: Parameter extrahieren, die Drain gefunden hat (Wildcards)
|
||||
}
|
||||
}
|
||||
|
||||
allExtractors := append(p.CommonExt, p.Extractors...)
|
||||
|
||||
matchedAny := false
|
||||
|
|
@ -92,6 +132,17 @@ func (p *GenericParser) Parse(line string) (models.LogMessage, error) {
|
|||
return entry, nil
|
||||
}
|
||||
|
||||
func (p *GenericParser) Close() error {
|
||||
if p.drainEnabled && p.drainMiner != nil {
|
||||
if err := p.drainMiner.SaveState("shutdown"); err != nil {
|
||||
slog.Error("Failed to save drain3 state", "service", p.ServiceName, "error", err)
|
||||
return err
|
||||
}
|
||||
slog.Debug("Drain3 state saved", "service", p.ServiceName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *GenericParser) safeConvert(value, typeDef string) any {
|
||||
if value == "" || value == "-" {
|
||||
if strings.HasPrefix(typeDef, "int") || strings.HasPrefix(typeDef, "float") {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue