initial commit

This commit is contained in:
mr0xb 2026-08-24 14:44:54 -04:00
commit 885e7d6e02
22 changed files with 3001 additions and 0 deletions

67
internal/parser/error.go Normal file
View file

@ -0,0 +1,67 @@
package parser
import (
"fmt"
"regexp"
"strconv"
"time"
)
// ErrorEntry holds a parsed nginx error log entry.
type ErrorEntry struct {
Time time.Time
Level string // debug/info/notice/warn/error/crit/alert/emerg
PID int
TID int
ConnID int // 0 if not present
Message string
}
// errorLogRe matches nginx error log format.
// Groups: time, level, pid, tid, connID (optional), message
var errorLogRe = regexp.MustCompile(
`^(\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}) \[(\w+)\] (\d+)#(\d+): (?:\*(\d+) )?(.+)$`,
)
const errorTimeLayout = "2006/01/02 15:04:05"
// ParseErrorLine parses a single nginx error log line.
// Returns an error for malformed lines.
func ParseErrorLine(line string) (ErrorEntry, error) {
m := errorLogRe.FindStringSubmatch(line)
if m == nil {
return ErrorEntry{}, fmt.Errorf("error: no match: %q", line)
}
t, err := time.ParseInLocation(errorTimeLayout, m[1], time.UTC)
if err != nil {
return ErrorEntry{}, fmt.Errorf("error: parse time %q: %w", m[1], err)
}
pid, err := strconv.Atoi(m[3])
if err != nil {
return ErrorEntry{}, fmt.Errorf("error: parse pid %q: %w", m[3], err)
}
tid, err := strconv.Atoi(m[4])
if err != nil {
return ErrorEntry{}, fmt.Errorf("error: parse tid %q: %w", m[4], err)
}
var connID int
if m[5] != "" {
connID, err = strconv.Atoi(m[5])
if err != nil {
return ErrorEntry{}, fmt.Errorf("error: parse connid %q: %w", m[5], err)
}
}
return ErrorEntry{
Time: t,
Level: m[2],
PID: pid,
TID: tid,
ConnID: connID,
Message: m[6],
}, nil
}