feat(config): add temporary logging for failed reloads

- Add tmpLogBuf and tmpLog fields to capture config loading logs
  - Flush temporary logs only when reload succeeds
  - Extract NewLogger function for creating custom loggers
  - Update State interface to include FlushTmpLog method
This commit is contained in:
yusing
2025-10-10 22:20:12 +08:00
parent 357ce38b18
commit 38c0419483
4 changed files with 34 additions and 9 deletions

View File

@@ -45,6 +45,9 @@ func Load() error {
notifyError("init", err)
}
SetState(state)
// flush temporary log
state.FlushTmpLog()
return nil
}
@@ -69,6 +72,9 @@ func Reload() gperr.Error {
return gperr.New(ansi.Warning("using last config")).With(err)
}
// flush temporary log
newState.FlushTmpLog()
// cancel all current subtasks -> wait
// -> replace config -> start new subtasks
GetState().Task().FinishAndWait(config.ErrConfigChanged)

View File

@@ -1,6 +1,7 @@
package config
import (
"bytes"
"context"
"fmt"
"iter"
@@ -21,6 +22,7 @@ import (
config "github.com/yusing/godoxy/internal/config/types"
"github.com/yusing/godoxy/internal/entrypoint"
homepage "github.com/yusing/godoxy/internal/homepage/types"
"github.com/yusing/godoxy/internal/logging"
"github.com/yusing/godoxy/internal/maxmind"
"github.com/yusing/godoxy/internal/notif"
route "github.com/yusing/godoxy/internal/route/provider"
@@ -40,13 +42,21 @@ type state struct {
entrypoint entrypoint.Entrypoint
task *task.Task
// used for temporary logging
// discarded on failed reload
tmpLogBuf *bytes.Buffer
tmpLog zerolog.Logger
}
func NewState() config.State {
tmpLogBuf := bytes.NewBuffer(make([]byte, 0, 4096))
return &state{
providers: xsync.NewMap[string, types.RouteProvider](),
entrypoint: entrypoint.NewEntrypoint(),
task: task.RootTask("config", false),
tmpLogBuf: tmpLogBuf,
tmpLog: logging.NewLogger(tmpLogBuf),
}
}
@@ -167,6 +177,11 @@ func (state *state) NumProviders() int {
return state.providers.Size()
}
func (state *state) FlushTmpLog() {
state.tmpLogBuf.WriteTo(os.Stdout)
state.tmpLogBuf.Reset()
}
// this one is connection level access logger, different from entrypoint access logger
func (state *state) initAccessLogger() error {
if !state.ACL.Valid() {
@@ -336,8 +351,7 @@ func (state *state) loadRouteProviders() error {
}
providersLoader.Wait()
log.Info().Msg(results.String())
state.tmpLog.Info().Msg(results.String())
state.printRoutesByProvider(lenLongestName)
state.printState()
return errs.Error()
@@ -389,12 +403,11 @@ func (state *state) printRoutesByProvider(lenLongestName int) {
// Always print the routes since we want to show even empty providers
routeStr := routeResults.String()
if routeStr != "" {
log.Info().Msg(routeStr)
state.tmpLog.Info().Msg(routeStr)
}
}
func (state *state) printState() {
log.Info().Msg("active config")
l := log.Level(zerolog.InfoLevel)
yaml.NewEncoder(l).Encode(state.Config)
state.tmpLog.Info().Msg("active config:")
yaml.NewEncoder(state.tmpLog).Encode(state.Config)
}

View File

@@ -30,6 +30,8 @@ type State interface {
IterProviders() iter.Seq2[string, types.RouteProvider]
NumProviders() int
StartProviders() error
FlushTmpLog()
}
// could be nil

View File

@@ -48,7 +48,7 @@ func fmtMessage(msg string) string {
return strutils.JoinRune(lines, '\n')
}
func InitLogger(out ...io.Writer) {
func NewLogger(out ...io.Writer) zerolog.Logger {
writer := zerolog.ConsoleWriter{
Out: zerolog.MultiLevelWriter(out...),
TimeFormat: timeFmt,
@@ -56,10 +56,14 @@ func InitLogger(out ...io.Writer) {
return fmtMessage(msgI.(string))
},
}
logger = zerolog.New(
return zerolog.New(
writer,
).Level(level).With().Timestamp().Logger()
log.SetOutput(writer)
}
func InitLogger(out ...io.Writer) {
logger = NewLogger(out...)
log.SetOutput(logger)
log.SetPrefix("")
log.SetFlags(0)
zerolog.TimeFieldFormat = timeFmt