99 lines
2 KiB
Go
99 lines
2 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log/slog"
|
|
"regexp"
|
|
"strings"
|
|
"watch-tool/models"
|
|
"watch-tool/parser"
|
|
|
|
"github.com/hpcloud/tail"
|
|
)
|
|
|
|
type FileMonitor struct {
|
|
config ToolConfig
|
|
parser parser.Parser
|
|
hostname string
|
|
}
|
|
|
|
func NewFileMonitor(config ToolConfig, hostname string) *FileMonitor {
|
|
var logParser parser.Parser
|
|
|
|
if config.Format.Pattern != "" {
|
|
pattern, err := regexp.Compile(config.Format.Pattern)
|
|
if err != nil {
|
|
slog.Error("invalid regex pattern", "tool", config.Name, "error", err)
|
|
logParser = &parser.DefaultParser{}
|
|
} else {
|
|
logParser = &parser.RegexLogParser{
|
|
Pattern: pattern,
|
|
Fields: config.Format.Fields,
|
|
Toolname: config.Name,
|
|
}
|
|
}
|
|
} else {
|
|
var err error
|
|
logParser, err = parser.New(config.Name, "custom", hostname)
|
|
if err != nil {
|
|
slog.Error("cannot get tool specific parser", "error", err)
|
|
}
|
|
}
|
|
|
|
return &FileMonitor{
|
|
config: config,
|
|
parser: logParser,
|
|
hostname: hostname,
|
|
}
|
|
}
|
|
|
|
func (fm *FileMonitor) Start(ctx context.Context, out chan<- models.LogMessage) error {
|
|
t, err := tail.TailFile(fm.config.LogFile, tail.Config{
|
|
Follow: true,
|
|
ReOpen: true,
|
|
MustExist: false,
|
|
Poll: true,
|
|
Location: &tail.SeekInfo{Offset: 0, Whence: 2},
|
|
})
|
|
if err != nil {
|
|
return fmt.Errorf("tail.TailFile: %w", err)
|
|
}
|
|
defer t.Stop()
|
|
|
|
slog.Debug("Started tailing file", "file", fm.config.LogFile, "tool", fm.config.Name)
|
|
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
slog.Debug("File monitor stopped", "tool", fm.config.Name)
|
|
return nil
|
|
case line, ok := <-t.Lines:
|
|
if !ok {
|
|
return nil
|
|
}
|
|
|
|
if line.Err != nil {
|
|
slog.Error("error reading log file", "tool", fm.config.Name, "error", line.Err)
|
|
continue
|
|
}
|
|
|
|
if strings.TrimSpace(line.Text) == "" {
|
|
continue
|
|
}
|
|
|
|
entry, err := fm.parser.Parse(line.Text)
|
|
if err != nil {
|
|
slog.Error("error parsing log line", "error", err)
|
|
}
|
|
|
|
select {
|
|
case out <- entry:
|
|
case <-ctx.Done():
|
|
return nil
|
|
default:
|
|
slog.Warn("Log-Channel is full, entry dropped", "tool", fm.config.Name)
|
|
}
|
|
}
|
|
}
|
|
}
|