package logging
import (
"errors"
"fmt"
"time"
"github.com/rs/zerolog"
"github.com/yusing/go-proxy/internal/common"
)
var levelHTMLFormats = [][]byte{
[]byte(` TRC `),
[]byte(` DBG `),
[]byte(` INF `),
[]byte(` WRN `),
[]byte(` ERR `),
[]byte(` FTL `),
[]byte(` PAN `),
}
var colorToClass = map[string]string{
"1": "log-bold",
"3": "log-italic",
"4": "log-underline",
"30": "log-black",
"31": "log-red",
"32": "log-green",
"33": "log-yellow",
"34": "log-blue",
"35": "log-magenta",
"36": "log-cyan",
"37": "log-white",
"90": "log-bright-black",
"91": "log-red",
"92": "log-bright-green",
"93": "log-bright-yellow",
"94": "log-bright-blue",
"95": "log-bright-magenta",
"96": "log-bright-cyan",
"97": "log-bright-white",
}
// FormatMessageToHTMLBytes converts text with ANSI color codes to HTML with class names.
// ANSI codes are mapped to classes via a static map, and reset codes ([0m) close all spans.
// Time complexity is O(n) with minimal allocations.
func FormatMessageToHTMLBytes(msg string, buf []byte) ([]byte, error) {
buf = append(buf, " "...)
}
stack = stack[:0]
} else {
className, ok := colorToClass[part]
if !ok {
return nil, fmt.Errorf("invalid ANSI code: %s", part)
}
stack = append(stack, className)
buf = append(buf, ``...)
}
startPart = j + 1
}
}
} else {
i++
}
}
if lastPos < len(msg) {
escapeAndAppend(msg[lastPos:], &buf)
}
for range stack {
buf = append(buf, ""...)
}
buf = append(buf, ""...)
return buf, nil
}
func isANSICodeChar(c byte) bool {
return (c >= '0' && c <= '9') || c == ';'
}
func escapeAndAppend(s string, buf *[]byte) {
for i, r := range s {
switch r {
case '•':
*buf = append(*buf, "·"...)
case '&':
*buf = append(*buf, "&"...)
case '<':
*buf = append(*buf, "<"...)
case '>':
*buf = append(*buf, ">"...)
case '\t':
*buf = append(*buf, " "...)
case '\n':
*buf = append(*buf, "
"...)
default:
*buf = append(*buf, s[i])
}
}
}
func timeNowHTML() []byte {
if !common.IsTest {
return []byte(time.Now().Format(timeFmt))
}
return []byte(time.Date(2024, 1, 1, 1, 1, 1, 1, time.UTC).Format(timeFmt))
}
func FormatLogEntryHTML(level zerolog.Level, message string, buf []byte) []byte {
buf = append(buf, []byte(`
`)...) buf = append(buf, timeNowHTML()...) if level < zerolog.NoLevel { buf = append(buf, levelHTMLFormats[level+1]...) } buf, _ = FormatMessageToHTMLBytes(message, buf) buf = append(buf, []byte("")...) return buf }