diff --git a/app/app.go b/app/app.go index b401474..179fbf2 100644 --- a/app/app.go +++ b/app/app.go @@ -18,33 +18,22 @@ package app import ( - "os" - - "github.com/acmestack/devstack/http" + "github.com/acmestack/devstack/app/settings" "github.com/acmestack/devstack/logging" - "github.com/acmestack/devstack/settings" ) -type App struct { - setting *settings.Setting -} - -var app *App +var ( + Logger logging.Logger + // SugaredLogger *zap.SugaredLogger +) -func Run(enginePatch http.EnginePatchFunc, patch ...interface{}) { - writer := logging.MultiWriter() - cfg := settings.NewSetting(settings.AppConfigurations, patch...) +func Run(routerFunc GinEngineRouterFunc) { + setting := settings.NewSetting() - logging.InitLogger(os.Getenv(settings.LogLevel)) + Logger = logging.InitLogger(setting.LogLevel) + // SugaredLogger = Logger.Sugar - engine := http.InitEngine(cfg, writer) - if enginePatch != nil { - enginePatch(engine) - } - http.Run(engine) - app = &App{setting: cfg} -} - -func Settings() *settings.Setting { - return app.setting + httpEngine := newEngine(setting) + engine := httpEngine.initGinEngine(routerFunc) + httpEngine.serverRun(engine) } diff --git a/http/http.go b/app/engine.go similarity index 75% rename from http/http.go rename to app/engine.go index 6b2345d..2241499 100644 --- a/http/http.go +++ b/app/engine.go @@ -15,23 +15,28 @@ * limitations under the License. */ -package http +package app import ( "fmt" - "io" "net/http" - "os" "time" "github.com/gin-gonic/gin" - "github.com/acmestack/devstack/logging" - "github.com/acmestack/devstack/settings" + "github.com/acmestack/devstack/app/settings" ) -func InitEngine(cfg *settings.Setting, writer io.Writer) *gin.Engine { - gin.SetMode(os.Getenv(gin.EnvGinMode)) +type engine struct { + setting *settings.Setting +} + +func newEngine(setting *settings.Setting) *engine { + return &engine{setting: setting} +} + +func (e *engine) initGinEngine(routerFunc GinEngineRouterFunc) *gin.Engine { + gin.SetMode(e.setting.EnvGinMode) router := gin.Default() @@ -50,22 +55,23 @@ func InitEngine(cfg *settings.Setting, writer io.Writer) *gin.Engine { param.ErrorMessage, ) }, - Output: writer, + Output: e.setting.Writer, SkipPaths: nil, })) // Recovery middleware recovers from any panics and writes a 500 if there was one. router.Use(gin.CustomRecovery(func(context *gin.Context, recovered interface{}) { - if err, ok := recovered.(string); ok { - logging.Logger.Errorf("error %v", err) - context.JSON(http.StatusInternalServerError, http.StatusInternalServerError) - } - context.AbortWithStatus(http.StatusInternalServerError) + Logger.Error(fmt.Errorf("%v", recovered), "") + context.JSON(http.StatusInternalServerError, http.StatusInternalServerError) })) router.GET("/health", func(c *gin.Context) { c.String(http.StatusOK, "ok") }) + if routerFunc != nil { + routerFunc(router) + } + return router } diff --git a/http/server.go b/app/server.go similarity index 67% rename from http/server.go rename to app/server.go index 4963406..d9135a1 100644 --- a/http/server.go +++ b/app/server.go @@ -15,28 +15,28 @@ * limitations under the License. */ -package http +package app import ( "net/http" "github.com/gin-gonic/gin" - - "github.com/acmestack/devstack/logging" ) -type EnginePatchFunc func(engine *gin.Engine) +type GinEngineRouterFunc func(engine *gin.Engine) -func Run(engine *gin.Engine) { - httpServer := &http.Server{ - Addr: ":8080", - Handler: engine, - } - - logging.Logger.Infof("start http server listening %s", httpServer.Addr) - - err := httpServer.ListenAndServe() - if err != nil { - logging.Logger.Errorf("start http server error %v", err) +func (e *engine) serverRun(engine *gin.Engine) { + { + httpServer := &http.Server{ + Addr: ":8080", + Handler: engine, + } + + Logger.Info("start https server listening", "addr", httpServer.Addr) + + err := httpServer.ListenAndServe() + if err != nil { + Logger.Error(err, "start https server error") + } } } diff --git a/settings/settings.go b/app/settings/settings.go similarity index 59% rename from settings/settings.go rename to app/settings/settings.go index 654218f..83f6601 100644 --- a/settings/settings.go +++ b/app/settings/settings.go @@ -17,19 +17,32 @@ package settings +import ( + "io" + "os" + + "github.com/acmestack/godkits/gox/stringsx" + "github.com/gin-gonic/gin" + + "github.com/acmestack/devstack/logging" +) + const ( AppConfigurations = "app.yaml" - LogLevel = "LOG_LEVEL" ) type Setting struct { - path string -} - -func NewSetting(path string, patch ...interface{}) *Setting { - return &Setting{path: path} + LogLevel logging.LogLevel + Port string + Writer io.Writer + EnvGinMode string } -func Patch(patch interface{}) interface{} { - return nil +func NewSetting() *Setting { + return &Setting{ + LogLevel: logging.LogLevel(stringsx.DefaultIfEmpty(os.Getenv("LOG_LEVEL"), string(logging.LogLevelInfo))), + Port: stringsx.DefaultIfEmpty(os.Getenv("PORT"), "8080"), + Writer: io.MultiWriter(os.Stdout), + EnvGinMode: stringsx.DefaultIfEmpty(os.Getenv(gin.EnvGinMode), "debug"), + } } diff --git a/go.mod b/go.mod index bfc334a..6db1c64 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,10 @@ module github.com/acmestack/devstack go 1.18 require ( + github.com/acmestack/godkits v0.0.11 github.com/gin-gonic/gin v1.9.0 + github.com/go-logr/logr v1.2.4 + github.com/go-logr/zapr v1.2.4 go.uber.org/zap v1.24.0 ) diff --git a/go.sum b/go.sum index e3cfcae..b20b579 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,7 @@ +github.com/acmestack/godkits v0.0.11 h1:XVXn7iq60xbqOrBMUA3ktMDRDYlXA21vmwIHMxrbg2s= +github.com/acmestack/godkits v0.0.11/go.mod h1:d5kiqEvQl/LpXd8VTy7PZvQ5DDiasCX+QKA3+q8fWos= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.8.0 h1:ea0Xadu+sHlu7x5O3gKhRpQ1IKiMrSiHttPF0ybECuA= github.com/bytedance/sonic v1.8.0/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= @@ -12,6 +15,10 @@ 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.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8= github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH89961k= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= +github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/zapr v1.2.4 h1:QHVo+6stLbfJmYGkQ7uGHUCu5hnAFAj6mDe6Ea0SeOo= +github.com/go-logr/zapr v1.2.4/go.mod h1:FyHWQIzQORZ0QVE1BtVHv3cKtNLuXsbNLtpuhNapBOA= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= 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= @@ -29,7 +36,10 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= @@ -41,10 +51,13 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= +github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= 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= @@ -59,31 +72,60 @@ github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.9 h1:rmenucSohSTiyL09Y+l2OCk+FrMxGMzho2+tjr5ticU= github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg= golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/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.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= 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= diff --git a/logging/level.go b/logging/level.go new file mode 100644 index 0000000..fb2970b --- /dev/null +++ b/logging/level.go @@ -0,0 +1,18 @@ +package logging + +// LogLevel defines a log level for system logs. +type LogLevel string + +const ( + // LogLevelDebug defines the "debug" logging level. + LogLevelDebug LogLevel = "debug" + + // LogLevelInfo defines the "Info" logging level. + LogLevelInfo LogLevel = "info" + + // LogLevelWarn defines the "Warn" logging level. + LogLevelWarn LogLevel = "warn" + + // LogLevelError defines the "Error" logging level. + LogLevelError LogLevel = "error" +) diff --git a/logging/logger.go b/logging/logger.go index 1be7501..42622d8 100644 --- a/logging/logger.go +++ b/logging/logger.go @@ -1,55 +1,70 @@ -/* - * Licensed to the AcmeStack under one or more contributor license - * agreements. See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - package logging import ( - "io" "os" - + + "github.com/go-logr/logr" + "github.com/go-logr/zapr" "go.uber.org/zap" "go.uber.org/zap/zapcore" ) -var ( - Logger *zap.SugaredLogger -) +// Logger 's Sugar A Sugar wraps the base Logger functionality in a slower, but less +// verbose, API. Any Logger can be converted to a SugaredLogger with its Sugar +// method. +// +// Unlike the Logger, the SugaredLogger doesn't insist on structured logging. +// For each log level, it exposes four methods: +// +// - methods named after the log level for log.Print-style logging +// - methods ending in "w" for loosely-typed structured logging +// - methods ending in "f" for log.Printf-style logging +// - methods ending in "ln" for log.Println-style logging +// +// For example, the methods for InfoLevel are: +// +// Info(...any) Print-style logging +// Infow(...any) Structured logging (read as "info with") +// Infof(string, ...any) Printf-style logging +// Infoln(...any) Println-style logging +type Logger struct { + logr.Logger + level LogLevel + Sugar *zap.SugaredLogger +} -func init() { - InitLogger("info") +func InitLogger(level LogLevel) Logger { + logger := initZapLogger(level) + return Logger{ + Logger: zapr.NewLogger(logger), + Sugar: logger.Sugar(), + } } -func InitLogger(level string) { - l, err := zapcore.ParseLevel(level) - if err != nil { - l = zapcore.InfoLevel +// WithName returns a new Logger instance with the specified name element added +// to the Logger's name. Successive calls with WithName append additional +// suffixes to the Logger's name. It's strongly recommended that name segments +// contain only letters, digits, and hyphens (see the package documentation for +// more information). +func (l Logger) WithName(name string) Logger { + logger := initZapLogger(l.level) + + return Logger{ + Logger: zapr.NewLogger(logger).WithName(name), + Sugar: l.Sugar, } - - encoderConfig := zap.NewProductionEncoderConfig() - encoderConfig.EncodeTime = zapcore.RFC3339TimeEncoder - encoderConfig.EncodeLevel = zapcore.CapitalLevelEncoder - - encoder := zapcore.NewConsoleEncoder(encoderConfig) - core := zapcore.NewCore(encoder, zapcore.NewMultiWriteSyncer(zapcore.AddSync(os.Stdout)), zap.NewAtomicLevelAt(l)) - zapLogger := zap.New(core, zap.AddCaller()) - - Logger = zapLogger.Sugar() } -func MultiWriter() io.Writer { - return io.MultiWriter(os.Stdout) +// WithValues returns a new Logger instance with additional key/value pairs. +// See Info for documentation on how key/value pairs work. +func (l Logger) WithValues(keysAndValues ...interface{}) Logger { + l.Logger = l.Logger.WithValues(keysAndValues...) + return l +} + +func initZapLogger(level LogLevel) *zap.Logger { + parseLevel, _ := zapcore.ParseLevel(string(level)) + core := zapcore.NewCore(zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig()), zapcore.AddSync(os.Stdout), zap.NewAtomicLevelAt(parseLevel)) + + return zap.New(core, zap.AddCaller()) } diff --git a/logging/logger_test.go b/logging/logger_test.go index e952e4a..1f8c21a 100644 --- a/logging/logger_test.go +++ b/logging/logger_test.go @@ -1,29 +1,13 @@ -/* - * Licensed to the AcmeStack under one or more contributor license - * agreements. See the NOTICE file distributed with this work for - * additional information regarding copyright ownership. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - package logging import ( + "errors" "testing" ) func TestInitLogger(t *testing.T) { type args struct { - level string + level LogLevel } tests := []struct { name string @@ -36,8 +20,10 @@ func TestInitLogger(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - InitLogger(tt.args.level) + logger := InitLogger(tt.args.level) + logger.Error(errors.New("error"), "error occur") + + logger.WithName("sys").WithValues("key", "value").Info("msg", "infok", "infovalue") }) - Logger.Errorf("error %s", "msg") } } diff --git a/structcp/structcp.go b/structcp/structcp.go new file mode 100644 index 0000000..5924577 --- /dev/null +++ b/structcp/structcp.go @@ -0,0 +1,28 @@ +package structcp + +import ( + "reflect" +) + +const ( + AlignToTag = "alignTo" +) + +func Align(target any, source any) { + sourceValueOf := reflect.ValueOf(source) + targetValueOf := reflect.ValueOf(target).Elem() + + sourceTypeOf := reflect.TypeOf(source) + sourceFields := reflect.VisibleFields(sourceTypeOf) + for _, field := range sourceFields { + targetFieldName := field.Name + tag := field.Tag.Get(AlignToTag) + if tag != "" { + targetFieldName = tag + } + value := targetValueOf.FieldByName(targetFieldName) + if value.Kind() != reflect.Invalid && value.Type() == field.Type { + value.Set(sourceValueOf.FieldByName(field.Name)) + } + } +} diff --git a/structcp/structcp_test.go b/structcp/structcp_test.go new file mode 100644 index 0000000..d6cebfe --- /dev/null +++ b/structcp/structcp_test.go @@ -0,0 +1,83 @@ +package structcp + +import ( + "reflect" + "testing" + + "github.com/acmestack/devstack/logging" +) + +func Test(t *testing.T) { + type Target struct { + Name string + Addr int + Other1 string + Other2 string + } + tests := []struct { + name string + source any + target Target + align bool + }{ + { + name: "convert case 0", + source: struct { + Name string + Addr string + Other0 string + Other2 string + }{Name: "name value", Addr: "addr value", Other2: "other2 value"}, + target: Target{Name: "bb", Other1: "other1"}, + align: true, + }, + { + name: "convert case 1", + source: struct { + Name1 string + Addr1 string + Other01 string + Other21 string + }{Name1: "name value", Addr1: "addr value", Other21: "other2 value"}, + target: Target{Name: "bb", Other1: "other1"}, + align: false, + }, + { + name: "convert case 2", + source: struct { + Name1 string `alignTo:"Name"` + Addr1 string + Other01 string `alignTo:"Other1"` + Other21 string + }{Name1: "name value", Addr1: "addr value", Other01: "other01 value"}, + target: Target{Name: "bb", Other1: "other1"}, + align: true, + }, + } + + logger := logging.InitLogger("info") + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + logger.Sugar.Infof("case name %s", test.name) + Align(&test.target, test.source) + if test.align { + sourceValueOf := reflect.ValueOf(test.source) + targetValueOf := reflect.ValueOf(&test.target).Elem() + + sourceTypeOf := reflect.TypeOf(test.source) + sourceFields := reflect.VisibleFields(sourceTypeOf) + for i, field := range sourceFields { + logger.Sugar.Infof("file index %d, field %v", i, field) + value := targetValueOf.FieldByName(field.Name) + + sourceValue := sourceValueOf.FieldByName(field.Name).String() + if value.Kind() != reflect.Invalid && value.Type() == field.Type && !reflect.DeepEqual(value.String(), sourceValue) { + t.Error("align error") + } + logger.Sugar.Infof("value %s, sourcevalue %s", value.String(), sourceValue) + } + } + logger.Sugar.Infof("bb addr: %d, name: %s, others1 %s", test.target.Addr, test.target.Name, test.target.Other1) + }) + } +}