6050d11f27
- 创建基于 CloudWego Hertz 的 Go 微服务脚手架 - 集成 Nacos 服务注册/发现功能 - 添加 gRPC 客户端支持 - 实现环境变量配置管理 (.env.example) - 添加 HTTP 中间件 (Recovery, AccessLog, CORS) - 配置 Gitea CI/CD 构建部署流程 BREAKING CHANGE: 项目结构调整,从简单的 API 服务升级为完整的微服务架构
172 lines
3.8 KiB
Go
172 lines
3.8 KiB
Go
package logger
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"reflect"
|
|
"runtime"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
const (
|
|
reset = "\033[0m"
|
|
red = "\033[31m"
|
|
green = "\033[32m"
|
|
yellow = "\033[33m"
|
|
blue = "\033[34m"
|
|
cyan = "\033[36m"
|
|
white = "\033[97m"
|
|
)
|
|
|
|
type colorFormatter struct{}
|
|
|
|
func (f *colorFormatter) Format(entry *logrus.Entry) ([]byte, error) {
|
|
var levelColor string
|
|
switch entry.Level {
|
|
case logrus.DebugLevel:
|
|
levelColor = cyan
|
|
case logrus.InfoLevel:
|
|
levelColor = green
|
|
case logrus.WarnLevel:
|
|
levelColor = yellow
|
|
case logrus.ErrorLevel:
|
|
levelColor = red
|
|
case logrus.FatalLevel, logrus.PanicLevel:
|
|
levelColor = red
|
|
default:
|
|
levelColor = white
|
|
}
|
|
|
|
timestamp := fmt.Sprintf("%s%s%s", levelColor, entry.Time.Format("01-02 15:04:05"), reset)
|
|
|
|
file := "unknown"
|
|
line := 0
|
|
if entry.Caller != nil {
|
|
file = entry.Caller.File
|
|
if idx := strings.LastIndex(file, "/"); idx >= 0 {
|
|
file = file[idx+1:]
|
|
}
|
|
line = entry.Caller.Line
|
|
}
|
|
|
|
title, _ := entry.Data["title"].(string)
|
|
if title == "" {
|
|
title = "-"
|
|
}
|
|
|
|
level := fmt.Sprintf("%s[%s]%s", levelColor, strings.ToUpper(entry.Level.String()), reset)
|
|
titleStr := fmt.Sprintf("%s「%s」%s", levelColor, title, reset)
|
|
|
|
msg := fmt.Sprintf("%s %s:%d: %s >> %s %s\n",
|
|
timestamp, file, line, level, titleStr, entry.Message,
|
|
)
|
|
return []byte(msg), nil
|
|
}
|
|
|
|
var (
|
|
instance *logrus.Logger
|
|
once sync.Once
|
|
)
|
|
|
|
func GetLogger() *logrus.Logger {
|
|
once.Do(func() {
|
|
instance = logrus.New()
|
|
|
|
switch strings.ToLower(os.Getenv("LOG_LEVEL")) {
|
|
case "debug":
|
|
instance.SetLevel(logrus.DebugLevel)
|
|
case "info":
|
|
instance.SetLevel(logrus.InfoLevel)
|
|
case "warn":
|
|
instance.SetLevel(logrus.WarnLevel)
|
|
case "error":
|
|
instance.SetLevel(logrus.ErrorLevel)
|
|
case "fatal":
|
|
instance.SetLevel(logrus.FatalLevel)
|
|
default:
|
|
instance.SetLevel(logrus.InfoLevel)
|
|
}
|
|
|
|
instance.SetFormatter(&colorFormatter{})
|
|
instance.SetReportCaller(true)
|
|
|
|
if os.Getenv("LOG_SAVE") == "true" {
|
|
logDir := os.Getenv("LOG_SAVE_PATH")
|
|
if logDir != "" {
|
|
if err := os.MkdirAll(logDir, 0755); err != nil {
|
|
instance.Errorf("创建日志目录失败: %v", err)
|
|
} else {
|
|
logFile := logDir + "/" + time.Now().Format("20060102") + ".log"
|
|
f, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
|
if err == nil {
|
|
instance.SetOutput(io.MultiWriter(os.Stdout, f))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
})
|
|
return instance
|
|
}
|
|
|
|
func callerSkip() *runtime.Frame {
|
|
pcs := make([]uintptr, 10)
|
|
n := runtime.Callers(3, pcs)
|
|
frames := runtime.CallersFrames(pcs[:n])
|
|
for {
|
|
frame, more := frames.Next()
|
|
if !strings.Contains(frame.File, "utils/logger/") {
|
|
return &frame
|
|
}
|
|
if !more {
|
|
break
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func toString(v interface{}) string {
|
|
rv := reflect.ValueOf(v)
|
|
if rv.Kind() == reflect.Struct || (rv.Kind() == reflect.Ptr && rv.Elem().Kind() == reflect.Struct) {
|
|
data, err := json.Marshal(v)
|
|
if err != nil {
|
|
return fmt.Sprintf("%v", v)
|
|
}
|
|
return string(data)
|
|
}
|
|
return fmt.Sprintf("%v", v)
|
|
}
|
|
|
|
func joinToString(parts ...interface{}) string {
|
|
strs := make([]string, 0, len(parts))
|
|
for _, p := range parts {
|
|
strs = append(strs, toString(p))
|
|
}
|
|
return strings.Join(strs, " ")
|
|
}
|
|
|
|
func Debug(title string, content ...interface{}) {
|
|
GetLogger().WithField("title", title).Debug(joinToString(content...))
|
|
}
|
|
|
|
func Info(title string, content ...interface{}) {
|
|
GetLogger().WithField("title", title).Info(joinToString(content...))
|
|
}
|
|
|
|
func Warn(title string, content ...interface{}) {
|
|
GetLogger().WithField("title", title).Warn(joinToString(content...))
|
|
}
|
|
|
|
func Error(title string, content ...interface{}) {
|
|
GetLogger().WithField("title", title).Error(joinToString(content...))
|
|
}
|
|
|
|
func Fatal(title string, content ...interface{}) {
|
|
GetLogger().WithField("title", title).Fatal(joinToString(content...))
|
|
}
|