fix
This commit is contained in:
+24
-2
@@ -7,6 +7,14 @@ import (
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrTokenExpired = errors.New("token expired")
|
||||
ErrTokenMalformed = errors.New("token malformed")
|
||||
ErrTokenSignatureInvalid = errors.New("token signature invalid")
|
||||
ErrTokenNotValidYet = errors.New("token not valid yet")
|
||||
ErrTokenInvalid = errors.New("token invalid")
|
||||
)
|
||||
|
||||
type Claims struct {
|
||||
UUID string
|
||||
ID uint
|
||||
@@ -35,8 +43,22 @@ func Parse(tokenString, secret string) (*Claims, error) {
|
||||
}
|
||||
return []byte(secret), nil
|
||||
})
|
||||
if err != nil || !token.Valid {
|
||||
return nil, errors.New("token is invalid")
|
||||
if err != nil {
|
||||
switch {
|
||||
case errors.Is(err, jwt.ErrTokenExpired):
|
||||
return nil, ErrTokenExpired
|
||||
case errors.Is(err, jwt.ErrTokenMalformed):
|
||||
return nil, ErrTokenMalformed
|
||||
case errors.Is(err, jwt.ErrTokenSignatureInvalid):
|
||||
return nil, ErrTokenSignatureInvalid
|
||||
case errors.Is(err, jwt.ErrTokenNotValidYet):
|
||||
return nil, ErrTokenNotValidYet
|
||||
default:
|
||||
return nil, ErrTokenInvalid
|
||||
}
|
||||
}
|
||||
if !token.Valid {
|
||||
return nil, ErrTokenInvalid
|
||||
}
|
||||
claims, ok := token.Claims.(*Claims)
|
||||
if !ok {
|
||||
|
||||
+30
-7
@@ -11,15 +11,38 @@ import (
|
||||
// file handle open for the active day and rotates on the first write after
|
||||
// midnight, matching the directory layout consumed by the log viewer.
|
||||
type DailyWriter struct {
|
||||
mu sync.Mutex
|
||||
root string
|
||||
name string
|
||||
date string
|
||||
file *os.File
|
||||
mu sync.Mutex
|
||||
root string
|
||||
name string
|
||||
date string
|
||||
file *os.File
|
||||
retentionDay int
|
||||
}
|
||||
|
||||
func NewDailyWriter(root, name string) *DailyWriter {
|
||||
return &DailyWriter{root: root, name: name}
|
||||
func NewDailyWriter(root, name string, retentionDay int) *DailyWriter {
|
||||
w := &DailyWriter{root: root, name: name, retentionDay: retentionDay}
|
||||
w.removeExpired()
|
||||
return w
|
||||
}
|
||||
|
||||
func (w *DailyWriter) removeExpired() {
|
||||
if w.retentionDay <= 0 {
|
||||
return
|
||||
}
|
||||
entries, err := os.ReadDir(w.root)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
cutoff := time.Now().AddDate(0, 0, -w.retentionDay)
|
||||
for _, entry := range entries {
|
||||
if !entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
date, err := time.Parse("2006-01-02", entry.Name())
|
||||
if err == nil && date.Before(cutoff) {
|
||||
_ = os.RemoveAll(filepath.Join(w.root, entry.Name()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (w *DailyWriter) Write(value []byte) (int, error) {
|
||||
|
||||
+98
-9
@@ -3,6 +3,8 @@ package logging
|
||||
import (
|
||||
"log/slog"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-kratos/kratos/contrib/otel/v3/tracing"
|
||||
kratoslog "github.com/go-kratos/kratos/v3/log"
|
||||
@@ -11,20 +13,107 @@ import (
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
Level, Format, EncodeLevel, Prefix, StacktraceKey string
|
||||
LogInConsole, ShowLine bool
|
||||
RetentionDay int
|
||||
FileOnlyModules []string
|
||||
}
|
||||
|
||||
type moduleFilterCore struct {
|
||||
zapcore.Core
|
||||
fileOnly map[string]struct{}
|
||||
mod string
|
||||
}
|
||||
|
||||
func (c *moduleFilterCore) With(fields []zapcore.Field) zapcore.Core {
|
||||
mod := c.mod
|
||||
if value := moduleField(fields); value != "" {
|
||||
mod = value
|
||||
}
|
||||
return &moduleFilterCore{Core: c.Core.With(fields), fileOnly: c.fileOnly, mod: mod}
|
||||
}
|
||||
|
||||
func (c *moduleFilterCore) Check(entry zapcore.Entry, checked *zapcore.CheckedEntry) *zapcore.CheckedEntry {
|
||||
if c.Enabled(entry.Level) {
|
||||
return checked.AddCore(entry, c)
|
||||
}
|
||||
return checked
|
||||
}
|
||||
|
||||
func (c *moduleFilterCore) Write(entry zapcore.Entry, fields []zapcore.Field) error {
|
||||
mod := c.mod
|
||||
if value := moduleField(fields); value != "" {
|
||||
mod = value
|
||||
}
|
||||
if _, excluded := c.fileOnly[mod]; excluded {
|
||||
return nil
|
||||
}
|
||||
return c.Core.Write(entry, fields)
|
||||
}
|
||||
|
||||
func moduleField(fields []zapcore.Field) string {
|
||||
for _, field := range fields {
|
||||
if field.Key == "mod" {
|
||||
return field.String
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// 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, attrs ...any) (*slog.Logger, func()) {
|
||||
file := NewDailyWriter(root, filename)
|
||||
func NewZapLogger(root, filename string, options Options, attrs ...any) (*slog.Logger, func()) {
|
||||
file := NewDailyWriter(root, filename, options.RetentionDay)
|
||||
encoder := zap.NewProductionEncoderConfig()
|
||||
encoder.EncodeTime = zapcore.ISO8601TimeEncoder
|
||||
encoder.EncodeLevel = zapcore.LowercaseLevelEncoder
|
||||
core := zapcore.NewCore(
|
||||
zapcore.NewJSONEncoder(encoder),
|
||||
zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout), zapcore.AddSync(file)),
|
||||
zap.NewAtomicLevelAt(zap.InfoLevel),
|
||||
encoder.EncodeTime = zapcore.RFC3339NanoTimeEncoder
|
||||
if options.StacktraceKey != "" {
|
||||
encoder.StacktraceKey = options.StacktraceKey
|
||||
}
|
||||
switch options.EncodeLevel {
|
||||
case "CapitalLevelEncoder":
|
||||
encoder.EncodeLevel = zapcore.CapitalLevelEncoder
|
||||
case "CapitalColorLevelEncoder":
|
||||
encoder.EncodeLevel = zapcore.CapitalColorLevelEncoder
|
||||
case "LowercaseColorLevelEncoder":
|
||||
encoder.EncodeLevel = zapcore.LowercaseColorLevelEncoder
|
||||
default:
|
||||
encoder.EncodeLevel = zapcore.LowercaseLevelEncoder
|
||||
}
|
||||
var outputEncoder zapcore.Encoder = zapcore.NewJSONEncoder(encoder)
|
||||
if options.Format != "" && options.Format != "json" {
|
||||
if options.Prefix != "" {
|
||||
encoder.EncodeTime = func(value time.Time, output zapcore.PrimitiveArrayEncoder) {
|
||||
output.AppendString(options.Prefix + value.Format("2006-01-02 15:04:05.000"))
|
||||
}
|
||||
}
|
||||
outputEncoder = zapcore.NewConsoleEncoder(encoder)
|
||||
}
|
||||
level := zap.InfoLevel
|
||||
if parsed := level.Set(strings.ToLower(options.Level)); parsed != nil {
|
||||
level = zap.DebugLevel
|
||||
}
|
||||
levelEnabler := zap.NewAtomicLevelAt(level)
|
||||
fileCore := zapcore.NewCore(
|
||||
outputEncoder.Clone(),
|
||||
zapcore.AddSync(file),
|
||||
levelEnabler,
|
||||
)
|
||||
core := zapcore.Core(fileCore)
|
||||
if options.LogInConsole {
|
||||
fileOnly := make(map[string]struct{}, len(options.FileOnlyModules))
|
||||
for _, module := range options.FileOnlyModules {
|
||||
fileOnly[module] = struct{}{}
|
||||
}
|
||||
consoleCore := zapcore.NewCore(outputEncoder.Clone(), zapcore.AddSync(os.Stdout), levelEnabler)
|
||||
core = zapcore.NewTee(fileCore, &moduleFilterCore{Core: consoleCore, fileOnly: fileOnly})
|
||||
}
|
||||
zapLogger := zap.New(core)
|
||||
handler := zapslog.NewHandler(zapLogger.Core(), zapslog.WithCaller(true), zapslog.AddStacktraceAt(slog.LevelError))
|
||||
handlerOptions := []zapslog.HandlerOption{zapslog.AddStacktraceAt(slog.LevelError)}
|
||||
if options.ShowLine {
|
||||
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()
|
||||
|
||||
Reference in New Issue
Block a user