fix
This commit is contained in:
+98
-3
@@ -1,9 +1,11 @@
|
||||
package logging
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/go-kratos/kratos/contrib/otel/v3/tracing"
|
||||
@@ -20,6 +22,85 @@ type Options struct {
|
||||
FileOnlyModules []string
|
||||
}
|
||||
|
||||
type handlerOperation struct {
|
||||
attrs []slog.Attr
|
||||
group string
|
||||
}
|
||||
|
||||
type reloadableHandlerState struct {
|
||||
mu sync.RWMutex
|
||||
handler slog.Handler
|
||||
cleanup func()
|
||||
}
|
||||
|
||||
type reloadableHandler struct {
|
||||
state *reloadableHandlerState
|
||||
ops []handlerOperation
|
||||
}
|
||||
|
||||
func (h *reloadableHandler) resolved() slog.Handler {
|
||||
current := h.state.handler
|
||||
for _, operation := range h.ops {
|
||||
if operation.group != "" {
|
||||
current = current.WithGroup(operation.group)
|
||||
} else {
|
||||
current = current.WithAttrs(operation.attrs)
|
||||
}
|
||||
}
|
||||
return current
|
||||
}
|
||||
|
||||
func (h *reloadableHandler) Enabled(ctx context.Context, level slog.Level) bool {
|
||||
h.state.mu.RLock()
|
||||
defer h.state.mu.RUnlock()
|
||||
return h.resolved().Enabled(ctx, level)
|
||||
}
|
||||
|
||||
func (h *reloadableHandler) Handle(ctx context.Context, record slog.Record) error {
|
||||
h.state.mu.RLock()
|
||||
defer h.state.mu.RUnlock()
|
||||
return h.resolved().Handle(ctx, record)
|
||||
}
|
||||
|
||||
func (h *reloadableHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
|
||||
next := append([]handlerOperation(nil), h.ops...)
|
||||
next = append(next, handlerOperation{attrs: append([]slog.Attr(nil), attrs...)})
|
||||
return &reloadableHandler{state: h.state, ops: next}
|
||||
}
|
||||
|
||||
func (h *reloadableHandler) WithGroup(name string) slog.Handler {
|
||||
next := append([]handlerOperation(nil), h.ops...)
|
||||
next = append(next, handlerOperation{group: name})
|
||||
return &reloadableHandler{state: h.state, ops: next}
|
||||
}
|
||||
|
||||
type ReloadableLogger struct {
|
||||
state *reloadableHandlerState
|
||||
filename string
|
||||
}
|
||||
|
||||
func (l *ReloadableLogger) Reload(root string, options Options) {
|
||||
handler, cleanup := newZapHandler(root, l.filename, options)
|
||||
l.state.mu.Lock()
|
||||
previous := l.state.cleanup
|
||||
l.state.handler = handler
|
||||
l.state.cleanup = cleanup
|
||||
l.state.mu.Unlock()
|
||||
if previous != nil {
|
||||
previous()
|
||||
}
|
||||
}
|
||||
|
||||
func (l *ReloadableLogger) Close() {
|
||||
l.state.mu.Lock()
|
||||
cleanup := l.state.cleanup
|
||||
l.state.cleanup = nil
|
||||
l.state.mu.Unlock()
|
||||
if cleanup != nil {
|
||||
cleanup()
|
||||
}
|
||||
}
|
||||
|
||||
type moduleFilterCore struct {
|
||||
zapcore.Core
|
||||
fileOnly map[string]struct{}
|
||||
@@ -63,7 +144,7 @@ func moduleField(fields []zapcore.Field) string {
|
||||
|
||||
// NewZapLogger adapts a Zap core to the slog logger used by Kratos v3.
|
||||
// The file layout remains compatible with the administration log viewer.
|
||||
func NewZapLogger(root, filename string, options Options, attrs ...any) (*slog.Logger, func()) {
|
||||
func newZapHandler(root, filename string, options Options) (slog.Handler, func()) {
|
||||
file := NewDailyWriter(root, filename, options.RetentionDay)
|
||||
encoder := zap.NewProductionEncoderConfig()
|
||||
encoder.EncodeTime = zapcore.RFC3339NanoTimeEncoder
|
||||
@@ -114,10 +195,24 @@ func NewZapLogger(root, filename string, options Options, attrs ...any) (*slog.L
|
||||
handlerOptions = append(handlerOptions, zapslog.WithCaller(true))
|
||||
}
|
||||
handler := zapslog.NewHandler(zapLogger.Core(), handlerOptions...)
|
||||
logger := kratoslog.NewLogger(handler, kratoslog.WithExtractor(tracing.TraceAttrs)).With(attrs...)
|
||||
cleanup := func() {
|
||||
_ = zapLogger.Sync()
|
||||
_ = file.Close()
|
||||
}
|
||||
return logger, cleanup
|
||||
return handler, cleanup
|
||||
}
|
||||
|
||||
// NewReloadableZapLogger keeps the slog/Kratos adapter stable while replacing
|
||||
// the underlying Zap core when the runtime configuration changes.
|
||||
func NewReloadableZapLogger(root, filename string, options Options, attrs ...any) (*slog.Logger, *ReloadableLogger) {
|
||||
handler, cleanup := newZapHandler(root, filename, options)
|
||||
state := &reloadableHandlerState{handler: handler, cleanup: cleanup}
|
||||
control := &ReloadableLogger{state: state, filename: filename}
|
||||
logger := kratoslog.NewLogger(&reloadableHandler{state: state}, kratoslog.WithExtractor(tracing.TraceAttrs)).With(attrs...)
|
||||
return logger, control
|
||||
}
|
||||
|
||||
func NewZapLogger(root, filename string, options Options, attrs ...any) (*slog.Logger, func()) {
|
||||
logger, control := NewReloadableZapLogger(root, filename, options, attrs...)
|
||||
return logger, control.Close
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user