67 lines
1.5 KiB
Go
67 lines
1.5 KiB
Go
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
|
|
}
|