From 2937bf6579bdd3929a95a13a66a41f6b10feef09 Mon Sep 17 00:00:00 2001 From: liuchangshun <961347548@qq.com> Date: Wed, 22 Nov 2023 08:28:52 +0800 Subject: [PATCH] xxx --- go.mod | 34 ++++++ go.sum | 90 +++++++++++++++ lxcors/cors.go | 55 +++++++++ lxlog/lxlog.go | 279 ++++++++++++++++++++++++++++++++++++++++++++++ lxzap/lxzap.go | 137 +++++++++++++++++++++++ lxzap/zapGorm2.go | 106 ++++++++++++++++++ 6 files changed, 701 insertions(+) create mode 100644 go.sum create mode 100644 lxcors/cors.go create mode 100644 lxlog/lxlog.go create mode 100644 lxzap/lxzap.go create mode 100644 lxzap/zapGorm2.go diff --git a/go.mod b/go.mod index e293193..173ed9c 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,37 @@ module git.listensoft.net/tool/lxutils go 1.19 + +require ( + github.com/bytedance/sonic v1.9.1 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/gin-gonic/gin v1.9.1 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.14.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/leodido/go-urn v1.2.4 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/natefinch/lumberjack v2.0.0+incompatible // indirect + github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/twitchyliquid64/golang-asm v0.15.1 // indirect + github.com/ugorji/go/codec v1.2.11 // indirect + go.uber.org/multierr v1.10.0 // indirect + go.uber.org/zap v1.26.0 // indirect + golang.org/x/arch v0.3.0 // indirect + golang.org/x/crypto v0.9.0 // indirect + golang.org/x/net v0.10.0 // indirect + golang.org/x/sys v0.8.0 // indirect + golang.org/x/text v0.9.0 // indirect + google.golang.org/protobuf v1.30.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + gorm.io/gorm v1.25.5 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..96475a2 --- /dev/null +++ b/go.sum @@ -0,0 +1,90 @@ +github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= +github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= +github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= +github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= +github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= +github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM= +github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk= +github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= +github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +go.uber.org/multierr v1.10.0 h1:S0h4aNzvfcFsC3dRF1jLoaov7oRaKqRGC/pUEJ2yvPQ= +go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= +go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= +golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= +golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls= +gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/lxcors/cors.go b/lxcors/cors.go new file mode 100644 index 0000000..a834d54 --- /dev/null +++ b/lxcors/cors.go @@ -0,0 +1,55 @@ +package lxcors + +import ( + "fmt" + "github.com/gin-gonic/gin" + "net/http" + "strings" +) + +func Cors() gin.HandlerFunc { + return func(c *gin.Context) { + method := c.Request.Method + + //origin := c.Request.Header.Get("Origin") + //fmt.Println("origin----", origin) + var headerKeys []string + for k, _ := range c.Request.Header { + headerKeys = append(headerKeys, k) + } + headerStr := strings.Join(headerKeys, ", ") + if headerStr != "" { + headerStr = fmt.Sprintf("access-control-allow-origin, access-control-allow-headers, Content-Type, %s", headerStr) + } else { + headerStr = "access-control-allow-origin, access-control-allow-headers" + } + headerStr += "access-control-allow-origin, access-control-allow-headers, Content-Type,token" + //var origins = []string{"https://www.qizhangfang.com", "https://wx.qizhangfang.net", "https://qizhangfang.com", "http://www.qizhangfang.com", "http://qizhangfang.com", + // "http://192.168.3.153:8000", "http://localhost:8000"} // 允许跨域 + //fmt.Println(origins) + //if origin != "" { + // + // + //} + + //下面的都是乱添加的-_-~ + //c.Writer.Header().Set("Access-Control-Allow-Origin", "*") + + //c.Header("Access-Control-Allow-Origin", ogn) + c.Header("Access-Control-Allow-Origin", "*") + c.Header("Access-Control-Allow-Headers", headerStr) + c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE") + // c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Accept, Origin, Host, Connection, Accept-Encoding, Accept-Language,DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Pragma") + c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers, Content-Type, Token, token") + // c.Header("Access-Control-Max-Age", "172800") + c.Header("Access-Control-Allow-Credentials", "true") + c.Set("content-type", "application/json") + + //放行所有OPTIONS方法 + if method == "OPTIONS" { + c.JSON(http.StatusOK, "Options Request!") + } + + c.Next() + } +} diff --git a/lxlog/lxlog.go b/lxlog/lxlog.go new file mode 100644 index 0000000..866d1e3 --- /dev/null +++ b/lxlog/lxlog.go @@ -0,0 +1,279 @@ +package lxlog + +import ( + "fmt" + "os" + "runtime" + "strconv" + "time" +) + +// 异步写日志 + +var MyLog *FileLog + +const ( + LogSplitTypeHour = iota + LogSplitTypeSize + logPath = "myLog" + logName = "myLog" + chanSize = 5000 +) + +type FileLog struct { + logPath string + logName string + file *os.File //普通日志 + warnFile *os.File //错误日志 级别低 + logDataChan chan *LogData + logSplitType int //分割类型 + logSplitSize int64 //分割体积 + lastSplitHour int //分割时间 +} + +type LogData struct { + Message string + TimeStr string + LevelStr string + IsWarn bool + File string +} + +// _ = tools.InitLog() +func InitLog() (log *FileLog) { + config := make(map[string]string, 8) + config["log_path"] = "." + config["log_name"] = "server" + config["log_chan_size"] = "50000" //chan size 可以不用 + config["log_split_type"] = "size" + config["log_split_size"] = strconv.Itoa(1024 * 1024 * 1024) // 1g + log, err := NewFileLog(config) + if err != nil { + panic("init log err") + } + MyLog = log + return log +} + +func NewFileLog(config map[string]string) (logFile *FileLog, err error) { + + var logSplitType = LogSplitTypeSize + var logSplitSize int64 + + splitType, ok := config["log_split_type"] + if !ok { + splitType = "hour" + } else { + if splitType == "size" { + splitSize, ok := config["log_split_size"] + if !ok { + splitSize = "104857600" //100M 以文字来讲很多了 + } + + logSplitSize, err = strconv.ParseInt(splitSize, 10, 64) + if err != nil { + logSplitSize = 104857600 + } + + logSplitType = LogSplitTypeSize + } else { + logSplitType = LogSplitTypeHour + } + } + //打开日志文件 + exist, err := PathIsExists(logPath) + if err != nil { + fmt.Printf("get dir error![%v]\n", err) + return + } + if !exist { + err = os.Mkdir(logPath, os.ModePerm) + if err != nil { + fmt.Printf("mkdir failed![%v]\n", err) + return + } else { + fmt.Printf("mkdir success!\n") + } + } + //正常日志 + fileName := fmt.Sprintf("%s/%s.log", logPath, logName) + file, err := os.OpenFile(fileName, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0755) + //错误日志 + fileNameWarn := fmt.Sprintf("%s/%s.log.err", logPath, logName) + fileWarn, err := os.OpenFile(fileNameWarn, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0755) + if err != nil { + return + } + logFile = &FileLog{ + logPath: logPath, + logName: logName, + logDataChan: make(chan *LogData, chanSize), + file: file, + warnFile: fileWarn, + logSplitType: logSplitType, + logSplitSize: logSplitSize, + lastSplitHour: time.Now().Hour(), + } + go logFile.writeLogBackGround() + return +} + +// 判断文件夹是否存在 +func PathIsExists(path string) (bool, error) { + _, err := os.Stat(path) + if err == nil { + return true, nil + } + if os.IsNotExist(err) { + return false, nil + } + return false, err +} + +func (f *FileLog) Info(message string) { + _, file, line, _ := runtime.Caller(1) + fi := file + ":" + strconv.Itoa(line) + f.print(message, "info", fi) +} +func (f *FileLog) Debug(message string) { + _, file, line, _ := runtime.Caller(1) + fi := file + ":" + strconv.Itoa(line) + f.print(message, "debug", fi) +} +func (f *FileLog) Warn(message string) { + _, file, line, _ := runtime.Caller(1) + fi := file + ":" + strconv.Itoa(line) + f.print(message, "warn", fi) +} +func (f *FileLog) Error(message string) { + _, file, line, _ := runtime.Caller(1) + fi := file + ":" + strconv.Itoa(line) + f.print(message, "error", fi) +} + +func (f *FileLog) print(message, Type string, file string) { + isWarn := false + if Type == "error" { + isWarn = true + } + msg := &LogData{ + Message: message, + TimeStr: time.Now().Format("2006-01-02 15:04:05"), + LevelStr: Type, + IsWarn: isWarn, + File: file, + } + // 怕chan满了插不进去 + select { + case f.logDataChan <- msg: + default: + + } +} + +func (f *FileLog) writeLogBackGround() { + for logData := range f.logDataChan { + var file = f.file + if logData.IsWarn { + file = f.warnFile + } + + f.checkSplitFile(logData.IsWarn) // 检查文件分割类型 + fmt.Fprintf(file, "%s %s %s %s\n", logData.TimeStr, logData.LevelStr, logData.Message, logData.File) + } +} + +func (f *FileLog) checkSplitFile(isWarn bool) { + if f.logSplitType == LogSplitTypeHour { + f.splitHour(isWarn) + return + } + f.splitSize(isWarn) +} + +// 根据时间切割 +func (f *FileLog) splitHour(isWarn bool) { + + now := time.Now() + hour := now.Hour() + + if hour == f.lastSplitHour { + return + } + + f.lastSplitHour = hour + + var backupFileName string + var fileName string + + if isWarn { + backupFileName = fmt.Sprintf("%s/%s.log.err_%s", f.logPath, f.logName, now.Format("20060102150405")) + fileName = fmt.Sprintf("%s/%s.log.err", f.logPath, f.logName) + } else { + backupFileName = fmt.Sprintf("%s/%s.log_%s", f.logPath, f.logName, now.Format("20060102150405")) + fileName = fmt.Sprintf("%s/%s.log", f.logPath, f.logName) + } + + file := f.file + if isWarn { + file = f.warnFile + } + file.Close() + os.Rename(fileName, backupFileName) + + file, err := os.OpenFile(fileName, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0755) + if err != nil { + return + } + + if isWarn { + f.warnFile = file + } else { + f.file = file + } + +} + +// 根据文件大小来分割 +func (f *FileLog) splitSize(isWarn bool) { + file := f.file + if isWarn { + file = f.warnFile + } + fileInfo, err := file.Stat() // 可以得到文件的参数 + if err != nil { + return + } + + fileSize := fileInfo.Size() + if fileSize <= f.logSplitSize { + return + } + + var backupFileName string + var fileName string + + now := time.Now() + + if isWarn { + backupFileName = fmt.Sprintf("%s/%s.log.err_%s", f.logPath, f.logName, now.Format("20060102150405")) + fileName = fmt.Sprintf("%s/%s.log.err", f.logPath, f.logName) + } else { + backupFileName = fmt.Sprintf("%s/%s.log_%s", f.logPath, f.logName, now.Format("20060102150405")) + fileName = fmt.Sprintf("%s/%s.log", f.logPath, f.logName) + } + + file.Close() + os.Rename(fileName, backupFileName) + + file, err = os.OpenFile(fileName, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0755) + if err != nil { + return + } + + if isWarn { + f.warnFile = file + } else { + f.file = file + } +} diff --git a/lxzap/lxzap.go b/lxzap/lxzap.go new file mode 100644 index 0000000..ffee29d --- /dev/null +++ b/lxzap/lxzap.go @@ -0,0 +1,137 @@ +package lxzap + +import ( + "net" + "net/http" + "net/http/httputil" + "os" + "runtime/debug" + "strings" + "time" + + "github.com/gin-gonic/gin" + "github.com/natefinch/lumberjack" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +var Lg *zap.Logger + +// Level = "info" +// Filename = "./log/a.log" +// MaxSize = 2 +// MaxAge = 1000 +// MaxBackups = 1000 +type LogConfig struct { + Level string `json:"level"` + Filename string `json:"filename"` + MaxSize int `json:"maxsize"` + MaxAge int `json:"max_age"` + MaxBackups int `json:"max_backups"` +} + +// InitLogger 初始化Logger +func InitLogger(cfg LogConfig) (err error) { + writeSyncer := getLogWriter(cfg.Filename, cfg.MaxSize, cfg.MaxBackups, cfg.MaxAge) + encoder := getEncoder() + var l = new(zapcore.Level) + err = l.UnmarshalText([]byte(cfg.Level)) + if err != nil { + return + } + core := zapcore.NewCore(encoder, writeSyncer, l) + + Lg = zap.New(core, zap.AddCaller()) + zap.ReplaceGlobals(Lg) // 替换zap包中全局的logger实例,后续在其他包中只需使用zap.L()调用即可 + return +} + +func getEncoder() zapcore.Encoder { + encoderConfig := zap.NewProductionEncoderConfig() + encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder + encoderConfig.TimeKey = "time" + encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder + encoderConfig.EncodeDuration = zapcore.SecondsDurationEncoder + encoderConfig.EncodeCaller = zapcore.ShortCallerEncoder + return zapcore.NewJSONEncoder(encoderConfig) +} + +func getLogWriter(filename string, maxSize, maxBackup, maxAge int) zapcore.WriteSyncer { + lumberJackLogger := &lumberjack.Logger{ + Filename: filename, + MaxSize: maxSize, + MaxBackups: maxBackup, + MaxAge: maxAge, + LocalTime: true, + } + return zapcore.AddSync(lumberJackLogger) +} + +// GinLogger 接收gin框架默认的日志 +func GinLogger() gin.HandlerFunc { + return func(c *gin.Context) { + start := time.Now() + path := c.Request.URL.Path + query := c.Request.URL.RawQuery + c.Next() + + cost := time.Since(start) + Lg.Info(path, + zap.Int("status", c.Writer.Status()), + zap.String("method", c.Request.Method), + zap.String("path", path), + zap.String("query", query), + zap.String("ip", c.ClientIP()), + zap.String("user-agent", c.Request.UserAgent()), + zap.String("errors", c.Errors.ByType(gin.ErrorTypePrivate).String()), + zap.Duration("cost", cost), + ) + } +} + +// GinRecovery recover掉项目可能出现的panic,并使用zap记录相关日志 +func GinRecovery(stack bool) gin.HandlerFunc { + return func(c *gin.Context) { + defer func() { + if err := recover(); err != nil { + // Check for a broken connection, as it is not really a + // condition that warrants a panic stack trace. + var brokenPipe bool + if ne, ok := err.(*net.OpError); ok { + if se, ok := ne.Err.(*os.SyscallError); ok { + if strings.Contains(strings.ToLower(se.Error()), "broken pipe") || strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") { + brokenPipe = true + } + } + } + + httpRequest, _ := httputil.DumpRequest(c.Request, false) + if brokenPipe { + Lg.Error(c.Request.URL.Path, + zap.Any("error", err), + zap.String("request", string(httpRequest)), + ) + // If the connection is dead, we can't write a status to it. + c.Error(err.(error)) // nolint: errcheck + c.Abort() + return + } + + if stack { + Lg.Error("[Recovery from panic]", + zap.Any("error", err), + zap.String("request", string(httpRequest)), + zap.String("stack", string(debug.Stack())), + ) + } else { + Lg.Error("[Recovery from panic]", + zap.Any("error", err), + zap.String("request", string(httpRequest)), + ) + } + c.AbortWithStatus(http.StatusInternalServerError) + } + }() + c.Next() + } +} diff --git a/lxzap/zapGorm2.go b/lxzap/zapGorm2.go new file mode 100644 index 0000000..91ea44c --- /dev/null +++ b/lxzap/zapGorm2.go @@ -0,0 +1,106 @@ +package lxzap + +import ( + "context" + "errors" + "path/filepath" + "runtime" + "strings" + "time" + + "go.uber.org/zap" + "gorm.io/gorm" + gormlogger "gorm.io/gorm/logger" +) + +type Logger struct { + ZapLogger *zap.Logger + LogLevel gormlogger.LogLevel + SlowThreshold time.Duration + SkipCallerLookup bool + IgnoreRecordNotFoundError bool +} + +func NewGormZap(zapLogger *zap.Logger) Logger { + return Logger{ + ZapLogger: zapLogger, + LogLevel: gormlogger.Info, + SlowThreshold: 100 * time.Millisecond, + SkipCallerLookup: false, + IgnoreRecordNotFoundError: false, + } +} + +func (l Logger) SetAsDefault() { + gormlogger.Default = l +} + +func (l Logger) LogMode(level gormlogger.LogLevel) gormlogger.Interface { + return Logger{ + ZapLogger: l.ZapLogger, + SlowThreshold: l.SlowThreshold, + LogLevel: level, + SkipCallerLookup: l.SkipCallerLookup, + IgnoreRecordNotFoundError: l.IgnoreRecordNotFoundError, + } +} + +func (l Logger) Info(ctx context.Context, str string, args ...interface{}) { + if l.LogLevel < gormlogger.Info { + return + } + l.logger().Sugar().Debugf(str, args...) +} + +func (l Logger) Warn(ctx context.Context, str string, args ...interface{}) { + if l.LogLevel < gormlogger.Warn { + return + } + l.logger().Sugar().Warnf(str, args...) +} + +func (l Logger) Error(ctx context.Context, str string, args ...interface{}) { + if l.LogLevel < gormlogger.Error { + return + } + l.logger().Sugar().Errorf(str, args...) +} + +func (l Logger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) { + if l.LogLevel <= 0 { + return + } + elapsed := time.Since(begin) + switch { + case err != nil && l.LogLevel >= gormlogger.Error && (!l.IgnoreRecordNotFoundError || !errors.Is(err, gorm.ErrRecordNotFound)): + sql, rows := fc() + l.logger().Error("trace", zap.Error(err), zap.Duration("elapsed", elapsed), zap.Int64("rows", rows), zap.String("sql", sql)) + case l.SlowThreshold != 0 && elapsed > l.SlowThreshold && l.LogLevel >= gormlogger.Warn: + sql, rows := fc() + l.logger().Warn("trace", zap.Duration("elapsed", elapsed), zap.Int64("rows", rows), zap.String("sql", sql)) + case l.LogLevel >= gormlogger.Info: + sql, rows := fc() + l.logger().Info("trace", zap.Duration("elapsed", elapsed), zap.Int64("rows", rows), zap.String("sql", sql)) + } +} + +var ( + gormPackage = filepath.Join("gorm.io", "gorm") + zapgormPackage = filepath.Join("moul.io", "zapgorm2") +) + +func (l Logger) logger() *zap.Logger { + for i := 2; i < 15; i++ { + _, file, _, ok := runtime.Caller(i) + file = filepath.Clean(file) + switch { + case !ok: + case strings.HasSuffix(file, "_test.go"): + case strings.Contains(file, gormPackage): + case strings.Contains(file, zapgormPackage): + default: + return l.ZapLogger.WithOptions(zap.AddCallerSkip(i - 1)) + } + } + return l.ZapLogger +}