mirror of
https://github.com/amir20/dozzle.git
synced 2025-12-21 21:33:18 +01:00
126 lines
3.2 KiB
Go
126 lines
3.2 KiB
Go
package container
|
|
|
|
import (
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/rs/zerolog/log"
|
|
orderedmap "github.com/wk8/go-ordered-map/v2"
|
|
)
|
|
|
|
var SupportedLogLevels map[string]struct{}
|
|
|
|
// Changing this also needs to change the logContext.ts file
|
|
var logLevels = [][]string{
|
|
{"error", "err"},
|
|
{"warn", "warning", "wrn"},
|
|
{"info", "inf"},
|
|
{"debug", "dbg"},
|
|
{"trace"},
|
|
{"fatal", "sev", "severe", "crit", "critical"},
|
|
}
|
|
|
|
var plainLevels = map[string]*regexp.Regexp{}
|
|
var bracketLevels = map[string]*regexp.Regexp{}
|
|
var separatorLevels = map[string]*regexp.Regexp{}
|
|
var timestampRegex = regexp.MustCompile(`^(?:\d{4}[-/]\d{2}[-/]\d{2}(?:[T ](?:\d{2}:\d{2}:\d{2}(?:\.\d+)?Z?|\d{2}:\d{2}(?:AM|PM)))?\s+)`)
|
|
|
|
func init() {
|
|
for _, levelGroup := range logLevels {
|
|
first := levelGroup[0]
|
|
levelsGroup := "(?:" + strings.Join(levelGroup, "|") + ")"
|
|
plainLevels[first] = regexp.MustCompile("(?i)^" + levelsGroup + "[^a-z]")
|
|
bracketLevels[first] = regexp.MustCompile("(?i)\\[ ?" + levelsGroup + " ?\\]")
|
|
separatorLevels[first] = regexp.MustCompile("(?i) " + levelsGroup + "[/-]")
|
|
}
|
|
|
|
SupportedLogLevels = make(map[string]struct{}, len(logLevels)+1)
|
|
for _, levelGroup := range logLevels {
|
|
SupportedLogLevels[levelGroup[0]] = struct{}{}
|
|
}
|
|
SupportedLogLevels["unknown"] = struct{}{}
|
|
}
|
|
|
|
func guessLogLevel(logEvent LogEvent) string {
|
|
switch value := logEvent.Message.(type) {
|
|
case string:
|
|
value = stripANSI(value)
|
|
value = timestampRegex.ReplaceAllString(value, "")
|
|
for _, levelGroup := range logLevels {
|
|
first := levelGroup[0]
|
|
// Look for the level at the beginning of the message
|
|
if plainLevels[first].MatchString(value) {
|
|
return first
|
|
}
|
|
|
|
// Look for the level in brackets
|
|
if bracketLevels[first].MatchString(value) {
|
|
return first
|
|
}
|
|
|
|
// Look for the level with a separator after
|
|
if separatorLevels[first].MatchString(value) {
|
|
return first
|
|
}
|
|
|
|
// Look for the level in the middle of the message that are uppercase and surrounded by quotes
|
|
if strings.Contains(value, "\""+strings.ToUpper(first)+"\"") {
|
|
return first
|
|
}
|
|
|
|
// Look for the level in the middle of the message that are uppercase
|
|
if strings.Contains(value, " "+strings.ToUpper(first)+" ") {
|
|
return first
|
|
}
|
|
}
|
|
|
|
return "unknown"
|
|
|
|
case *orderedmap.OrderedMap[string, any]:
|
|
if value == nil {
|
|
return "unknown"
|
|
}
|
|
|
|
if level, ok := value.Get("level"); ok {
|
|
if level, ok := level.(string); ok {
|
|
return normalizeLogLevel(level)
|
|
}
|
|
} else if severity, ok := value.Get("severity"); ok {
|
|
if severity, ok := severity.(string); ok {
|
|
return normalizeLogLevel(severity)
|
|
}
|
|
}
|
|
|
|
case *orderedmap.OrderedMap[string, string]:
|
|
if value == nil {
|
|
return "unknown"
|
|
}
|
|
if level, ok := value.Get("level"); ok {
|
|
return normalizeLogLevel(level)
|
|
} else if severity, ok := value.Get("severity"); ok {
|
|
return normalizeLogLevel(severity)
|
|
}
|
|
|
|
case map[string]interface{}:
|
|
panic("not implemented")
|
|
|
|
case map[string]string:
|
|
panic("not implemented")
|
|
|
|
default:
|
|
log.Debug().Type("type", value).Msg("unknown logEvent type")
|
|
}
|
|
|
|
return "unknown"
|
|
}
|
|
|
|
func normalizeLogLevel(level string) string {
|
|
level = stripANSI(level)
|
|
level = strings.ToLower(level)
|
|
if _, ok := SupportedLogLevels[level]; ok {
|
|
return level
|
|
}
|
|
|
|
return "unknown"
|
|
}
|