feat: 添加微服务模板基础架构
- 创建基于 CloudWego Hertz 的 Go 微服务脚手架 - 集成 Nacos 服务注册/发现功能 - 添加 gRPC 客户端支持 - 实现环境变量配置管理 (.env.example) - 添加 HTTP 中间件 (Recovery, AccessLog, CORS) - 配置 Gitea CI/CD 构建部署流程 BREAKING CHANGE: 项目结构调整,从简单的 API 服务升级为完整的微服务架构
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
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...))
|
||||
}
|
||||
Reference in New Issue
Block a user