Config Component :

- Change reloading component method : try to reload all component and store errors, report list of errors but don't break the reloading process

Package Logger :
- Fix bug with entry logger filtering

Package Viper:
- reword message log before reloading config file (watchFS)
- add message log after reloading config file (watchFS)

Package Status :
- Fix DATA Race with status/info
- Add component key into log error message for health
- Add component key into function to use it into info (name)
- Reword health message : no OK/KO (still into status info), add error message reporting

Package httpserver :
- status info : apply update status component, use key in name
- status info : optimize code

Package Request :
- Fix error in url path operation
- Status info : optimize code
- Status info : apply update component, add endpoint hostname with name

Package Static :
- apply status component update

Other :
- Bump dependencies
This commit is contained in:
nabbar
2022-11-17 16:54:51 +01:00
parent eb8097fad8
commit 52f0d6fa04
13 changed files with 131 additions and 74 deletions

View File

@@ -269,7 +269,8 @@ func (c *componentList) ComponentIsStarted() bool {
func (c *componentList) reloadOne(isReload []string, key string, getCfg FuncComponentConfigGet) ([]string, liberr.Error) { func (c *componentList) reloadOne(isReload []string, key string, getCfg FuncComponentConfigGet) ([]string, liberr.Error) {
var ( var (
err liberr.Error err = ErrorComponentReload.Error(nil)
e liberr.Error
cpt Component cpt Component
) )
@@ -283,37 +284,48 @@ func (c *componentList) reloadOne(isReload []string, key string, getCfg FuncComp
if dep := cpt.Dependencies(); len(dep) > 0 { if dep := cpt.Dependencies(); len(dep) > 0 {
for _, k := range dep { for _, k := range dep {
if isReload, err = c.reloadOne(isReload, k, getCfg); err != nil { if isReload, e = c.reloadOne(isReload, k, getCfg); e != nil {
return isReload, err err.AddParentError(e)
} }
} }
} }
if err = cpt.Reload(getCfg); err != nil { if e = cpt.Reload(getCfg); e != nil {
return isReload, err er := ErrorComponentReload.ErrorParent(fmt.Errorf("component: %s", key))
er.AddParentError(e)
err.AddParentError(er)
} else { } else {
c.ComponentSet(key, cpt) c.ComponentSet(key, cpt)
isReload = append(isReload, key) isReload = append(isReload, key)
} }
return isReload, nil if !err.HasParent() {
err = nil
}
return isReload, err
} }
func (c *componentList) ComponentReload(getCfg FuncComponentConfigGet) liberr.Error { func (c *componentList) ComponentReload(getCfg FuncComponentConfigGet) liberr.Error {
var ( var (
err liberr.Error err = ErrorComponentReload.Error(nil)
e liberr.Error
key string key string
isReload = make([]string, 0) isReload = make([]string, 0)
) )
for _, key = range c.ComponentKeys() { for _, key = range c.ComponentKeys() {
if isReload, err = c.reloadOne(isReload, key, getCfg); err != nil { if isReload, e = c.reloadOne(isReload, key, getCfg); e != nil {
return err err.AddParent(e)
} }
} }
return nil if !err.HasParent() {
err = nil
}
return err
} }
func (c *componentList) ComponentStop() { func (c *componentList) ComponentStop() {

16
go.mod
View File

@@ -4,10 +4,10 @@ go 1.19
require ( require (
github.com/aws/aws-sdk-go-v2 v1.17.1 github.com/aws/aws-sdk-go-v2 v1.17.1
github.com/aws/aws-sdk-go-v2/config v1.18.0 github.com/aws/aws-sdk-go-v2/config v1.18.1
github.com/aws/aws-sdk-go-v2/credentials v1.13.0 github.com/aws/aws-sdk-go-v2/credentials v1.13.1
github.com/aws/aws-sdk-go-v2/service/iam v1.18.23 github.com/aws/aws-sdk-go-v2/service/iam v1.18.23
github.com/aws/aws-sdk-go-v2/service/s3 v1.29.2 github.com/aws/aws-sdk-go-v2/service/s3 v1.29.3
github.com/bits-and-blooms/bitset v1.3.3 github.com/bits-and-blooms/bitset v1.3.3
github.com/c-bata/go-prompt v0.2.6 github.com/c-bata/go-prompt v0.2.6
github.com/fatih/color v1.13.0 github.com/fatih/color v1.13.0
@@ -63,6 +63,7 @@ require (
github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e // indirect github.com/Azure/go-ntlmssp v0.0.0-20220621081337-cb9428e4ac1e // indirect
github.com/ClickHouse/ch-go v0.49.0 // indirect github.com/ClickHouse/ch-go v0.49.0 // indirect
github.com/ClickHouse/clickhouse-go/v2 v2.3.0 // indirect github.com/ClickHouse/clickhouse-go/v2 v2.3.0 // indirect
github.com/DataDog/zstd v1.5.2 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver v1.5.0 // indirect github.com/Masterminds/semver v1.5.0 // indirect
github.com/Masterminds/sprig v2.22.0+incompatible // indirect github.com/Masterminds/sprig v2.22.0+incompatible // indirect
@@ -72,6 +73,7 @@ require (
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
github.com/andybalholm/brotli v1.0.4 // indirect github.com/andybalholm/brotli v1.0.4 // indirect
github.com/andybalholm/cascadia v1.3.1 // indirect github.com/andybalholm/cascadia v1.3.1 // indirect
github.com/aokoli/goutils v1.1.1 // indirect
github.com/armon/go-metrics v0.4.1 // indirect github.com/armon/go-metrics v0.4.1 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.9 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.9 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.19 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.19 // indirect
@@ -85,7 +87,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.19 // indirect github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.19 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.11.25 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.11.25 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.13.8 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.17.2 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.17.3 // indirect
github.com/aws/smithy-go v1.13.4 // indirect github.com/aws/smithy-go v1.13.4 // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/bwmarrin/snowflake v0.3.0 // indirect github.com/bwmarrin/snowflake v0.3.0 // indirect
@@ -163,13 +165,13 @@ require (
github.com/nats-io/nuid v1.0.1 // indirect github.com/nats-io/nuid v1.0.1 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/paulmach/orb v0.7.1 // indirect github.com/paulmach/orb v0.7.1 // indirect
github.com/pelletier/go-toml/v2 v2.0.5 // indirect github.com/pelletier/go-toml/v2 v2.0.6 // indirect
github.com/pierrec/lz4/v4 v4.1.17 // indirect github.com/pierrec/lz4/v4 v4.1.17 // indirect
github.com/pkg/term v1.2.0-beta.2 // indirect github.com/pkg/term v1.2.0-beta.2 // indirect
github.com/prometheus/client_model v0.3.0 // indirect github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.37.0 // indirect github.com/prometheus/common v0.37.0 // indirect
github.com/prometheus/procfs v0.8.0 // indirect github.com/prometheus/procfs v0.8.0 // indirect
github.com/rivo/uniseg v0.4.2 // indirect github.com/rivo/uniseg v0.4.3 // indirect
github.com/rogpeppe/go-internal v1.9.0 // indirect github.com/rogpeppe/go-internal v1.9.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect
@@ -190,7 +192,7 @@ require (
github.com/yusufpapurcu/wmi v1.2.2 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect
go.opentelemetry.io/otel v1.11.1 // indirect go.opentelemetry.io/otel v1.11.1 // indirect
go.opentelemetry.io/otel/trace v1.11.1 // indirect go.opentelemetry.io/otel/trace v1.11.1 // indirect
golang.org/x/crypto v0.2.0 // indirect golang.org/x/crypto v0.3.0 // indirect
golang.org/x/mod v0.7.0 // indirect golang.org/x/mod v0.7.0 // indirect
golang.org/x/text v0.4.0 // indirect golang.org/x/text v0.4.0 // indirect
golang.org/x/time v0.2.0 // indirect golang.org/x/time v0.2.0 // indirect

View File

@@ -467,6 +467,7 @@ func (p pool) StatusHealth(bindAddress string) error {
func (p pool) StatusRoute(keyPrefix string, sts libsts.RouteStatus) { func (p pool) StatusRoute(keyPrefix string, sts libsts.RouteStatus) {
p.MapRun(func(srv Server) { p.MapRun(func(srv Server) {
bind := srv.GetBindable() bind := srv.GetBindable()
sts.ComponentNew(fmt.Sprintf("%s-%s", keyPrefix, bind), srv.StatusComponent()) name := fmt.Sprintf("%s-%s", keyPrefix, bind)
sts.ComponentNew(name, srv.StatusComponent(name))
}) })
} }

View File

@@ -74,7 +74,7 @@ type Server interface {
StatusInfo() (name string, release string, hash string) StatusInfo() (name string, release string, hash string)
StatusHealth() error StatusHealth() error
StatusComponent() libsts.Component StatusComponent(key string) libsts.Component
} }
func NewServer(cfg *ServerConfig) Server { func NewServer(cfg *ServerConfig) Server {
@@ -238,7 +238,7 @@ func (s *server) StatusInfo() (name string, release string, hash string) {
vers = strings.TrimLeft(vers, "Go") vers = strings.TrimLeft(vers, "Go")
vers = strings.TrimLeft(vers, "GO") vers = strings.TrimLeft(vers, "GO")
return fmt.Sprintf("%s [%s]", s.GetName(), s.GetBindable()), vers, "" return fmt.Sprintf("%s [%s]", s.GetName(), s.GetBindable()), runtime.Version()[2:], ""
} }
func (s *server) StatusHealth() error { func (s *server) StatusHealth() error {
@@ -253,7 +253,7 @@ func (s *server) StatusHealth() error {
} }
} }
func (s *server) StatusComponent() libsts.Component { func (s *server) StatusComponent(key string) libsts.Component {
if cfg := s.GetConfig(); cfg == nil { if cfg := s.GetConfig(); cfg == nil {
cnf := config.ConfigStatus{ cnf := config.ConfigStatus{
Mandatory: true, Mandatory: true,
@@ -262,8 +262,8 @@ func (s *server) StatusComponent() libsts.Component {
CacheTimeoutInfo: 30 * time.Second, CacheTimeoutInfo: 30 * time.Second,
CacheTimeoutHealth: 5 * time.Second, CacheTimeoutHealth: 5 * time.Second,
} }
return cnf.Component(s.StatusInfo, s.StatusHealth) return cnf.Component(key, s.StatusInfo, s.StatusHealth)
} else { } else {
return cfg.Status.Component(s.StatusInfo, s.StatusHealth) return cfg.Status.Component(key, s.StatusInfo, s.StatusHealth)
} }
} }

View File

@@ -182,11 +182,11 @@ func (o *_HookFile) Fire(entry *logrus.Entry) error {
ent := entry.Dup() ent := entry.Dup()
ent.Level = entry.Level ent.Level = entry.Level
if !o.isStack() { if o.isStack() {
ent.Data = o.filterKey(ent.Data, FieldStack) ent.Data = o.filterKey(ent.Data, FieldStack)
} }
if !o.isTimeStamp() { if o.isTimeStamp() {
ent.Data = o.filterKey(ent.Data, FieldTime) ent.Data = o.filterKey(ent.Data, FieldTime)
} }

View File

@@ -163,11 +163,11 @@ func (o *_HookSyslog) Fire(entry *logrus.Entry) error {
ent := entry.Dup() ent := entry.Dup()
ent.Level = entry.Level ent.Level = entry.Level
if !o.isStack() { if o.isStack() {
ent.Data = o.filterKey(ent.Data, FieldStack) ent.Data = o.filterKey(ent.Data, FieldStack)
} }
if !o.isTimeStamp() { if o.isTimeStamp() {
ent.Data = o.filterKey(ent.Data, FieldTime) ent.Data = o.filterKey(ent.Data, FieldTime)
} }

View File

@@ -35,7 +35,6 @@ import (
"io" "io"
"net/http" "net/http"
"net/url" "net/url"
"os"
"path" "path"
"runtime" "runtime"
"strings" "strings"
@@ -85,11 +84,11 @@ func (r *request) _StatusInfo() (name string, release string, build string) {
} }
if release == "" { if release == "" {
release = strings.TrimLeft(runtime.Version(), "go") release = runtime.Version()[2:]
release = strings.TrimLeft(release, "Go")
release = strings.TrimLeft(release, "GO")
} }
name = fmt.Sprintf("[%s] %s", edp, name)
return name, release, build return name, release, build
} }
@@ -448,9 +447,9 @@ func (r *request) AddPath(raw bool, pathPart ...string) {
var str string var str string
if raw { if raw {
str = strings.Replace(r.u.RawPath, "/", string(os.PathSeparator), -1) str = path.Clean(r.u.RawPath)
} else { } else {
str = strings.Replace(r.u.Path, "/", string(os.PathSeparator), -1) str = path.Clean(r.u.Path)
} }
for i := range pathPart { for i := range pathPart {

View File

@@ -669,7 +669,7 @@ func (s *staticHandler) _statusHealthPath(pathFile string) error {
return nil return nil
} }
func (s *staticHandler) _statusComponentPath(pathFile string, mandatory bool, message libsts.FctMessage, infoCacheTimeout, healthCacheTimeout time.Duration) libsts.Component { func (s *staticHandler) _statusComponentPath(key string, pathFile string, mandatory bool, message libsts.FctMessage, infoCacheTimeout, healthCacheTimeout time.Duration) libsts.Component {
fctSts := func() (name string, release string, hash string) { fctSts := func() (name string, release string, hash string) {
return s._statusInfoPath(pathFile) return s._statusInfoPath(pathFile)
} }
@@ -678,13 +678,13 @@ func (s *staticHandler) _statusComponentPath(pathFile string, mandatory bool, me
return s._statusHealthPath(pathFile) return s._statusHealthPath(pathFile)
} }
return libsts.NewComponent(mandatory, fctSts, fctHlt, message, infoCacheTimeout, healthCacheTimeout) return libsts.NewComponent(key, mandatory, fctSts, fctHlt, message, infoCacheTimeout, healthCacheTimeout)
} }
func (s *staticHandler) StatusComponent(mandatory bool, message libsts.FctMessage, infoCacheTimeout, healthCacheTimeout time.Duration, sts libsts.RouteStatus) { func (s *staticHandler) StatusComponent(mandatory bool, message libsts.FctMessage, infoCacheTimeout, healthCacheTimeout time.Duration, sts libsts.RouteStatus) {
for _, p := range s._getBase() { for _, p := range s._getBase() {
name := fmt.Sprintf("%s-%s", strings.ReplaceAll(textEmbed, " ", "."), p) name := fmt.Sprintf("%s-%s", strings.ReplaceAll(textEmbed, " ", "."), p)
sts.ComponentNew(name, s._statusComponentPath(p, mandatory, message, infoCacheTimeout, healthCacheTimeout)) sts.ComponentNew(name, s._statusComponentPath(name, p, mandatory, message, infoCacheTimeout, healthCacheTimeout))
} }
} }

View File

@@ -41,10 +41,10 @@ type Component interface {
Clean() Clean()
} }
func NewComponent(mandatory bool, info FctInfo, health FctHealth, msg FctMessage, infoCacheDuration, statusCacheDuration time.Duration) Component { func NewComponent(key string, mandatory bool, info FctInfo, health FctHealth, msg FctMessage, infoCacheDuration, statusCacheDuration time.Duration) Component {
return &cpt{ return &cpt{
i: NewInfo(info, mandatory, infoCacheDuration), i: NewInfo(info, mandatory, infoCacheDuration),
s: NewStatus(health, msg, statusCacheDuration), s: NewStatus(key, health, msg, statusCacheDuration),
} }
} }

View File

@@ -111,9 +111,9 @@ func (c *ConfigStatus) fctMessage() (msgOk string, msgKO string) {
} }
func (c *ConfigStatus) RegisterStatus(sts libsts.RouteStatus, key string, fctInfo libsts.FctInfo, fctHealth libsts.FctHealth) { func (c *ConfigStatus) RegisterStatus(sts libsts.RouteStatus, key string, fctInfo libsts.FctInfo, fctHealth libsts.FctHealth) {
sts.ComponentNew(key, status.NewComponent(c.Mandatory, fctInfo, fctHealth, c.fctMessage, c.CacheTimeoutInfo, c.CacheTimeoutHealth)) sts.ComponentNew(key, status.NewComponent(key, c.Mandatory, fctInfo, fctHealth, c.fctMessage, c.CacheTimeoutInfo, c.CacheTimeoutHealth))
} }
func (c *ConfigStatus) Component(fctInfo libsts.FctInfo, fctHealth libsts.FctHealth) libsts.Component { func (c *ConfigStatus) Component(key string, fctInfo libsts.FctInfo, fctHealth libsts.FctHealth) libsts.Component {
return status.NewComponent(c.Mandatory, fctInfo, fctHealth, c.fctMessage, c.CacheTimeoutInfo, c.CacheTimeoutHealth) return status.NewComponent(key, c.Mandatory, fctInfo, fctHealth, c.fctMessage, c.CacheTimeoutInfo, c.CacheTimeoutHealth)
} }

View File

@@ -26,11 +26,14 @@
package status package status
import ( import (
"fmt"
"sync" "sync"
"time" "time"
"github.com/gin-gonic/gin" liberr "github.com/nabbar/golib/errors"
liblog "github.com/nabbar/golib/logger" liblog "github.com/nabbar/golib/logger"
"github.com/gin-gonic/gin"
) )
type FctHealth func() error type FctHealth func() error
@@ -54,11 +57,12 @@ type Status interface {
IsValid() bool IsValid() bool
} }
func NewStatus(health FctHealth, msg FctMessage, cacheDuration time.Duration) Status { func NewStatus(key string, health FctHealth, msg FctMessage, cacheDuration time.Duration) Status {
return &status{ return &status{
m: sync.Mutex{}, m: sync.Mutex{},
fh: health, fh: health,
fm: msg, fm: msg,
k: key,
c: nil, c: nil,
t: time.Time{}, t: time.Time{},
d: cacheDuration, d: cacheDuration,
@@ -70,6 +74,7 @@ type status struct {
fh FctHealth fh FctHealth
fm FctMessage fm FctMessage
k string
c *StatusResponse c *StatusResponse
t time.Time t time.Time
d time.Duration d time.Duration
@@ -112,26 +117,34 @@ func (s *status) getCache() StatusResponse {
return s.c.Clone() return s.c.Clone()
} }
func (s *status) getKey() string {
s.m.Lock()
defer s.m.Unlock()
return s.k
}
func (s *status) Get(x *gin.Context) StatusResponse { func (s *status) Get(x *gin.Context) StatusResponse {
if !s.IsValid() { if !s.IsValid() {
var ( var err error
err error
msgOk string
msgKO string
)
msgOk, msgKO = s.getInfo()
err = s.getHealth() err = s.getHealth()
c := &StatusResponse{} c := &StatusResponse{}
if err != nil { if err != nil {
c.Status = DefMessageKO c.Status = DefMessageKO
c.Message = msgKO
liblog.ErrorLevel.LogErrorCtx(liblog.DebugLevel, "get health status", err) if e, ok := err.(liberr.Error); ok {
c.Message = fmt.Sprintf("%v", e.GetError())
liblog.ErrorLevel.LogErrorCtxf(liblog.DebugLevel, "[%s] get health status", e.GetErrorFull(", "), s.getKey())
} else {
c.Message = fmt.Sprintf("%v", err)
liblog.ErrorLevel.LogErrorCtxf(liblog.DebugLevel, "[%s] get health status", err, s.getKey())
}
} else { } else {
c.Status = DefMessageOK c.Status = DefMessageOK
c.Message = msgOk c.Message = ""
} }
s.setCache(c) s.setCache(c)

View File

@@ -26,6 +26,7 @@
package status package status
import ( import (
"sync"
"time" "time"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@@ -58,7 +59,7 @@ type Info interface {
func NewInfo(fct FctInfo, mandatory bool, cacheDuration time.Duration) Info { func NewInfo(fct FctInfo, mandatory bool, cacheDuration time.Duration) Info {
return &info{ return &info{
f: fct, f: fct,
m: mandatory, o: mandatory,
c: nil, c: nil,
t: time.Time{}, t: time.Time{},
d: cacheDuration, d: cacheDuration,
@@ -66,8 +67,9 @@ func NewInfo(fct FctInfo, mandatory bool, cacheDuration time.Duration) Info {
} }
type info struct { type info struct {
m sync.Mutex
f FctInfo f FctInfo
m bool o bool
c *InfoResponse c *InfoResponse
t time.Time t time.Time
d time.Duration d time.Duration
@@ -75,34 +77,24 @@ type info struct {
func (i *info) Get(x *gin.Context) InfoResponse { func (i *info) Get(x *gin.Context) InfoResponse {
if !i.IsValid() { if !i.IsValid() {
var ( i.regenCache()
name string
vers string
hash string
)
if i.f != nil {
name, vers, hash = i.f()
} }
i.c = &InfoResponse{ return i.clone()
Name: name,
Release: vers,
HashBuild: hash,
Mandatory: i.m,
}
i.t = time.Now()
}
return i.c.Clone()
} }
func (i *info) Clean() { func (i *info) Clean() {
i.m.Lock()
defer i.m.Unlock()
i.c = nil i.c = nil
i.t = time.Now() i.t = time.Now()
} }
func (i *info) IsValid() bool { func (i *info) IsValid() bool {
i.m.Lock()
defer i.m.Unlock()
if i.c == nil { if i.c == nil {
return false return false
} else if i.t.IsZero() { } else if i.t.IsZero() {
@@ -112,3 +104,40 @@ func (i *info) IsValid() bool {
} }
return true return true
} }
func (i *info) regenCache() {
var (
name string
vers string
hash string
)
i.m.Lock()
defer i.m.Unlock()
if i.f != nil {
name, vers, hash = i.f()
}
i.c = &InfoResponse{
Name: name,
Release: vers,
HashBuild: hash,
Mandatory: i.o,
}
i.t = time.Now()
}
func (i *info) clone() InfoResponse {
i.m.Lock()
defer i.m.Unlock()
if i.c != nil {
return i.c.Clone()
}
return InfoResponse{
Mandatory: i.o,
}
}

View File

@@ -67,8 +67,9 @@ func (v *viper) WatchFS(logLevelFSInfo liblog.Level) {
v.v.WatchConfig() v.v.WatchConfig()
v.v.OnConfigChange(func(e libnot.Event) { v.v.OnConfigChange(func(e libnot.Event) {
if v.remote.fct != nil { if v.remote.fct != nil {
logLevelFSInfo.Logf("reloaded config file '%s'...", e.Name) logLevelFSInfo.Logf("Reloading local config file '%s'...", e.Name)
v.remote.fct() v.remote.fct()
logLevelFSInfo.Logf("local config file '%s' has been reloaded.", e.Name)
} }
}) })
} }