Compare commits
No commits in common. "main" and "v1.0.1016" have entirely different histories.
|
|
@ -0,0 +1 @@
|
||||||
|
package log
|
||||||
110
log/log.go
110
log/log.go
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
@ -19,9 +18,6 @@ import (
|
||||||
var (
|
var (
|
||||||
logPath string
|
logPath string
|
||||||
sysLog *log.Logger
|
sysLog *log.Logger
|
||||||
filePath string
|
|
||||||
currentDate string // 当前日志文件对应的日期
|
|
||||||
fileLogger *lumberjack.Logger
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -63,103 +59,10 @@ func (w *logWriter) Write(p []byte) (n int, err error) {
|
||||||
return len(p), nil
|
return len(p), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// cleanOldLogs 删除指定天数之前的日志文件(包括主文件和备份文件)
|
func init() {
|
||||||
func cleanOldLogs(days int) {
|
|
||||||
if !gfile.Exists(logPath) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取所有日志文件
|
|
||||||
files, err := gfile.DirNames(logPath)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
now := time.Now()
|
|
||||||
for _, file := range files {
|
|
||||||
path := filepath.Join(logPath, file)
|
|
||||||
if gfile.IsDir(path) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var dateStr string
|
|
||||||
var matched bool
|
|
||||||
|
|
||||||
// 匹配主日志文件格式:log-YYYY-MM-DD.log
|
|
||||||
if strings.HasPrefix(file, "log-") && strings.HasSuffix(file, ".log") {
|
|
||||||
// 检查是否是主文件(没有备份时间戳)
|
|
||||||
// 主文件格式:log-2026-04-25.log
|
|
||||||
// 备份文件格式:log-2026-04-25-2026-04-25T10-30-45.123.log
|
|
||||||
parts := strings.Split(strings.TrimSuffix(file, ".log"), "-")
|
|
||||||
if len(parts) == 4 {
|
|
||||||
// 主文件:log-YYYY-MM-DD
|
|
||||||
dateStr = parts[1] + "-" + parts[2] + "-" + parts[3]
|
|
||||||
matched = true
|
|
||||||
} else if len(parts) > 4 {
|
|
||||||
// 备份文件:log-YYYY-MM-DD-YYYY-MM-DDTHH-MM-SS.mmm
|
|
||||||
// 提取主日期部分(第一个日期)
|
|
||||||
dateStr = parts[1] + "-" + parts[2] + "-" + parts[3]
|
|
||||||
matched = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !matched {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// 解析日期
|
|
||||||
fileTime, err := time.Parse("2006-01-02", dateStr)
|
|
||||||
if err != nil {
|
|
||||||
continue // 日期格式不正确,跳过
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计算文件年龄
|
|
||||||
tage := now.Sub(fileTime)
|
|
||||||
if tage.Hours() > float64(days*24) {
|
|
||||||
// 超过指定天数,删除文件
|
|
||||||
err = os.Remove(path)
|
|
||||||
if err == nil {
|
|
||||||
Info(fmt.Sprintf("已删除过期日志文件:%s", file))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// checkAndRotateLogFile 检查是否需要切换日志文件(跨天时)
|
|
||||||
func checkAndRotateLogFile() {
|
|
||||||
date := gtime.Date()
|
|
||||||
if currentDate != date {
|
|
||||||
// 日期变化,需要重新初始化
|
|
||||||
currentDate = date
|
|
||||||
filePath = gfile.Join(logPath, fmt.Sprintf("log-%s.log", currentDate))
|
|
||||||
fileLogger = &lumberjack.Logger{
|
|
||||||
Filename: filePath,
|
|
||||||
MaxSize: 2, // 单个文件最大 10MB
|
|
||||||
MaxBackups: 5, // 最多保留 5 个备份
|
|
||||||
MaxAge: 30, // 保留 30 天
|
|
||||||
Compress: false, // 启用压缩
|
|
||||||
}
|
|
||||||
// 创建新的 writer
|
|
||||||
multiWriter := &logWriter{
|
|
||||||
console: os.Stdout,
|
|
||||||
file: fileLogger,
|
|
||||||
}
|
|
||||||
sysLog = log.New(multiWriter, "", 0)
|
|
||||||
|
|
||||||
// 清理 30 天前的旧日志
|
|
||||||
cleanOldLogs(30)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Init() {
|
|
||||||
if sysLog != nil {
|
|
||||||
checkAndRotateLogFile() // 检查是否需要切换文件
|
|
||||||
return
|
|
||||||
}
|
|
||||||
logPath = gfile.Join(gfile.Pwd(), "logs")
|
logPath = gfile.Join(gfile.Pwd(), "logs")
|
||||||
currentDate = gtime.Date()
|
filePath := gfile.Join(logPath, fmt.Sprintf("log-%s.log", gtime.Date()))
|
||||||
filePath = gfile.Join(logPath, fmt.Sprintf("log-%s.log", currentDate))
|
fileLogger := &lumberjack.Logger{
|
||||||
fileLogger = &lumberjack.Logger{
|
|
||||||
Filename: filePath,
|
Filename: filePath,
|
||||||
MaxSize: 2, // 单个文件最大 10MB
|
MaxSize: 2, // 单个文件最大 10MB
|
||||||
MaxBackups: 5, // 最多保留 5 个备份
|
MaxBackups: 5, // 最多保留 5 个备份
|
||||||
|
|
@ -172,29 +75,22 @@ func Init() {
|
||||||
file: fileLogger,
|
file: fileLogger,
|
||||||
}
|
}
|
||||||
sysLog = log.New(multiWriter, "", 0)
|
sysLog = log.New(multiWriter, "", 0)
|
||||||
|
|
||||||
// 启动时清理 30 天前的旧日志
|
|
||||||
cleanOldLogs(30)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Info(v ...any) {
|
func Info(v ...any) {
|
||||||
Init()
|
|
||||||
sysLog.SetPrefix(fmt.Sprintf("[%s] %s[INFO]%s ", time.Now().Format("2006-01-02 15:04:05"), Green, Reset))
|
sysLog.SetPrefix(fmt.Sprintf("[%s] %s[INFO]%s ", time.Now().Format("2006-01-02 15:04:05"), Green, Reset))
|
||||||
sysLog.Println(fmt.Sprint(v...))
|
sysLog.Println(fmt.Sprint(v...))
|
||||||
}
|
}
|
||||||
func Error(v ...any) {
|
func Error(v ...any) {
|
||||||
Init()
|
|
||||||
sysLog.SetPrefix(fmt.Sprintf("[%s] %s[ERROR]%s ", time.Now().Format("2006-01-02 15:04:05"), Red, Reset))
|
sysLog.SetPrefix(fmt.Sprintf("[%s] %s[ERROR]%s ", time.Now().Format("2006-01-02 15:04:05"), Red, Reset))
|
||||||
msg := fmt.Sprint(v...)
|
msg := fmt.Sprint(v...)
|
||||||
sysLog.Println(msg, strings.TrimSpace(string(debug.Stack())))
|
sysLog.Println(msg, strings.TrimSpace(string(debug.Stack())))
|
||||||
}
|
}
|
||||||
func Warn(v ...any) {
|
func Warn(v ...any) {
|
||||||
Init()
|
|
||||||
sysLog.SetPrefix(fmt.Sprintf("[%s] %s[WARN]%s ", time.Now().Format("2006-01-02 15:04:05"), Yellow, Reset))
|
sysLog.SetPrefix(fmt.Sprintf("[%s] %s[WARN]%s ", time.Now().Format("2006-01-02 15:04:05"), Yellow, Reset))
|
||||||
sysLog.Println(fmt.Sprint(v...))
|
sysLog.Println(fmt.Sprint(v...))
|
||||||
}
|
}
|
||||||
func Debug(v ...any) {
|
func Debug(v ...any) {
|
||||||
Init()
|
|
||||||
sysLog.SetPrefix(fmt.Sprintf("[%s] %s[DEBUG]%s ", time.Now().Format("2006-01-02 15:04:05"), Blue, Reset))
|
sysLog.SetPrefix(fmt.Sprintf("[%s] %s[DEBUG]%s ", time.Now().Format("2006-01-02 15:04:05"), Blue, Reset))
|
||||||
sysLog.Println(fmt.Sprint(v...))
|
sysLog.Println(fmt.Sprint(v...))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,14 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httputil"
|
"net/http/httputil"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.magicany.cc/black1552/gf-common/log"
|
"git.magicany.cc/black1552/gf-common/log"
|
||||||
"github.com/gogf/gf/v2/net/gclient"
|
|
||||||
"github.com/gogf/gf/v2/net/ghttp"
|
"github.com/gogf/gf/v2/net/ghttp"
|
||||||
"github.com/gogf/gf/v2/os/gctx"
|
"github.com/gogf/gf/v2/os/gctx"
|
||||||
"github.com/gogf/gf/v2/text/gstr"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// hasProtocol 检查字符串是否包含协议前缀
|
// hasProtocol 检查字符串是否包含协议前缀
|
||||||
|
|
@ -26,49 +22,17 @@ func hasProtocol(s string) bool {
|
||||||
// BuildRequest 反向代理请求到指定主机
|
// BuildRequest 反向代理请求到指定主机
|
||||||
// 自动支持所有 HTTP 方法及 WebSocket 连接
|
// 自动支持所有 HTTP 方法及 WebSocket 连接
|
||||||
func BuildRequest(r *ghttp.Request, host string) {
|
func BuildRequest(r *ghttp.Request, host string) {
|
||||||
if gstr.Contains(r.RequestURI, "/ws") {
|
// 自动添加协议前缀
|
||||||
proxyWebSocket(r, host)
|
targetHost := host
|
||||||
return
|
if !hasProtocol(host) {
|
||||||
|
// 根据请求判断协议:WebSocket 用 ws,普通 HTTP 用 http
|
||||||
|
if r.Header.Get("Upgrade") == "websocket" {
|
||||||
|
targetHost = "ws://" + host
|
||||||
|
} else {
|
||||||
|
targetHost = "http://" + host
|
||||||
}
|
}
|
||||||
client := gclient.New()
|
|
||||||
// 构建目标URL而不是直接复制RequestURI
|
|
||||||
targetURL := host + r.URL.Path
|
|
||||||
if r.URL.RawQuery != "" {
|
|
||||||
targetURL += "?" + r.URL.RawQuery
|
|
||||||
}
|
|
||||||
// 复制请求头
|
|
||||||
for key, values := range r.Header {
|
|
||||||
for _, value := range values {
|
|
||||||
client.SetHeader(key, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
response, err := client.DoRequest(gctx.New(), r.Method, targetURL, r.GetBody())
|
|
||||||
if err != nil {
|
|
||||||
log.Error(gctx.New(), "request error:", err)
|
|
||||||
panic(fmt.Sprintf("request error: %v", err))
|
|
||||||
}
|
|
||||||
defer response.Body.Close()
|
|
||||||
// 读取响应体
|
|
||||||
respBody, err := io.ReadAll(response.Body)
|
|
||||||
if err != nil {
|
|
||||||
log.Error(gctx.New(), "read response body error:", err)
|
|
||||||
panic(fmt.Sprintf("read response body error: %v", err))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 复制响应头
|
|
||||||
for key, values := range response.Header {
|
|
||||||
for _, value := range values {
|
|
||||||
r.Response.Header().Add(key, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 设置响应状态码并写入响应体
|
|
||||||
r.Response.Status = response.StatusCode
|
|
||||||
r.Response.Write(respBody)
|
|
||||||
}
|
|
||||||
|
|
||||||
// proxyWebSocket 处理 WebSocket 连接的代理
|
|
||||||
func proxyWebSocket(r *ghttp.Request, targetHost string) {
|
|
||||||
// 解析目标主机 URL
|
|
||||||
targetURL, err := url.Parse(targetHost)
|
targetURL, err := url.Parse(targetHost)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(gctx.New(), "parse target host error:", err)
|
log.Error(gctx.New(), "parse target host error:", err)
|
||||||
|
|
@ -77,13 +41,33 @@ func proxyWebSocket(r *ghttp.Request, targetHost string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建反向代理
|
|
||||||
proxy := httputil.NewSingleHostReverseProxy(targetURL)
|
proxy := httputil.NewSingleHostReverseProxy(targetURL)
|
||||||
|
|
||||||
// 修改请求 URL,保留原始路径和查询参数
|
// 自定义 Director 来设置目标 URL,保留原始请求的所有参数
|
||||||
r.URL.Scheme = targetURL.Scheme
|
proxy.Director = func(req *http.Request) {
|
||||||
r.URL.Host = targetURL.Host
|
req.URL.Scheme = targetURL.Scheme
|
||||||
log.Info(gctx.New(), r.GetBodyString())
|
req.URL.Host = targetURL.Host
|
||||||
// 处理 WebSocket 连接
|
req.URL.Path = r.URL.Path
|
||||||
proxy.ServeHTTP(r.Response.Writer, r.Request)
|
req.URL.RawQuery = r.URL.RawQuery
|
||||||
|
// 保留原始 Host 头
|
||||||
|
req.Host = r.Host
|
||||||
|
}
|
||||||
|
|
||||||
|
// 错误处理
|
||||||
|
proxy.ErrorHandler = func(w http.ResponseWriter, req *http.Request, err error) {
|
||||||
|
log.Error(gctx.New(), "proxy error:", err)
|
||||||
|
w.WriteHeader(http.StatusBadGateway)
|
||||||
|
w.Write([]byte("Bad Gateway"))
|
||||||
|
}
|
||||||
|
proxy.ModifyResponse = func(resp *http.Response) error {
|
||||||
|
// 获取原始响应的 Header
|
||||||
|
for k, v := range resp.Header {
|
||||||
|
r.Response.Header().Set(k, v[0])
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// ServeHTTP 会自动处理 WebSocket 升级和所有 HTTP 方法
|
||||||
|
// 使用 RawWriter() 获取原始的 http.ResponseWriter,避免 gf 框架的封装影响
|
||||||
|
proxy.ServeHTTP(r.Response.RawWriter(), r.Request)
|
||||||
|
r.Response.WriteJson(r.Response.RawWriter())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
21
utils/sql.go
21
utils/sql.go
|
|
@ -3,7 +3,6 @@ package utils
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"git.magicany.cc/black1552/gf-common/log"
|
|
||||||
_ "github.com/gogf/gf/contrib/drivers/mysql/v2"
|
_ "github.com/gogf/gf/contrib/drivers/mysql/v2"
|
||||||
"github.com/gogf/gf/v2/crypto/gmd5"
|
"github.com/gogf/gf/v2/crypto/gmd5"
|
||||||
"github.com/gogf/gf/v2/database/gdb"
|
"github.com/gogf/gf/v2/database/gdb"
|
||||||
|
|
@ -52,51 +51,51 @@ func NewClient[R any](request any, url string, header map[string]string) *SClien
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
func (w *SClient[R]) Post(ctx context.Context) (res *R, err error) {
|
func (w *SClient[R]) Post(ctx context.Context) (res *R, err error) {
|
||||||
log.Info("请求Url:%s,请求头:%v,请求方法:%s,请求内容:%s", w.url, w.header, "post", w.request)
|
g.Log().Infof(ctx, "请求Url:%s,请求头:%v,请求方法:%s,请求内容:%s", w.url, w.header, "post", w.request)
|
||||||
resp := w.client.PostVar(ctx, w.url, w.request)
|
resp := w.client.PostVar(ctx, w.url, w.request)
|
||||||
err = gconv.Struct(resp, &res)
|
err = gconv.Struct(resp, &res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("请求异常:", err)
|
g.Log().Errorf(ctx, "解析响应体异常:%s", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (w *SClient[R]) Get(ctx context.Context) (res *R, err error) {
|
func (w *SClient[R]) Get(ctx context.Context) (res *R, err error) {
|
||||||
log.Info("请求Url:%s,请求头:%v,请求方法:%s,请求内容:%s", w.url, w.header, "get", w.request)
|
g.Log().Infof(ctx, "请求Url:%s,请求头:%v,请求方法:%s,请求内容:%s", w.url, w.header, "get", w.request)
|
||||||
resp := w.client.GetVar(ctx, w.url, w.request)
|
resp := w.client.GetVar(ctx, w.url, w.request)
|
||||||
err = gconv.Struct(resp, &res)
|
err = gconv.Struct(resp, &res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("解析响应体异常:", err)
|
g.Log().Errorf(ctx, "解析响应体异常:%s", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (w *SClient[R]) Put(ctx context.Context) (res *R, err error) {
|
func (w *SClient[R]) Put(ctx context.Context) (res *R, err error) {
|
||||||
log.Info("请求Url:%s,请求头:%v,请求方法:%s,请求内容:%s", w.url, w.header, "put", w.request)
|
g.Log().Infof(ctx, "请求Url:%s,请求头:%v,请求方法:%s,请求内容:%s", w.url, w.header, "put", w.request)
|
||||||
resp := w.client.PutVar(ctx, w.url, w.request)
|
resp := w.client.PutVar(ctx, w.url, w.request)
|
||||||
err = gconv.Struct(resp, &res)
|
err = gconv.Struct(resp, &res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("解析响应体异常:", err)
|
g.Log().Errorf(ctx, "解析响应体异常:%s", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (w *SClient[R]) Delete(ctx context.Context) (res *R, err error) {
|
func (w *SClient[R]) Delete(ctx context.Context) (res *R, err error) {
|
||||||
log.Info("请求Url:%s,请求头:%v,请求方法:%s,请求内容:%s", w.url, w.header, "delete", w.request)
|
g.Log().Infof(ctx, "请求Url:%s,请求头:%v,请求方法:%s,请求内容:%s", w.url, w.header, "delete", w.request)
|
||||||
resp := w.client.DeleteVar(ctx, w.url, w.request)
|
resp := w.client.DeleteVar(ctx, w.url, w.request)
|
||||||
err = gconv.Struct(resp, &res)
|
err = gconv.Struct(resp, &res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("解析响应体异常:", err)
|
g.Log().Errorf(ctx, "解析响应体异常:%s", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
func (w *SClient[R]) Patch(ctx context.Context) (res *R, err error) {
|
func (w *SClient[R]) Patch(ctx context.Context) (res *R, err error) {
|
||||||
log.Info("请求Url:%s,请求头:%v,请求方法:%s,请求内容:%s", w.url, w.header, "patch", w.request)
|
g.Log().Infof(ctx, "请求Url:%s,请求头:%v,请求方法:%s,请求内容:%s", w.url, w.header, "patch", w.request)
|
||||||
resp := w.client.PatchVar(ctx, w.url, w.request)
|
resp := w.client.PatchVar(ctx, w.url, w.request)
|
||||||
err = gconv.Struct(resp, &res)
|
err = gconv.Struct(resp, &res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("解析响应体异常:", err)
|
g.Log().Errorf(ctx, "解析响应体异常:%s", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue