mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-03 15:06:36 +08:00
[优化] go 引用调整
This commit is contained in:
@@ -0,0 +1,242 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type logLevel int
|
||||
|
||||
const (
|
||||
logLevelDebug logLevel = iota
|
||||
logLevelInfo
|
||||
logLevelWarn
|
||||
logLevelError
|
||||
)
|
||||
|
||||
var currentLogLevel = logLevelInfo
|
||||
var currentLogLevelName = "info"
|
||||
var commonLogWriter io.Writer = os.Stdout
|
||||
var errorLogWriter io.Writer = os.Stderr
|
||||
var defaultLogger *slog.Logger
|
||||
|
||||
type customTextHandler struct {
|
||||
writer io.Writer
|
||||
level slog.Level
|
||||
attrs []slog.Attr
|
||||
groups []string
|
||||
}
|
||||
|
||||
type levelRouterHandler struct {
|
||||
commonHandler slog.Handler
|
||||
errorHandler slog.Handler
|
||||
}
|
||||
|
||||
func (h *customTextHandler) Enabled(_ context.Context, level slog.Level) bool {
|
||||
return level >= h.level
|
||||
}
|
||||
|
||||
func (h *customTextHandler) Handle(_ context.Context, record slog.Record) error {
|
||||
var builder strings.Builder
|
||||
builder.WriteString(record.Time.Format("2006-01-02 15:04:05.000"))
|
||||
builder.WriteString(" | ")
|
||||
builder.WriteString(fmt.Sprintf("%-8s", levelLabel(record.Level)))
|
||||
builder.WriteString(" | ")
|
||||
builder.WriteString(sourceLocation(record.PC))
|
||||
builder.WriteString(" - ")
|
||||
builder.WriteString(record.Message)
|
||||
|
||||
attrs := make([]slog.Attr, 0, len(h.attrs)+record.NumAttrs())
|
||||
attrs = append(attrs, h.attrs...)
|
||||
record.Attrs(func(attr slog.Attr) bool {
|
||||
attrs = append(attrs, attr)
|
||||
return true
|
||||
})
|
||||
if len(attrs) > 0 {
|
||||
builder.WriteString(" | ")
|
||||
builder.WriteString(formatAttrs(h.groups, attrs))
|
||||
}
|
||||
builder.WriteByte('\n')
|
||||
_, err := io.WriteString(h.writer, builder.String())
|
||||
return err
|
||||
}
|
||||
|
||||
func (h *customTextHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
|
||||
cloned := *h
|
||||
cloned.attrs = append(slices.Clone(h.attrs), attrs...)
|
||||
return &cloned
|
||||
}
|
||||
|
||||
func (h *customTextHandler) WithGroup(name string) slog.Handler {
|
||||
if strings.TrimSpace(name) == "" {
|
||||
return h
|
||||
}
|
||||
cloned := *h
|
||||
cloned.groups = append(slices.Clone(h.groups), name)
|
||||
return &cloned
|
||||
}
|
||||
|
||||
func (h *levelRouterHandler) Enabled(ctx context.Context, level slog.Level) bool {
|
||||
return h.commonHandler.Enabled(ctx, level) || h.errorHandler.Enabled(ctx, level)
|
||||
}
|
||||
|
||||
func (h *levelRouterHandler) Handle(ctx context.Context, record slog.Record) error {
|
||||
if record.Level >= slog.LevelError {
|
||||
return h.errorHandler.Handle(ctx, record)
|
||||
}
|
||||
return h.commonHandler.Handle(ctx, record)
|
||||
}
|
||||
|
||||
func (h *levelRouterHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
|
||||
return &levelRouterHandler{
|
||||
commonHandler: h.commonHandler.WithAttrs(attrs),
|
||||
errorHandler: h.errorHandler.WithAttrs(attrs),
|
||||
}
|
||||
}
|
||||
|
||||
func (h *levelRouterHandler) WithGroup(name string) slog.Handler {
|
||||
return &levelRouterHandler{
|
||||
commonHandler: h.commonHandler.WithGroup(name),
|
||||
errorHandler: h.errorHandler.WithGroup(name),
|
||||
}
|
||||
}
|
||||
|
||||
func configureGinWriters() {
|
||||
if shouldLog(logLevelDebug) {
|
||||
gin.DefaultWriter = commonLogWriter
|
||||
} else {
|
||||
gin.DefaultWriter = io.Discard
|
||||
}
|
||||
gin.DefaultErrorWriter = errorLogWriter
|
||||
}
|
||||
|
||||
func slogLevel() slog.Level {
|
||||
switch currentLogLevel {
|
||||
case logLevelDebug:
|
||||
return slog.LevelDebug
|
||||
case logLevelWarn:
|
||||
return slog.LevelWarn
|
||||
case logLevelError:
|
||||
return slog.LevelError
|
||||
default:
|
||||
return slog.LevelInfo
|
||||
}
|
||||
}
|
||||
|
||||
func ensureLogger() *slog.Logger {
|
||||
if defaultLogger != nil {
|
||||
return defaultLogger
|
||||
}
|
||||
defaultLogger = slog.New(&levelRouterHandler{
|
||||
commonHandler: &customTextHandler{writer: commonLogWriter, level: slogLevel()},
|
||||
errorHandler: &customTextHandler{writer: errorLogWriter, level: slogLevel()},
|
||||
})
|
||||
slog.SetDefault(defaultLogger)
|
||||
return defaultLogger
|
||||
}
|
||||
|
||||
func SetLogLevel(level string) {
|
||||
normalized := strings.TrimSpace(strings.ToLower(level))
|
||||
switch normalized {
|
||||
case "debug":
|
||||
currentLogLevel = logLevelDebug
|
||||
currentLogLevelName = "debug"
|
||||
case "warn", "warning":
|
||||
currentLogLevel = logLevelWarn
|
||||
currentLogLevelName = "warn"
|
||||
case "error":
|
||||
currentLogLevel = logLevelError
|
||||
currentLogLevelName = "error"
|
||||
default:
|
||||
currentLogLevel = logLevelInfo
|
||||
currentLogLevelName = "info"
|
||||
}
|
||||
configureGinWriters()
|
||||
}
|
||||
|
||||
func GetLogLevel() string {
|
||||
return currentLogLevelName
|
||||
}
|
||||
|
||||
func shouldLog(level logLevel) bool {
|
||||
return level >= currentLogLevel
|
||||
}
|
||||
|
||||
func SetupGinLog() {
|
||||
if *LogDir != "" {
|
||||
commonLogPath := filepath.Join(*LogDir, "common.log")
|
||||
errorLogPath := filepath.Join(*LogDir, "error.log")
|
||||
commonFd, err := os.OpenFile(commonLogPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
_, _ = io.WriteString(os.Stderr, "failed to open common log file\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
errorFd, err := os.OpenFile(errorLogPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
_, _ = io.WriteString(os.Stderr, "failed to open error log file\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
commonLogWriter = io.MultiWriter(os.Stdout, commonFd)
|
||||
errorLogWriter = io.MultiWriter(os.Stderr, errorFd)
|
||||
}
|
||||
configureGinWriters()
|
||||
defaultLogger = nil
|
||||
ensureLogger()
|
||||
}
|
||||
|
||||
func levelLabel(level slog.Level) string {
|
||||
switch {
|
||||
case level <= slog.LevelDebug:
|
||||
return "DEBUG"
|
||||
case level < slog.LevelWarn:
|
||||
return "INFO"
|
||||
case level < slog.LevelError:
|
||||
return "WARNING"
|
||||
default:
|
||||
return "ERROR"
|
||||
}
|
||||
}
|
||||
|
||||
func sourceLocation(pc uintptr) string {
|
||||
if pc == 0 {
|
||||
return "unknown:unknown:0"
|
||||
}
|
||||
frame, _ := runtime.CallersFrames([]uintptr{pc}).Next()
|
||||
fileName := strings.TrimSuffix(filepath.Base(frame.File), filepath.Ext(frame.File))
|
||||
if fileName == "" {
|
||||
fileName = "unknown"
|
||||
}
|
||||
functionName := "unknown"
|
||||
if frame.Function != "" {
|
||||
parts := strings.Split(frame.Function, "/")
|
||||
functionName = parts[len(parts)-1]
|
||||
if dot := strings.LastIndex(functionName, "."); dot >= 0 && dot < len(functionName)-1 {
|
||||
functionName = functionName[dot+1:]
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("%s:%s:%d", fileName, functionName, frame.Line)
|
||||
}
|
||||
|
||||
func formatAttrs(groups []string, attrs []slog.Attr) string {
|
||||
parts := make([]string, 0, len(attrs))
|
||||
for _, attr := range attrs {
|
||||
key := attr.Key
|
||||
if key == "" {
|
||||
continue
|
||||
}
|
||||
if len(groups) > 0 {
|
||||
key = strings.Join(append(slices.Clone(groups), key), ".")
|
||||
}
|
||||
parts = append(parts, fmt.Sprintf("%s=%v", key, attr.Value.Any()))
|
||||
}
|
||||
return strings.Join(parts, " ")
|
||||
}
|
||||
Reference in New Issue
Block a user