PKG Logger :

- fix issue #109
- fix issue #106
- fix bug with color linux / win
- fix bug with color between std, file and syslog
- fix using default logger instead of setup logger
- fix logrus logger level
- add debug message to test logger (test-httpserver)

PKG httpserver :
- apply logger's changes
- optimize httpserver shutdown process

PKG httpcli :
- add new params for log error / log check

PKG ldap :
- add new params for log error / log check
This commit is contained in:
Nicolas JUHEL
2021-06-07 15:26:48 +02:00
parent 00a825bea5
commit f015ad5283
12 changed files with 212 additions and 129 deletions

View File

@@ -62,7 +62,7 @@ type PoolServer interface {
Del(bindAddress string) PoolServer
Has(bindAddress string) bool
Len() int
SetLogger(log FuncGetLogger)
SetLogger(log liblog.FuncLog)
MapRun(f MapRunPoolServer)
MapUpd(f MapUpdPoolServer)
@@ -191,7 +191,7 @@ func (p pool) Len() int {
return len(p)
}
func (p pool) SetLogger(log FuncGetLogger) {
func (p pool) SetLogger(log liblog.FuncLog) {
p.MapUpd(func(srv Server) Server {
srv.SetLogger(log)
return srv

View File

@@ -48,13 +48,15 @@ import (
const _TimeoutWaitingPortFreeing = 500 * time.Microsecond
type srvRun struct {
log func() liblog.Logger
err *atomic.Value
run *atomic.Value
snm string
srv *http.Server
ctx context.Context
cnl context.CancelFunc
log liblog.FuncLog // return golib logger interface
err *atomic.Value // last err occured
run *atomic.Value // is running
snm string // server name
bnd string // server bind
tls bool // is tls server or tls mandatory
srv *http.Server // golang http server
ctx context.Context // context
cnl context.CancelFunc // cancel func of context
}
type run interface {
@@ -66,7 +68,7 @@ type run interface {
Shutdown()
}
func newRun(log FuncGetLogger) run {
func newRun(log liblog.FuncLog) run {
return &srvRun{
log: log,
err: new(atomic.Value),
@@ -138,7 +140,11 @@ func (s *srvRun) WaitNotify() {
case <-quit:
s.Shutdown()
case <-s.ctx.Done():
if s.IsRunning() {
s.Shutdown()
} else if s.srv != nil {
s.srvShutdown()
}
}
}
@@ -146,6 +152,21 @@ func (s *srvRun) Merge(srv Server) bool {
panic("implement me")
}
func (s *srvRun) getLogger() liblog.Logger {
var _log liblog.Logger
if s.log == nil {
_log = liblog.GetDefault()
} else if l := s.log(); l == nil {
_log = liblog.GetDefault()
} else {
_log = l
}
_log.SetFields(_log.GetFields().Add("server_name", s.snm).Add("server_bind", s.bnd).Add("server_tls", s.tls))
return _log
}
//nolint #gocognit
func (s *srvRun) Listen(cfg *ServerConfig, handler http.Handler) liberr.Error {
ssl, err := cfg.GetTLS()
@@ -160,21 +181,13 @@ func (s *srvRun) Listen(cfg *ServerConfig, handler http.Handler) liberr.Error {
name = bind
}
var _log liblog.Logger
if s.log == nil {
_log = liblog.GetDefault()
} else if l := s.log(); l == nil {
_log = liblog.GetDefault()
} else {
_log = l
}
_log.SetFields(_log.GetFields().Add("http server '%s'", name))
s.snm = name
s.bnd = bind
s.tls = sTls || ssl.LenCertificatePair() > 0
srv := &http.Server{
Addr: cfg.GetListen().Host,
ErrorLog: _log.GetStdLogger(liblog.ErrorLevel, log.LstdFlags|log.Lmicroseconds),
ErrorLog: s.getLogger().GetStdLogger(liblog.ErrorLevel, log.LstdFlags|log.Lmicroseconds),
}
if cfg.ReadTimeout > 0 {
@@ -257,12 +270,14 @@ func (s *srvRun) Listen(cfg *ServerConfig, handler http.Handler) liberr.Error {
}
s.ctx, s.cnl = context.WithCancel(cfg.getContext())
s.snm = name
s.srv = srv
go func(name, host string, tlsMandatory bool) {
var _log = s.getLogger()
ent := _log.Entry(liblog.InfoLevel, "server stopped")
defer func() {
ent.Log()
if s.ctx != nil && s.cnl != nil && s.ctx.Err() == nil {
s.cnl()
}
@@ -274,18 +289,15 @@ func (s *srvRun) Listen(cfg *ServerConfig, handler http.Handler) liberr.Error {
}
var err error
_log.Entry(liblog.InfoLevel, "Server is starting").Log()
if ssl.LenCertificatePair() > 0 {
liblog.InfoLevel.Logf("TLS Server '%s' is starting with bindable: %s", name, host)
s.setRunning(true)
err = s.srv.ListenAndServeTLS("", "")
} else if tlsMandatory {
//nolint #goerr113
err = fmt.Errorf("missing valid server certificates")
} else {
liblog.InfoLevel.Logf("Server '%s' is starting with bindable: %s", name, host)
s.setRunning(true)
err = s.srv.ListenAndServe()
}
@@ -296,7 +308,8 @@ func (s *srvRun) Listen(cfg *ServerConfig, handler http.Handler) liberr.Error {
return
} else if err != nil {
s.setErr(err)
liblog.ErrorLevel.LogErrorCtxf(liblog.NilLevel, "Listen Server '%s'", err, name)
ent.Level = liblog.ErrorLevel
ent.ErrorAdd(true, err)
}
}(name, bind, sTls)
@@ -308,28 +321,31 @@ func (s *srvRun) Restart(cfg *ServerConfig) {
}
func (s *srvRun) Shutdown() {
ctx, cancel := context.WithTimeout(context.Background(), timeoutShutdown)
defer func() {
cancel()
if s.srv != nil {
_ = s.srv.Close()
}
s.srvShutdown()
s.setRunning(false)
}()
liblog.InfoLevel.Logf("Shutdown Server '%s'...", s.snm)
if s.cnl != nil && s.ctx != nil && s.ctx.Err() == nil {
s.cnl()
}
}
func (s *srvRun) srvShutdown() {
ctx, cancel := context.WithTimeout(context.Background(), timeoutShutdown)
_log := s.getLogger()
defer func() {
cancel()
if s.srv != nil {
err := s.srv.Close()
s.srv = nil
_log.Entry(liblog.ErrorLevel, "closing server").ErrorAdd(true, err).Check(liblog.InfoLevel)
}
}()
if s.srv != nil {
err := s.srv.Shutdown(ctx)
if err != nil && !errors.Is(err, http.ErrServerClosed) {
liblog.ErrorLevel.Logf("Shutdown Server '%s' Error: %v", s.snm, err)
_log.Entry(liblog.ErrorLevel, "Shutdown server").ErrorAdd(true, err).Check(liblog.InfoLevel)
}
}
}

View File

@@ -44,8 +44,6 @@ const (
timeoutShutdown = 10 * time.Second
)
type FuncGetLogger func() liblog.Logger
type server struct {
log *atomic.Value
run *atomic.Value
@@ -53,7 +51,7 @@ type server struct {
}
type Server interface {
SetLogger(log FuncGetLogger)
SetLogger(log liblog.FuncLog)
GetConfig() *ServerConfig
SetConfig(cfg *ServerConfig) bool
@@ -88,14 +86,14 @@ func NewServer(cfg *ServerConfig) Server {
}
}
func (s *server) SetLogger(log FuncGetLogger) {
func (s *server) SetLogger(log liblog.FuncLog) {
s.log.Store(log)
}
func (s *server) GetLogger() FuncGetLogger {
func (s *server) GetLogger() liblog.FuncLog {
if i := s.log.Load(); i == nil {
return nil
} else if f, ok := i.(FuncGetLogger); ok {
} else if f, ok := i.(liblog.FuncLog); ok {
return f
}
@@ -201,6 +199,8 @@ func (s *server) Listen(handler http.Handler) liberr.Error {
e := r.Listen(s.GetConfig(), handler)
s.setRun(r)
runtime.GC()
return e
}

View File

@@ -38,7 +38,7 @@ import (
var defaultLogger Logger
func init() {
defaultLogger = New()
defaultLogger = New(context.Background())
defaultLogger.SetLevel(InfoLevel)
}
@@ -66,7 +66,7 @@ func SetLevel(level Level) {
func AddGID(enable bool) {
opt := defaultLogger.GetOptions()
opt.DisableStack = !enable
_ = defaultLogger.SetOptions(context.TODO(), opt)
_ = defaultLogger.SetOptions(opt)
}
// Timestamp Reconfigure the current logger to add or not the timestamp before each message.
@@ -74,7 +74,7 @@ func AddGID(enable bool) {
func Timestamp(enable bool) {
opt := defaultLogger.GetOptions()
opt.DisableTimestamp = !enable
_ = defaultLogger.SetOptions(context.TODO(), opt)
_ = defaultLogger.SetOptions(opt)
}
// IsTimeStamp will return true if timestamp is added or not on log message
@@ -89,7 +89,7 @@ func IsTimeStamp() bool {
func FileTrace(enable bool) {
opt := defaultLogger.GetOptions()
opt.EnableTrace = enable
_ = defaultLogger.SetOptions(context.TODO(), opt)
_ = defaultLogger.SetOptions(opt)
}
// IsFileTrace will return true if trace is added or not on log message
@@ -104,7 +104,7 @@ func IsFileTrace() bool {
func ModeColor(enable bool) {
opt := defaultLogger.GetOptions()
opt.DisableColor = !enable
_ = defaultLogger.SetOptions(context.TODO(), opt)
_ = defaultLogger.SetOptions(opt)
}
// IsModeColor will return true if color is configured on log message
@@ -138,7 +138,7 @@ func EnableViperLog(enable bool) {
func SetTracePathFilter(path string) {
opt := defaultLogger.GetOptions()
opt.TraceFilter = path
_ = defaultLogger.SetOptions(context.TODO(), opt)
_ = defaultLogger.SetOptions(opt)
}
// Log Simple function to log directly the given message with the attached log Level.

View File

@@ -57,7 +57,7 @@ type Logger interface {
GetIOWriterLevel() Level
//SetOptions allow to set or update the options for the logger
SetOptions(ctx context.Context, opt *Options) error
SetOptions(opt *Options) error
//GetOptions return the options for the logger
GetOptions() *Options
@@ -71,7 +71,7 @@ type Logger interface {
GetFields() Fields
//Clone allow to duplicate the logger with a copy of the logger
Clone(ctx context.Context) (Logger, error)
Clone() (Logger, error)
//SetSPF13Level allow to plus spf13 logger (jww) to this logger
SetSPF13Level(lvl Level, log *jww.Notepad)
@@ -111,7 +111,7 @@ type Logger interface {
//LogDetails add an entry to the logger
LogDetails(lvl Level, message string, data interface{}, err []error, fields Fields, args ...interface{})
//CheckError will check if a not nil error is given add if yes, will add an entry to the logger.
//CheckError will check if a not nil error is given and if yes, will add an entry to the logger.
// Othwise if the lvlOK is given (and not NilLevel) the function will add entry and said ok
CheckError(lvlKO, lvlOK Level, message string, err ...error) bool
@@ -120,11 +120,13 @@ type Logger interface {
}
//New return a new logger interface pointer
func New() Logger {
func New(ctx context.Context) Logger {
lvl := new(atomic.Value)
lvl.Store(InfoLevel)
return &logger{
x: ctx,
n: nil,
m: &sync.Mutex{},
l: lvl,
o: new(atomic.Value),

View File

@@ -34,18 +34,18 @@ import (
var _ = Describe("Logger", func() {
Context("Create New Logger with Default Config", func() {
It("Must succeed", func() {
log := logger.New()
log := logger.New(GetContext())
log.SetLevel(logger.DebugLevel)
err := log.SetOptions(GetContext(), &logger.Options{})
err := log.SetOptions(&logger.Options{})
Expect(err).ToNot(HaveOccurred())
log.LogDetails(logger.InfoLevel, "test logger", nil, nil, nil)
})
})
Context("Create New Logger with Default Config and trace", func() {
It("Must succeed", func() {
log := logger.New()
log := logger.New(GetContext())
log.SetLevel(logger.DebugLevel)
err := log.SetOptions(GetContext(), &logger.Options{
err := log.SetOptions(&logger.Options{
EnableTrace: true,
})
Expect(err).ToNot(HaveOccurred())
@@ -54,9 +54,9 @@ var _ = Describe("Logger", func() {
})
Context("Create New Logger with field", func() {
It("Must succeed", func() {
log := logger.New()
log := logger.New(GetContext())
log.SetLevel(logger.DebugLevel)
err := log.SetOptions(GetContext(), &logger.Options{
err := log.SetOptions(&logger.Options{
EnableTrace: true,
})
log.SetFields(logger.NewFields().Add("test-field", "ok"))
@@ -66,7 +66,7 @@ var _ = Describe("Logger", func() {
})
Context("Create New Logger with file", func() {
It("Must succeed", func() {
log := logger.New()
log := logger.New(GetContext())
log.SetLevel(logger.DebugLevel)
fsp, err := GetTempFile()
@@ -78,7 +78,7 @@ var _ = Describe("Logger", func() {
Expect(err).ToNot(HaveOccurred())
err = log.SetOptions(GetContext(), &logger.Options{
err = log.SetOptions(&logger.Options{
EnableTrace: true,
LogFile: []logger.OptionsFile{
{
@@ -102,7 +102,7 @@ var _ = Describe("Logger", func() {
})
Context("Create New Logger with file in multithread mode", func() {
It("Must succeed", func() {
log := logger.New()
log := logger.New(GetContext())
log.SetLevel(logger.DebugLevel)
fsp, err := GetTempFile()
@@ -114,7 +114,7 @@ var _ = Describe("Logger", func() {
Expect(err).ToNot(HaveOccurred())
err = log.SetOptions(GetContext(), &logger.Options{
err = log.SetOptions(&logger.Options{
EnableTrace: true,
LogFile: []logger.OptionsFile{
{
@@ -136,7 +136,7 @@ var _ = Describe("Logger", func() {
log.LogDetails(logger.InfoLevel, "test logger with field", nil, nil, nil)
var sub logger.Logger
sub, err = log.Clone(GetContext())
sub, err = log.Clone()
Expect(err).ToNot(HaveOccurred())
go func(log logger.Logger) {

View File

@@ -30,19 +30,21 @@ package logger
import "sync/atomic"
func (l *logger) Close() error {
lst := l.closeGet()
for _, c := range l.closeGetMutex() {
l.m.Lock()
defer func() {
l.m.Unlock()
l.closeClean()
l.cancelCall()
}()
for _, c := range lst {
if c != nil {
_ = c.Close()
}
}
if l.n != nil {
l.n()
}
l.closeClean()
return nil
}

View File

@@ -67,7 +67,7 @@ func defaultFormatter() logrus.TextFormatter {
return logrus.TextFormatter{
ForceColors: false,
DisableColors: false,
ForceQuote: false,
ForceQuote: true,
DisableQuote: false,
EnvironmentOverrideColors: false,
DisableTimestamp: true,
@@ -75,7 +75,7 @@ func defaultFormatter() logrus.TextFormatter {
TimestampFormat: time.RFC3339,
DisableSorting: false,
SortingFunc: nil,
DisableLevelTruncation: false,
DisableLevelTruncation: true,
PadLevelText: true,
QuoteEmptyFields: true,
FieldMap: nil,
@@ -109,6 +109,9 @@ func (l *logger) defaultFormatterNoColor() logrus.Formatter {
func (l *logger) closeAdd(clo io.Closer) {
lst := append(l.closeGet(), clo)
l.m.Lock()
defer l.m.Unlock()
if l.c == nil {
l.c = new(atomic.Value)
}
@@ -138,6 +141,9 @@ func (l *logger) closeGet() []io.Closer {
return res
}
l.m.Lock()
defer l.m.Unlock()
if l.c == nil {
l.c = new(atomic.Value)
}
@@ -151,16 +157,9 @@ func (l *logger) closeGet() []io.Closer {
return res
}
func (l *logger) closeGetMutex() []io.Closer {
l.m.Lock()
defer l.m.Unlock()
return l.closeGet()
}
func (l *logger) Clone(ctx context.Context) (Logger, error) {
func (l *logger) Clone() (Logger, error) {
c := &logger{
x: nil,
x: l.contextGet(),
n: nil,
m: &sync.Mutex{},
l: new(atomic.Value),
@@ -171,15 +170,62 @@ func (l *logger) Clone(ctx context.Context) (Logger, error) {
c: new(atomic.Value),
}
c.SetLevel(l.GetLevel())
c.setLoggerMutex(l.GetLevel())
c.SetIOWriterLevel(l.GetIOWriterLevel())
c.SetFields(l.GetFields())
if err := c.SetOptions(ctx, l.GetOptions()); err != nil {
if err := c.SetOptions(l.GetOptions()); err != nil {
return nil, err
}
return c, nil
}
func (l *logger) contextGet() context.Context {
l.m.Lock()
defer l.m.Unlock()
if l.x == nil {
l.x = context.Background()
}
return l.x
}
func (l *logger) contextNew() context.Context {
ctx, cnl := context.WithCancel(l.contextGet())
l.m.Lock()
l.n = cnl
l.m.Unlock()
return ctx
}
func (l *logger) cancelCall() {
l.m.Lock()
defer l.m.Unlock()
if l.n == nil {
return
}
l.n()
l.n = nil
}
func (l *logger) cancelClear() {
l.m.Lock()
if l.n == nil {
l.m.Unlock()
return
}
l.n()
l.m.Unlock()
}
func (l *logger) setLoggerMutex(lvl Level) {
if l == nil {
return
@@ -197,6 +243,7 @@ func (l *logger) setLoggerMutex(lvl Level) {
func (l *logger) SetLevel(lvl Level) {
l.setLoggerMutex(lvl)
l.setLogrusLevel(l.GetLevel())
if opt := l.GetOptions(); opt.change != nil {
opt.change(l)
@@ -260,17 +307,30 @@ func (l *logger) GetFields() Fields {
return NewFields()
}
func (l *logger) setOptionsMutex(ctx context.Context, opt *Options) error {
func (l *logger) setOptionsMutex(opt *Options) error {
l.setOptions(opt)
opt = l.GetOptions()
lvl := l.GetLevel()
_ = l.Close()
l.x, l.n = context.WithCancel(ctx)
l.m.Lock()
defer l.m.Unlock()
go func() {
var ctx = l.contextNew()
defer func() {
l.cancelClear()
}()
select {
case <-ctx.Done():
_ = l.Close()
return
}
}()
obj := logrus.New()
obj.SetLevel(lvl.Logrus())
obj.SetFormatter(l.defaultFormatter(opt))
obj.SetOutput(ioutil.Discard) // Send all logs to nowhere by default
@@ -314,19 +374,11 @@ func (l *logger) setOptionsMutex(ctx context.Context, opt *Options) error {
l.s = new(atomic.Value)
l.s.Store(obj)
go func() {
select {
case <-l.x.Done():
_ = l.Close()
return
}
}()
return nil
}
func (l *logger) SetOptions(ctx context.Context, opt *Options) error {
if err := l.setOptionsMutex(ctx, opt); err != nil {
func (l *logger) SetOptions(opt *Options) error {
if err := l.setOptionsMutex(opt); err != nil {
return err
}
@@ -373,6 +425,21 @@ func (l *logger) setOptions(opt *Options) {
l.o.Store(opt)
}
func (l *logger) setLogrusLevel(lvl Level) {
if _log := l.getLog(); _log != nil {
_log.SetLevel(lvl.Logrus())
l.m.Lock()
defer l.m.Unlock()
if l.s == nil {
return
}
l.s.Store(_log)
}
}
func (l *logger) getLog() *logrus.Logger {
if l == nil {
return nil

View File

@@ -73,16 +73,16 @@ var (
cfgPool libsrv.PoolServerConfig
ctx context.Context
cnl context.CancelFunc
log = liblog.New()
log liblog.Logger
)
func init() {
liberr.SetModeReturnError(liberr.ErrorReturnCodeErrorTraceFull)
ctx, cnl = context.WithCancel(context.Background())
log = liblog.New(ctx)
log.SetLevel(liblog.DebugLevel)
if err := log.SetOptions(ctx, &liblog.Options{
if err := log.SetOptions(&liblog.Options{
DisableStandard: false,
DisableStack: false,
DisableTimestamp: false,
@@ -197,6 +197,6 @@ func headers(w http.ResponseWriter, req *http.Request) {
}
func getLogger() liblog.Logger {
l, _ := log.Clone(ctx)
l, _ := log.Clone()
return l
}

View File

@@ -73,7 +73,7 @@ var (
cfgPool libsrv.PoolServerConfig
ctx context.Context
cnl context.CancelFunc
log = liblog.New()
log liblog.Logger
)
func init() {
@@ -81,8 +81,9 @@ func init() {
ctx, cnl = context.WithCancel(context.Background())
log = liblog.New(ctx)
log.SetLevel(liblog.DebugLevel)
if err := log.SetOptions(ctx, &liblog.Options{
if err := log.SetOptions(&liblog.Options{
DisableStandard: false,
DisableStack: false,
DisableTimestamp: false,
@@ -141,7 +142,7 @@ func main() {
pool.MapRun(func(srv libsrv.Server) {
n, v, _ := srv.StatusInfo()
e := l.Entry(liblog.ErrorLevel, "status message")
e := l.Entry(liblog.ErrorLevel, "check status")
e = e.FieldAdd("server_name", n).FieldAdd("server_release", v)
e.ErrorAdd(true, srv.StatusHealth())
e.Check(liblog.InfoLevel)
@@ -163,6 +164,7 @@ func main() {
if i%3 == 0 {
for s := range pool.List(libsrv.FieldBind, libsrv.FieldName, "", ".*") {
l.Entry(liblog.DebugLevel, "Restarting server...").FieldAdd("server_name", s).Log()
l.Entry(liblog.InfoLevel, "Restarting server...").FieldAdd("server_name", s).Log()
}
pool.Restart()
@@ -184,6 +186,6 @@ func headers(w http.ResponseWriter, req *http.Request) {
}
func getLogger() liblog.Logger {
l, _ := log.Clone(ctx)
l, _ := log.Clone()
return l
}

View File

@@ -57,7 +57,7 @@ func init() {
ctx, cnl = context.WithCancel(context.TODO())
liblog.SetLevel(liblog.DebugLevel)
if err := liblog.GetDefault().SetOptions(ctx, &liblog.Options{
if err := liblog.GetDefault().SetOptions(&liblog.Options{
DisableStandard: false,
DisableStack: false,
DisableTimestamp: false,

View File

@@ -65,32 +65,26 @@ var (
bg = new(atomic.Value)
bp = new(atomic.Value)
log = new(atomic.Value)
ctx context.Context
cnl context.CancelFunc
)
func init() {
ctx, cnl = context.WithCancel(context.Background())
liberr.SetModeReturnError(liberr.ErrorReturnCodeErrorTraceFull)
log.Store(liblog.New())
log.Store(liblog.New(ctx))
initLogger()
}
type EmptyStruct struct{}
func main() {
ctx, cnl := context.WithCancel(context.Background())
defer func() {
if cnl != nil {
cnl()
}
}()
initLogger(ctx)
/*
err := liblog.GetDefault().SetOptions(ctx, log.GetOptions())
if err != nil {
panic(err)
}
*/
println(fmt.Sprintf("Running test with %d threads...", runtime.GOMAXPROCS(0)))
println(fmt.Sprintf("Init cluster..."))
tStart := time.Now()
@@ -360,11 +354,11 @@ func configNutDB() libndb.Config {
func getLogger() liblog.Logger {
if log == nil {
return liblog.New()
return liblog.New(context.Background())
} else if i := log.Load(); i == nil {
return liblog.New()
return liblog.New(context.Background())
} else if l, ok := i.(liblog.Logger); !ok {
return liblog.New()
return liblog.New(context.Background())
} else {
return l
}
@@ -384,10 +378,10 @@ func setLogger(l liblog.Logger) {
log.Store(l)
}
func initLogger(ctx context.Context) {
func initLogger() {
l := getLogger()
l.SetLevel(liblog.InfoLevel)
if err := l.SetOptions(ctx, &liblog.Options{
if err := l.SetOptions(&liblog.Options{
DisableStandard: true,
DisableStack: false,
DisableTimestamp: false,