New file |
| | |
| | | package constvar |
| | | |
| | | type UserType int |
| | | |
| | | const ( |
| | | UserTypeSuper UserType = iota + 1 // 超级管理员 |
| | | UserTypePrimary // 主账户 |
| | | UserTypeSub // 子账户 |
| | | ) |
| | |
| | | go 1.18 |
| | | |
| | | require ( |
| | | github.com/dgrijalva/jwt-go v3.2.0+incompatible |
| | | github.com/fsnotify/fsnotify v1.6.0 |
| | | github.com/fvbock/endless v0.0.0-20170109170031-447134032cb6 |
| | | github.com/gin-gonic/gin v1.9.1 |
| | | github.com/glebarez/sqlite v1.8.0 |
| | | github.com/go-sql-driver/mysql v1.7.1 |
| | | github.com/golang-jwt/jwt/v4 v4.5.0 |
| | | github.com/h2non/filetype v1.1.3 |
| | | github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible |
| | | github.com/redis/go-redis/v9 v9.0.5 |
| | |
| | | golang.org/x/sync v0.3.0 |
| | | google.golang.org/grpc v1.55.0 |
| | | google.golang.org/protobuf v1.30.0 |
| | | gopkg.in/natefinch/lumberjack.v2 v2.2.1 |
| | | gorm.io/driver/mysql v1.5.1 |
| | | gorm.io/driver/postgres v1.5.2 |
| | | gorm.io/driver/sqlserver v1.5.1 |
| | |
| | | github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= |
| | | github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= |
| | | github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= |
| | | github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= |
| | | github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= |
| | | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= |
| | | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= |
| | |
| | | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
| | | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= |
| | | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
| | | github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= |
| | | github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= |
| | | github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= |
| | | github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= |
| | | github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= |
| | |
| | | github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= |
| | | github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= |
| | | github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= |
| | | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= |
| | | 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-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= |
| | | github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= |
| | | github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= |
| | | github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= |
| | | github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= |
| | |
| | | github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= |
| | | github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= |
| | | github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= |
| | | github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= |
| | | github.com/jackc/pgconn v1.10.1/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= |
| | | github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= |
| | | github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= |
| | | github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= |
| | | github.com/jackc/pgproto3/v2 v2.2.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= |
| | | github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= |
| | | github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= |
| | | github.com/jackc/pgtype v1.9.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= |
| | | github.com/jackc/pgx/v4 v4.14.0/go.mod h1:jT3ibf/A0ZVCp89rtCIN0zCJxcE74ypROmHEZYsG/j8= |
| | | github.com/jackc/pgx/v5 v5.3.1 h1:Fcr8QJ1ZeLi5zsPZqQeUZhNhxfkkKBOgJuYkJHoBOtU= |
| | | github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8= |
| | | github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= |
| | |
| | | gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= |
| | | gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= |
| | | gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= |
| | | gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= |
| | | gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= |
| | | gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= |
| | | gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= |
| | | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
| | |
| | | |
| | | import ( |
| | | "net/http" |
| | | "srm/middleware" |
| | | "srm/router/purchase" |
| | | |
| | | "github.com/gin-gonic/gin" |
| | |
| | | global.GVA_LOG.Info("register swagger handler") |
| | | // 方便统一添加路由组前缀 多服务器上线使用 |
| | | |
| | | PublicGroup := Router.Group(global.GVA_CONFIG.System.RouterPrefix) |
| | | PrivateGroup := Router.Group(global.GVA_CONFIG.System.RouterPrefix) |
| | | { |
| | | // 健康监测 |
| | | PublicGroup.GET("/health", func(c *gin.Context) { |
| | | PrivateGroup.GET("/health", func(c *gin.Context) { |
| | | c.JSON(http.StatusOK, "ok") |
| | | }) |
| | | //systemRouter.InitInitRouter(PublicGroup) // 自动初始化相关 |
| | | } |
| | | |
| | | PrivateGroup := Router.Group(global.GVA_CONFIG.System.RouterPrefix) |
| | | PrivateGroup.Use(middleware.JWTAuth()) |
| | | { |
| | | systemRouter.InitSystemRouter(PrivateGroup) // system相关路由 |
| | | //exampleRouter.InitFileUploadAndDownloadRouter(PrivateGroup) // 文件上传下载功能路由 |
New file |
| | |
| | | package middleware |
| | | |
| | | import ( |
| | | "github.com/gin-gonic/gin" |
| | | "srm/pkg/contextx" |
| | | "srm/pkg/ecode" |
| | | "strings" |
| | | ) |
| | | |
| | | func JWTAuth() gin.HandlerFunc { |
| | | return func(c *gin.Context) { |
| | | ctx := new(contextx.Context).SetCtx(c) |
| | | // 我们这里jwt鉴权取头部信息 Authorization 登录时回返回token信息 这里前端需要把token存储到cookie或者本地localStorage中 不过需要跟后端协商过期时间 可以约定刷新令牌或者重新登录 |
| | | token := c.Request.Header.Get("Authorization") |
| | | if token == "" { |
| | | ctx.Fail(ecode.JWTEmpty) |
| | | c.Abort() |
| | | return |
| | | } |
| | | slices := strings.Split(token, " ") |
| | | if len(slices) == 2 { |
| | | token = slices[1] |
| | | } |
| | | j := NewJWT() |
| | | // parseToken 解析token包含的信息 |
| | | claims, err := j.ParseToken(token) |
| | | if err != nil { |
| | | if err == TokenExpired { |
| | | c.Next() |
| | | return |
| | | } |
| | | c.Next() |
| | | return |
| | | } |
| | | |
| | | c.Set("claims", claims) |
| | | c.Next() |
| | | } |
| | | } |
New file |
| | |
| | | package middleware |
| | | |
| | | import ( |
| | | "errors" |
| | | "github.com/golang-jwt/jwt/v4" |
| | | "srm/request" |
| | | ) |
| | | |
| | | type JWT struct { |
| | | SigningKey []byte |
| | | } |
| | | |
| | | var ( |
| | | TokenExpired = errors.New("Token is expired") |
| | | TokenNotValidYet = errors.New("Token not active yet") |
| | | TokenMalformed = errors.New("That's not even a token") |
| | | TokenInvalid = errors.New("Couldn't handle this token:") |
| | | ) |
| | | |
| | | func NewJWT() *JWT { |
| | | return &JWT{ |
| | | []byte("327a9457-899a-481e-8b30-58cc97e5b808"), |
| | | } |
| | | } |
| | | |
| | | // CreateToken 创建一个token |
| | | func (j *JWT) CreateToken(claims request.CustomClaims) (string, error) { |
| | | token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) |
| | | return token.SignedString(j.SigningKey) |
| | | } |
| | | |
| | | // ParseToken 解析token |
| | | func (j *JWT) ParseToken(tokenString string) (*request.CustomClaims, error) { |
| | | token, err := jwt.ParseWithClaims(tokenString, &request.CustomClaims{}, func(token *jwt.Token) (i interface{}, e error) { |
| | | return j.SigningKey, nil |
| | | }) |
| | | if err != nil { |
| | | if ve, ok := err.(*jwt.ValidationError); ok { |
| | | if ve.Errors&jwt.ValidationErrorMalformed != 0 { |
| | | return nil, TokenMalformed |
| | | } else if ve.Errors&jwt.ValidationErrorExpired != 0 { |
| | | // Token is expired |
| | | return nil, TokenExpired |
| | | } else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 { |
| | | return nil, TokenNotValidYet |
| | | } else { |
| | | return nil, TokenInvalid |
| | | } |
| | | } |
| | | } |
| | | if token != nil { |
| | | if claims, ok := token.Claims.(*request.CustomClaims); ok && token.Valid { |
| | | return claims, nil |
| | | } |
| | | return nil, TokenInvalid |
| | | |
| | | } else { |
| | | return nil, TokenInvalid |
| | | } |
| | | } |
New file |
| | |
| | | package contextx |
| | | |
| | | import ( |
| | | "github.com/gin-gonic/gin" |
| | | "net/http" |
| | | "srm/pkg/ecode" |
| | | "srm/pkg/logx" |
| | | ) |
| | | |
| | | type ( |
| | | Context struct { |
| | | ctx *gin.Context |
| | | paramsMap map[string]interface{} |
| | | } |
| | | |
| | | Response struct { |
| | | Code int `json:"code"` |
| | | Data interface{} `json:"data"` |
| | | Msg string `json:"msg"` |
| | | } |
| | | ) |
| | | |
| | | func NewContext(ctx *gin.Context, params interface{}) (r *Context, isAllow bool) { |
| | | r = &Context{ |
| | | ctx: ctx, |
| | | } |
| | | if r.ctx.Request.Method == "OPTIONS" { |
| | | r.ctx.String(http.StatusOK, "") |
| | | return |
| | | } |
| | | |
| | | defer func() { |
| | | query := r.ctx.Request.URL.RawQuery |
| | | if query != "" { |
| | | query = "?" + query |
| | | } |
| | | urlPath := r.ctx.Request.URL.Path |
| | | logx.Infof("%s | %s %s | uid: %s | %+v", ctx.ClientIP(), r.ctx.Request.Method, urlPath+query, r.GetUserId(), params) |
| | | }() |
| | | |
| | | // validate params |
| | | if params != nil { |
| | | if err := r.ctx.ShouldBind(params); err != nil { |
| | | r.Fail(ecode.ParamsErr) |
| | | return |
| | | } |
| | | } |
| | | isAllow = true |
| | | return |
| | | } |
| | | |
| | | func (slf *Context) GetRequestPath() (r string) { |
| | | r = slf.ctx.Request.URL.Path |
| | | return |
| | | } |
| | | |
| | | func (slf *Context) GetUserId() (r string) { |
| | | v := slf.paramsMap["userId"] |
| | | switch v.(type) { |
| | | case string: |
| | | r = v.(string) |
| | | } |
| | | return |
| | | } |
| | | |
| | | func (slf *Context) Result(code int, data interface{}, msg string) { |
| | | slf.ctx.JSON(http.StatusOK, Response{ |
| | | Code: code, |
| | | Data: data, |
| | | Msg: msg, |
| | | }) |
| | | } |
| | | |
| | | func (slf *Context) Ok() { |
| | | slf.Result(ecode.OK, map[string]interface{}{}, "") |
| | | } |
| | | |
| | | func (slf *Context) OkWithDetailed(data interface{}) { |
| | | slf.Result(ecode.OK, data, "") |
| | | } |
| | | |
| | | func (slf *Context) Fail(errCode int) { |
| | | slf.Result(errCode, map[string]interface{}{}, ecode.GetMsg(errCode)) |
| | | } |
| | | |
| | | func (slf *Context) FailWithDetailed(errCode int, data interface{}) { |
| | | slf.Result(errCode, data, ecode.GetMsg(errCode)) |
| | | } |
| | | |
| | | func (slf *Context) GetCtx() *gin.Context { |
| | | return slf.ctx |
| | | } |
| | | |
| | | func (slf *Context) SetCtx(c *gin.Context) *Context { |
| | | slf.ctx = c |
| | | return slf |
| | | } |
New file |
| | |
| | | package ecode |
| | | |
| | | const ( |
| | | OK = 200 |
| | | |
| | | UnknownErr = 2001 // 未知错误 |
| | | DBErr = 2002 // db错误 |
| | | RedisErr = 2003 // redis错误 |
| | | ParamsErr = 2004 // 请求参数错误 |
| | | UserNotExist = 2005 // 用户不存在 |
| | | PasswordErr = 2006 // 密码错误 |
| | | UserForbidden = 2007 // 用户被禁用 |
| | | CaptchaGenerateFailed = 2008 // 验证码生成失败 |
| | | CaptchaErr = 2009 // 验证码错误 |
| | | CreateTokenErr = 2010 // 创建token失败 |
| | | JWTInBlackList = 2011 // JWT在白名单 |
| | | JWTDisabled = 2012 // JWT失效 |
| | | JWTEmpty = 2013 // JWT为空 |
| | | JWTExpire = 2014 // JWT过期 |
| | | JWTParseErr = 2015 // JWT解析失败 |
| | | ) |
New file |
| | |
| | | package ecode |
| | | |
| | | var MsgFlags = map[int]string{ |
| | | UnknownErr: "未知错误", |
| | | DBErr: "db错误", |
| | | RedisErr: "redis错误", |
| | | ParamsErr: "请求参数错误", |
| | | UserNotExist: "用户不存在", |
| | | PasswordErr: "密码错误", |
| | | UserForbidden: "用户被禁用", |
| | | CaptchaGenerateFailed: "验证码生成失败", |
| | | CaptchaErr: "验证码错误", |
| | | CreateTokenErr: "创建token失败", |
| | | JWTInBlackList: "JWT在白名单", |
| | | JWTDisabled: "JWT失效", |
| | | JWTEmpty: "JWT为空", |
| | | JWTExpire: "JWT过期", |
| | | JWTParseErr: "JWT解析失败", |
| | | } |
| | | |
| | | func GetMsg(errCode int) (errMsg string) { |
| | | errMsg, _ = MsgFlags[errCode] |
| | | return |
| | | } |
New file |
| | |
| | | package logx |
| | | |
| | | import ( |
| | | "fmt" |
| | | "go.uber.org/zap" |
| | | "go.uber.org/zap/zapcore" |
| | | "time" |
| | | ) |
| | | |
| | | type ConsoleLog struct { |
| | | val string |
| | | } |
| | | |
| | | func NewConsoleLog() Encoder { |
| | | return new(ConsoleLog) |
| | | } |
| | | |
| | | // Config 自定义配置. |
| | | func (slf *ConsoleLog) Config() zapcore.Encoder { |
| | | var ( |
| | | cfg = zap.NewProductionEncoderConfig() |
| | | ) |
| | | |
| | | // 时间格式自定义 |
| | | cfg.EncodeTime = func(t time.Time, enc zapcore.PrimitiveArrayEncoder) { |
| | | enc.AppendString("[" + t.Format("2006-01-02 15:04:05") + "]") |
| | | } |
| | | // 打印路径自定义 |
| | | cfg.EncodeCaller = func(caller zapcore.EntryCaller, encoder zapcore.PrimitiveArrayEncoder) { |
| | | encoder.AppendString("[" + getFilePath(caller) + "]") |
| | | } |
| | | // 级别显示自定义 |
| | | cfg.EncodeLevel = func(level zapcore.Level, encoder zapcore.PrimitiveArrayEncoder) { |
| | | encoder.AppendString("[" + level.String() + "]") |
| | | } |
| | | return zapcore.NewConsoleEncoder(cfg) |
| | | } |
| | | |
| | | // WithKey 添加单个键. |
| | | func (slf *ConsoleLog) WithKey(key string) Encoder { |
| | | slf.val = slf.val + "[" + key + "] " |
| | | return slf |
| | | } |
| | | |
| | | // WithField 添加字段. |
| | | func (slf *ConsoleLog) WithField(key, val string) Encoder { |
| | | slf.val = slf.val + fmt.Sprintf("[%s:%s] ", key, val) |
| | | return slf |
| | | } |
| | | |
| | | func (slf *ConsoleLog) Debug(msg string) { |
| | | _logger.Debug(slf.val + msg) |
| | | } |
| | | |
| | | func (slf *ConsoleLog) Debugf(format string, v ...interface{}) { |
| | | _logger.Debug(fmt.Sprintf(slf.val+format, v...)) |
| | | } |
| | | |
| | | func (slf *ConsoleLog) Info(msg string) { |
| | | _logger.Info(slf.val + msg) |
| | | } |
| | | |
| | | func (slf *ConsoleLog) Infof(format string, v ...interface{}) { |
| | | _logger.Info(fmt.Sprintf(slf.val+format, v...)) |
| | | } |
| | | |
| | | func (slf *ConsoleLog) Warn(msg string) { |
| | | _logger.Warn(slf.val + msg) |
| | | } |
| | | |
| | | func (slf *ConsoleLog) Warnf(format string, v ...interface{}) { |
| | | _logger.Warn(fmt.Sprintf(slf.val+format, v...)) |
| | | } |
| | | |
| | | func (slf *ConsoleLog) Error(msg string) { |
| | | _logger.Error(slf.val + msg) |
| | | } |
| | | |
| | | func (slf *ConsoleLog) Errorf(format string, v ...interface{}) { |
| | | _logger.Error(fmt.Sprintf(slf.val+format, v...)) |
| | | } |
| | | |
| | | func (slf *ConsoleLog) Fatal(msg string) { |
| | | _logger.Fatal(slf.val + msg) |
| | | } |
| | | |
| | | func (slf *ConsoleLog) Fatalf(format string, v ...interface{}) { |
| | | _logger.Fatal(fmt.Sprintf(slf.val+format, v...)) |
| | | } |
New file |
| | |
| | | package logx |
| | | |
| | | import ( |
| | | "go.uber.org/zap" |
| | | "go.uber.org/zap/buffer" |
| | | "go.uber.org/zap/zapcore" |
| | | "gopkg.in/natefinch/lumberjack.v2" |
| | | "os" |
| | | "path" |
| | | "strings" |
| | | ) |
| | | |
| | | type ( |
| | | Conf struct { |
| | | Path string // 日志路径 |
| | | Encoder string // 编码器选择 |
| | | } |
| | | logItem struct { |
| | | FileName string |
| | | Level zap.LevelEnablerFunc |
| | | } |
| | | Encoder interface { |
| | | Config() zapcore.Encoder |
| | | WithKey(key string) Encoder |
| | | WithField(key, val string) Encoder |
| | | Debug(msg string) |
| | | Debugf(format string, v ...interface{}) |
| | | Info(msg string) |
| | | Infof(format string, v ...interface{}) |
| | | Warn(msg string) |
| | | Warnf(format string, v ...interface{}) |
| | | Error(msg string) |
| | | Errorf(format string, v ...interface{}) |
| | | Fatal(msg string) |
| | | Fatalf(format string, v ...interface{}) |
| | | } |
| | | ) |
| | | |
| | | var ( |
| | | maxSize = 200 // 每个日志文件最大尺寸200M |
| | | maxBackups = 20 // 日志文件最多保存20个备份 |
| | | maxAge = 30 // 保留最大天数 |
| | | _logger *zap.Logger |
| | | _pool = buffer.NewPool() |
| | | c Conf |
| | | |
| | | ConsoleEncoder = "console" // 控制台输出 |
| | | JsonEncoder = "json" // json输出 |
| | | ) |
| | | |
| | | // Init 初始化日志. |
| | | func Init(conf Conf) { |
| | | c = conf |
| | | prefix, suffix := getFileSuffixPrefix(c.Path) |
| | | |
| | | infoPath := path.Join(prefix + ".info" + suffix) |
| | | errPath := path.Join(prefix + ".err" + suffix) |
| | | items := []logItem{ |
| | | { |
| | | FileName: infoPath, |
| | | Level: func(level zapcore.Level) bool { |
| | | return level <= zap.InfoLevel |
| | | }, |
| | | }, |
| | | { |
| | | FileName: errPath, |
| | | Level: func(level zapcore.Level) bool { |
| | | return level > zap.InfoLevel |
| | | }, |
| | | }, |
| | | } |
| | | |
| | | NewLogger(items) |
| | | } |
| | | |
| | | // NewLogger 日志. |
| | | func NewLogger(items []logItem) { |
| | | var ( |
| | | cfg zapcore.Encoder |
| | | cores []zapcore.Core |
| | | ) |
| | | switch c.Encoder { |
| | | case JsonEncoder: |
| | | cfg = NewJsonLog().Config() |
| | | case ConsoleEncoder: |
| | | cfg = NewConsoleLog().Config() |
| | | default: |
| | | cfg = NewConsoleLog().Config() |
| | | } |
| | | |
| | | for _, v := range items { |
| | | hook := lumberjack.Logger{ |
| | | Filename: v.FileName, |
| | | MaxSize: maxSize, // 每个日志文件保存的最大尺寸 单位:M |
| | | MaxBackups: maxBackups, // 日志文件最多保存多少个备份 |
| | | MaxAge: maxAge, // 文件最多保存多少天 |
| | | Compress: true, // 是否压缩 |
| | | LocalTime: true, // 备份文件名本地/UTC时间 |
| | | } |
| | | core := zapcore.NewCore( |
| | | cfg, // 编码器配置; |
| | | zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout), zapcore.AddSync(&hook)), // 打印到控制台和文件 |
| | | v.Level, // 日志级别 |
| | | ) |
| | | cores = append(cores, core) |
| | | } |
| | | |
| | | // 开启开发模式,堆栈跟踪 |
| | | caller := zap.AddCaller() |
| | | // 开发模式 |
| | | development := zap.Development() |
| | | // 二次封装 |
| | | skip := zap.AddCallerSkip(1) |
| | | // 构造日志 |
| | | _logger = zap.New(zapcore.NewTee(cores...), caller, development, skip) |
| | | return |
| | | } |
| | | |
| | | // GetEncoder 获取自定义编码器. |
| | | func GetEncoder() Encoder { |
| | | switch c.Encoder { |
| | | case JsonEncoder: |
| | | return NewJsonLog() |
| | | case ConsoleEncoder: |
| | | return NewConsoleLog() |
| | | default: |
| | | return NewConsoleLog() |
| | | } |
| | | } |
| | | |
| | | // GetLogger 获取日志记录器. |
| | | func GetLogger() *zap.Logger { |
| | | return _logger |
| | | } |
| | | |
| | | // getFileSuffixPrefix 文件路径切割 |
| | | func getFileSuffixPrefix(fileName string) (prefix, suffix string) { |
| | | paths, _ := path.Split(fileName) |
| | | base := path.Base(fileName) |
| | | suffix = path.Ext(fileName) |
| | | prefix = strings.TrimSuffix(base, suffix) |
| | | prefix = path.Join(paths, prefix) |
| | | return |
| | | } |
| | | |
| | | // getFilePath 自定义获取文件路径. |
| | | func getFilePath(ec zapcore.EntryCaller) string { |
| | | if !ec.Defined { |
| | | return "undefined" |
| | | } |
| | | buf := _pool.Get() |
| | | buf.AppendString(ec.Function) |
| | | buf.AppendByte(':') |
| | | buf.AppendInt(int64(ec.Line)) |
| | | caller := buf.String() |
| | | buf.Free() |
| | | return caller |
| | | } |
New file |
| | |
| | | package logx |
| | | |
| | | import ( |
| | | "fmt" |
| | | "go.uber.org/zap" |
| | | "go.uber.org/zap/zapcore" |
| | | "time" |
| | | ) |
| | | |
| | | type JsonLog struct { |
| | | fields []zap.Field |
| | | val string |
| | | } |
| | | |
| | | // NewJsonLog 自定义添加log field. |
| | | func NewJsonLog() Encoder { |
| | | return &JsonLog{fields: make([]zap.Field, 0)} |
| | | } |
| | | |
| | | // Config 自定义配置. |
| | | func (slf *JsonLog) Config() zapcore.Encoder { |
| | | var ( |
| | | cfg = zap.NewProductionEncoderConfig() |
| | | ) |
| | | |
| | | // 时间格式自定义 |
| | | cfg.EncodeTime = func(t time.Time, enc zapcore.PrimitiveArrayEncoder) { |
| | | enc.AppendString(t.Format("2006-01-02 15:04:05")) |
| | | } |
| | | // 打印路径自定义 |
| | | cfg.EncodeCaller = func(caller zapcore.EntryCaller, encoder zapcore.PrimitiveArrayEncoder) { |
| | | encoder.AppendString(getFilePath(caller)) |
| | | } |
| | | // 级别显示自定义 |
| | | cfg.EncodeLevel = func(level zapcore.Level, encoder zapcore.PrimitiveArrayEncoder) { |
| | | encoder.AppendString(level.String()) |
| | | } |
| | | return zapcore.NewJSONEncoder(cfg) |
| | | } |
| | | |
| | | // WithKey 添加单个键. |
| | | func (slf *JsonLog) WithKey(key string) Encoder { |
| | | slf.val = slf.val + key + " " |
| | | return slf |
| | | } |
| | | |
| | | // WithField 添加字段. |
| | | func (slf *JsonLog) WithField(key, val string) Encoder { |
| | | slf.fields = append(slf.fields, zap.String(key, val)) |
| | | return slf |
| | | } |
| | | |
| | | func (slf *JsonLog) Debug(msg string) { |
| | | _logger.Debug(slf.val+msg, slf.fields...) |
| | | } |
| | | |
| | | func (slf *JsonLog) Debugf(format string, v ...interface{}) { |
| | | _logger.Debug(fmt.Sprintf(slf.val+format, v...), slf.fields...) |
| | | } |
| | | |
| | | func (slf *JsonLog) Info(msg string) { |
| | | _logger.Info(slf.val+msg, slf.fields...) |
| | | } |
| | | |
| | | func (slf *JsonLog) Infof(format string, v ...interface{}) { |
| | | _logger.Info(fmt.Sprintf(slf.val+format, v...), slf.fields...) |
| | | } |
| | | |
| | | func (slf *JsonLog) Warn(msg string) { |
| | | _logger.Warn(slf.val+msg, slf.fields...) |
| | | } |
| | | |
| | | func (slf *JsonLog) Warnf(format string, v ...interface{}) { |
| | | _logger.Warn(fmt.Sprintf(slf.val+format, v...), slf.fields...) |
| | | } |
| | | |
| | | func (slf *JsonLog) Error(msg string) { |
| | | _logger.Error(slf.val+msg, slf.fields...) |
| | | } |
| | | |
| | | func (slf *JsonLog) Errorf(format string, v ...interface{}) { |
| | | _logger.Error(fmt.Sprintf(slf.val+format, v...), slf.fields...) |
| | | } |
| | | |
| | | func (slf *JsonLog) Fatal(msg string) { |
| | | _logger.Fatal(slf.val+msg, slf.fields...) |
| | | } |
| | | |
| | | func (slf *JsonLog) Fatalf(format string, v ...interface{}) { |
| | | _logger.Fatal(fmt.Sprintf(slf.val+format, v...), slf.fields...) |
| | | } |
New file |
| | |
| | | package logx |
| | | |
| | | import ( |
| | | "fmt" |
| | | ) |
| | | |
| | | func Sync() { |
| | | _ = _logger.Sync() |
| | | } |
| | | |
| | | func Debug(msg string) { |
| | | _logger.Debug(msg) |
| | | } |
| | | |
| | | func Debugf(format string, v ...interface{}) { |
| | | _logger.Debug(fmt.Sprintf(format, v...)) |
| | | } |
| | | |
| | | func Info(msg string) { |
| | | _logger.Info(msg) |
| | | } |
| | | |
| | | func Infof(format string, v ...interface{}) { |
| | | _logger.Info(fmt.Sprintf(format, v...)) |
| | | } |
| | | |
| | | func Warn(msg string) { |
| | | _logger.Warn(msg) |
| | | } |
| | | |
| | | func Warnf(format string, v ...interface{}) { |
| | | _logger.Warn(fmt.Sprintf(format, v...)) |
| | | } |
| | | |
| | | func Error(msg string) { |
| | | _logger.Error(msg) |
| | | } |
| | | |
| | | func Errorf(format string, v ...interface{}) { |
| | | _logger.Error(fmt.Sprintf(format, v...)) |
| | | } |
| | | |
| | | func Fatal(msg string) { |
| | | _logger.Fatal(msg) |
| | | } |
| | | |
| | | func Fatalf(format string, v ...interface{}) { |
| | | _logger.Fatal(fmt.Sprintf(format, v...)) |
| | | } |
New file |
| | |
| | | package request |
| | | |
| | | import ( |
| | | "github.com/dgrijalva/jwt-go" |
| | | "srm/constvar" |
| | | ) |
| | | |
| | | // Custom claims structure |
| | | type CustomClaims struct { |
| | | BaseClaims |
| | | BufferTime int64 |
| | | jwt.StandardClaims |
| | | } |
| | | |
| | | type BaseClaims struct { |
| | | UserId string |
| | | Username string |
| | | ParentId string |
| | | UserType constvar.UserType |
| | | } |