This commit is contained in:
oneao committed 2026-04-03 17:29:24 +08:00
1 parent 3420976bd6
commit ad47e5167b
8 files changed
+184 -70

No files matched your search

+1 -1
View File
@@ -12,7 +12,7 @@ func main() {
defer app.Close()
if err := app.Run(); err != nil {
if err := bootstrap.RunServer(app.Config); err != nil {
panic(err)
}
}
@@ -4,9 +4,6 @@ import (
"allapp-go/internal/bootstrap/boots"
"allapp-go/internal/config"
"allapp-go/pkg/logger"
"os"
"os/signal"
"syscall"
"github.com/jackc/pgx/v5/pgxpool"
)
@@ -16,7 +13,10 @@ type App struct {
PgSql *pgxpool.Pool
}
// NewApp 初始化(不阻塞)
// ======================
// 初始化
// ======================
func NewApp() (*App, error) {
cfg, err := config.Load()
if err != nil {
@@ -26,6 +26,7 @@ func NewApp() (*App, error) {
// 日志
boots.InitLogger(cfg)
// 数据库
pgsql, err := boots.InitPgsql(cfg)
if err != nil {
return nil, err
@@ -41,30 +42,10 @@ func NewApp() (*App, error) {
}, nil
}
// Run 启动服务(阻塞)
func (a *App) Run() error {
app, err := boots.RunServer(a.Config)
if err != nil {
return err
}
// ======================
// 释放资源
// ======================
// 监听退出信号
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
logger.Log.Info("shutting down server...")
if err := app.Shutdown(); err != nil {
logger.Log.Error("shutdown failed")
return err
}
return nil
}
// Close 释放资源
func (a *App) Close() {
if a.PgSql != nil {
a.PgSql.Close()
@@ -1,32 +1,30 @@
package boots
package bootstrap
import (
"allapp-go/internal/config"
"allapp-go/internal/middleware"
"allapp-go/internal/router"
"allapp-go/pkg/logger"
"fmt"
"github.com/gofiber/fiber/v3"
"github.com/gofiber/fiber/v3/middleware/requestid"
)
func RunServer(cfg *config.Config) (*fiber.App, error) {
func RunServer(cfg *config.Config) error {
app := fiber.New()
// ===== middleware =====
app.Use(requestid.New())
// TODO: 你可以加 logger middleware / recover
app.Use(middleware.Logger())
// ===== router =====
router.Setup(app)
addr := fmt.Sprintf(":%d", cfg.App.Port)
go func() {
if err := app.Listen(addr); err != nil {
panic(err)
}
}()
logger.Log.Info("服务启动")
return app, nil
// ❗ 关键:直接阻塞
return app.Listen(addr)
}
@@ -0,0 +1,35 @@
package middleware
import (
"allapp-go/pkg/logger"
"time"
"github.com/gofiber/fiber/v3"
"go.uber.org/zap"
)
func Logger() fiber.Handler {
return func(c fiber.Ctx) error {
traceID := c.RequestID()
logger.SetTraceID(c, traceID)
start := time.Now()
err := c.Next()
// ✅ 计算耗时
cost := time.Since(start)
log := logger.FromCtx(c.Context())
log.Info("HTTP 请求",
zap.String("method", c.Method()),
zap.String("path", c.Path()),
zap.Int("status", c.Response().StatusCode()),
zap.String("ip", c.IP()),
zap.String("duration", cost.String()),
)
return err
}
}
@@ -1,12 +1,18 @@
package router
import (
"allapp-go/pkg/logger"
"github.com/gofiber/fiber/v3"
)
func Setup(app *fiber.App) {
// 健康检查
app.Get("/ping", func(c fiber.Ctx) error {
log := logger.FromCtx(c)
log.Info("测试")
return c.SendString("pong")
})
@@ -0,0 +1,64 @@
{"level":"INFO","time":"2026-04-03T15:49:55.765+0800","caller":"app/main.go:15","msg":"服务停止...","service":"allapp-go"}
{"level":"INFO","time":"2026-04-03T16:14:38.128+0800","caller":"app/main.go:15","msg":"服务停止...","service":"allapp-go"}
{"level":"INFO","time":"2026-04-03T16:14:49.107+0800","caller":"v3@v3.1.0/ctx.go:252","msg":"HTTP Request","service":"allapp-go","trace_id":"gft4NtXgApIcOA_VjqiE1rJojH1dMzwZT9CzFYzYAXA"}
{"level":"INFO","time":"2026-04-03T16:15:26.633+0800","caller":"app/main.go:15","msg":"服务停止...","service":"allapp-go"}
{"level":"INFO","time":"2026-04-03T16:15:53.500+0800","msg":"HTTP Request","trace_id":"Y9W3uFZVY21B5TEpJg9yyHCf9NOxArUXvZV_qJlrlCM"}
{"level":"INFO","time":"2026-04-03T16:16:33.816+0800","msg":"服务停止..."}
{"level":"INFO","time":"2026-04-03T16:16:46.436+0800","msg":"测试","trace_id":"5yrg3bI_h76pEzG249pZQXBuiIdbRMX_NZwU5uFR2OE"}
{"level":"INFO","time":"2026-04-03T16:16:46.456+0800","msg":"HTTP Request","trace_id":"5yrg3bI_h76pEzG249pZQXBuiIdbRMX_NZwU5uFR2OE"}
{"level":"INFO","time":"2026-04-03T16:27:21.073+0800","msg":"服务停止..."}
{"level":"INFO","time":"2026-04-03T16:27:30.054+0800","msg":"测试","trace_id":"zL-aFoHmf6ueyOkQB3HlIWR1OCEx4HZNG7qJt7pM7zM"}
{"level":"INFO","time":"2026-04-03T16:27:30.076+0800","msg":"HTTP Request","trace_id":"zL-aFoHmf6ueyOkQB3HlIWR1OCEx4HZNG7qJt7pM7zM"}
{"level":"INFO","time":"2026-04-03T16:27:55.631+0800","msg":"服务停止..."}
{"level":"INFO","time":"2026-04-03T16:45:35.641+0800","msg":"服务停止..."}
{"level":"INFO","time":"2026-04-03T16:45:40.240+0800","msg":"服务停止..."}
{"level":"INFO","time":"2026-04-03T16:45:45.270+0800","msg":"测试","trace_id":"wkEAsYzV99gWsa3kWmLG30kJMQHQEjDu9ocxNxLQzQU"}
{"level":"INFO","time":"2026-04-03T16:45:45.289+0800","msg":"HTTP Request","trace_id":"wkEAsYzV99gWsa3kWmLG30kJMQHQEjDu9ocxNxLQzQU"}
{"level":"INFO","time":"2026-04-03T16:45:48.144+0800","msg":"服务停止..."}
{"level":"INFO","time":"2026-04-03T16:56:48.995+0800","msg":"服务启动"}
{"level":"INFO","time":"2026-04-03T16:56:52.533+0800","msg":"测试","trace_id":"Fbc4o1PTmARfNbFYAM-iY43s84GNPdMXWq4c7IgXCds"}
{"level":"INFO","time":"2026-04-03T16:56:52.533+0800","msg":"HTTP Request","trace_id":"Fbc4o1PTmARfNbFYAM-iY43s84GNPdMXWq4c7IgXCds"}
{"level":"INFO","time":"2026-04-03T16:56:56.909+0800","msg":"服务启动"}
{"level":"INFO","time":"2026-04-03T16:57:04.658+0800","msg":"测试","trace_id":"Me6jLlSvQGHapO-VJho73fMiOYcOyYThbpAafpGhqE8"}
{"level":"INFO","time":"2026-04-03T16:57:04.658+0800","msg":"HTTP Request","trace_id":"Me6jLlSvQGHapO-VJho73fMiOYcOyYThbpAafpGhqE8"}
{"level":"INFO","time":"2026-04-03T16:57:49.543+0800","msg":"服务启动"}
{"level":"INFO","time":"2026-04-03T16:58:32.252+0800","msg":"测试"}
{"level":"INFO","time":"2026-04-03T16:58:32.252+0800","msg":"HTTP Request","trace_id":"kFurkMd7r6FIBAMzNZzEmzIoD81UnqYusKulk-lRXNY"}
{"level":"INFO","time":"2026-04-03T17:02:09.848+0800","msg":"服务启动"}
{"level":"INFO","time":"2026-04-03T17:05:19.925+0800","msg":"测试"}
{"level":"INFO","time":"2026-04-03T17:05:19.926+0800","msg":"HTTP Request","trace_id":"1NK3UDYFdnsUQ_gqapDlrtLuwQHjePUe5-QgDuTUZEY"}
{"level":"INFO","time":"2026-04-03T17:05:25.218+0800","msg":"服务启动"}
{"level":"INFO","time":"2026-04-03T17:05:26.759+0800","msg":"测试"}
{"level":"INFO","time":"2026-04-03T17:05:26.759+0800","msg":"HTTP Request","trace_id":"3wfoCwM25ZVd2ALWs8sgoyj8UBimSTiYNu27x_bCfT4"}
{"level":"INFO","time":"2026-04-03T17:07:25.207+0800","msg":"服务启动"}
{"level":"INFO","time":"2026-04-03T17:07:31.929+0800","msg":"测试","trace_id":"N_1ZQOZcUXnvPG6IWNy3CoqlOCBs3WSWIx8d8-ftY7I"}
{"level":"INFO","time":"2026-04-03T17:07:31.929+0800","msg":"HTTP Request","trace_id":"N_1ZQOZcUXnvPG6IWNy3CoqlOCBs3WSWIx8d8-ftY7I"}
{"level":"INFO","time":"2026-04-03T17:08:17.051+0800","msg":"服务启动"}
{"level":"INFO","time":"2026-04-03T17:08:48.035+0800","msg":"服务启动"}
{"level":"INFO","time":"2026-04-03T17:10:13.495+0800","msg":"测试","trace_id":"poaftsTyHSfOg4sf1iCd76aehpVwgqCC_oV1F3j3uW8"}
{"level":"INFO","time":"2026-04-03T17:10:13.495+0800","msg":"HTTP Request","trace_id":"poaftsTyHSfOg4sf1iCd76aehpVwgqCC_oV1F3j3uW8"}
{"level":"INFO","time":"2026-04-03T17:12:36.069+0800","msg":"服务启动"}
{"level":"INFO","time":"2026-04-03T17:12:39.296+0800","msg":"测试","trace_id":"I_Cu1O_AKGduLgrC5BQ9BmMvjaKzxX2z0ErHTYAp95I"}
{"level":"INFO","time":"2026-04-03T17:12:39.297+0800","msg":"HTTP 请求","trace_id":"I_Cu1O_AKGduLgrC5BQ9BmMvjaKzxX2z0ErHTYAp95I","method":"GET","path":"/ping","status":200,"ip":"127.0.0.1","duration":999200}
{"level":"INFO","time":"2026-04-03T17:14:18.164+0800","msg":"服务启动"}
{"level":"INFO","time":"2026-04-03T17:14:20.840+0800","msg":"测试","trace_id":"RaYGTF5vYvcYH510JISeHXT3q9nAMuaX3CVytD5dbG4"}
{"level":"INFO","time":"2026-04-03T17:14:20.840+0800","msg":"HTTP 请求","trace_id":"RaYGTF5vYvcYH510JISeHXT3q9nAMuaX3CVytD5dbG4","method":"GET","path":"/ping","status":200,"ip":"127.0.0.1","latency":283600,"latency_ms":0}
{"level":"INFO","time":"2026-04-03T17:16:05.807+0800","msg":"服务启动"}
{"level":"INFO","time":"2026-04-03T17:16:08.888+0800","msg":"测试","trace_id":"6AcgmyWwTVAjeNp-X4kQzrfwin6AMt4H0WNxTUcAndI"}
{"level":"INFO","time":"2026-04-03T17:16:08.888+0800","msg":"HTTP 请求","trace_id":"6AcgmyWwTVAjeNp-X4kQzrfwin6AMt4H0WNxTUcAndI","method":"GET","path":"/ping","status":200,"ip":"127.0.0.1","latency_ms":0}
{"level":"INFO","time":"2026-04-03T17:16:38.443+0800","msg":"服务启动"}
{"level":"INFO","time":"2026-04-03T17:16:41.373+0800","msg":"测试","trace_id":"iRArQodllLgkkUoNaLQxx19tnGcMZJCLjb289tZCeLo"}
{"level":"INFO","time":"2026-04-03T17:16:41.373+0800","msg":"HTTP 请求","trace_id":"iRArQodllLgkkUoNaLQxx19tnGcMZJCLjb289tZCeLo","method":"GET","path":"/ping","status":200,"ip":"127.0.0.1","duration":"504.7µs"}
{"level":"INFO","time":"2026-04-03T17:22:21.980+0800","msg":"服务启动"}
{"level":"INFO","time":"2026-04-03T17:22:24.708+0800","msg":"测试","trace_id":"-A1bWcH4S56yPgY7QtcNJKVEfk7dZYYO3iE8UwdfGec"}
{"level":"INFO","time":"2026-04-03T17:22:24.708+0800","msg":"HTTP 请求","trace_id":"-A1bWcH4S56yPgY7QtcNJKVEfk7dZYYO3iE8UwdfGec","method":"GET","path":"/ping","status":200,"ip":"127.0.0.1","duration":"0s"}
{"level":"INFO","time":"2026-04-03T17:22:33.502+0800","msg":"测试","trace_id":"95otefa9Cf-0DKIn1wJyhtAK137RF39I928RCKw1wXU"}
{"level":"INFO","time":"2026-04-03T17:22:33.502+0800","msg":"HTTP 请求","trace_id":"95otefa9Cf-0DKIn1wJyhtAK137RF39I928RCKw1wXU","method":"GET","path":"/ping","status":200,"ip":"127.0.0.1","duration":"0s"}
{"level":"INFO","time":"2026-04-03T17:22:35.893+0800","msg":"测试","trace_id":"mKSzOa9FqlG6tfribi2yZhkXUPUXMYJocWs8TvQ0gzk"}
{"level":"INFO","time":"2026-04-03T17:22:35.893+0800","msg":"HTTP 请求","trace_id":"mKSzOa9FqlG6tfribi2yZhkXUPUXMYJocWs8TvQ0gzk","method":"GET","path":"/ping","status":200,"ip":"127.0.0.1","duration":"0s"}
{"level":"INFO","time":"2026-04-03T17:22:54.306+0800","msg":"服务启动"}
{"level":"INFO","time":"2026-04-03T17:23:46.090+0800","msg":"测试","trace_id":"dcgGTmUE4Zhaqm2GPGhKplL2ypgRrHb2yfsPYWpasAk"}
{"level":"INFO","time":"2026-04-03T17:23:46.090+0800","msg":"HTTP 请求","trace_id":"dcgGTmUE4Zhaqm2GPGhKplL2ypgRrHb2yfsPYWpasAk","method":"GET","path":"/ping","status":200,"ip":"127.0.0.1","duration":"557.7µs"}
{"level":"INFO","time":"2026-04-03T17:25:10.656+0800","msg":"服务启动"}
{"level":"INFO","time":"2026-04-03T17:25:12.876+0800","msg":"测试","trace_id":"HP6MsYAn3gEeurwlsBPImOgJHuEcwOcaPeTIUiFJnbA"}
{"level":"INFO","time":"2026-04-03T17:25:12.876+0800","msg":"HTTP 请求","trace_id":"HP6MsYAn3gEeurwlsBPImOgJHuEcwOcaPeTIUiFJnbA","method":"GET","path":"/ping","status":200,"ip":"127.0.0.1","duration":"31µs"}
@@ -1 +0,0 @@
{"level":"INFO","time":"2026-04-02T22:07:05.693+0800","caller":"app/main.go:15","msg":"shutting down server..."}
+62 -31
View File
@@ -5,6 +5,7 @@ import (
"os"
"path/filepath"
"strings"
"time"
"github.com/gofiber/fiber/v3"
"go.uber.org/zap"
@@ -59,10 +60,8 @@ func Init(cfg Config) {
// 控制台
consoleWriter := zapcore.AddSync(os.Stdout)
// 文件 writer(info)
// 文件 writer(按天)
infoWriter := getWriter(cfg, "info")
// 文件 writer(error)
errorWriter := getWriter(cfg, "error")
// info core
@@ -85,24 +84,66 @@ func Init(cfg Config) {
core := zapcore.NewTee(infoCore, errorCore)
Log = zap.New(core, zap.AddCaller(), zap.AddCallerSkip(1))
Log = zap.New(
core,
)
}
// ======================
// lumberjack writer
// Daily Writer(核心)
// ======================
type DailyWriter struct {
cfg Config
level string
log *lumberjack.Logger
date string
}
func newDailyWriter(cfg Config, level string) *DailyWriter {
return &DailyWriter{
cfg: cfg,
level: level,
}
}
func (w *DailyWriter) Write(p []byte) (n int, err error) {
today := time.Now().Format("2006-01-02")
// 跨天自动切换
if w.log == nil || w.date != today {
dir := filepath.Join(w.cfg.Dir, w.level)
_ = os.MkdirAll(dir, os.ModePerm)
filename := filepath.Join(dir, today+".log")
w.log = &lumberjack.Logger{
Filename: filename,
MaxSize: w.cfg.MaxSize,
MaxBackups: w.cfg.MaxBackups,
MaxAge: w.cfg.MaxAge,
Compress: w.cfg.Compress,
}
w.date = today
}
return w.log.Write(p)
}
func (w *DailyWriter) Sync() error {
if w.log != nil {
return w.log.Close()
}
return nil
}
// ======================
// writer 封装
// ======================
func getWriter(cfg Config, level string) zapcore.WriteSyncer {
dir := filepath.Join(cfg.Dir, level)
_ = os.MkdirAll(dir, os.ModePerm)
return zapcore.AddSync(&lumberjack.Logger{
Filename: filepath.Join(dir, level+".log"),
MaxSize: cfg.MaxSize,
MaxBackups: cfg.MaxBackups,
MaxAge: cfg.MaxAge,
Compress: cfg.Compress,
})
return zapcore.AddSync(newDailyWriter(cfg, level))
}
// ======================
@@ -123,24 +164,19 @@ func parseLevel(lvl string) zapcore.Level {
}
// ======================
// trace 支持(核心)
// trace 支持
// ======================
// Ctx Fiber 中使用
func Ctx(c fiber.Ctx) *zap.Logger {
func SetTraceID(c fiber.Ctx, traceID string) {
if c == nil {
return Log
return
}
traceID, _ := c.Locals(TraceIDKey).(string)
if traceID == "" {
return Log
}
return Log.With(zap.String("trace_id", traceID))
// context
ctx := context.WithValue(c.Context(), TraceIDKey, traceID)
c.SetContext(ctx)
}
// FromCtx Service / Repo 使用
func FromCtx(ctx context.Context) *zap.Logger {
if ctx == nil {
return Log
@@ -154,11 +190,6 @@ func FromCtx(ctx context.Context) *zap.Logger {
return Log.With(zap.String("trace_id", traceID))
}
// WithTrace 注入 trace
func WithTrace(ctx context.Context, traceID string) context.Context {
return context.WithValue(ctx, TraceIDKey, traceID)
}
// ======================
// 优雅退出
// ======================