perf(logging): optimize multi-line message formatting

- Refactors the fmtMessage function to use strings.Builder
  - Simplifies multi-writer creation with a helper function
  - Updates the new console writer initialization pattern
  - Moves InitLogger function to the top
  - Fixed NewLoggerWithFixedLevel
This commit is contained in:
yusing
2025-10-15 21:18:25 +08:00
parent f5a006ce81
commit ddf78aacba
3 changed files with 59 additions and 42 deletions

View File

@@ -55,7 +55,7 @@ func NewState() config.State {
entrypoint: entrypoint.NewEntrypoint(),
task: task.RootTask("config", false),
tmpLogBuf: tmpLogBuf,
tmpLog: logging.NewLogger(tmpLogBuf),
tmpLog: logging.NewLoggerWithFixedLevel(zerolog.InfoLevel, tmpLogBuf),
}
}

View File

@@ -8,11 +8,19 @@ import (
"github.com/rs/zerolog"
"github.com/yusing/godoxy/internal/common"
strutils "github.com/yusing/goutils/strings"
zerologlog "github.com/rs/zerolog/log"
)
func InitLogger(out ...io.Writer) {
logger = NewLogger(out...)
log.SetOutput(logger)
log.SetPrefix("")
log.SetFlags(0)
zerolog.TimeFieldFormat = timeFmt
zerologlog.Logger = logger
}
var (
logger zerolog.Logger
timeFmt string
@@ -38,54 +46,62 @@ func init() {
}
func fmtMessage(msg string) string {
lines := strutils.SplitRune(msg, '\n')
if len(lines) == 1 {
nLines := strings.Count(msg, "\n")
if nLines == 0 {
return msg
}
for i := 1; i < len(lines); i++ {
lines[i] = prefix + lines[i]
var sb strings.Builder
sb.Grow(len(msg) + nLines*len(prefix))
// write first line unindented
idx := strings.IndexByte(msg, '\n')
sb.WriteString(msg[:idx])
sb.WriteByte('\n')
msg = msg[idx+1:]
// write remaining lines indented
for line := range strings.Lines(msg) {
sb.WriteString(prefix)
sb.WriteString(line)
}
return strutils.JoinRune(lines, '\n')
return sb.String()
}
func multiLevelWriter(out ...io.Writer) io.Writer {
if len(out) == 0 {
return os.Stdout
}
if len(out) == 1 {
return out[0]
}
return io.MultiWriter(out...)
}
func NewLogger(out ...io.Writer) zerolog.Logger {
writer := zerolog.ConsoleWriter{
Out: zerolog.MultiLevelWriter(out...),
TimeFormat: timeFmt,
FormatMessage: func(msgI interface{}) string { // pad spaces for each line
return fmtMessage(msgI.(string))
},
}
return zerolog.New(
writer,
).Level(level).With().Timestamp().Logger()
}
func NewLoggerWithFixedLevel(level zerolog.Level, out ...io.Writer) zerolog.Logger {
levelStr := level.String()
writer := zerolog.ConsoleWriter{
Out: zerolog.MultiLevelWriter(out...),
TimeFormat: timeFmt,
FormatMessage: func(msgI interface{}) string { // pad spaces for each line
writer := zerolog.NewConsoleWriter(func(w *zerolog.ConsoleWriter) {
w.Out = multiLevelWriter(out...)
w.TimeFormat = timeFmt
w.FormatMessage = func(msgI any) string { // pad spaces for each line
if msgI == nil {
return ""
}
return fmtMessage(msgI.(string))
},
FormatLevel: func(_ any) string {
return levelStr
},
}
return zerolog.New(
writer,
).Level(level).With().Timestamp().Logger()
}
})
return zerolog.New(writer).Level(level).With().Timestamp().Logger()
}
func InitLogger(out ...io.Writer) {
logger = NewLogger(out...)
log.SetOutput(logger)
log.SetPrefix("")
log.SetFlags(0)
zerolog.TimeFieldFormat = timeFmt
zerologlog.Logger = logger
func NewLoggerWithFixedLevel(level zerolog.Level, out ...io.Writer) zerolog.Logger {
writer := zerolog.NewConsoleWriter(func(w *zerolog.ConsoleWriter) {
w.Out = multiLevelWriter(out...)
w.TimeFormat = timeFmt
w.FormatMessage = func(msgI any) string { // pad spaces for each line
if msgI == nil {
return ""
}
return fmtMessage(msgI.(string))
}
})
return zerolog.New(writer).Level(level).With().Str("level", level.String()).Timestamp().Logger()
}

View File

@@ -8,6 +8,7 @@ import (
"github.com/rs/zerolog/log"
"github.com/yusing/godoxy/internal/route/rules"
"github.com/yusing/godoxy/internal/serialization"
gperr "github.com/yusing/goutils/errs"
)
//go:embed *.yml
@@ -34,12 +35,12 @@ func initPresets() {
var rules rules.Rules
content, err := fs.ReadFile(file.Name())
if err != nil {
log.Error().Str("name", file.Name()).Err(err).Msg("failed to read rule preset")
gperr.LogError("failed to read rule preset", err)
continue
}
_, err = serialization.ConvertString(string(content), reflect.ValueOf(&rules))
if err != nil {
log.Error().Str("name", file.Name()).Err(err).Msg("failed to unmarshal rule preset")
gperr.LogError("failed to unmarshal rule preset", err)
continue
}
rulePresets[file.Name()] = rules