Files
mayfly-go/server/pkg/logx/logx.go
2025-10-07 15:41:19 +08:00

236 lines
6.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package logx
import (
"context"
"fmt"
"log/slog"
"mayfly-go/pkg/contextx"
"mayfly-go/pkg/utils/runtimex"
"path/filepath"
"runtime"
)
var (
config *Config
)
func GetConfig() *Config {
if config == nil {
return &Config{
Level: "info",
Type: "text",
AddSource: false,
}
}
return config
}
func Init(logConf Config) {
config = &logConf
var handler slog.Handler
if logConf.IsJsonType() {
handler = NewJsonHandler(config)
} else {
handler = NewTextHandler(config)
}
slog.SetDefault(slog.New(handler))
}
func Print(msg string, args ...any) {
Log(context.Background(), slog.LevelInfo, msg, args...)
}
func Debug(msg string, args ...any) {
Log(context.Background(), slog.LevelDebug, msg, args...)
}
func DebugContext(ctx context.Context, msg string, args ...any) {
Log(ctx, slog.LevelDebug, msg, args...)
}
func DebugfContext(ctx context.Context, format string, args ...any) {
Log(ctx, slog.LevelDebug, fmt.Sprintf(format, args...))
}
func Debugf(format string, args ...any) {
Log(context.Background(), slog.LevelDebug, fmt.Sprintf(format, args...))
}
func DebugWithFields(ctx context.Context, msg string, mapFields map[string]any) {
Log(context.Background(), slog.LevelDebug, msg, map2Attrs(mapFields)...)
}
// debug记录并将堆栈信息添加至msg里默认记录10个堆栈信息
func DebugTrace(msg string, err error) {
Log(context.Background(), slog.LevelDebug, fmt.Sprintf(msg+" %s\n%s", err.Error(), runtimex.StackStr(2, 10)))
}
func Info(msg string, args ...any) {
Log(context.Background(), slog.LevelInfo, msg, args...)
}
func InfoContext(ctx context.Context, msg string, args ...any) {
Log(ctx, slog.LevelInfo, msg, args...)
}
func InfofContext(ctx context.Context, format string, args ...any) {
Log(ctx, slog.LevelInfo, fmt.Sprintf(format, args...))
}
func Infof(format string, args ...any) {
Log(context.Background(), slog.LevelInfo, fmt.Sprintf(format, args...))
}
func InfoWithFields(ctx context.Context, msg string, mapFields map[string]any) {
Log(ctx, slog.LevelInfo, msg, map2Attrs(mapFields)...)
}
func Warn(msg string, args ...any) {
Log(context.Background(), slog.LevelWarn, msg, args...)
}
func WarnContext(ctx context.Context, msg string, args ...any) {
Log(ctx, slog.LevelWarn, msg, args...)
}
func WarnfContext(ctx context.Context, format string, args ...any) {
Log(ctx, slog.LevelWarn, fmt.Sprintf(format, args...))
}
func Warnf(format string, args ...any) {
Log(context.Background(), slog.LevelWarn, fmt.Sprintf(format, args...))
}
func WarnWithFields(msg string, mapFields map[string]any) {
Log(context.Background(), slog.LevelWarn, msg, map2Attrs(mapFields)...)
}
func Error(msg string, args ...any) {
Log(context.Background(), slog.LevelError, msg, args...)
}
func ErrorContext(ctx context.Context, msg string, args ...any) {
Log(ctx, slog.LevelError, msg, args...)
}
func ErrorfContext(ctx context.Context, format string, args ...any) {
Log(ctx, slog.LevelError, fmt.Sprintf(format, args...))
}
func Errorf(format string, args ...any) {
Log(context.Background(), slog.LevelError, fmt.Sprintf(format, args...))
}
// ErrorTraceContext 错误记录并将堆栈信息添加至msg里默认记录10个堆栈信息
func ErrorTraceContext(ctx context.Context, msg string, err any) {
errMsg := ""
switch t := err.(type) {
case error:
errMsg = t.Error()
case string:
errMsg = t
default:
errMsg = fmt.Sprintf("%v", t)
}
Log(ctx, slog.LevelError, fmt.Sprintf(msg+"\n%s\n%s", errMsg, runtimex.StackStr(2, 20)))
}
// ErrorTrace 错误记录并将堆栈信息添加至msg里默认记录10个堆栈信息
func ErrorTrace(msg string, err any) {
ErrorTraceContext(context.Background(), msg, err)
}
func ErrorWithFields(ctx context.Context, msg string, mapFields map[string]any) {
Log(ctx, slog.LevelError, msg, map2Attrs(mapFields)...)
}
func Panic(msg string, args ...any) {
Log(context.Background(), slog.LevelError, msg, args...)
panic(msg)
}
func Panicf(format string, args ...any) {
msg := fmt.Sprintf(format, args...)
Log(context.Background(), slog.LevelError, fmt.Sprintf(format, args...))
panic(msg)
}
func Log(ctx context.Context, level slog.Level, msg string, args ...any) {
slog.Log(ctx, level, msg, appendCommonAttr(ctx, level, args)...)
}
// 获取日志公共属性
func getCommonAttr(ctx context.Context, level slog.Level) []any {
commonAttrs := make([]any, 0)
// 尝试从上下文获取traceId若存在则记录
if traceId := contextx.GetTraceId(ctx); traceId != "" {
commonAttrs = append(commonAttrs, "tid", traceId)
}
// 如果系统配置添加方法信息或者为错误级别时则 记录方法信息及行号
if GetConfig().AddSource || level == slog.LevelError {
// skip [runtime.Callers, getCommonAttr, appendCommonAttr, logx.Log, logx.Info|Debug|Warn|Error..]
var pcs [1]uintptr
runtime.Callers(5, pcs[:])
fs := runtime.CallersFrames(pcs[:])
f, _ := fs.Next()
source := &Source{
Function: f.Function,
Fileline: fmt.Sprintf("%s:%d", filepath.Base(f.File), f.Line),
}
commonAttrs = append(commonAttrs, slog.SourceKey, source)
}
return commonAttrs
}
func appendCommonAttr(ctx context.Context, level slog.Level, args []any) []any {
commonAttrs := getCommonAttr(ctx, level)
if len(commonAttrs) > 0 {
args = append(commonAttrs, args...)
}
return args
}
// map类型转为attr
func map2Attrs(mapArg map[string]any) []any {
atts := make([]any, 0)
for k, v := range mapArg {
atts = append(atts, slog.Any(k, v))
}
return atts
}
type Source struct {
// Function is the package path-qualified function name containing the
// source line. If non-empty, this string uniquely identifies a single
// function in the program. This may be the empty string if not known.
Function string `json:"function"`
// File and Line are the file name and line number (1-based) of the source
// line. These may be the empty string and zero, respectively, if not known.
Fileline string `json:"fileline"`
}
func (s Source) String() string {
return fmt.Sprintf("%s (%s)", s.Function, s.Fileline)
}
// An Attr is a key-value pair.
type Attr = slog.Attr
// String returns an Attr for a string value.
func String(key, value string) Attr {
return slog.String(key, value)
}
// Int64 returns an Attr for an int64.
func Int64(key string, value int64) Attr {
return slog.Int64(key, value)
}
// Bool returns an Attr for an bool.
func Bool(key string, value bool) Attr {
return slog.Bool(key, value)
}