admin_backend/sdk/login/main.go
2026-05-13 17:37:31 +08:00

154 lines
4.2 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 main
import (
"backend/common"
logincommon "backend/sdk/login/common"
"backend/sdk/login/model/test"
"backend/sdk/login/model/tuyou"
"backend/util"
"context"
"fmt"
"io"
"log"
"net/http"
"os"
"os/signal"
"runtime/debug"
"syscall"
"time"
"github.com/gin-gonic/gin"
rotatelogs "github.com/lestrrat-go/file-rotatelogs"
)
var (
rl *rotatelogs.RotateLogs
logWriter io.Writer
errWriter io.Writer
)
func init() {
// 确保日志目录存在
if err := os.MkdirAll("./log", 0755); err != nil {
log.Fatalf("failed to create log dir: %v", err)
}
// 使用按天轮转的日志文件,保留最近 30 个文件
var err error
rl, err = rotatelogs.New(
"./log/login.%Y-%m-%d.log",
rotatelogs.WithRotationTime(24*time.Hour),
rotatelogs.WithRotationCount(30),
)
if err != nil {
log.Fatalf("failed to initialize log rotator: %v", err)
}
// 打开一个普通的最新日志文件(不使用 symlink用于提供固定路径的最新日志
currFile, err := os.OpenFile("./log/login.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
// 如果打开失败,仍然继续使用轮转器+控制台
util.LogStructured("warn", "failed to open current log file", map[string]any{"error": err.Error()})
logWriter = io.MultiWriter(rl, os.Stdout)
errWriter = io.MultiWriter(rl, os.Stderr)
} else {
// 同时输出到轮转日志、固定最新日志文件和控制台
logWriter = io.MultiWriter(rl, currFile, os.Stdout)
errWriter = io.MultiWriter(rl, currFile, os.Stderr)
}
log.SetOutput(logWriter)
// 保持全局默认 writer以兼容其他调用
gin.DefaultWriter = logWriter
gin.DefaultErrorWriter = errWriter
common.Init()
util.InitBBolt()
go util.MonitorServerList()
}
func requestLogger() gin.HandlerFunc {
return func(c *gin.Context) {
startedAt := time.Now()
c.Next()
util.LogStructured("info", "http request", map[string]any{
"clientIp": c.ClientIP(),
"latencyMs": time.Since(startedAt).Milliseconds(),
"method": c.Request.Method,
"path": c.Request.URL.Path,
"query": c.Request.URL.RawQuery,
"status": c.Writer.Status(),
"userAgent": c.Request.UserAgent(),
})
}
}
func recoveryLogger() gin.HandlerFunc {
return gin.CustomRecovery(func(c *gin.Context, recovered any) {
util.LogStructured("error", "panic recovered", map[string]any{
"clientIp": c.ClientIP(),
"method": c.Request.Method,
"path": c.Request.URL.Path,
"query": c.Request.URL.RawQuery,
"panic": fmt.Sprint(recovered),
"stackTrace": string(debug.Stack()),
"userAgent": c.Request.UserAgent(),
})
c.AbortWithStatus(http.StatusInternalServerError)
})
}
func main() {
r := gin.New()
r.Use(requestLogger())
r.Use(recoveryLogger())
loginApi := r.Group("/api/auth")
{
// 认证
loginApi.GET("/tuyou/login", tuyou.Login)
loginApi.GET("/test/login", test.Login)
}
server := &http.Server{
Addr: fmt.Sprintf(":%d", logincommon.AppConf.Port),
Handler: r,
ReadHeaderTimeout: 5 * time.Second,
ReadTimeout: 15 * time.Second,
WriteTimeout: 30 * time.Second,
IdleTimeout: 60 * time.Second,
}
shutdownCtx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
defer stop()
serverErr := make(chan error, 1)
go func() {
util.LogStructured("info", "login sdk started", map[string]any{
"port": logincommon.AppConf.Port,
"version": logincommon.AppConf.Version,
})
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
serverErr <- err
}
close(serverErr)
}()
select {
case err, ok := <-serverErr:
if ok && err != nil {
util.LogStructured("error", "login sdk start failed", map[string]any{"error": err.Error()})
os.Exit(1)
}
case <-shutdownCtx.Done():
util.LogStructured("info", "login sdk shutting down", map[string]any{"reason": shutdownCtx.Err().Error()})
}
gracefulCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
if err := server.Shutdown(gracefulCtx); err != nil {
util.LogStructured("error", "login sdk shutdown failed", map[string]any{"error": err.Error()})
os.Exit(1)
}
util.LogStructured("info", "login sdk stopped", nil)
}