feat(log): 新建 logger 包,基于 log/slog 提供结构化日志
- 新建 internal/logger/logger.go,提供 Init/FromCtx/WithRequestID 方法 - Config 新增 LogConfig(level/format),支持 GEN2D_LOG_LEVEL/GEN2D_LOG_FORMAT 环境变量 - config.yml 和 .env.example 添加日志配置示例
This commit is contained in:
@@ -5,6 +5,10 @@
|
||||
GEN2D_PORT=8080
|
||||
GEN2D_MODE=debug
|
||||
|
||||
# 日志配置
|
||||
GEN2D_LOG_LEVEL=info # debug / info / warn / error
|
||||
GEN2D_LOG_FORMAT=text # text / json
|
||||
|
||||
# SQLite 数据库路径
|
||||
GEN2D_DSN=data/gen2d.db
|
||||
|
||||
|
||||
@@ -12,11 +12,18 @@ type Config struct {
|
||||
Server ServerConfig `mapstructure:"server"`
|
||||
Database DatabaseConfig `mapstructure:"database"`
|
||||
JWT JWTConfig `mapstructure:"jwt"`
|
||||
Log LogConfig `mapstructure:"log"`
|
||||
LLM LLMConfig `mapstructure:"llm"`
|
||||
ImageGen ImageGenConfig `mapstructure:"image_gen"`
|
||||
Qiniu QiniuConfig `mapstructure:"qiniu"`
|
||||
}
|
||||
|
||||
// LogConfig 日志配置。
|
||||
type LogConfig struct {
|
||||
Level string `mapstructure:"level"` // debug / info / warn / error
|
||||
Format string `mapstructure:"format"` // text / json
|
||||
}
|
||||
|
||||
// ServerConfig HTTP 服务配置。
|
||||
type ServerConfig struct {
|
||||
Port int `mapstructure:"port"`
|
||||
@@ -103,6 +110,9 @@ func setDefaults(v *viper.Viper) {
|
||||
v.SetDefault("server.mode", "debug")
|
||||
v.SetDefault("server.max_file_size", int64(10<<20))
|
||||
|
||||
v.SetDefault("log.level", "info")
|
||||
v.SetDefault("log.format", "text")
|
||||
|
||||
v.SetDefault("database.dsn", "data/gen2d.db")
|
||||
|
||||
v.SetDefault("jwt.secret", "gen2d-dev-secret")
|
||||
@@ -139,6 +149,9 @@ func bindEnvVars(v *viper.Viper) {
|
||||
v.BindEnv("server.mode", "GEN2D_MODE")
|
||||
v.BindEnv("server.max_file_size", "GEN2D_MAX_FILE_SIZE")
|
||||
v.BindEnv("database.dsn", "GEN2D_DSN")
|
||||
|
||||
v.BindEnv("log.level", "GEN2D_LOG_LEVEL")
|
||||
v.BindEnv("log.format", "GEN2D_LOG_FORMAT")
|
||||
v.BindEnv("jwt.secret", "GEN2D_JWT_SECRET")
|
||||
v.BindEnv("jwt.expire", "GEN2D_JWT_EXPIRE")
|
||||
|
||||
|
||||
@@ -6,6 +6,10 @@ server:
|
||||
mode: debug
|
||||
max_file_size: 10485760 # 10MB
|
||||
|
||||
log:
|
||||
level: info # debug / info / warn / error
|
||||
format: text # text / json
|
||||
|
||||
database:
|
||||
dsn: "data/gen2d.db"
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ctxKey struct{}
|
||||
|
||||
// L 全局 logger,Init 之前使用默认 text 输出。
|
||||
var L *slog.Logger
|
||||
|
||||
func init() {
|
||||
L = slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug}))
|
||||
}
|
||||
|
||||
// Init 初始化全局 logger。
|
||||
// level: debug / info / warn / error
|
||||
// format: text / json
|
||||
func Init(level, format string) {
|
||||
var lvl slog.Level
|
||||
switch strings.ToLower(level) {
|
||||
case "debug":
|
||||
lvl = slog.LevelDebug
|
||||
case "warn":
|
||||
lvl = slog.LevelWarn
|
||||
case "error":
|
||||
lvl = slog.LevelError
|
||||
default:
|
||||
lvl = slog.LevelInfo
|
||||
}
|
||||
|
||||
opts := &slog.HandlerOptions{Level: lvl}
|
||||
|
||||
var h slog.Handler
|
||||
switch strings.ToLower(format) {
|
||||
case "json":
|
||||
h = slog.NewJSONHandler(os.Stdout, opts)
|
||||
default:
|
||||
h = slog.NewTextHandler(os.Stdout, opts)
|
||||
}
|
||||
|
||||
L = slog.New(h)
|
||||
slog.SetDefault(L)
|
||||
}
|
||||
|
||||
// With 创建带附加字段的 logger。
|
||||
func With(args ...any) *slog.Logger {
|
||||
return L.With(args...)
|
||||
}
|
||||
|
||||
// IntoCtx 将 logger 存入 context。
|
||||
func IntoCtx(ctx context.Context, l *slog.Logger) context.Context {
|
||||
return context.WithValue(ctx, ctxKey{}, l)
|
||||
}
|
||||
|
||||
// FromCtx 从 context 取出 logger,不存在时返回全局 L。
|
||||
func FromCtx(ctx context.Context) *slog.Logger {
|
||||
if l, ok := ctx.Value(ctxKey{}).(*slog.Logger); ok {
|
||||
return l
|
||||
}
|
||||
return L
|
||||
}
|
||||
|
||||
// WithRequestID 创建带 request_id 的 logger 并存入 context。
|
||||
func WithRequestID(ctx context.Context, requestID string) (context.Context, *slog.Logger) {
|
||||
l := L.With("request_id", requestID)
|
||||
return IntoCtx(ctx, l), l
|
||||
}
|
||||
Reference in New Issue
Block a user