Skip to content

Commit

Permalink
Merge pull request #83 from nabbar/refactor_status
Browse files Browse the repository at this point in the history
Refactor Status PKG
  • Loading branch information
Nicolas JUHEL authored Feb 19, 2021
2 parents 0d9a3db + 818122d commit a7348db
Show file tree
Hide file tree
Showing 8 changed files with 677 additions and 463 deletions.
9 changes: 5 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ require (
github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7 // indirect
github.com/json-iterator/go v1.1.10 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/magefile/mage v1.11.0 // indirect
github.com/matcornic/hermes/v2 v2.1.0
github.com/mattn/go-runewidth v0.0.10 // indirect
github.com/mitchellh/copystructure v1.1.1 // indirect
Expand All @@ -48,18 +49,18 @@ require (
github.com/rogpeppe/go-internal v1.7.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/shirou/gopsutil v3.21.1+incompatible
github.com/sirupsen/logrus v1.7.0
github.com/sirupsen/logrus v1.8.0
github.com/spf13/jwalterweatherman v1.1.0
github.com/ugorji/go v1.2.4 // indirect
github.com/vanng822/go-premailer v1.9.0 // indirect
github.com/vbauerster/mpb/v5 v5.4.0
github.com/xanzy/go-gitlab v0.44.0
github.com/xhit/go-simple-mail v2.2.2+incompatible
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
golang.org/x/crypto v0.0.0-20210218145215-b8e89b74b9df
golang.org/x/net v0.0.0-20210119194325-5f4716e94777
golang.org/x/oauth2 v0.0.0-20210210192628-66670185b0cd
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c // indirect
golang.org/x/sys v0.0.0-20210218155724-8ebf48af031b // indirect
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf // indirect
golang.org/x/text v0.3.5 // indirect
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 // indirect
Expand Down
66 changes: 43 additions & 23 deletions status/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ import (

const (
msgOk = "API is working"
msgKO = "something is not well working"
msgKO = "API is not working"
msgWarn = "something is not well working"
)

type EmptyStruct struct{}
Expand All @@ -39,22 +40,45 @@ func init() {
vers = version.NewVersion(version.License_MIT, "Package", "Description", "2017-10-21T00:00:00+0200", "0123456789abcdef", "v0.0-dev", "Author Name", "pfx", EmptyStruct{}, 1)

// to create new status, you will need some small function to give data, this is type func :
// FctMessagesAll func() (ok string, ko string, cpt string)
// FctMessageItem func() (ok string, ko string)
// FctHealth func() error
// FctInfo func() (name, release, build string)
// FctVersion func() version.Version

// create new status not as later
sts := status.NewVersionStatus(getVersion, getMessageAll, GetHealth, GetHeader, false)
// add a new component
sts.AddComponent(infoAws, getMessageItem, GetAWSHealth, true, false)
// add a new component
sts.AddComponent(infoLDAP, getMessageItem, GetLDAPHealth, true, false)

sts := status.NewVersion(vers, msgOk, msgKO, msgWarn)

// add some middleware before router
sts.MiddlewareAdd(func(context *gin.Context) {
// add here your middleware need to be run before the status route
})

// register to the router list
sts.Register("/status", routers.RouterList.Register)


// register to the router list with a group
sts.Register("/v1", "/status", routers.RouterList.Register)

// add a new component mandatory
sts.ComponentNew(
"myComponentMandatory",
NewComponent(true, infoMandatory, healthMandatory,
func() (msgOk string, msgKo string) {
return msgOk, msgKO
},
24 * time.Hour, 5 * time.second,
),
)

// add a new component mandatory
sts.ComponentNew(
"myComponentNotMandatory",
NewComponent(true, infoNotMandatory, healthNotMandatory,
func() (msgOk string, msgKo string) {
return msgOk, msgKO
},
24 * time.Hour, 5 * time.second,
),
)

// use this func to customize return code for each status
sts.SetErrorCode(http.StatusOK, http.StatusInternalServerError, http.StatusAccepted)
}
Expand All @@ -78,26 +102,22 @@ func GetLDAPHealth() error {
return nil
}

func infoAws() (name, release, build string) {
return "AWS S3 Helper", "v0.1.2.3.4", ""
func infoMandatory() (name, release, build string) {
return "Name of my component mandatory", "v0.1.2.3.4", "abcd1234abcd1234"
}

func infoLDAP() (name, release, build string) {
return "OpenLDAP Lib", "v0.1.2.3.4", ""
func healthMandatory() error {
return nil
}

func getVersion() version.Version {
return vers
func infoNotMandatory() (name, release, build string) {
return "Name of my component not mandatory", "v0.1.2.3.4", "abcd1234abcd1234"
}

func getMessageItem() (ok string, ko string) {
return "all is ok", "there is a mistake somewhere"
func healthNotMandatory() error {
return nil
}

func getMessageAll() (ok string, ko string, cptErr string) {
ok, ko = getMessageItem()
return ok, ko, "at least one component is in failed"
}
```

In some case, using init function could make mistake (specially if you need to read flag or config file).
Expand Down
66 changes: 66 additions & 0 deletions status/component.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* MIT License
*
* Copyright (c) 2021 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/

package status

import (
"time"

"github.com/gin-gonic/gin"
)

type CptResponse struct {
InfoResponse
StatusResponse
}

type Component interface {
Get(x *gin.Context) CptResponse
Clean()
}

func NewComponent(mandatory bool, info FctInfo, health FctHealth, msg FctMessage, infoCacheDuration, statusCacheDuration time.Duration) Component {
return &cpt{
i: NewInfo(info, mandatory, infoCacheDuration),
s: NewStatus(health, msg, statusCacheDuration),
}
}

type cpt struct {
i Info
s Status
}

func (c *cpt) Get(x *gin.Context) CptResponse {
return CptResponse{
InfoResponse: c.i.Get(x),
StatusResponse: c.s.Get(x),
}
}

func (c *cpt) Clean() {
c.i.Clean()
c.s.Clean()
}
124 changes: 124 additions & 0 deletions status/health.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*
* MIT License
*
* Copyright (c) 2021 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/

package status

import (
"time"

"github.com/gin-gonic/gin"
liblog "github.com/nabbar/golib/logger"
)

type FctHealth func() error
type FctMessage func() (msgOk string, msgKO string)

type StatusResponse struct {
Status string `json:"status"`
Message string `json:"message"`
}

func (s *StatusResponse) Clone() StatusResponse {
return StatusResponse{
Status: s.Status,
Message: s.Message,
}
}

type Status interface {
Get(x *gin.Context) StatusResponse
Clean()
IsValid() bool
}

func NewStatus(health FctHealth, msg FctMessage, cacheDuration time.Duration) Status {
return &status{
fh: health,
fm: msg,
c: nil,
t: time.Time{},
d: cacheDuration,
}
}

type status struct {
fh FctHealth
fm FctMessage

c *StatusResponse
t time.Time
d time.Duration
}

func (s *status) Get(x *gin.Context) StatusResponse {
if !s.IsValid() {
var (
err error
msgOk string
msgKO string
)

if s.fm != nil {
msgOk, msgKO = s.fm()
}

if s.fh != nil {
err = s.fh()
}

c := &StatusResponse{}

if err != nil {
c.Status = statusKO
c.Message = msgKO
liblog.ErrorLevel.LogGinErrorCtx(liblog.DebugLevel, "get health status", err, x)
} else {
c.Status = statusOK
c.Message = msgOk
}

s.c = c
s.t = time.Now()
}

return s.c.Clone()
}

func (s *status) Clean() {
s.c = nil
s.t = time.Now()
}

func (s *status) IsValid() bool {
if s.c == nil {
return false
} else if s.t.IsZero() {
return false
} else if time.Since(s.t) > s.d {
return false
}

return true
}
Loading

0 comments on commit a7348db

Please sign in to comment.