mirror of
https://github.com/nabbar/golib.git
synced 2025-11-03 01:43:40 +08:00
- Remove logger as globals to use dedicated pointer (#104)
# Refactor Logger : - Remove logger as globals to use dedicated pointer - Add compat file to allow retro-compatibility (function are deprecated) - Add field management to allow add custom information - Add option struct to manage options - Add entry struct to manage all log entry - Add multithreading capabilities (with race prevention) - Allow to log to file + stdout/stderr + syslog - Add io.WriteCloser compatibility interface - Add logrus hook to manage option by hook instance - Add capabilities to custom each logfile/syslog/standard independently - Add small test suite # Update Packages for logger new options : - archive - cluster - context - httpcli - httpserver - ldap - tests # Other : - bump dependancies - update minio server for aws test
This commit is contained in:
@@ -200,7 +200,6 @@ func ExtractAll(src libiot.FileProgress, originalName, outputPath string, defaul
|
||||
}
|
||||
|
||||
func CreateArchive(archiveType ArchiveType, archive libiot.FileProgress, stripPath string, pathContent ...string) (created bool, err liberr.Error) {
|
||||
//@TODO: make function
|
||||
if len(pathContent) < 1 {
|
||||
//nolint #goerr113
|
||||
return false, ErrorParamsEmpty.ErrorParent(fmt.Errorf("pathContent is empty"))
|
||||
@@ -213,6 +212,8 @@ func CreateArchive(archiveType ArchiveType, archive libiot.FileProgress, stripPa
|
||||
return libtar.Create(archive, stripPath, pathContent...)
|
||||
case TypeTarGzip:
|
||||
return libtar.CreateGzip(archive, stripPath, pathContent...)
|
||||
|
||||
//@TODO: add zip mode
|
||||
}
|
||||
|
||||
return false, nil
|
||||
|
||||
@@ -40,37 +40,71 @@ func init() {
|
||||
pkg: pkgName,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type FuncLogger func() liblog.Logger
|
||||
|
||||
func SetLoggerFactory(log FuncLogger) {
|
||||
if log == nil {
|
||||
log = liblog.GetDefault
|
||||
}
|
||||
|
||||
dgblog.SetLoggerFactory(func(pkgName string) dgblog.ILogger {
|
||||
return &logDragonBoart{
|
||||
pkg: pkgName,
|
||||
log: log,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type logDragonBoart struct {
|
||||
pkg string
|
||||
log FuncLogger
|
||||
}
|
||||
|
||||
func (l *logDragonBoart) SetLevel(level dgblog.LogLevel) {
|
||||
if l.log == nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch level {
|
||||
case dgblog.CRITICAL:
|
||||
l.log().SetLevel(liblog.FatalLevel)
|
||||
case dgblog.ERROR:
|
||||
l.log().SetLevel(liblog.ErrorLevel)
|
||||
case dgblog.WARNING:
|
||||
l.log().SetLevel(liblog.WarnLevel)
|
||||
case dgblog.INFO:
|
||||
l.log().SetLevel(liblog.InfoLevel)
|
||||
case dgblog.DEBUG:
|
||||
l.log().SetLevel(liblog.DebugLevel)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *logDragonBoart) logMsg(lvl liblog.Level, message string, args ...interface{}) {
|
||||
if l.log == nil {
|
||||
l.log = liblog.GetDefault
|
||||
}
|
||||
|
||||
l.log().Entry(lvl, message, args...).FieldAdd("dragonboat.package", l.pkg).Log()
|
||||
}
|
||||
|
||||
func (l *logDragonBoart) Debugf(format string, args ...interface{}) {
|
||||
var newArg = append(make([]interface{}, 0), l.pkg)
|
||||
liblog.DebugLevel.Logf("[DragonBoat: %s] "+format, append(newArg, args...)...)
|
||||
l.logMsg(liblog.DebugLevel, format, args...)
|
||||
}
|
||||
|
||||
func (l *logDragonBoart) Infof(format string, args ...interface{}) {
|
||||
var newArg = append(make([]interface{}, 0), l.pkg)
|
||||
liblog.InfoLevel.Logf("[DragonBoat: %s] "+format, append(newArg, args...)...)
|
||||
l.logMsg(liblog.InfoLevel, format, args...)
|
||||
}
|
||||
|
||||
func (l *logDragonBoart) Warningf(format string, args ...interface{}) {
|
||||
var newArg = append(make([]interface{}, 0), l.pkg)
|
||||
liblog.WarnLevel.Logf("[DragonBoat: %s] "+format, append(newArg, args...)...)
|
||||
l.logMsg(liblog.WarnLevel, format, args...)
|
||||
}
|
||||
|
||||
func (l *logDragonBoart) Errorf(format string, args ...interface{}) {
|
||||
var newArg = append(make([]interface{}, 0), l.pkg)
|
||||
liblog.ErrorLevel.Logf("[DragonBoat: %s] "+format, append(newArg, args...)...)
|
||||
l.logMsg(liblog.ErrorLevel, format, args...)
|
||||
}
|
||||
|
||||
func (l *logDragonBoart) Panicf(format string, args ...interface{}) {
|
||||
var newArg = append(make([]interface{}, 0), l.pkg)
|
||||
liblog.FatalLevel.Logf("[DragonBoat: %s] "+format, append(newArg, args...)...)
|
||||
l.logMsg(liblog.FatalLevel, format, args...)
|
||||
}
|
||||
|
||||
@@ -56,9 +56,14 @@ type GinTonic interface {
|
||||
GetStringMap(key string) (sm map[string]interface{})
|
||||
GetStringMapString(key string) (sms map[string]string)
|
||||
GetStringMapStringSlice(key string) (smss map[string][]string)
|
||||
|
||||
SetLogger(log FuncLogger)
|
||||
}
|
||||
|
||||
type FuncLogger func() liblog.Logger
|
||||
|
||||
type ctxGinTonic struct {
|
||||
l FuncLogger
|
||||
g *gin.Context
|
||||
x context.Context
|
||||
c context.CancelFunc
|
||||
@@ -88,9 +93,22 @@ func NewGinTonic(c *gin.Context) GinTonic {
|
||||
}
|
||||
|
||||
return &ctxGinTonic{
|
||||
c,
|
||||
x,
|
||||
l,
|
||||
l: liblog.GetDefault,
|
||||
g: c,
|
||||
x: x,
|
||||
c: l,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ctxGinTonic) SetLogger(fct FuncLogger) {
|
||||
c.l = fct
|
||||
}
|
||||
|
||||
func (c *ctxGinTonic) log(lvl liblog.Level, msg string, args ...interface{}) {
|
||||
if c.l != nil {
|
||||
c.l().Entry(lvl, msg, args...).Log()
|
||||
} else {
|
||||
liblog.GetDefault().Entry(lvl, msg, args...).Log()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,11 +119,11 @@ func (c *ctxGinTonic) CancelOnSignal(s ...os.Signal) {
|
||||
|
||||
select {
|
||||
case <-sc:
|
||||
liblog.InfoLevel.Logf("Os Signal received, calling context cancel !")
|
||||
c.log(liblog.InfoLevel, "OS Signal received, calling context cancel !")
|
||||
c.c()
|
||||
return
|
||||
case <-c.Done():
|
||||
liblog.InfoLevel.Logf("Context has been closed...")
|
||||
c.log(liblog.InfoLevel, "Context has been closed !")
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
22
go.mod
22
go.mod
@@ -14,14 +14,14 @@ require (
|
||||
github.com/andybalholm/cascadia v1.2.0 // indirect
|
||||
github.com/aokoli/goutils v1.1.1 // indirect
|
||||
github.com/armon/go-metrics v0.3.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2 v1.5.0
|
||||
github.com/aws/aws-sdk-go-v2/config v1.2.0
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.2.0
|
||||
github.com/aws/aws-sdk-go-v2/service/iam v1.4.0
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.7.0
|
||||
github.com/aws/aws-sdk-go-v2 v1.6.0
|
||||
github.com/aws/aws-sdk-go-v2/config v1.3.0
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.2.1
|
||||
github.com/aws/aws-sdk-go-v2/service/iam v1.5.0
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.8.0
|
||||
github.com/c-bata/go-prompt v0.2.6
|
||||
github.com/cockroachdb/errors v1.8.4 // indirect
|
||||
github.com/cockroachdb/pebble v0.0.0-20210515132633-39fe91db49c0 // indirect
|
||||
github.com/cockroachdb/pebble v0.0.0-20210520205706-edcfca5432fb // indirect
|
||||
github.com/cockroachdb/redact v1.0.9 // indirect
|
||||
github.com/fatih/color v1.11.0
|
||||
github.com/fxamacker/cbor/v2 v2.2.0
|
||||
@@ -40,6 +40,7 @@ require (
|
||||
github.com/google/uuid v1.2.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-hclog v0.16.1
|
||||
github.com/hashicorp/go-immutable-radix v1.3.0 // indirect
|
||||
github.com/hashicorp/go-msgpack v1.1.5 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
@@ -59,13 +60,14 @@ require (
|
||||
github.com/leodido/go-urn v1.2.1 // indirect
|
||||
github.com/lni/dragonboat/v3 v3.3.4
|
||||
github.com/matcornic/hermes/v2 v2.1.0
|
||||
github.com/mattn/go-isatty v0.0.12 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.12 // indirect
|
||||
github.com/miekg/dns v1.1.42 // indirect
|
||||
github.com/minio/highwayhash v1.0.2 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/nats-io/jwt/v2 v2.0.2
|
||||
github.com/nats-io/nats-server/v2 v2.2.4
|
||||
github.com/nats-io/nats-server/v2 v2.2.5
|
||||
github.com/nats-io/nats.go v1.11.0
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/onsi/ginkgo v1.16.2
|
||||
@@ -76,6 +78,7 @@ require (
|
||||
github.com/shirou/gopsutil v3.21.4+incompatible
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/spf13/jwalterweatherman v1.1.0
|
||||
github.com/stretchr/testify v1.7.0 // indirect
|
||||
github.com/ugorji/go v1.2.6 // indirect
|
||||
github.com/vanng822/go-premailer v1.20.1 // indirect
|
||||
github.com/vbauerster/mpb/v5 v5.4.0
|
||||
@@ -85,11 +88,12 @@ require (
|
||||
github.com/xujiajun/utils v0.0.0-20190123093513-8bf096c4f53b
|
||||
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a // indirect
|
||||
golang.org/x/exp v0.0.0-20210514180818-737f94c0881e // indirect
|
||||
golang.org/x/net v0.0.0-20210510120150-4163338589ed
|
||||
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023
|
||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 // indirect
|
||||
golang.org/x/sys v0.0.0-20210521090106-6ca3eb03dfc2 // indirect
|
||||
golang.org/x/term v0.0.0-20210503060354-a79de5458b56
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
)
|
||||
|
||||
@@ -33,8 +33,8 @@ import (
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/nabbar/golib/errors"
|
||||
"github.com/nabbar/golib/logger"
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
liblog "github.com/nabbar/golib/logger"
|
||||
)
|
||||
|
||||
type httpClient struct {
|
||||
@@ -45,11 +45,11 @@ type httpClient struct {
|
||||
|
||||
type HTTP interface {
|
||||
SetContext(ctx context.Context)
|
||||
Check() errors.Error
|
||||
Call(file *bytes.Buffer) (bool, *bytes.Buffer, errors.Error)
|
||||
Check() liberr.Error
|
||||
Call(file *bytes.Buffer) (bool, *bytes.Buffer, liberr.Error)
|
||||
}
|
||||
|
||||
func NewClient(uri string) (HTTP, errors.Error) {
|
||||
func NewClient(uri string) (HTTP, liberr.Error) {
|
||||
var (
|
||||
pUri *url.URL
|
||||
err error
|
||||
@@ -88,7 +88,7 @@ func (obj *httpClient) SetContext(ctx context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
func (obj *httpClient) Check() errors.Error {
|
||||
func (obj *httpClient) Check() liberr.Error {
|
||||
req, e := obj.newRequest(http.MethodHead, nil)
|
||||
|
||||
if e != nil {
|
||||
@@ -106,7 +106,7 @@ func (obj *httpClient) Check() errors.Error {
|
||||
return e
|
||||
}
|
||||
|
||||
func (obj *httpClient) Call(body *bytes.Buffer) (bool, *bytes.Buffer, errors.Error) {
|
||||
func (obj *httpClient) Call(body *bytes.Buffer) (bool, *bytes.Buffer, liberr.Error) {
|
||||
req, e := obj.newRequest(http.MethodPost, body)
|
||||
|
||||
if e != nil {
|
||||
@@ -122,7 +122,7 @@ func (obj *httpClient) Call(body *bytes.Buffer) (bool, *bytes.Buffer, errors.Err
|
||||
return obj.checkResponse(res)
|
||||
}
|
||||
|
||||
func (obj *httpClient) newRequest(method string, body *bytes.Buffer) (*http.Request, errors.Error) {
|
||||
func (obj *httpClient) newRequest(method string, body *bytes.Buffer) (*http.Request, liberr.Error) {
|
||||
var reader *bytes.Reader
|
||||
|
||||
if body != nil && body.Len() > 0 {
|
||||
@@ -137,7 +137,7 @@ func (obj *httpClient) newRequest(method string, body *bytes.Buffer) (*http.Requ
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func (obj *httpClient) doRequest(req *http.Request) (*http.Response, errors.Error) {
|
||||
func (obj *httpClient) doRequest(req *http.Request) (*http.Response, liberr.Error) {
|
||||
res, e := obj.cli.Do(req)
|
||||
|
||||
if e != nil {
|
||||
@@ -147,7 +147,7 @@ func (obj *httpClient) doRequest(req *http.Request) (*http.Response, errors.Erro
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (obj *httpClient) checkResponse(res *http.Response) (bool, *bytes.Buffer, errors.Error) {
|
||||
func (obj *httpClient) checkResponse(res *http.Response) (bool, *bytes.Buffer, liberr.Error) {
|
||||
var buf *bytes.Buffer
|
||||
|
||||
if res.Body != nil {
|
||||
@@ -163,7 +163,7 @@ func (obj *httpClient) checkResponse(res *http.Response) (bool, *bytes.Buffer, e
|
||||
return false, nil, BUFFER_WRITE.ErrorParent(err)
|
||||
}
|
||||
|
||||
logger.DebugLevel.LogError(err)
|
||||
liblog.GetDefault().Entry(liblog.DebugLevel, "").ErrorAdd(err).FieldAdd("remote.uri", res.Request.URL.String()).FieldAdd("remote.method", res.Request.Method).Log()
|
||||
}
|
||||
|
||||
return strings.HasPrefix(res.Status, "2"), buf, nil
|
||||
|
||||
@@ -62,6 +62,7 @@ type PoolServer interface {
|
||||
Del(bindAddress string) PoolServer
|
||||
Has(bindAddress string) bool
|
||||
Len() int
|
||||
SetLogger(log FuncGetLogger)
|
||||
|
||||
MapRun(f MapRunPoolServer)
|
||||
MapUpd(f MapUpdPoolServer)
|
||||
@@ -190,6 +191,13 @@ func (p pool) Len() int {
|
||||
return len(p)
|
||||
}
|
||||
|
||||
func (p pool) SetLogger(log FuncGetLogger) {
|
||||
p.MapUpd(func(srv Server) Server {
|
||||
srv.SetLogger(log)
|
||||
return srv
|
||||
})
|
||||
}
|
||||
|
||||
func (p pool) List(fieldFilter, fieldReturn FieldType, pattern, regex string) []string {
|
||||
var (
|
||||
r = make([]string, 0)
|
||||
|
||||
@@ -48,6 +48,7 @@ import (
|
||||
const _TimeoutWaitingPortFreeing = 500 * time.Microsecond
|
||||
|
||||
type srvRun struct {
|
||||
log func() liblog.Logger
|
||||
err *atomic.Value
|
||||
run *atomic.Value
|
||||
snm string
|
||||
@@ -65,8 +66,9 @@ type run interface {
|
||||
Shutdown()
|
||||
}
|
||||
|
||||
func newRun() run {
|
||||
func newRun(log FuncGetLogger) run {
|
||||
return &srvRun{
|
||||
log: log,
|
||||
err: new(atomic.Value),
|
||||
run: new(atomic.Value),
|
||||
srv: nil,
|
||||
@@ -158,9 +160,21 @@ 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))
|
||||
|
||||
srv := &http.Server{
|
||||
Addr: cfg.GetListen().Host,
|
||||
ErrorLog: liblog.GetLogger(liblog.ErrorLevel, log.LstdFlags|log.Lmicroseconds, "[http/http2 server '%s']", name),
|
||||
ErrorLog: _log.GetStdLogger(liblog.ErrorLevel, log.LstdFlags|log.Lmicroseconds),
|
||||
}
|
||||
|
||||
if cfg.ReadTimeout > 0 {
|
||||
|
||||
@@ -34,6 +34,8 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
liblog "github.com/nabbar/golib/logger"
|
||||
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
libsts "github.com/nabbar/golib/status"
|
||||
)
|
||||
@@ -42,12 +44,17 @@ const (
|
||||
timeoutShutdown = 10 * time.Second
|
||||
)
|
||||
|
||||
type FuncGetLogger func() liblog.Logger
|
||||
|
||||
type server struct {
|
||||
log *atomic.Value
|
||||
run *atomic.Value
|
||||
cfg *atomic.Value
|
||||
}
|
||||
|
||||
type Server interface {
|
||||
SetLogger(log FuncGetLogger)
|
||||
|
||||
GetConfig() *ServerConfig
|
||||
SetConfig(cfg *ServerConfig) bool
|
||||
|
||||
@@ -75,11 +82,26 @@ func NewServer(cfg *ServerConfig) Server {
|
||||
c.Store(cfg.Clone())
|
||||
|
||||
return &server{
|
||||
log: new(atomic.Value),
|
||||
cfg: c,
|
||||
run: new(atomic.Value),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *server) SetLogger(log FuncGetLogger) {
|
||||
s.log.Store(log)
|
||||
}
|
||||
|
||||
func (s *server) GetLogger() FuncGetLogger {
|
||||
if i := s.log.Load(); i == nil {
|
||||
return nil
|
||||
} else if f, ok := i.(FuncGetLogger); ok {
|
||||
return f
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *server) GetConfig() *ServerConfig {
|
||||
if s.cfg == nil {
|
||||
return nil
|
||||
@@ -121,11 +143,11 @@ func (s *server) SetConfig(cfg *ServerConfig) bool {
|
||||
|
||||
func (s *server) getRun() run {
|
||||
if s.run == nil {
|
||||
return newRun()
|
||||
return newRun(s.GetLogger())
|
||||
} else if i := s.run.Load(); i == nil {
|
||||
return newRun()
|
||||
return newRun(s.GetLogger())
|
||||
} else if r, ok := i.(run); !ok {
|
||||
return newRun()
|
||||
return newRun(s.GetLogger())
|
||||
} else {
|
||||
return r
|
||||
}
|
||||
|
||||
56
ldap/ldap.go
56
ldap/ldap.go
@@ -39,6 +39,8 @@ import (
|
||||
liblog "github.com/nabbar/golib/logger"
|
||||
)
|
||||
|
||||
type FuncLogger func() liblog.Logger
|
||||
|
||||
//HelperLDAP struct use to manage connection to server and request it.
|
||||
type HelperLDAP struct {
|
||||
Attributes []string
|
||||
@@ -49,6 +51,7 @@ type HelperLDAP struct {
|
||||
bindDN string
|
||||
bindPass string
|
||||
ctx context.Context
|
||||
log FuncLogger
|
||||
}
|
||||
|
||||
//NewLDAP build a new LDAP helper based on config struct given.
|
||||
@@ -67,6 +70,37 @@ func NewLDAP(ctx context.Context, cnf *Config, attributes []string) (*HelperLDAP
|
||||
}, nil
|
||||
}
|
||||
|
||||
//SetLogger is used to specify the logger to be used for debug messgae
|
||||
func (lc *HelperLDAP) SetLogger(fct FuncLogger) {
|
||||
lc.log = fct
|
||||
}
|
||||
|
||||
func (lc HelperLDAP) getLogEntry(lvl liblog.Level, msg string, args ...interface{}) *liblog.Entry {
|
||||
var log liblog.Logger
|
||||
if lc.log == nil {
|
||||
log = liblog.GetDefault()
|
||||
} else if l := lc.log(); l == nil {
|
||||
log = liblog.GetDefault()
|
||||
} else {
|
||||
log = l
|
||||
}
|
||||
|
||||
return log.Entry(lvl, msg, args...).FieldAdd("ldap.host", lc.config.ServerAddr(lc.tlsMode == TLSModeTLS)).FieldAdd("ldap.tlsMode", lc.tlsMode.String())
|
||||
}
|
||||
|
||||
func (lc HelperLDAP) getLogEntryErr(lvlKO liblog.Level, err error, msg string, args ...interface{}) *liblog.Entry {
|
||||
var log liblog.Logger
|
||||
if lc.log == nil {
|
||||
log = liblog.GetDefault()
|
||||
} else if l := lc.log(); l == nil {
|
||||
log = liblog.GetDefault()
|
||||
} else {
|
||||
log = l
|
||||
}
|
||||
|
||||
return log.Entry(lvlKO, msg, args...).FieldAdd("ldap.host", lc.config.ServerAddr(lc.tlsMode == TLSModeTLS)).ErrorAdd(err)
|
||||
}
|
||||
|
||||
//SetCredentials used to defined the BindDN and password for connection.
|
||||
func (lc *HelperLDAP) SetCredentials(user, pass string) {
|
||||
lc.bindDN = user
|
||||
@@ -193,7 +227,7 @@ func (lc *HelperLDAP) tryConnect() (TLSMode, liberr.Error) {
|
||||
if lc.config.Portldaps != 0 {
|
||||
l, err = lc.dialTLS()
|
||||
|
||||
liblog.DebugLevel.LogErrorCtxf(liblog.DebugLevel, "connecting ldap with tls mode '%s'", err, TLSModeTLS.String())
|
||||
lc.getLogEntryErr(liblog.DebugLevel, err, "connecting ldap with tls mode '%s'", TLSModeTLS.String()).Check(liblog.DebugLevel)
|
||||
|
||||
if err == nil {
|
||||
return TLSModeTLS, nil
|
||||
@@ -205,14 +239,14 @@ func (lc *HelperLDAP) tryConnect() (TLSMode, liberr.Error) {
|
||||
}
|
||||
|
||||
l, err = lc.dial()
|
||||
liblog.DebugLevel.LogErrorCtxf(liblog.DebugLevel, "connecting ldap with tls mode '%s'", err, TLSModeNone.String())
|
||||
lc.getLogEntryErr(liblog.DebugLevel, err, "connecting ldap with tls mode '%s'", TLSModeNone.String()).Check(liblog.DebugLevel)
|
||||
|
||||
if err != nil {
|
||||
return _TLSModeInit, err
|
||||
}
|
||||
|
||||
err = lc.starttls(l)
|
||||
liblog.DebugLevel.LogErrorCtxf(liblog.DebugLevel, "connecting ldap with tls mode '%s'", err, TLSModeStarttls.String())
|
||||
lc.getLogEntryErr(liblog.DebugLevel, err, "connecting ldap with tls mode '%s'", TLSModeStarttls.String()).Check(liblog.DebugLevel)
|
||||
|
||||
if err == nil {
|
||||
return TLSModeStarttls, nil
|
||||
@@ -276,7 +310,7 @@ func (lc *HelperLDAP) connect() liberr.Error {
|
||||
}
|
||||
}
|
||||
|
||||
liblog.DebugLevel.Logf("ldap connected with tls mode '%s'", lc.tlsMode.String())
|
||||
lc.getLogEntry(liblog.DebugLevel, "ldap connected").Log()
|
||||
lc.conn = l
|
||||
}
|
||||
|
||||
@@ -347,7 +381,7 @@ func (lc *HelperLDAP) Connect() liberr.Error {
|
||||
return err
|
||||
}
|
||||
|
||||
liblog.DebugLevel.Logf("Bind success on LDAP server %s with tls mode '%s'", lc.config.ServerAddr(lc.tlsMode == TLSModeTLS), lc.tlsMode.String())
|
||||
lc.getLogEntry(liblog.DebugLevel, "ldap bind success").FieldAdd("bind.dn", lc.bindDN).Log()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -377,7 +411,7 @@ func (lc *HelperLDAP) runSearch(filter string, attributes []string) (*ldap.Searc
|
||||
return nil, ErrorLDAPSearch.ErrorParent(err)
|
||||
}
|
||||
|
||||
liblog.DebugLevel.Logf("Search success on server '%s' with tls mode '%s', with filter [%s] and attribute %v", lc.config.ServerAddr(lc.tlsMode == TLSModeTLS), lc.tlsMode.String(), filter, attributes)
|
||||
lc.getLogEntry(liblog.DebugLevel, "ldap search success").FieldAdd("ldap.filter", filter).FieldAdd("ldap.attributes", attributes).Log()
|
||||
return src, nil
|
||||
}
|
||||
|
||||
@@ -446,7 +480,7 @@ func (lc *HelperLDAP) UserInfoByField(username string, fieldOfUnicValue string)
|
||||
userRes["DN"] = src.Entries[0].DN
|
||||
}
|
||||
|
||||
liblog.DebugLevel.Logf("Map info retrieve in ldap server '%s' with tls mode '%s' about user [%s] : %v", lc.config.ServerAddr(lc.tlsMode == TLSModeTLS), lc.tlsMode.String(), username, userRes)
|
||||
lc.getLogEntry(liblog.DebugLevel, "ldap user find success").FieldAdd("ldap.user", username).FieldAdd("ldap.map", userRes).Log()
|
||||
return userRes, nil
|
||||
}
|
||||
|
||||
@@ -479,7 +513,7 @@ func (lc *HelperLDAP) GroupInfoByField(groupname string, fieldForUnicValue strin
|
||||
}
|
||||
}
|
||||
|
||||
liblog.DebugLevel.Logf("Info for group [%s] find on server '%s' with tls mode '%s' : %v", groupname, lc.config.ServerAddr(lc.tlsMode == TLSModeTLS), lc.tlsMode.String(), grpInfo)
|
||||
lc.getLogEntry(liblog.DebugLevel, "ldap group find success").FieldAdd("ldap.group", groupname).FieldAdd("ldap.map", grpInfo).Log()
|
||||
return grpInfo, nil
|
||||
}
|
||||
|
||||
@@ -504,13 +538,13 @@ func (lc *HelperLDAP) UserMemberOf(username string) ([]string, liberr.Error) {
|
||||
|
||||
for _, entry := range src.Entries {
|
||||
for _, mmb := range entry.GetAttributeValues("memberOf") {
|
||||
liblog.DebugLevel.Logf("Group find for uid '%s' on server '%s' with tls mode '%s' : %v", username, lc.config.ServerAddr(lc.tlsMode == TLSModeTLS), lc.tlsMode.String(), mmb)
|
||||
lc.getLogEntry(liblog.DebugLevel, "ldap find user group list building").FieldAdd("ldap.user", username).FieldAdd("ldap.raw.groups", mmb).Log()
|
||||
mmo := lc.ParseEntries(mmb)
|
||||
grp = append(grp, mmo["cn"]...)
|
||||
}
|
||||
}
|
||||
|
||||
liblog.DebugLevel.Logf("Groups find for uid '%s' on server '%s' with tls mode '%s' : %v", username, lc.config.ServerAddr(lc.tlsMode == TLSModeTLS), lc.tlsMode.String(), grp)
|
||||
lc.getLogEntry(liblog.DebugLevel, "ldap user group list success").FieldAdd("ldap.user", username).FieldAdd("ldap.grouplist", grp).Log()
|
||||
return grp, nil
|
||||
}
|
||||
|
||||
@@ -560,7 +594,7 @@ func (lc *HelperLDAP) UsersOfGroup(groupname string) ([]string, liberr.Error) {
|
||||
}
|
||||
}
|
||||
|
||||
liblog.DebugLevel.Logf("Member of groups [%s] find on server '%s' with tls mode '%s' : %v", groupname, lc.config.ServerAddr(lc.tlsMode == TLSModeTLS), lc.tlsMode.String(), grp)
|
||||
lc.getLogEntry(liblog.DebugLevel, "ldap group user list success").FieldAdd("ldap.group", groupname).FieldAdd("ldap.userlist", grp).Log()
|
||||
return grp, nil
|
||||
}
|
||||
|
||||
|
||||
281
logger/compat.go
Normal file
281
logger/compat.go
Normal file
@@ -0,0 +1,281 @@
|
||||
/***********************************************************************************************************************
|
||||
*
|
||||
* 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 logger
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
//@deprecated: only for retro compatibility
|
||||
var defaultLogger Logger
|
||||
|
||||
func init() {
|
||||
defaultLogger = New()
|
||||
defaultLogger.SetLevel(InfoLevel)
|
||||
}
|
||||
|
||||
//GetDefault return the default logger
|
||||
//@deprecated: create a logger and call GetLevel() like New().GetLevel()
|
||||
func GetDefault() Logger {
|
||||
return defaultLogger
|
||||
}
|
||||
|
||||
//GetCurrentLevel return the current loglevel setting in the logger. All log entry matching this level or below will be logged.
|
||||
//@deprecated: create a logger and call GetLevel() like New().GetLevel()
|
||||
func GetCurrentLevel() Level {
|
||||
return defaultLogger.GetLevel()
|
||||
}
|
||||
|
||||
// SetLevel Change the Level of all log entry with the Level type given in parameter. The change is apply for next log entry only.
|
||||
// If the given Level type is not matching a correct Level type, no change will be apply.
|
||||
//@deprecated: create a logger and call GetLevel() like New().GetLevel...
|
||||
func SetLevel(level Level) {
|
||||
defaultLogger.SetLevel(level)
|
||||
}
|
||||
|
||||
// AddGID Reconfigure the current logger to add or not the thread GID before each message.
|
||||
//@deprecated: create a logger and update the options like New().SetOptions...
|
||||
func AddGID(enable bool) {
|
||||
opt := defaultLogger.GetOptions()
|
||||
opt.DisableStack = !enable
|
||||
_ = defaultLogger.SetOptions(context.TODO(), opt)
|
||||
}
|
||||
|
||||
// Timestamp Reconfigure the current logger to add or not the timestamp before each message.
|
||||
//@deprecated: create a logger and update the options like New().SetOptions...
|
||||
func Timestamp(enable bool) {
|
||||
opt := defaultLogger.GetOptions()
|
||||
opt.DisableTimestamp = !enable
|
||||
_ = defaultLogger.SetOptions(context.TODO(), opt)
|
||||
}
|
||||
|
||||
// IsTimeStamp will return true if timestamp is added or not on log message
|
||||
//@deprecated: create a logger and get the options like New().GetOptions...
|
||||
func IsTimeStamp() bool {
|
||||
return !defaultLogger.GetOptions().DisableTimestamp
|
||||
}
|
||||
|
||||
// FileTrace Reconfigure the current logger to add or not the origin file/line of each message.
|
||||
// This option is apply for all message except info message.
|
||||
//@deprecated: create a logger and update the options like New().SetOptions...
|
||||
func FileTrace(enable bool) {
|
||||
opt := defaultLogger.GetOptions()
|
||||
opt.EnableTrace = enable
|
||||
_ = defaultLogger.SetOptions(context.TODO(), opt)
|
||||
}
|
||||
|
||||
// IsFileTrace will return true if trace is added or not on log message
|
||||
//@deprecated: create a logger and get the options like New().GetOptions...
|
||||
func IsFileTrace() bool {
|
||||
return defaultLogger.GetOptions().EnableTrace
|
||||
}
|
||||
|
||||
// ModeColor will reconfigure the current logger to use or not color in messages format.
|
||||
// This apply only for next message and only for TextFormat.
|
||||
//@deprecated: create a logger and update the options like New().SetOptions...
|
||||
func ModeColor(enable bool) {
|
||||
opt := defaultLogger.GetOptions()
|
||||
opt.DisableColor = !enable
|
||||
_ = defaultLogger.SetOptions(context.TODO(), opt)
|
||||
}
|
||||
|
||||
// IsModeColor will return true if color is configured on log message
|
||||
//@deprecated: create a logger and get the options like New().GetOptions...
|
||||
func IsModeColor() bool {
|
||||
return !defaultLogger.GetOptions().DisableColor
|
||||
}
|
||||
|
||||
// EnableColor Reconfigure the current logger to use color in messages format.
|
||||
// This apply only for next message and only for TextFormat.
|
||||
//@deprecated: create a logger and update the options like New().SetOptions...
|
||||
func EnableColor() {
|
||||
ModeColor(true)
|
||||
}
|
||||
|
||||
// DisableColor Reconfigure the current logger to not use color in messages format.
|
||||
// This apply only for next message and only for TextFormat.
|
||||
//@deprecated: create a logger and update the options like New().SetOptions...
|
||||
func DisableColor() {
|
||||
ModeColor(false)
|
||||
}
|
||||
|
||||
// EnableViperLog enable or not the Gin Logger configuration.
|
||||
//@deprecated: create a logger and call function SetSPF13Level like New().SetSPF13Level...
|
||||
func EnableViperLog(enable bool) {
|
||||
defaultLogger.SetSPF13Level(defaultLogger.GetLevel(), nil)
|
||||
}
|
||||
|
||||
// SetTracePathFilter customize the filter apply to filepath on trace.
|
||||
//@deprecated: create a logger and update the options like New().SetOptions...
|
||||
func SetTracePathFilter(path string) {
|
||||
opt := defaultLogger.GetOptions()
|
||||
opt.TraceFilter = path
|
||||
_ = defaultLogger.SetOptions(context.TODO(), opt)
|
||||
}
|
||||
|
||||
// Log Simple function to log directly the given message with the attached log Level.
|
||||
/*
|
||||
message a string message to be logged with the attached log Level
|
||||
*/
|
||||
//@deprecated: create a logger and call one of this function : New().Debug, New().Info, New().Warning, New().Error, New().Fatal, New().Panic, New().LogDetails or New().Entry
|
||||
func (l Level) Log(message string) {
|
||||
defaultLogger.LogDetails(l, message, nil, nil, nil)
|
||||
}
|
||||
|
||||
// Logf Simple function to log (to the attached log Level) with a fmt function a given pattern and arguments in parameters.
|
||||
/*
|
||||
format a string pattern for fmt function
|
||||
args a list of interface to match the references in the pattern
|
||||
*/
|
||||
//@deprecated: create a logger and call one of this function : New().Debug, New().Info, New().Warning, New().Error, New().Fatal, New().Panic, New().LogDetails or New().Entry
|
||||
func (l Level) Logf(format string, args ...interface{}) {
|
||||
defaultLogger.LogDetails(l, fmt.Sprintf(format, args...), nil, nil, nil)
|
||||
}
|
||||
|
||||
// LogData Simple function to log directly the given message with given data with the attached log Level.
|
||||
/*
|
||||
message a string message to be logged with the attached log Level
|
||||
data an interface of data to be logged with the message. (In Text format, the data will be json marshaled)
|
||||
*/
|
||||
//@deprecated: create a logger and call one of this function : New().Debug, New().Info, New().Warning, New().Error, New().Fatal, New().Panic, New().LogDetails or New().Entry
|
||||
func (l Level) LogData(message string, data interface{}) {
|
||||
defaultLogger.LogDetails(l, message, data, nil, nil)
|
||||
}
|
||||
|
||||
// WithFields Simple function to log directly the given message with given fields with the attached log Level.
|
||||
/*
|
||||
message a string message to be logged with the attached log Level
|
||||
fields a map of string key and interfaces value for a complete list of field ("field name" => value interface)
|
||||
*/
|
||||
//@deprecated: create a logger and call one of this function : New().Debug, New().Info, New().Warning, New().Error, New().Fatal, New().Panic, New().LogDetails or New().Entry
|
||||
func (l Level) WithFields(message string, fields Fields) {
|
||||
defaultLogger.LogDetails(l, message, nil, nil, fields)
|
||||
}
|
||||
|
||||
// LogError Simple function to log directly the given error with the attached log Level.
|
||||
//
|
||||
// How iot works :
|
||||
// + when the err is a valid error, this function will :
|
||||
// +--- log the Error with the attached log Level
|
||||
// +--- return true
|
||||
// + when the err is nil, this function will :
|
||||
// +--- return false
|
||||
/*
|
||||
err an error object message to be logged with the attached log Level
|
||||
*/
|
||||
//@deprecated: create a logger and call one of this function : New().CheckError or New().Entry.Check
|
||||
func (l Level) LogError(err error) bool {
|
||||
return defaultLogger.CheckError(l, NilLevel, "", nil, []error{err}, nil)
|
||||
}
|
||||
|
||||
// LogErrorCtx Function to test, log and inform about the given error object.
|
||||
//
|
||||
// How iot works :
|
||||
// + when the err is a valid error, this function will :
|
||||
// +--- log the Error with the attached log Level
|
||||
// +--- return true
|
||||
// + when the err is nil, this function will :
|
||||
// +--- use the levelElse if valid to inform with context there is no error found
|
||||
// +--- return false
|
||||
/*
|
||||
levelElse level used if the err is nil before returning a False result
|
||||
context a string for the context of the current test of the error
|
||||
err a error object to be log with the attached log level before return true, if the err is nil, the levelElse is used to log there are no error and return false
|
||||
*/
|
||||
//@deprecated: create a logger and call one of this function : New().CheckError or New().Entry.Check
|
||||
func (l Level) LogErrorCtx(levelElse Level, context string, err error) bool {
|
||||
return defaultLogger.Entry(l, context).ErrorAdd(err).Check(levelElse)
|
||||
}
|
||||
|
||||
// LogErrorCtxf Function to test, log and inform about the given error object, but with a context based on a pattern and matching args.
|
||||
//
|
||||
// How iot works :
|
||||
// + when the err is a valid error, this function will :
|
||||
// +--- log the Error with the attached log Level
|
||||
// +--- return true
|
||||
// + when the err is nil, this function will :
|
||||
// +--- use the levelElse if valid to inform with context there is no error found
|
||||
// +--- return false
|
||||
/*
|
||||
levelElse level used if the err is nil before returning a False result
|
||||
contextPattern a pattern string for the context of the current test of the error. This string will be used in a fmt function as pattern string
|
||||
err a error object to be log with the attached log level before return true, if the err is nil, the levelElse is used to log there are no error and return false
|
||||
args a list of interface for the context of the current test of the error. This list of interface will be used in a fmt function as the matching args for the pattern string
|
||||
*/
|
||||
//@deprecated: create a logger and call one of this function : New().CheckError or New().Entry.Check
|
||||
func (l Level) LogErrorCtxf(levelElse Level, contextPattern string, err error, args ...interface{}) bool {
|
||||
return defaultLogger.Entry(l, contextPattern, args...).ErrorAdd(err).Check(levelElse)
|
||||
}
|
||||
|
||||
// LogGinErrorCtxf Function to test, log and inform about the given error object, but with a context based on a couple of pattern and matching args.
|
||||
// This function will also add an Gin Tonic Error if the c parameters is a valid GinTonic Context reference.
|
||||
//
|
||||
// How iot works :
|
||||
// + when the err is a valid error, this function will :
|
||||
// +--- log the Error with the attached log Level
|
||||
// +--- if the Context Gin Tonic is valid, add the Error into this context
|
||||
// +--- return true
|
||||
// + when the err is nil, this function will :
|
||||
// +--- use the levelElse if valid to inform with context there is no error found
|
||||
// +--- return false
|
||||
/*
|
||||
levelElse level used if the err is nil before returning a False result
|
||||
contextPattern a pattern string for the context of the current test of the error. This string will be used in a fmt function as pattern string
|
||||
err a error object to be log with the attached log level before return true, if the err is nil, the levelElse is used to log there are no error and return false
|
||||
c a valid Go GinTonic Context reference to add current error to the Gin Tonic Error Context
|
||||
args a list of interface for the context of the current test of the error. This list of interface will be used in a fmt function as the matching args for the pattern string
|
||||
*/
|
||||
//@deprecated: create a logger and call one of this function : New().CheckError or New().Entry.SetGinContext.Check
|
||||
func (l Level) LogGinErrorCtxf(levelElse Level, contextPattern string, err error, c *gin.Context, args ...interface{}) bool {
|
||||
return defaultLogger.Entry(l, contextPattern, args...).SetGinContext(c).ErrorAdd(err).Check(levelElse)
|
||||
}
|
||||
|
||||
// LogGinErrorCtx Function to test, log and inform about the given error object.
|
||||
// This function will also add an Gin Tonic Error if the c parameters is a valid GinTonic Context reference.
|
||||
//
|
||||
// How iot works :
|
||||
// + when the err is a valid error, this function will :
|
||||
// +--- log the Error with the attached log Level
|
||||
// +--- if the Context Gin Tonic is valid, add the Error into this context
|
||||
// +--- return true
|
||||
// + when the err is nil, this function will :
|
||||
// +--- use the levelElse if valid to inform with context there is no error found
|
||||
// +--- return false
|
||||
/*
|
||||
levelElse level used if the err is nil before returning a False result
|
||||
context a string for the context of the current test of the error
|
||||
err a error object to be log with the attached log level before return true, if the err is nil, the levelElse is used to log there are no error and return false
|
||||
c a valid Go GinTonic Context reference to add current error to the Gin Tonic Error Context.
|
||||
*/
|
||||
//@deprecated: create a logger and call one of this function : New().CheckError or New().Entry.SetGinContext.Check
|
||||
func (l Level) LogGinErrorCtx(levelElse Level, context string, err error, c *gin.Context) bool {
|
||||
return defaultLogger.Entry(l, context).SetGinContext(c).ErrorAdd(err).Check(levelElse)
|
||||
}
|
||||
243
logger/entry.go
Normal file
243
logger/entry.go
Normal file
@@ -0,0 +1,243 @@
|
||||
/***********************************************************************************************************************
|
||||
*
|
||||
* 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 logger
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
liberr "github.com/nabbar/golib/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
FieldTime = "time"
|
||||
FieldLevel = "level"
|
||||
FieldStack = "stack"
|
||||
FieldCaller = "caller"
|
||||
FieldFile = "file"
|
||||
FieldLine = "line"
|
||||
FieldMessage = "message"
|
||||
FieldError = "error"
|
||||
FieldData = "data"
|
||||
)
|
||||
|
||||
type Entry struct {
|
||||
log func() *logrus.Logger
|
||||
gin *gin.Context
|
||||
|
||||
//Time is the time of the event (can be empty time if disabled timestamp)
|
||||
Time time.Time `json:"time"`
|
||||
|
||||
//Level define the level of the entry (cannot be empty or nil)
|
||||
Level Level `json:"level"`
|
||||
|
||||
//Stack define the process goroutine number (can be 0 if disabled)
|
||||
Stack uint64 `json:"stack"`
|
||||
|
||||
//Caller define the function caller of the entry (can be empty if trace disabled, not found or anonymous function)
|
||||
Caller string `json:"caller"`
|
||||
|
||||
//File define the file function caller of the entry (can be empty if trace disabled, not found or anonymous function)
|
||||
File string `json:"file"`
|
||||
|
||||
//Caller define the line in file caller of the entry (can be 0 if trace disabled, not found or anonymous function)
|
||||
Line uint32 `json:"line"`
|
||||
|
||||
//Message define the main message of the entry (can be empty)
|
||||
Message string `json:"message"`
|
||||
|
||||
//Error define a slice of error interface (can be nil, or a silce with one or more nil values)
|
||||
Error []error `json:"error"`
|
||||
|
||||
//Data is a unknown type data to add to logger (can be nil)
|
||||
Data interface{} `json:"data"`
|
||||
|
||||
//Fields are a list of custom information to add to log entry (can be nil or can overwrite Entry values)
|
||||
Fields Fields `json:"fields"`
|
||||
}
|
||||
|
||||
//SetGinContext allow to register a gin context pointer to register the errors of the current entry intro gin Context Error Slice.
|
||||
func (e *Entry) SetGinContext(ctx *gin.Context) *Entry {
|
||||
e.gin = ctx
|
||||
return e
|
||||
}
|
||||
|
||||
//FieldAdd allow to add one couple key/val as type string/interface into the custom field of the entry.
|
||||
func (e *Entry) FieldAdd(key string, val interface{}) *Entry {
|
||||
e.Fields.Add(key, val)
|
||||
return e
|
||||
}
|
||||
|
||||
//FieldMerge allow to merge a Field pointer into the custom field of the entry.
|
||||
func (e *Entry) FieldMerge(fields Fields) *Entry {
|
||||
e.Fields.Merge(fields)
|
||||
return e
|
||||
}
|
||||
|
||||
//FieldSet allow to change the custom field of the entry with the given Fields in parameter.
|
||||
func (e *Entry) FieldSet(fields Fields) *Entry {
|
||||
e.Fields = fields
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *Entry) FieldClean(keys ...string) *Entry {
|
||||
e.Fields.Clean(keys...)
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *Entry) DataSet(data interface{}) *Entry {
|
||||
e.Data = data
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *Entry) ErrorClean() *Entry {
|
||||
e.Error = make([]error, 0)
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *Entry) ErrorSet(err []error) *Entry {
|
||||
e.Error = err
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *Entry) ErrorAdd(err ...error) *Entry {
|
||||
for _, er := range err {
|
||||
e.Error = append(e.Error, er)
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *Entry) ErrorAddLib(err ...liberr.Error) *Entry {
|
||||
for _, er := range err {
|
||||
e.ErrorAdd(er.GetErrorSlice()...)
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *Entry) Check(lvlNoErr Level) bool {
|
||||
var found = false
|
||||
if len(e.Error) > 0 {
|
||||
for _, er := range e.Error {
|
||||
if er == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
e.Level = lvlNoErr
|
||||
}
|
||||
|
||||
e.Log()
|
||||
return found
|
||||
}
|
||||
|
||||
func (e *Entry) Log() {
|
||||
var (
|
||||
ent *logrus.Entry
|
||||
tag = NewFields().Add(FieldLevel, e.Level.String())
|
||||
log *logrus.Logger
|
||||
)
|
||||
|
||||
if !e.Time.IsZero() {
|
||||
tag.Add(FieldTime, e.Time.Format(time.RFC3339Nano))
|
||||
}
|
||||
|
||||
if e.Stack > 0 {
|
||||
tag.Add(FieldStack, e.Stack)
|
||||
}
|
||||
|
||||
if e.Caller != "" {
|
||||
tag.Add(FieldCaller, e.Caller)
|
||||
} else if e.File != "" {
|
||||
tag.Add(FieldFile, e.File)
|
||||
}
|
||||
|
||||
if e.Line > 0 {
|
||||
tag.Add(FieldLine, e.Line)
|
||||
}
|
||||
|
||||
if e.Message != "" {
|
||||
tag.Add(FieldMessage, e.Message)
|
||||
}
|
||||
|
||||
if len(e.Error) > 0 {
|
||||
tag.Add(FieldError, e.Error)
|
||||
}
|
||||
|
||||
if e.Data != nil {
|
||||
tag.Add(FieldData, e.Data)
|
||||
}
|
||||
|
||||
if len(e.Fields) > 0 {
|
||||
tag.Merge(e.Fields)
|
||||
}
|
||||
|
||||
if e.log == nil {
|
||||
return
|
||||
} else if log = e.log(); log == nil {
|
||||
return
|
||||
} else {
|
||||
ent = log.WithFields(tag.Logrus())
|
||||
}
|
||||
|
||||
//nolint exhaustive
|
||||
switch e.Level {
|
||||
case NilLevel:
|
||||
return
|
||||
|
||||
case DebugLevel:
|
||||
ent.Debugln()
|
||||
|
||||
case InfoLevel:
|
||||
ent.Infoln()
|
||||
|
||||
case WarnLevel:
|
||||
ent.Warnln()
|
||||
|
||||
case ErrorLevel:
|
||||
ent.Errorln()
|
||||
|
||||
case FatalLevel:
|
||||
ent.Fatalln()
|
||||
|
||||
case PanicLevel:
|
||||
ent.Panicln()
|
||||
}
|
||||
|
||||
if e.gin != nil && len(e.Error) > 0 {
|
||||
for _, err := range e.Error {
|
||||
_ = e.gin.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
107
logger/fields.go
Normal file
107
logger/fields.go
Normal file
@@ -0,0 +1,107 @@
|
||||
/***********************************************************************************************************************
|
||||
*
|
||||
* 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 logger
|
||||
|
||||
import "github.com/sirupsen/logrus"
|
||||
|
||||
type Fields map[string]interface{}
|
||||
|
||||
func NewFields() Fields {
|
||||
return make(Fields)
|
||||
}
|
||||
|
||||
func (f Fields) new() map[string]interface{} {
|
||||
return make(map[string]interface{}, 0)
|
||||
}
|
||||
|
||||
func (f Fields) clone() map[string]interface{} {
|
||||
if len(f) > 0 {
|
||||
return f
|
||||
}
|
||||
|
||||
return f.new()
|
||||
}
|
||||
|
||||
func (f Fields) Add(key string, val interface{}) Fields {
|
||||
res := f.clone()
|
||||
res[key] = val
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func (f Fields) Map(fct func(key string, val interface{}) interface{}) Fields {
|
||||
res := f.clone()
|
||||
|
||||
for k, v := range res {
|
||||
if v = fct(k, v); v != nil {
|
||||
res[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func (f Fields) Merge(other Fields) Fields {
|
||||
if len(other) < 1 {
|
||||
return f
|
||||
} else if len(f) < 1 {
|
||||
return other
|
||||
}
|
||||
|
||||
res := f.clone()
|
||||
|
||||
other.Map(func(key string, val interface{}) interface{} {
|
||||
res[key] = val
|
||||
return nil
|
||||
})
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func (f Fields) Clean(keys ...string) Fields {
|
||||
res := f.new()
|
||||
|
||||
if len(keys) > 0 {
|
||||
f.Map(func(key string, val interface{}) interface{} {
|
||||
for _, kk := range keys {
|
||||
if kk == key {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
res[key] = val
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func (f Fields) Logrus() logrus.Fields {
|
||||
return f.clone()
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 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 logger
|
||||
|
||||
import (
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Format a uint8 type customized with function to manage the result logger format.
|
||||
type Format uint8
|
||||
|
||||
const (
|
||||
nilFormat Format = iota
|
||||
// TextFormat a text format for logger entry.
|
||||
TextFormat
|
||||
// JsonFormat a json format for logger entry.
|
||||
JsonFormat
|
||||
)
|
||||
|
||||
var (
|
||||
curFormat = nilFormat
|
||||
)
|
||||
|
||||
func init() {
|
||||
updateFormatter(TextFormat)
|
||||
}
|
||||
|
||||
func SetOutput(out io.WriteCloser) {
|
||||
logrus.SetOutput(out)
|
||||
}
|
||||
|
||||
func updateFormatter(newFormat Format) {
|
||||
switch newFormat {
|
||||
|
||||
case curFormat:
|
||||
return
|
||||
|
||||
case TextFormat:
|
||||
curFormat = TextFormat
|
||||
logrus.SetFormatter(&logrus.TextFormatter{
|
||||
ForceColors: modeColor,
|
||||
DisableColors: !modeColor,
|
||||
DisableLevelTruncation: !modeColor,
|
||||
DisableTimestamp: true,
|
||||
DisableSorting: true,
|
||||
})
|
||||
|
||||
case JsonFormat:
|
||||
curFormat = JsonFormat
|
||||
logrus.SetFormatter(&logrus.JSONFormatter{
|
||||
DisableTimestamp: true,
|
||||
})
|
||||
|
||||
case nilFormat:
|
||||
return
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// GetFormatListString return the full list (slice of string) of all available formats.
|
||||
func GetFormatListString() []string {
|
||||
return []string{
|
||||
strings.ToLower(TextFormat.String()),
|
||||
strings.ToLower(JsonFormat.String()),
|
||||
}
|
||||
}
|
||||
|
||||
// SetFormat Change the format of all log entry with the Format type given in parameter. The change is apply for next entry only.
|
||||
// If the given Format type is not matching a correct Format type, no change will be apply.
|
||||
/*
|
||||
fmt a Format type for the format to use
|
||||
*/
|
||||
func SetFormat(fmt Format) {
|
||||
switch fmt {
|
||||
case TextFormat, JsonFormat:
|
||||
updateFormatter(fmt)
|
||||
case curFormat, nilFormat:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// GetCurrentFormat Return the current Format Type used for all log entry.
|
||||
func GetCurrentFormat() Format {
|
||||
return curFormat
|
||||
}
|
||||
|
||||
// GetFormatString return a valid Format Type matching the given string parameter.
|
||||
/*
|
||||
format the string representation of a Format type
|
||||
*/
|
||||
func GetFormatString(format string) Format {
|
||||
switch strings.ToLower(format) {
|
||||
case strings.ToLower(TextFormat.String()):
|
||||
return TextFormat
|
||||
|
||||
case strings.ToLower(JsonFormat.String()):
|
||||
return JsonFormat
|
||||
}
|
||||
|
||||
return GetFormatString(TextFormat.String())
|
||||
}
|
||||
|
||||
// String Return the string name of the Format Type.
|
||||
func (f Format) String() string {
|
||||
switch f {
|
||||
case JsonFormat:
|
||||
return "Json"
|
||||
case TextFormat:
|
||||
return "Text"
|
||||
case nilFormat, curFormat:
|
||||
return ""
|
||||
}
|
||||
|
||||
return TextFormat.String()
|
||||
}
|
||||
181
logger/hclog.go
Normal file
181
logger/hclog.go
Normal file
@@ -0,0 +1,181 @@
|
||||
/***********************************************************************************************************************
|
||||
*
|
||||
* 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 logger
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
|
||||
"github.com/hashicorp/go-hclog"
|
||||
)
|
||||
|
||||
const (
|
||||
HCLogArgs = "hclog.args"
|
||||
HCLogName = "hclog.name"
|
||||
)
|
||||
|
||||
type _hclog struct {
|
||||
l Logger
|
||||
}
|
||||
|
||||
func (l *_hclog) Log(level hclog.Level, msg string, args ...interface{}) {
|
||||
switch level {
|
||||
case hclog.Off, hclog.NoLevel:
|
||||
return
|
||||
case hclog.Trace:
|
||||
l.l.Debug(msg, nil, args...)
|
||||
case hclog.Debug:
|
||||
l.l.Debug(msg, nil, args...)
|
||||
case hclog.Info:
|
||||
l.l.Info(msg, nil, args...)
|
||||
case hclog.Warn:
|
||||
l.l.Warning(msg, nil, args...)
|
||||
case hclog.Error:
|
||||
l.l.Error(msg, nil, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *_hclog) Trace(msg string, args ...interface{}) {
|
||||
l.l.Debug(msg, nil, args...)
|
||||
}
|
||||
|
||||
func (l *_hclog) Debug(msg string, args ...interface{}) {
|
||||
l.l.Debug(msg, nil, args...)
|
||||
}
|
||||
|
||||
func (l *_hclog) Info(msg string, args ...interface{}) {
|
||||
l.l.Info(msg, nil, args...)
|
||||
}
|
||||
|
||||
func (l *_hclog) Warn(msg string, args ...interface{}) {
|
||||
l.l.Warning(msg, nil, args...)
|
||||
}
|
||||
|
||||
func (l *_hclog) Error(msg string, args ...interface{}) {
|
||||
l.l.Error(msg, nil, args...)
|
||||
}
|
||||
|
||||
func (l *_hclog) IsTrace() bool {
|
||||
return l.l.GetOptions().EnableTrace
|
||||
}
|
||||
|
||||
func (l *_hclog) IsDebug() bool {
|
||||
return l.l.GetLevel() >= DebugLevel
|
||||
}
|
||||
|
||||
func (l *_hclog) IsInfo() bool {
|
||||
return l.l.GetLevel() >= InfoLevel
|
||||
}
|
||||
|
||||
func (l *_hclog) IsWarn() bool {
|
||||
return l.l.GetLevel() >= WarnLevel
|
||||
}
|
||||
|
||||
func (l *_hclog) IsError() bool {
|
||||
return l.l.GetLevel() >= ErrorLevel
|
||||
}
|
||||
|
||||
func (l *_hclog) ImpliedArgs() []interface{} {
|
||||
fields := l.l.GetFields()
|
||||
|
||||
if a, ok := fields[HCLogArgs]; !ok {
|
||||
return make([]interface{}, 0)
|
||||
} else if s, ok := a.([]interface{}); ok {
|
||||
return s
|
||||
}
|
||||
|
||||
return make([]interface{}, 0)
|
||||
}
|
||||
|
||||
func (l *_hclog) With(args ...interface{}) hclog.Logger {
|
||||
l.l.SetFields(l.l.GetFields().Add(HCLogArgs, args))
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *_hclog) Name() string {
|
||||
fields := l.l.GetFields()
|
||||
|
||||
if a, ok := fields[HCLogName]; !ok {
|
||||
return ""
|
||||
} else if s, ok := a.(string); ok {
|
||||
return s
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (l *_hclog) Named(name string) hclog.Logger {
|
||||
l.l.SetFields(l.l.GetFields().Add(HCLogName, name))
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *_hclog) ResetNamed(name string) hclog.Logger {
|
||||
l.l.SetFields(l.l.GetFields().Add(HCLogName, name))
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *_hclog) SetLevel(level hclog.Level) {
|
||||
switch level {
|
||||
case hclog.Off, hclog.NoLevel:
|
||||
l.l.SetLevel(NilLevel)
|
||||
case hclog.Trace:
|
||||
l.l.SetLevel(DebugLevel)
|
||||
case hclog.Debug:
|
||||
l.l.SetLevel(DebugLevel)
|
||||
case hclog.Info:
|
||||
l.l.SetLevel(InfoLevel)
|
||||
case hclog.Warn:
|
||||
l.l.SetLevel(WarnLevel)
|
||||
case hclog.Error:
|
||||
l.l.SetLevel(ErrorLevel)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *_hclog) StandardLogger(opts *hclog.StandardLoggerOptions) *log.Logger {
|
||||
var lvl Level
|
||||
switch opts.ForceLevel {
|
||||
case hclog.Off, hclog.NoLevel:
|
||||
lvl = NilLevel
|
||||
case hclog.Trace:
|
||||
lvl = DebugLevel
|
||||
case hclog.Debug:
|
||||
lvl = DebugLevel
|
||||
case hclog.Info:
|
||||
lvl = InfoLevel
|
||||
case hclog.Warn:
|
||||
lvl = WarnLevel
|
||||
case hclog.Error:
|
||||
lvl = ErrorLevel
|
||||
}
|
||||
|
||||
return l.l.GetStdLogger(lvl, 0)
|
||||
}
|
||||
|
||||
func (l *_hclog) StandardWriter(opts *hclog.StandardLoggerOptions) io.Writer {
|
||||
return l.l
|
||||
}
|
||||
165
logger/hookfile.go
Normal file
165
logger/hookfile.go
Normal file
@@ -0,0 +1,165 @@
|
||||
/***********************************************************************************************************************
|
||||
*
|
||||
* 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 logger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/nabbar/golib/ioutils"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type HookFile interface {
|
||||
logrus.Hook
|
||||
io.WriteCloser
|
||||
RegisterHook(log *logrus.Logger)
|
||||
}
|
||||
|
||||
type _HookFile struct {
|
||||
f *os.File
|
||||
l []logrus.Level
|
||||
s bool
|
||||
d bool
|
||||
t bool
|
||||
}
|
||||
|
||||
func NewHookFile(opt OptionsFile) (HookFile, error) {
|
||||
if opt.Filepath == "" {
|
||||
return nil, fmt.Errorf("missing file path")
|
||||
}
|
||||
|
||||
var (
|
||||
flags = os.O_WRONLY | os.O_APPEND
|
||||
LVLs = make([]logrus.Level, 0)
|
||||
hdl *os.File
|
||||
err error
|
||||
)
|
||||
|
||||
if opt.FileMode == 0 {
|
||||
opt.FileMode = 0644
|
||||
}
|
||||
|
||||
if opt.PathMode == 0 {
|
||||
opt.PathMode = 0755
|
||||
}
|
||||
|
||||
if opt.CreatePath {
|
||||
if err = ioutils.PathCheckCreate(true, opt.Filepath, opt.FileMode, opt.PathMode); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if opt.Create {
|
||||
flags = os.O_CREATE | flags
|
||||
}
|
||||
|
||||
if hdl, err = os.OpenFile(opt.Filepath, flags, opt.FileMode); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(opt.LogLevel) > 0 {
|
||||
for _, ls := range opt.LogLevel {
|
||||
LVLs = append(LVLs, GetLevelString(ls).Logrus())
|
||||
}
|
||||
} else {
|
||||
LVLs = logrus.AllLevels
|
||||
}
|
||||
|
||||
return &_HookFile{
|
||||
f: hdl,
|
||||
l: LVLs,
|
||||
s: opt.DisableStack,
|
||||
d: opt.DisableTimestamp,
|
||||
t: opt.EnableTrace,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (o *_HookFile) RegisterHook(log *logrus.Logger) {
|
||||
log.AddHook(o)
|
||||
}
|
||||
|
||||
func (o *_HookFile) Levels() []logrus.Level {
|
||||
return o.l
|
||||
}
|
||||
|
||||
func (o *_HookFile) Fire(entry *logrus.Entry) error {
|
||||
ent := entry.Dup()
|
||||
|
||||
if o.s {
|
||||
ent.Data = o.filterKey(ent.Data, FieldStack)
|
||||
}
|
||||
|
||||
if o.d {
|
||||
ent.Data = o.filterKey(ent.Data, FieldTime)
|
||||
}
|
||||
|
||||
if !o.t {
|
||||
ent.Data = o.filterKey(ent.Data, FieldCaller)
|
||||
ent.Data = o.filterKey(ent.Data, FieldFile)
|
||||
ent.Data = o.filterKey(ent.Data, FieldLine)
|
||||
}
|
||||
|
||||
if p, err := ent.Bytes(); err != nil {
|
||||
return err
|
||||
} else if _, err = o.Write(p); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *_HookFile) Write(p []byte) (n int, err error) {
|
||||
if o.f == nil {
|
||||
return 0, fmt.Errorf("logrus.hookfile: file not setup")
|
||||
}
|
||||
|
||||
return o.f.Write(p)
|
||||
}
|
||||
|
||||
func (o *_HookFile) Close() error {
|
||||
err := o.f.Close()
|
||||
o.f = nil
|
||||
return err
|
||||
}
|
||||
|
||||
func (o *_HookFile) filterKey(f logrus.Fields, key string) logrus.Fields {
|
||||
if len(f) < 1 {
|
||||
return f
|
||||
}
|
||||
|
||||
var res = make(map[string]interface{}, 0)
|
||||
|
||||
for k, v := range f {
|
||||
if k == key {
|
||||
continue
|
||||
}
|
||||
res[k] = v
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
127
logger/hookstandard.go
Normal file
127
logger/hookstandard.go
Normal file
@@ -0,0 +1,127 @@
|
||||
/***********************************************************************************************************************
|
||||
*
|
||||
* 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 logger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type HookStandard interface {
|
||||
logrus.Hook
|
||||
io.WriteCloser
|
||||
RegisterHook(log *logrus.Logger)
|
||||
}
|
||||
|
||||
type _HookStd struct {
|
||||
w io.Writer
|
||||
l []logrus.Level
|
||||
s bool
|
||||
d bool
|
||||
t bool
|
||||
c bool
|
||||
}
|
||||
|
||||
func NewHookStandard(opt Options, w io.Writer, lvls []logrus.Level) HookFile {
|
||||
if len(lvls) < 1 {
|
||||
lvls = logrus.AllLevels
|
||||
}
|
||||
|
||||
return &_HookStd{
|
||||
w: w,
|
||||
l: lvls,
|
||||
s: opt.DisableStack,
|
||||
d: opt.DisableTimestamp,
|
||||
t: opt.EnableTrace,
|
||||
}
|
||||
}
|
||||
|
||||
func (o *_HookStd) RegisterHook(log *logrus.Logger) {
|
||||
log.AddHook(o)
|
||||
}
|
||||
|
||||
func (o *_HookStd) Levels() []logrus.Level {
|
||||
return o.l
|
||||
}
|
||||
|
||||
func (o *_HookStd) Fire(entry *logrus.Entry) error {
|
||||
ent := entry.Dup()
|
||||
|
||||
if o.s {
|
||||
ent.Data = o.filterKey(ent.Data, FieldStack)
|
||||
}
|
||||
|
||||
if o.d {
|
||||
ent.Data = o.filterKey(ent.Data, FieldTime)
|
||||
}
|
||||
|
||||
if !o.t {
|
||||
ent.Data = o.filterKey(ent.Data, FieldCaller)
|
||||
ent.Data = o.filterKey(ent.Data, FieldFile)
|
||||
ent.Data = o.filterKey(ent.Data, FieldLine)
|
||||
}
|
||||
|
||||
if p, err := ent.Bytes(); err != nil {
|
||||
return err
|
||||
} else if _, err = o.Write(p); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *_HookStd) Write(p []byte) (n int, err error) {
|
||||
if o.w == nil {
|
||||
return 0, fmt.Errorf("logrus.hookstd: writer not setup")
|
||||
}
|
||||
|
||||
return o.w.Write(p)
|
||||
}
|
||||
|
||||
func (o *_HookStd) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *_HookStd) filterKey(f logrus.Fields, key string) logrus.Fields {
|
||||
if len(f) < 1 {
|
||||
return f
|
||||
}
|
||||
|
||||
var res = make(map[string]interface{}, 0)
|
||||
|
||||
for k, v := range f {
|
||||
if k == key {
|
||||
continue
|
||||
}
|
||||
res[k] = v
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
143
logger/hooksyslog.go
Normal file
143
logger/hooksyslog.go
Normal file
@@ -0,0 +1,143 @@
|
||||
/***********************************************************************************************************************
|
||||
*
|
||||
* 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 logger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log/syslog"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type HookSyslog interface {
|
||||
logrus.Hook
|
||||
io.WriteCloser
|
||||
RegisterHook(log *logrus.Logger)
|
||||
}
|
||||
|
||||
type _HookSyslog struct {
|
||||
w *syslog.Writer
|
||||
l []logrus.Level
|
||||
s bool
|
||||
d bool
|
||||
t bool
|
||||
}
|
||||
|
||||
func NewHookSyslog(opt OptionsSyslog) (HookSyslog, error) {
|
||||
var (
|
||||
LVLs = make([]logrus.Level, 0)
|
||||
sys *syslog.Writer
|
||||
err error
|
||||
)
|
||||
|
||||
if len(opt.LogLevel) > 0 {
|
||||
for _, ls := range opt.LogLevel {
|
||||
LVLs = append(LVLs, GetLevelString(ls).Logrus())
|
||||
}
|
||||
} else {
|
||||
LVLs = logrus.AllLevels
|
||||
}
|
||||
|
||||
if sys, err = syslog.Dial(opt.Network.String(), opt.Host, opt.Priority, opt.Tag); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &_HookSyslog{
|
||||
w: sys,
|
||||
l: LVLs,
|
||||
s: opt.DisableStack,
|
||||
d: opt.DisableTimestamp,
|
||||
t: opt.EnableTrace,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (o *_HookSyslog) RegisterHook(log *logrus.Logger) {
|
||||
log.AddHook(o)
|
||||
}
|
||||
|
||||
func (o *_HookSyslog) Levels() []logrus.Level {
|
||||
return o.l
|
||||
}
|
||||
|
||||
func (o *_HookSyslog) Fire(entry *logrus.Entry) error {
|
||||
ent := entry.Dup()
|
||||
|
||||
if o.s {
|
||||
ent.Data = o.filterKey(ent.Data, FieldStack)
|
||||
}
|
||||
|
||||
if o.d {
|
||||
ent.Data = o.filterKey(ent.Data, FieldTime)
|
||||
}
|
||||
|
||||
if !o.t {
|
||||
ent.Data = o.filterKey(ent.Data, FieldCaller)
|
||||
ent.Data = o.filterKey(ent.Data, FieldFile)
|
||||
ent.Data = o.filterKey(ent.Data, FieldLine)
|
||||
}
|
||||
|
||||
if p, err := ent.Bytes(); err != nil {
|
||||
return err
|
||||
} else if _, err = o.Write(p); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *_HookSyslog) Write(p []byte) (n int, err error) {
|
||||
if o.w == nil {
|
||||
return 0, fmt.Errorf("logrus.hooksyslog: connection not setup")
|
||||
}
|
||||
|
||||
return o.w.Write(p)
|
||||
}
|
||||
|
||||
func (o *_HookSyslog) Close() error {
|
||||
err := o.w.Close()
|
||||
o.w = nil
|
||||
return err
|
||||
}
|
||||
|
||||
func (o *_HookSyslog) filterKey(f logrus.Fields, key string) logrus.Fields {
|
||||
if len(f) < 1 {
|
||||
return f
|
||||
}
|
||||
|
||||
var res = make(map[string]interface{}, 0)
|
||||
|
||||
for k, v := range f {
|
||||
if k == key {
|
||||
continue
|
||||
}
|
||||
res[k] = v
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
134
logger/interface.go
Normal file
134
logger/interface.go
Normal file
@@ -0,0 +1,134 @@
|
||||
/***********************************************************************************************************************
|
||||
*
|
||||
* 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 logger
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"log"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/hashicorp/go-hclog"
|
||||
|
||||
jww "github.com/spf13/jwalterweatherman"
|
||||
)
|
||||
|
||||
type Logger interface {
|
||||
io.WriteCloser
|
||||
|
||||
//SetLevel allow to change the minimal level of log message
|
||||
SetLevel(lvl Level)
|
||||
|
||||
//GetLevel return the minimal level of log message
|
||||
GetLevel() Level
|
||||
|
||||
//SetIOWriterLevel allow to change the minimal level of log message for io.WriterCloser interface
|
||||
SetIOWriterLevel(lvl Level)
|
||||
|
||||
//GetIOWriterLevel return the minimal level of log message for io.WriterCloser interface
|
||||
GetIOWriterLevel() Level
|
||||
|
||||
//SetOptions allow to set or update the options for the logger
|
||||
SetOptions(ctx context.Context, opt *Options) error
|
||||
|
||||
//GetOptions return the options for the logger
|
||||
GetOptions() *Options
|
||||
|
||||
//SetFields allow to set or update the default fields for all logger entry
|
||||
// Fields are custom information added into log message
|
||||
SetFields(field Fields)
|
||||
|
||||
//GetFields return the default fields for all logger entry
|
||||
// Fields are custom information added into log message
|
||||
GetFields() Fields
|
||||
|
||||
//Clone allow to duplicate the logger with a copy of the logger
|
||||
Clone(ctx context.Context) (Logger, error)
|
||||
|
||||
//SetSPF13Level allow to plus spf13 logger (jww) to this logger
|
||||
SetSPF13Level(lvl Level, log *jww.Notepad)
|
||||
|
||||
//GetStdLogger return a golang log.logger instance linked with this main logger.
|
||||
GetStdLogger(lvl Level, logFlags int) *log.Logger
|
||||
|
||||
//SetStdLogger force the default golang log.logger instance linked with this main logger.
|
||||
SetStdLogger(lvl Level, logFlags int)
|
||||
|
||||
//SetHashicorpHCLog force mapping default Hshicorp logger hclog to current logger
|
||||
SetHashicorpHCLog()
|
||||
|
||||
//NewHashicorpHCLog return a new Hshicorp logger hclog mapped current logger
|
||||
NewHashicorpHCLog() hclog.Logger
|
||||
|
||||
//Debug add an entry with DebugLevel to the logger
|
||||
Debug(message string, data interface{}, args ...interface{})
|
||||
|
||||
//Info add an entry with InfoLevel to the logger
|
||||
Info(message string, data interface{}, args ...interface{})
|
||||
|
||||
//Warning add an entry with WarnLevel to the logger
|
||||
Warning(message string, data interface{}, args ...interface{})
|
||||
|
||||
//Error add an entry with ErrorLevel level to the logger
|
||||
Error(message string, data interface{}, args ...interface{})
|
||||
|
||||
//Fatal add an entry with FatalLevel to the logger
|
||||
//The function will break the process (os.exit) after log entry.
|
||||
Fatal(message string, data interface{}, args ...interface{})
|
||||
|
||||
//Panic add an entry with PanicLevel level to the logger
|
||||
//The function will break the process (os.exit) after log entry.
|
||||
Panic(message string, data interface{}, args ...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.
|
||||
// Othwise if the lvlOK is given (and not NilLevel) the function will add entry and said ok
|
||||
CheckError(lvlKO, lvlOK Level, message string, data interface{}, err []error, fields Fields, args ...interface{}) bool
|
||||
|
||||
//Entry will return an entry struct to manage it (set gin context, add fields, log the entry...)
|
||||
Entry(lvl Level, message string, args ...interface{}) *Entry
|
||||
}
|
||||
|
||||
//New return a new logger interface pointer
|
||||
func New() Logger {
|
||||
lvl := new(atomic.Value)
|
||||
lvl.Store(InfoLevel)
|
||||
|
||||
return &logger{
|
||||
m: sync.Mutex{},
|
||||
l: lvl,
|
||||
o: new(atomic.Value),
|
||||
s: new(atomic.Value),
|
||||
f: new(atomic.Value),
|
||||
w: new(atomic.Value),
|
||||
c: new(atomic.Value),
|
||||
}
|
||||
}
|
||||
160
logger/interface_test.go
Normal file
160
logger/interface_test.go
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 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 logger_test
|
||||
|
||||
import (
|
||||
"github.com/nabbar/golib/logger"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Logger", func() {
|
||||
Context("Create New Logger with Default Config", func() {
|
||||
It("Must succeed", func() {
|
||||
log := logger.New()
|
||||
log.SetLevel(logger.DebugLevel)
|
||||
err := log.SetOptions(GetContext(), &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.SetLevel(logger.DebugLevel)
|
||||
err := log.SetOptions(GetContext(), &logger.Options{
|
||||
EnableTrace: true,
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
log.LogDetails(logger.InfoLevel, "test logger with trace", nil, nil, nil)
|
||||
})
|
||||
})
|
||||
Context("Create New Logger with field", func() {
|
||||
It("Must succeed", func() {
|
||||
log := logger.New()
|
||||
log.SetLevel(logger.DebugLevel)
|
||||
err := log.SetOptions(GetContext(), &logger.Options{
|
||||
EnableTrace: true,
|
||||
})
|
||||
log.SetFields(logger.NewFields().Add("test-field", "ok"))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
log.LogDetails(logger.InfoLevel, "test logger with field", nil, nil, nil)
|
||||
})
|
||||
})
|
||||
Context("Create New Logger with file", func() {
|
||||
It("Must succeed", func() {
|
||||
log := logger.New()
|
||||
log.SetLevel(logger.DebugLevel)
|
||||
|
||||
fsp, err := GetTempFile()
|
||||
|
||||
defer func() {
|
||||
err = DelTempFile(fsp)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}()
|
||||
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = log.SetOptions(GetContext(), &logger.Options{
|
||||
EnableTrace: true,
|
||||
LogFile: []logger.OptionsFile{
|
||||
{
|
||||
LogLevel: nil,
|
||||
Filepath: fsp,
|
||||
Create: true,
|
||||
CreatePath: true,
|
||||
FileMode: 0644,
|
||||
PathMode: 0755,
|
||||
DisableStack: false,
|
||||
DisableTimestamp: false,
|
||||
EnableTrace: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
log.SetFields(logger.NewFields().Add("test-field", "ok"))
|
||||
log.LogDetails(logger.InfoLevel, "test logger with field", nil, nil, nil)
|
||||
})
|
||||
})
|
||||
Context("Create New Logger with file in multithread mode", func() {
|
||||
It("Must succeed", func() {
|
||||
log := logger.New()
|
||||
log.SetLevel(logger.DebugLevel)
|
||||
|
||||
fsp, err := GetTempFile()
|
||||
|
||||
defer func() {
|
||||
err = DelTempFile(fsp)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}()
|
||||
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = log.SetOptions(GetContext(), &logger.Options{
|
||||
EnableTrace: true,
|
||||
LogFile: []logger.OptionsFile{
|
||||
{
|
||||
LogLevel: nil,
|
||||
Filepath: fsp,
|
||||
Create: true,
|
||||
CreatePath: true,
|
||||
FileMode: 0644,
|
||||
PathMode: 0755,
|
||||
DisableStack: false,
|
||||
DisableTimestamp: false,
|
||||
EnableTrace: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
log.SetFields(logger.NewFields().Add("test-field", "ok"))
|
||||
log.LogDetails(logger.InfoLevel, "test logger with field", nil, nil, nil)
|
||||
|
||||
var sub logger.Logger
|
||||
sub, err = log.Clone(GetContext())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
go func(log logger.Logger) {
|
||||
defer func() {
|
||||
se := log.Close()
|
||||
Expect(se).ToNot(HaveOccurred())
|
||||
}()
|
||||
|
||||
log.SetFields(logger.NewFields().Add("logger", "sub"))
|
||||
for i := 0; i < 10; i++ {
|
||||
log.Entry(logger.InfoLevel, "test multithreading logger").FieldAdd("id", i).Log()
|
||||
}
|
||||
}(sub)
|
||||
|
||||
log.SetFields(logger.NewFields().Add("logger", "main"))
|
||||
for i := 0; i < 10; i++ {
|
||||
log.Entry(logger.InfoLevel, "test multithreading logger").FieldAdd("id", i).Log()
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
88
logger/iowritecloser.go
Normal file
88
logger/iowritecloser.go
Normal file
@@ -0,0 +1,88 @@
|
||||
/***********************************************************************************************************************
|
||||
*
|
||||
* 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 logger
|
||||
|
||||
import "sync/atomic"
|
||||
|
||||
func (l *logger) Close() error {
|
||||
|
||||
for _, c := range l.closeGetMutex() {
|
||||
if c != nil {
|
||||
_ = c.Close()
|
||||
}
|
||||
}
|
||||
|
||||
if l.n != nil {
|
||||
l.n()
|
||||
}
|
||||
|
||||
l.closeClean()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *logger) Write(p []byte) (n int, err error) {
|
||||
l.newEntry(l.GetIOWriterLevel(), string(p), nil, l.GetFields(), nil).Log()
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (l *logger) SetIOWriterLevel(lvl Level) {
|
||||
if l == nil {
|
||||
return
|
||||
}
|
||||
|
||||
l.m.Lock()
|
||||
defer l.m.Unlock()
|
||||
|
||||
if l.w == nil {
|
||||
l.w = new(atomic.Value)
|
||||
}
|
||||
|
||||
l.w.Store(lvl)
|
||||
}
|
||||
|
||||
func (l *logger) GetIOWriterLevel() Level {
|
||||
if l == nil {
|
||||
return NilLevel
|
||||
}
|
||||
|
||||
l.m.Lock()
|
||||
defer l.m.Unlock()
|
||||
|
||||
if l.w == nil {
|
||||
l.w = new(atomic.Value)
|
||||
}
|
||||
|
||||
if i := l.w.Load(); i == nil {
|
||||
return NilLevel
|
||||
} else if o, ok := i.(Level); ok {
|
||||
return o
|
||||
}
|
||||
|
||||
return NilLevel
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 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 logger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// IOWriter is struct redirected all entry to the current logger.
|
||||
type IOWriter struct {
|
||||
lvl Level
|
||||
prf string
|
||||
}
|
||||
|
||||
// GetIOWriter return a io.Writer instance to Write on logger with a specified log level.
|
||||
/*
|
||||
level specify the log level to use to redirect all entry to current logger
|
||||
msgPrefixPattern is a string pattern to prefix all entry
|
||||
msgPrefixArgs is a list of args to apply on the msgPrefixPattern pattern to prefix all entry
|
||||
*/
|
||||
func GetIOWriter(level Level, msgPrefixPattern string, msgPrefixArgs ...interface{}) io.Writer {
|
||||
return &IOWriter{
|
||||
lvl: level,
|
||||
prf: fmt.Sprintf(msgPrefixPattern, msgPrefixArgs...),
|
||||
}
|
||||
}
|
||||
|
||||
// Write implement the Write function of the io.Writer interface and redirect all entry to current logger.
|
||||
// The return n will always return the len on the p parameter and err will always be nil.
|
||||
/*
|
||||
p the entry to be redirect to current logger
|
||||
*/
|
||||
func (iow IOWriter) Write(p []byte) (n int, err error) {
|
||||
n = len(p)
|
||||
err = nil
|
||||
iow.lvl.Log(iow.prf + " " + string(p))
|
||||
return
|
||||
}
|
||||
372
logger/level.go
372
logger/level.go
@@ -25,15 +25,10 @@ SOFTWARE.
|
||||
package logger
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/jwalterweatherman"
|
||||
)
|
||||
|
||||
//Level a uint8 type customized with function to log message with the current log level.
|
||||
@@ -56,14 +51,6 @@ const (
|
||||
NilLevel
|
||||
)
|
||||
|
||||
var (
|
||||
curLevel *atomic.Value
|
||||
)
|
||||
|
||||
func init() {
|
||||
SetLevel(InfoLevel)
|
||||
}
|
||||
|
||||
// GetLevelListString return a list ([]string) of all string loglevel available.
|
||||
func GetLevelListString() []string {
|
||||
return []string{
|
||||
@@ -76,114 +63,12 @@ func GetLevelListString() []string {
|
||||
}
|
||||
}
|
||||
|
||||
//GetCurrentLevel return the current loglevel setting in the logger. All log entry matching this level or below will be logged.
|
||||
func GetCurrentLevel() Level {
|
||||
if curLevel == nil {
|
||||
curLevel = new(atomic.Value)
|
||||
}
|
||||
|
||||
if i := curLevel.Load(); i == nil {
|
||||
return NilLevel
|
||||
} else if l, ok := i.(Level); !ok {
|
||||
return NilLevel
|
||||
} else {
|
||||
return l
|
||||
}
|
||||
}
|
||||
|
||||
func setCurLevel(lvl Level) {
|
||||
if curLevel == nil {
|
||||
curLevel = new(atomic.Value)
|
||||
}
|
||||
curLevel.Store(lvl)
|
||||
}
|
||||
|
||||
// SetLevel Change the Level of all log entry with the Level type given in parameter. The change is apply for next log entry only.
|
||||
// If the given Level type is not matching a correct Level type, no change will be apply.
|
||||
/*
|
||||
level a Level type to use to specify the new level of logger message
|
||||
*/
|
||||
func SetLevel(level Level) {
|
||||
//nolint exhaustive
|
||||
switch level {
|
||||
|
||||
case PanicLevel:
|
||||
setCurLevel(PanicLevel)
|
||||
logrus.SetLevel(logrus.PanicLevel)
|
||||
|
||||
case FatalLevel:
|
||||
setCurLevel(FatalLevel)
|
||||
logrus.SetLevel(logrus.FatalLevel)
|
||||
|
||||
case ErrorLevel:
|
||||
setCurLevel(ErrorLevel)
|
||||
logrus.SetLevel(logrus.ErrorLevel)
|
||||
|
||||
case WarnLevel:
|
||||
setCurLevel(WarnLevel)
|
||||
logrus.SetLevel(logrus.WarnLevel)
|
||||
|
||||
case InfoLevel:
|
||||
setCurLevel(InfoLevel)
|
||||
logrus.SetLevel(logrus.InfoLevel)
|
||||
|
||||
case DebugLevel:
|
||||
setCurLevel(DebugLevel)
|
||||
logrus.SetLevel(logrus.DebugLevel)
|
||||
|
||||
case NilLevel:
|
||||
setCurLevel(NilLevel)
|
||||
return
|
||||
}
|
||||
|
||||
DebugLevel.Logf("Change Log Level to %s", logrus.GetLevel().String())
|
||||
setViperLogTrace()
|
||||
}
|
||||
|
||||
func setViperLogTrace() {
|
||||
if !enableVPR {
|
||||
return
|
||||
}
|
||||
|
||||
jwalterweatherman.SetLogOutput(GetIOWriter(GetCurrentLevel(), "[Log Config Viper]"))
|
||||
jwalterweatherman.SetStdoutOutput(GetIOWriter(GetCurrentLevel(), "[Std Config Viper]"))
|
||||
|
||||
if filetrace {
|
||||
jwalterweatherman.SetStdoutThreshold(jwalterweatherman.LevelTrace)
|
||||
return
|
||||
}
|
||||
|
||||
//nolint exhaustive
|
||||
switch GetCurrentLevel() {
|
||||
case PanicLevel:
|
||||
jwalterweatherman.SetStdoutThreshold(jwalterweatherman.LevelCritical)
|
||||
|
||||
case FatalLevel:
|
||||
jwalterweatherman.SetStdoutThreshold(jwalterweatherman.LevelFatal)
|
||||
|
||||
case ErrorLevel:
|
||||
jwalterweatherman.SetStdoutThreshold(jwalterweatherman.LevelError)
|
||||
|
||||
case WarnLevel:
|
||||
jwalterweatherman.SetStdoutThreshold(jwalterweatherman.LevelWarn)
|
||||
|
||||
case InfoLevel:
|
||||
jwalterweatherman.SetStdoutThreshold(jwalterweatherman.LevelInfo)
|
||||
|
||||
case DebugLevel:
|
||||
jwalterweatherman.SetStdoutThreshold(jwalterweatherman.LevelDebug)
|
||||
|
||||
case NilLevel:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// GetLevelString return a valid Level Type matching the given string parameter. If the given parameter don't represent a valid level, the InfoLevel will be return.
|
||||
/*
|
||||
level the string representation of a Level type
|
||||
*/
|
||||
func GetLevelString(level string) Level {
|
||||
switch strings.ToLower(level) {
|
||||
func GetLevelString(l string) Level {
|
||||
switch strings.ToLower(l) {
|
||||
case strings.ToLower(PanicLevel.String()):
|
||||
return PanicLevel
|
||||
|
||||
@@ -207,14 +92,14 @@ func GetLevelString(level string) Level {
|
||||
}
|
||||
|
||||
// Uint8 Convert the current Level type to a uint8 value. E.g. FatalLevel becomes 1.
|
||||
func (level Level) Uint8() uint8 {
|
||||
return uint8(level)
|
||||
func (l Level) Uint8() uint8 {
|
||||
return uint8(l)
|
||||
}
|
||||
|
||||
// String Convert the current Level type to a string. E.g. PanicLevel becomes "Critical Error".
|
||||
func (level Level) String() string {
|
||||
func (l Level) String() string {
|
||||
//nolint exhaustive
|
||||
switch level {
|
||||
switch l {
|
||||
case DebugLevel:
|
||||
return "Debug"
|
||||
case InfoLevel:
|
||||
@@ -234,244 +119,21 @@ func (level Level) String() string {
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
// Log Simple function to log directly the given message with the attached log Level.
|
||||
/*
|
||||
message a string message to be logged with the attached log Level
|
||||
*/
|
||||
func (level Level) Log(message string) {
|
||||
level.logDetails(message, nil, nil, nil)
|
||||
}
|
||||
|
||||
// Logf Simple function to log (to the attached log Level) with a fmt function a given pattern and arguments in parameters.
|
||||
/*
|
||||
format a string pattern for fmt function
|
||||
args a list of interface to match the references in the pattern
|
||||
*/
|
||||
func (level Level) Logf(format string, args ...interface{}) {
|
||||
level.logDetails(fmt.Sprintf(format, args...), nil, nil, nil)
|
||||
}
|
||||
|
||||
// LogData Simple function to log directly the given message with given data with the attached log Level.
|
||||
/*
|
||||
message a string message to be logged with the attached log Level
|
||||
data an interface of data to be logged with the message. (In Text format, the data will be json marshaled)
|
||||
*/
|
||||
func (level Level) LogData(message string, data interface{}) {
|
||||
level.logDetails(message, data, nil, nil)
|
||||
}
|
||||
|
||||
// WithFields Simple function to log directly the given message with given fields with the attached log Level.
|
||||
/*
|
||||
message a string message to be logged with the attached log Level
|
||||
fields a map of string key and interfaces value for a complete list of field ("field name" => value interface)
|
||||
*/
|
||||
func (level Level) WithFields(message string, fields map[string]interface{}) {
|
||||
level.logDetails(message, nil, nil, fields)
|
||||
}
|
||||
|
||||
// LogError Simple function to log directly the given error with the attached log Level.
|
||||
//
|
||||
// How iot works :
|
||||
// + when the err is a valid error, this function will :
|
||||
// +--- log the Error with the attached log Level
|
||||
// +--- return true
|
||||
// + when the err is nil, this function will :
|
||||
// +--- return false
|
||||
/*
|
||||
err an error object message to be logged with the attached log Level
|
||||
*/
|
||||
func (level Level) LogError(err error) bool {
|
||||
return level.LogGinErrorCtx(NilLevel, "", err, nil)
|
||||
}
|
||||
|
||||
// LogErrorCtx Function to test, log and inform about the given error object.
|
||||
//
|
||||
// How iot works :
|
||||
// + when the err is a valid error, this function will :
|
||||
// +--- log the Error with the attached log Level
|
||||
// +--- return true
|
||||
// + when the err is nil, this function will :
|
||||
// +--- use the levelElse if valid to inform with context there is no error found
|
||||
// +--- return false
|
||||
/*
|
||||
levelElse level used if the err is nil before returning a False result
|
||||
context a string for the context of the current test of the error
|
||||
err a error object to be log with the attached log level before return true, if the err is nil, the levelElse is used to log there are no error and return false
|
||||
*/
|
||||
func (level Level) LogErrorCtx(levelElse Level, context string, err error) bool {
|
||||
return level.LogGinErrorCtx(levelElse, context, err, nil)
|
||||
}
|
||||
|
||||
// LogErrorCtxf Function to test, log and inform about the given error object, but with a context based on a pattern and matching args.
|
||||
//
|
||||
// How iot works :
|
||||
// + when the err is a valid error, this function will :
|
||||
// +--- log the Error with the attached log Level
|
||||
// +--- return true
|
||||
// + when the err is nil, this function will :
|
||||
// +--- use the levelElse if valid to inform with context there is no error found
|
||||
// +--- return false
|
||||
/*
|
||||
levelElse level used if the err is nil before returning a False result
|
||||
contextPattern a pattern string for the context of the current test of the error. This string will be used in a fmt function as pattern string
|
||||
err a error object to be log with the attached log level before return true, if the err is nil, the levelElse is used to log there are no error and return false
|
||||
args a list of interface for the context of the current test of the error. This list of interface will be used in a fmt function as the matching args for the pattern string
|
||||
*/
|
||||
func (level Level) LogErrorCtxf(levelElse Level, contextPattern string, err error, args ...interface{}) bool {
|
||||
return level.LogGinErrorCtx(levelElse, fmt.Sprintf(contextPattern, args...), err, nil)
|
||||
}
|
||||
|
||||
// LogGinErrorCtxf Function to test, log and inform about the given error object, but with a context based on a couple of pattern and matching args.
|
||||
// This function will also add an Gin Tonic Error if the c parameters is a valid GinTonic Context reference.
|
||||
//
|
||||
// How iot works :
|
||||
// + when the err is a valid error, this function will :
|
||||
// +--- log the Error with the attached log Level
|
||||
// +--- if the Context Gin Tonic is valid, add the Error into this context
|
||||
// +--- return true
|
||||
// + when the err is nil, this function will :
|
||||
// +--- use the levelElse if valid to inform with context there is no error found
|
||||
// +--- return false
|
||||
/*
|
||||
levelElse level used if the err is nil before returning a False result
|
||||
contextPattern a pattern string for the context of the current test of the error. This string will be used in a fmt function as pattern string
|
||||
err a error object to be log with the attached log level before return true, if the err is nil, the levelElse is used to log there are no error and return false
|
||||
c a valid Go GinTonic Context reference to add current error to the Gin Tonic Error Context
|
||||
args a list of interface for the context of the current test of the error. This list of interface will be used in a fmt function as the matching args for the pattern string
|
||||
*/
|
||||
func (level Level) LogGinErrorCtxf(levelElse Level, contextPattern string, err error, c *gin.Context, args ...interface{}) bool {
|
||||
return level.LogGinErrorCtx(levelElse, fmt.Sprintf(contextPattern, args...), err, c)
|
||||
}
|
||||
|
||||
// LogGinErrorCtx Function to test, log and inform about the given error object.
|
||||
// This function will also add an Gin Tonic Error if the c parameters is a valid GinTonic Context reference.
|
||||
//
|
||||
// How iot works :
|
||||
// + when the err is a valid error, this function will :
|
||||
// +--- log the Error with the attached log Level
|
||||
// +--- if the Context Gin Tonic is valid, add the Error into this context
|
||||
// +--- return true
|
||||
// + when the err is nil, this function will :
|
||||
// +--- use the levelElse if valid to inform with context there is no error found
|
||||
// +--- return false
|
||||
/*
|
||||
levelElse level used if the err is nil before returning a False result
|
||||
context a string for the context of the current test of the error
|
||||
err a error object to be log with the attached log level before return true, if the err is nil, the levelElse is used to log there are no error and return false
|
||||
c a valid Go GinTonic Context reference to add current error to the Gin Tonic Error Context.
|
||||
*/
|
||||
func (level Level) LogGinErrorCtx(levelElse Level, context string, err error, c *gin.Context) bool {
|
||||
if err != nil {
|
||||
level.logDetails(fmt.Sprintf("KO : %s", context), nil, err, nil)
|
||||
ginTonicAddError(c, err)
|
||||
return true
|
||||
} else if proceed(levelElse) {
|
||||
levelElse.logDetails(fmt.Sprintf("OK : %s", context), nil, err, nil)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (level Level) logDetails(message string, data interface{}, err error, fields logrus.Fields) {
|
||||
if !proceed(level) {
|
||||
return
|
||||
}
|
||||
|
||||
var tags = make(map[string]interface{})
|
||||
|
||||
if enableGID {
|
||||
tags[tagStack] = getGID()
|
||||
}
|
||||
|
||||
if timestamp {
|
||||
tags[tagTime] = time.Now().Format(time.RFC3339Nano)
|
||||
}
|
||||
|
||||
tags[tagTime] = level.String()
|
||||
|
||||
if filetrace && GetCurrentLevel() == DebugLevel {
|
||||
frame := getFrame()
|
||||
tags[tagCaller] = frame.Function
|
||||
tags[tagFile] = filterPath(frame.File)
|
||||
tags[tagLine] = frame.Line
|
||||
}
|
||||
|
||||
tags[tagMsg] = message
|
||||
tags[tagErr] = err
|
||||
tags[tagData] = data
|
||||
|
||||
var (
|
||||
ent = logrus.NewEntry(logrus.StandardLogger())
|
||||
msg string
|
||||
)
|
||||
|
||||
if fields != nil && len(fields) > 0 {
|
||||
ent.WithFields(fields)
|
||||
}
|
||||
|
||||
//nolint exhaustive
|
||||
switch curFormat {
|
||||
case TextFormat:
|
||||
if _, ok := tags[tagStack]; ok {
|
||||
msg += fmt.Sprintf("[%d] ", tags[tagStack])
|
||||
}
|
||||
|
||||
if _, ok := tags[tagCaller]; ok {
|
||||
msg += fmt.Sprintf("[%s] ", tags[tagCaller])
|
||||
}
|
||||
|
||||
var line string
|
||||
if _, ok := tags[tagLine]; ok {
|
||||
line = fmt.Sprintf("(%d) ", tags[tagLine])
|
||||
}
|
||||
|
||||
if _, ok := tags[tagFile]; ok || len(line) > 0 {
|
||||
msg += fmt.Sprintf("[%s%s] ", line, tags[tagFile])
|
||||
}
|
||||
|
||||
msg += fmt.Sprintf("%s", tags[tagMsg])
|
||||
|
||||
if tags[tagErr] != nil {
|
||||
msg += fmt.Sprintf(" -- err : %v", err)
|
||||
}
|
||||
|
||||
if tags[tagData] != nil {
|
||||
if str, err := json.MarshalIndent(data, "", " "); err == nil {
|
||||
msg += fmt.Sprintf(" -- data : \n%s", string(str))
|
||||
} else {
|
||||
msg += fmt.Sprintf(" -- data : %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
case JsonFormat:
|
||||
ent.WithFields(tags)
|
||||
msg = tags[tagMsg].(string)
|
||||
|
||||
case nilFormat:
|
||||
return
|
||||
}
|
||||
|
||||
//nolint exhaustive
|
||||
switch level {
|
||||
case NilLevel:
|
||||
return
|
||||
|
||||
func (l Level) Logrus() logrus.Level {
|
||||
switch l {
|
||||
case DebugLevel:
|
||||
ent.Debugln(msg)
|
||||
|
||||
return logrus.DebugLevel
|
||||
case InfoLevel:
|
||||
ent.Infoln(msg)
|
||||
|
||||
return logrus.InfoLevel
|
||||
case WarnLevel:
|
||||
ent.Warnln(msg)
|
||||
|
||||
return logrus.WarnLevel
|
||||
case ErrorLevel:
|
||||
ent.Errorln(msg)
|
||||
|
||||
return logrus.ErrorLevel
|
||||
case FatalLevel:
|
||||
ent.Fatalln(msg)
|
||||
|
||||
return logrus.FatalLevel
|
||||
case PanicLevel:
|
||||
ent.Panicln(msg)
|
||||
return logrus.PanicLevel
|
||||
default:
|
||||
return math.MaxInt32
|
||||
}
|
||||
}
|
||||
|
||||
119
logger/log.go
Normal file
119
logger/log.go
Normal file
@@ -0,0 +1,119 @@
|
||||
/***********************************************************************************************************************
|
||||
*
|
||||
* 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 logger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (l logger) Debug(message string, data interface{}, args ...interface{}) {
|
||||
l.newEntry(DebugLevel, fmt.Sprintf(message, args...), nil, nil, data).Log()
|
||||
}
|
||||
|
||||
func (l logger) Info(message string, data interface{}, args ...interface{}) {
|
||||
l.newEntry(InfoLevel, fmt.Sprintf(message, args...), nil, nil, data).Log()
|
||||
}
|
||||
|
||||
func (l logger) Warning(message string, data interface{}, args ...interface{}) {
|
||||
l.newEntry(WarnLevel, fmt.Sprintf(message, args...), nil, nil, data).Log()
|
||||
}
|
||||
|
||||
func (l logger) Error(message string, data interface{}, args ...interface{}) {
|
||||
l.newEntry(ErrorLevel, fmt.Sprintf(message, args...), nil, nil, data).Log()
|
||||
}
|
||||
|
||||
func (l logger) Fatal(message string, data interface{}, args ...interface{}) {
|
||||
l.newEntry(FatalLevel, fmt.Sprintf(message, args...), nil, nil, data).Log()
|
||||
}
|
||||
|
||||
func (l logger) Panic(message string, data interface{}, args ...interface{}) {
|
||||
l.newEntry(PanicLevel, fmt.Sprintf(message, args...), nil, nil, data).Log()
|
||||
}
|
||||
|
||||
func (l logger) LogDetails(lvl Level, message string, data interface{}, err []error, fields Fields, args ...interface{}) {
|
||||
l.newEntry(lvl, fmt.Sprintf(message, args...), err, fields, data).Log()
|
||||
}
|
||||
|
||||
func (l logger) CheckError(lvlKO, lvlOK Level, message string, data interface{}, err []error, fields Fields, args ...interface{}) bool {
|
||||
ent := l.newEntry(lvlKO, fmt.Sprintf(message, args...), err, fields, data)
|
||||
return ent.Check(lvlOK)
|
||||
}
|
||||
|
||||
func (l logger) Entry(lvl Level, message string, args ...interface{}) *Entry {
|
||||
return l.newEntry(lvl, fmt.Sprintf(message, args...), nil, nil, nil)
|
||||
}
|
||||
|
||||
func (l logger) newEntry(lvl Level, message string, err []error, fields Fields, data interface{}) *Entry {
|
||||
opt := l.GetOptions()
|
||||
cLv := l.GetLevel()
|
||||
|
||||
if cLv == NilLevel || lvl > cLv {
|
||||
return &Entry{}
|
||||
}
|
||||
|
||||
var ent = &Entry{
|
||||
log: l.getLog,
|
||||
Time: time.Time{},
|
||||
Level: lvl,
|
||||
Stack: 0,
|
||||
Caller: "",
|
||||
File: "",
|
||||
Line: 0,
|
||||
Message: message,
|
||||
Error: err,
|
||||
Data: data,
|
||||
Fields: NewFields().Merge(l.GetFields()).Merge(fields),
|
||||
}
|
||||
|
||||
if !opt.DisableTimestamp {
|
||||
ent.Time = time.Now()
|
||||
}
|
||||
|
||||
if !opt.DisableStack {
|
||||
ent.Stack = l.getStack()
|
||||
}
|
||||
|
||||
if opt.EnableTrace {
|
||||
frm := l.getCaller()
|
||||
|
||||
if frm.Function != "" {
|
||||
ent.Caller = frm.Function
|
||||
}
|
||||
|
||||
if frm.File != "" {
|
||||
ent.File = l.filterPath(frm.File)
|
||||
}
|
||||
|
||||
if frm.Line > 0 {
|
||||
ent.Line = uint32(frm.Line)
|
||||
}
|
||||
}
|
||||
|
||||
return ent
|
||||
}
|
||||
273
logger/logger.go
273
logger/logger.go
@@ -1,223 +1,106 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 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.
|
||||
*/
|
||||
/***********************************************************************************************************************
|
||||
*
|
||||
* 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 logger
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"log"
|
||||
"path"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/hashicorp/go-hclog"
|
||||
jww "github.com/spf13/jwalterweatherman"
|
||||
)
|
||||
|
||||
const (
|
||||
tagStack = "stack"
|
||||
tagTime = "time"
|
||||
tagCaller = "func"
|
||||
tagFile = "file"
|
||||
tagLine = "line"
|
||||
tagMsg = "message"
|
||||
tagErr = "error"
|
||||
tagData = "data"
|
||||
)
|
||||
|
||||
var (
|
||||
currPkgs = path.Base(reflect.TypeOf(IOWriter{}).PkgPath())
|
||||
filterPkg = path.Clean(reflect.TypeOf(IOWriter{}).PkgPath())
|
||||
modeColor = true
|
||||
timestamp = true
|
||||
filetrace = false
|
||||
enableGID = false
|
||||
enableVPR = true
|
||||
)
|
||||
|
||||
func init() {
|
||||
if i := strings.LastIndex(filterPkg, "/vendor/"); i != -1 {
|
||||
filterPkg = filterPkg[:i+1]
|
||||
}
|
||||
func (l *logger) GetStdLogger(lvl Level, logFlags int) *log.Logger {
|
||||
l.SetIOWriterLevel(lvl)
|
||||
return log.New(l, "", logFlags)
|
||||
}
|
||||
|
||||
// GetLogger return a golang log.logger instance linked with this main logger.
|
||||
// This function is useful to keep the format, mode, color, output... same as current config.
|
||||
// - msgPrefixPattern a pattern prefix to identify or comment all message passed throw this log.logger instance.
|
||||
// - msgPrefixArgs a list of interface to apply on pattern with a fmt function.
|
||||
func GetLogger(lvl Level, logFlags int, msgPrefixPattern string, msgPrefixArgs ...interface{}) *log.Logger {
|
||||
return log.New(GetIOWriter(lvl, msgPrefixPattern, msgPrefixArgs...), "", logFlags)
|
||||
}
|
||||
|
||||
// SetStdLogger force the default golang log.logger instance linked with this main logger.
|
||||
// This function is useful to keep the format, mode, color, output... same as current config.
|
||||
// - msgPrefixPattern a pattern prefix to identify or comment all message passed throw this log.logger instance.
|
||||
// - msgPrefixArgs a list of interface to apply on pattern with a fmt function.
|
||||
func SetStdLogger(lvl Level, logFlags int, msgPrefixPattern string, msgPrefixArgs ...interface{}) {
|
||||
log.SetOutput(GetIOWriter(lvl, msgPrefixPattern, msgPrefixArgs...))
|
||||
func (l *logger) SetStdLogger(lvl Level, logFlags int) {
|
||||
l.SetIOWriterLevel(lvl)
|
||||
log.SetOutput(l)
|
||||
log.SetPrefix("")
|
||||
log.SetFlags(logFlags)
|
||||
}
|
||||
|
||||
// AddGID Reconfigure the current logger to add or not the thread GID before each message.
|
||||
func AddGID(enable bool) {
|
||||
enableGID = enable
|
||||
}
|
||||
|
||||
// Timestamp Reconfigure the current logger to add or not the timestamp before each message.
|
||||
func Timestamp(enable bool) {
|
||||
timestamp = enable
|
||||
}
|
||||
|
||||
// IsTimeStamp will return true if timestamp is added or not on log message
|
||||
func IsTimeStamp() bool {
|
||||
return timestamp
|
||||
}
|
||||
|
||||
// FileTrace Reconfigure the current logger to add or not the origin file/line of each message.
|
||||
// This option is apply for all message except info message.
|
||||
func FileTrace(enable bool) {
|
||||
filetrace = enable
|
||||
setViperLogTrace()
|
||||
}
|
||||
|
||||
// IsFileTrace will return true if trace is added or not on log message
|
||||
func IsFileTrace() bool {
|
||||
return filetrace
|
||||
}
|
||||
|
||||
// ModeColor will reconfigure the current logger to use or not color in messages format.
|
||||
// This apply only for next message and only for TextFormat.
|
||||
func ModeColor(enable bool) {
|
||||
modeColor = enable
|
||||
updateFormatter(nilFormat)
|
||||
}
|
||||
|
||||
// IsModeColor will return true if color is configured on log message
|
||||
func IsModeColor() bool {
|
||||
return modeColor
|
||||
}
|
||||
|
||||
// EnableColor Reconfigure the current logger to use color in messages format.
|
||||
// This apply only for next message and only for TextFormat.
|
||||
// @deprecated use ModeColor(true)
|
||||
func EnableColor() {
|
||||
ModeColor(true)
|
||||
}
|
||||
|
||||
// DisableColor Reconfigure the current logger to not use color in messages format.
|
||||
// This apply only for next message and only for TextFormat.
|
||||
// @deprecated use Color(false)
|
||||
func DisableColor() {
|
||||
ModeColor(false)
|
||||
}
|
||||
|
||||
// EnableViperLog enable or not the Gin Logger configuration.
|
||||
func EnableViperLog(enable bool) {
|
||||
enableVPR = enable
|
||||
setViperLogTrace()
|
||||
}
|
||||
|
||||
// SetTracePathFilter customize the filter apply to filepath on trace.
|
||||
func SetTracePathFilter(path string) {
|
||||
filterPkg = path
|
||||
}
|
||||
|
||||
func getFrame() runtime.Frame {
|
||||
// Set size to targetFrameIndex+2 to ensure we have room for one more caller than we need.
|
||||
programCounters := make([]uintptr, 10, 255)
|
||||
n := runtime.Callers(1, programCounters)
|
||||
|
||||
if n > 0 {
|
||||
frames := runtime.CallersFrames(programCounters[:n])
|
||||
more := true
|
||||
|
||||
for more {
|
||||
func (l *logger) SetSPF13Level(lvl Level, log *jww.Notepad) {
|
||||
var (
|
||||
frame runtime.Frame
|
||||
fOutLog func(handle io.Writer)
|
||||
fLvl func(threshold jww.Threshold)
|
||||
)
|
||||
|
||||
frame, more = frames.Next()
|
||||
|
||||
if strings.Contains(frame.Function, currPkgs) {
|
||||
continue
|
||||
if log == nil {
|
||||
jww.SetStdoutOutput(io.Discard)
|
||||
fOutLog = jww.SetLogOutput
|
||||
fLvl = jww.SetLogThreshold
|
||||
} else {
|
||||
fOutLog = log.SetLogOutput
|
||||
fLvl = log.SetLogThreshold
|
||||
}
|
||||
|
||||
return frame
|
||||
}
|
||||
switch lvl {
|
||||
case NilLevel:
|
||||
fOutLog(io.Discard)
|
||||
fLvl(jww.LevelCritical)
|
||||
|
||||
case DebugLevel:
|
||||
fOutLog(l)
|
||||
if opt := l.GetOptions(); opt.EnableTrace {
|
||||
fLvl(jww.LevelTrace)
|
||||
} else {
|
||||
fLvl(jww.LevelDebug)
|
||||
}
|
||||
|
||||
return runtime.Frame{Function: "unknown", File: "unknown", Line: 0}
|
||||
}
|
||||
|
||||
func getGID() uint64 {
|
||||
b := make([]byte, 64)
|
||||
|
||||
b = b[:runtime.Stack(b, false)]
|
||||
b = bytes.TrimPrefix(b, []byte("goroutine "))
|
||||
b = b[:bytes.IndexByte(b, ' ')]
|
||||
|
||||
//nolint #nosec
|
||||
/* #nosec */
|
||||
n, _ := strconv.ParseUint(string(b), 10, 64)
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
func ginTonicAddError(c *gin.Context, err error) {
|
||||
if c != nil && err != nil {
|
||||
_ = c.Error(err)
|
||||
case InfoLevel:
|
||||
fOutLog(l)
|
||||
fLvl(jww.LevelInfo)
|
||||
case WarnLevel:
|
||||
fOutLog(l)
|
||||
fLvl(jww.LevelWarn)
|
||||
case ErrorLevel:
|
||||
fOutLog(l)
|
||||
fLvl(jww.LevelError)
|
||||
case FatalLevel:
|
||||
fOutLog(l)
|
||||
fLvl(jww.LevelFatal)
|
||||
case PanicLevel:
|
||||
fOutLog(l)
|
||||
fLvl(jww.LevelCritical)
|
||||
}
|
||||
}
|
||||
|
||||
func proceed(lvl Level) bool {
|
||||
return lvl != NilLevel && lvl <= GetCurrentLevel()
|
||||
func (l *logger) SetHashicorpHCLog() {
|
||||
hclog.SetDefault(&_hclog{
|
||||
l: l,
|
||||
})
|
||||
}
|
||||
|
||||
func filterPath(pathname string) string {
|
||||
var (
|
||||
filterMod = "/pkg/mod/"
|
||||
filterVendor = "/vendor/"
|
||||
)
|
||||
|
||||
if i := strings.LastIndex(pathname, filterMod); i != -1 {
|
||||
i = i + len(filterMod)
|
||||
pathname = pathname[i:]
|
||||
func (l *logger) NewHashicorpHCLog() hclog.Logger {
|
||||
return &_hclog{
|
||||
l: l,
|
||||
}
|
||||
|
||||
if i := strings.LastIndex(pathname, filterPkg); i != -1 {
|
||||
i = i + len(filterPkg)
|
||||
pathname = pathname[i:]
|
||||
}
|
||||
|
||||
if i := strings.LastIndex(pathname, filterVendor); i != -1 {
|
||||
i = i + len(filterVendor)
|
||||
pathname = pathname[i:]
|
||||
}
|
||||
|
||||
pathname = path.Clean(pathname)
|
||||
|
||||
return strings.Trim(pathname, "/")
|
||||
}
|
||||
|
||||
84
logger/logger_suite_test.go
Normal file
84
logger/logger_suite_test.go
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2020 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 logger_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/nabbar/golib/ioutils"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var (
|
||||
ctx context.Context
|
||||
cnl context.CancelFunc
|
||||
)
|
||||
|
||||
/*
|
||||
Using https://onsi.github.io/ginkgo/
|
||||
Running with $> ginkgo -cover .
|
||||
*/
|
||||
|
||||
func TestGolibAwsHelper(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Logger Helper Suite")
|
||||
}
|
||||
|
||||
var _ = BeforeSuite(func() {
|
||||
ctx, cnl = context.WithCancel(context.Background())
|
||||
})
|
||||
|
||||
var _ = AfterSuite(func() {
|
||||
cnl()
|
||||
})
|
||||
|
||||
func GetContext() context.Context {
|
||||
return ctx
|
||||
}
|
||||
|
||||
func GetTempFile() (string, error) {
|
||||
hdf, err := ioutils.NewFileProgressTemp()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = hdf.Close()
|
||||
}()
|
||||
|
||||
return hdf.FilePath(), nil
|
||||
}
|
||||
|
||||
func DelTempFile(filepath string) error {
|
||||
if _, err := os.Stat(filepath); err != nil {
|
||||
return err
|
||||
}
|
||||
return os.RemoveAll(filepath)
|
||||
}
|
||||
440
logger/model.go
Normal file
440
logger/model.go
Normal file
@@ -0,0 +1,440 @@
|
||||
/***********************************************************************************************************************
|
||||
*
|
||||
* 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 logger
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
_TraceFilterMod = "/pkg/mod/"
|
||||
_TraceFilterVendor = "/vendor/"
|
||||
)
|
||||
|
||||
var _selfPackage = path.Base(reflect.TypeOf(logger{}).PkgPath())
|
||||
|
||||
type logger struct {
|
||||
x context.Context
|
||||
n context.CancelFunc
|
||||
m sync.Mutex
|
||||
l *atomic.Value //current level set for this logger
|
||||
o *atomic.Value //options
|
||||
s *atomic.Value //logrus logger
|
||||
f *atomic.Value //defaults fields
|
||||
w *atomic.Value //io writer level
|
||||
c *atomic.Value
|
||||
}
|
||||
|
||||
func (l *logger) defaultFormatter(opt *Options) *logrus.TextFormatter {
|
||||
if opt == nil {
|
||||
opt = &Options{}
|
||||
}
|
||||
|
||||
return &logrus.TextFormatter{
|
||||
ForceColors: false,
|
||||
DisableColors: opt.DisableColor,
|
||||
ForceQuote: false,
|
||||
DisableQuote: false,
|
||||
EnvironmentOverrideColors: false,
|
||||
DisableTimestamp: true,
|
||||
FullTimestamp: false,
|
||||
TimestampFormat: time.RFC3339,
|
||||
DisableSorting: false,
|
||||
SortingFunc: nil,
|
||||
DisableLevelTruncation: false,
|
||||
PadLevelText: true,
|
||||
QuoteEmptyFields: true,
|
||||
FieldMap: nil,
|
||||
CallerPrettyfier: nil,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *logger) closeAdd(clo io.Closer) {
|
||||
lst := append(l.closeGet(), clo)
|
||||
|
||||
if l.c == nil {
|
||||
l.c = new(atomic.Value)
|
||||
}
|
||||
|
||||
l.c.Store(lst)
|
||||
}
|
||||
|
||||
func (l *logger) closeClean() {
|
||||
if l == nil {
|
||||
return
|
||||
}
|
||||
|
||||
l.m.Lock()
|
||||
defer l.m.Unlock()
|
||||
|
||||
if l.c == nil {
|
||||
l.c = new(atomic.Value)
|
||||
}
|
||||
|
||||
l.c.Store(make([]io.Closer, 0))
|
||||
}
|
||||
|
||||
func (l *logger) closeGet() []io.Closer {
|
||||
res := make([]io.Closer, 0)
|
||||
|
||||
if l == nil {
|
||||
return res
|
||||
}
|
||||
|
||||
if l.c == nil {
|
||||
l.c = new(atomic.Value)
|
||||
}
|
||||
|
||||
if i := l.c.Load(); i == nil {
|
||||
return res
|
||||
} else if o, ok := i.([]io.Closer); ok {
|
||||
return o
|
||||
}
|
||||
|
||||
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) {
|
||||
c := &logger{
|
||||
x: nil,
|
||||
n: nil,
|
||||
m: sync.Mutex{},
|
||||
l: new(atomic.Value),
|
||||
o: new(atomic.Value),
|
||||
s: new(atomic.Value),
|
||||
f: new(atomic.Value),
|
||||
w: new(atomic.Value),
|
||||
c: new(atomic.Value),
|
||||
}
|
||||
|
||||
c.SetLevel(l.GetLevel())
|
||||
|
||||
if err := c.SetOptions(ctx, l.GetOptions()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (l *logger) setLoggerMutex(lvl Level) {
|
||||
if l == nil {
|
||||
return
|
||||
}
|
||||
|
||||
l.m.Lock()
|
||||
defer l.m.Unlock()
|
||||
|
||||
if l.l == nil {
|
||||
l.l = new(atomic.Value)
|
||||
}
|
||||
|
||||
l.l.Store(lvl)
|
||||
}
|
||||
|
||||
func (l *logger) SetLevel(lvl Level) {
|
||||
l.setLoggerMutex(lvl)
|
||||
|
||||
if opt := l.GetOptions(); opt.change != nil {
|
||||
opt.change(l)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *logger) GetLevel() Level {
|
||||
if l == nil {
|
||||
return NilLevel
|
||||
}
|
||||
|
||||
l.m.Lock()
|
||||
defer l.m.Unlock()
|
||||
|
||||
if l.l == nil {
|
||||
l.l = new(atomic.Value)
|
||||
}
|
||||
|
||||
if i := l.l.Load(); i == nil {
|
||||
return NilLevel
|
||||
} else if o, ok := i.(Level); ok {
|
||||
return o
|
||||
}
|
||||
|
||||
return NilLevel
|
||||
}
|
||||
|
||||
func (l *logger) SetFields(field Fields) {
|
||||
if l == nil {
|
||||
return
|
||||
}
|
||||
|
||||
l.m.Lock()
|
||||
defer l.m.Unlock()
|
||||
|
||||
if l.f == nil {
|
||||
l.f = new(atomic.Value)
|
||||
}
|
||||
|
||||
l.f.Store(field)
|
||||
}
|
||||
|
||||
func (l *logger) GetFields() Fields {
|
||||
if l == nil {
|
||||
return NewFields()
|
||||
}
|
||||
|
||||
l.m.Lock()
|
||||
defer l.m.Unlock()
|
||||
|
||||
if l.f == nil {
|
||||
l.f = new(atomic.Value)
|
||||
}
|
||||
|
||||
if i := l.f.Load(); i == nil {
|
||||
return NewFields()
|
||||
} else if o, ok := i.(Fields); ok {
|
||||
return o
|
||||
}
|
||||
|
||||
return NewFields()
|
||||
}
|
||||
|
||||
func (l *logger) setOptionsMutex(ctx context.Context, opt *Options) error {
|
||||
l.setOptions(opt)
|
||||
opt = l.GetOptions()
|
||||
|
||||
_ = l.Close()
|
||||
l.x, l.n = context.WithCancel(ctx)
|
||||
|
||||
l.m.Lock()
|
||||
defer l.m.Unlock()
|
||||
|
||||
obj := logrus.New()
|
||||
obj.SetFormatter(l.defaultFormatter(opt))
|
||||
obj.SetOutput(ioutil.Discard) // Send all logs to nowhere by default
|
||||
|
||||
if !opt.DisableStandard {
|
||||
obj.AddHook(NewHookStandard(*opt, os.Stdout, []logrus.Level{
|
||||
logrus.InfoLevel,
|
||||
logrus.DebugLevel,
|
||||
logrus.TraceLevel,
|
||||
}))
|
||||
|
||||
obj.AddHook(NewHookStandard(*opt, os.Stderr, []logrus.Level{
|
||||
logrus.PanicLevel,
|
||||
logrus.FatalLevel,
|
||||
logrus.ErrorLevel,
|
||||
logrus.WarnLevel,
|
||||
}))
|
||||
}
|
||||
|
||||
if len(opt.LogFile) > 0 {
|
||||
for _, fopt := range opt.LogFile {
|
||||
if hook, err := NewHookFile(fopt); err != nil {
|
||||
return err
|
||||
} else {
|
||||
l.closeAdd(hook)
|
||||
hook.RegisterHook(obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(opt.LogSyslog) > 0 {
|
||||
for _, lopt := range opt.LogSyslog {
|
||||
if hook, err := NewHookSyslog(lopt); err != nil {
|
||||
return err
|
||||
} else {
|
||||
l.closeAdd(hook)
|
||||
hook.RegisterHook(obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
||||
if opt.init != nil {
|
||||
opt.init(l)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *logger) GetOptions() *Options {
|
||||
if l == nil {
|
||||
return &Options{}
|
||||
}
|
||||
|
||||
l.m.Lock()
|
||||
defer l.m.Unlock()
|
||||
|
||||
if l.o == nil {
|
||||
l.o = new(atomic.Value)
|
||||
}
|
||||
|
||||
if i := l.o.Load(); i == nil {
|
||||
return &Options{}
|
||||
} else if o, ok := i.(*Options); ok {
|
||||
return o
|
||||
}
|
||||
|
||||
return &Options{}
|
||||
}
|
||||
|
||||
func (l *logger) setOptions(opt *Options) {
|
||||
if l == nil {
|
||||
return
|
||||
}
|
||||
|
||||
l.m.Lock()
|
||||
defer l.m.Unlock()
|
||||
|
||||
if l.o == nil {
|
||||
l.o = new(atomic.Value)
|
||||
}
|
||||
|
||||
l.o.Store(opt)
|
||||
}
|
||||
|
||||
func (l *logger) getLog() *logrus.Logger {
|
||||
if l == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
l.m.Lock()
|
||||
defer l.m.Unlock()
|
||||
|
||||
if l.s == nil {
|
||||
l.s = new(atomic.Value)
|
||||
}
|
||||
|
||||
if i := l.s.Load(); i == nil {
|
||||
return nil
|
||||
} else if o, ok := i.(*logrus.Logger); !ok {
|
||||
return nil
|
||||
} else {
|
||||
return o
|
||||
}
|
||||
}
|
||||
|
||||
func (l *logger) getStack() uint64 {
|
||||
b := make([]byte, 64)
|
||||
|
||||
b = b[:runtime.Stack(b, false)]
|
||||
b = bytes.TrimPrefix(b, []byte("goroutine "))
|
||||
b = b[:bytes.IndexByte(b, ' ')]
|
||||
|
||||
//nolint #nosec
|
||||
/* #nosec */
|
||||
n, _ := strconv.ParseUint(string(b), 10, 64)
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
func (l *logger) getCaller() runtime.Frame {
|
||||
// Set size to targetFrameIndex+2 to ensure we have room for one more caller than we need.
|
||||
programCounters := make([]uintptr, 10, 255)
|
||||
n := runtime.Callers(1, programCounters)
|
||||
|
||||
if n > 0 {
|
||||
frames := runtime.CallersFrames(programCounters[:n])
|
||||
more := true
|
||||
|
||||
for more {
|
||||
var frame runtime.Frame
|
||||
frame, more = frames.Next()
|
||||
|
||||
if strings.Contains(frame.Function, _selfPackage) {
|
||||
continue
|
||||
}
|
||||
|
||||
return frame
|
||||
}
|
||||
}
|
||||
|
||||
return runtime.Frame{Function: "unknown", File: "unknown", Line: 0}
|
||||
}
|
||||
|
||||
func (l *logger) filterPath(pathname string) string {
|
||||
var ()
|
||||
|
||||
if i := strings.LastIndex(pathname, _TraceFilterMod); i != -1 {
|
||||
i = i + len(_TraceFilterMod)
|
||||
pathname = pathname[i:]
|
||||
}
|
||||
|
||||
if i := strings.LastIndex(pathname, _TraceFilterVendor); i != -1 {
|
||||
i = i + len(_TraceFilterVendor)
|
||||
pathname = pathname[i:]
|
||||
}
|
||||
|
||||
opt := l.GetOptions()
|
||||
|
||||
if opt.TraceFilter != "" {
|
||||
if i := strings.LastIndex(pathname, opt.TraceFilter); i != -1 {
|
||||
i = i + len(opt.TraceFilter)
|
||||
pathname = pathname[i:]
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Trim(path.Clean(pathname), "/")
|
||||
}
|
||||
153
logger/options.go
Normal file
153
logger/options.go
Normal file
@@ -0,0 +1,153 @@
|
||||
/***********************************************************************************************************************
|
||||
*
|
||||
* 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 logger
|
||||
|
||||
import (
|
||||
"log/syslog"
|
||||
"os"
|
||||
)
|
||||
|
||||
type FuncCustomConfig func(log Logger)
|
||||
|
||||
type NetworkType uint8
|
||||
|
||||
const (
|
||||
NetworkEmpty NetworkType = iota
|
||||
NetworkTCP
|
||||
NetworkUDP
|
||||
)
|
||||
|
||||
func (n NetworkType) String() string {
|
||||
switch n {
|
||||
case NetworkTCP:
|
||||
return "tcp"
|
||||
case NetworkUDP:
|
||||
return "udp"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
type OptionsFile struct {
|
||||
// LogLevel define the allowed level of log for this file.
|
||||
LogLevel []string
|
||||
|
||||
// Filepath define the file path for log to file.
|
||||
Filepath string
|
||||
|
||||
// Create define if the log file must exist or can create it.
|
||||
Create bool
|
||||
|
||||
// CreatePath define if the path of the log file must exist or can try to create it.
|
||||
CreatePath bool
|
||||
|
||||
// FileMode define mode to be used for the log file if the create it.
|
||||
FileMode os.FileMode
|
||||
|
||||
// PathMode define mode to be used for the path of the log file if create it.
|
||||
PathMode os.FileMode
|
||||
|
||||
// DisableStack allow to disable the goroutine id before each message.
|
||||
DisableStack bool
|
||||
|
||||
// DisableTimestamp allow to disable the timestamp before each message.
|
||||
DisableTimestamp bool
|
||||
|
||||
// EnableTrace allow to add the origin caller/file/line of each message.
|
||||
EnableTrace bool
|
||||
}
|
||||
|
||||
type OptionsSyslog struct {
|
||||
// LogLevel define the allowed level of log for this syslog.
|
||||
LogLevel []string
|
||||
|
||||
// Network define the network used to connect to this syslog.
|
||||
Network NetworkType
|
||||
|
||||
// Host define the remote syslog to use.
|
||||
// If Host and Network are empty, local syslog will be used.
|
||||
Host string
|
||||
|
||||
// Priority define the priority used for this syslog.
|
||||
Priority syslog.Priority
|
||||
|
||||
// Tag define the syslog tag used for log message.
|
||||
Tag string
|
||||
|
||||
// DisableStack allow to disable the goroutine id before each message.
|
||||
DisableStack bool
|
||||
|
||||
// DisableTimestamp allow to disable the timestamp before each message.
|
||||
DisableTimestamp bool
|
||||
|
||||
// EnableTrace allow to add the origin caller/file/line of each message.
|
||||
EnableTrace bool
|
||||
}
|
||||
|
||||
type Options struct {
|
||||
// DisableStandard allow to disable writing log to standard output stdout/stderr.
|
||||
DisableStandard bool
|
||||
|
||||
// DisableStack allow to disable the goroutine id before each message.
|
||||
DisableStack bool
|
||||
|
||||
// DisableTimestamp allow to disable the timestamp before each message.
|
||||
DisableTimestamp bool
|
||||
|
||||
// EnableTrace allow to add the origin caller/file/line of each message.
|
||||
EnableTrace bool
|
||||
|
||||
// TraceFilter define the path to clean for trace.
|
||||
TraceFilter string
|
||||
|
||||
// DisableColor define if color could be use or not in messages format.
|
||||
// If the running process is not a tty, no color will be used.
|
||||
DisableColor bool
|
||||
|
||||
// LogFile define a list of log file configuration to allow log to files.
|
||||
LogFile []OptionsFile
|
||||
|
||||
// LogSyslog define a list of syslog configuration to allow log to syslog.
|
||||
LogSyslog []OptionsSyslog
|
||||
|
||||
// custom function handler.
|
||||
init FuncCustomConfig
|
||||
change FuncCustomConfig
|
||||
}
|
||||
|
||||
// RegisterFuncUpdateLogger allow to register a function called when init or update of logger.
|
||||
// To clean function, just call RegisterFuncUpdateLogger with nil as param.
|
||||
func (o Options) RegisterFuncUpdateLogger(fct FuncCustomConfig) {
|
||||
o.init = fct
|
||||
}
|
||||
|
||||
// RegisterFuncUpdateLevel allow to register a function called when init or update level
|
||||
// To clean function, just call RegisterFuncUpdateLevel with nil as param.
|
||||
func (o Options) RegisterFuncUpdateLevel(fct FuncCustomConfig) {
|
||||
o.change = fct
|
||||
}
|
||||
@@ -76,17 +76,22 @@ var (
|
||||
)
|
||||
|
||||
func init() {
|
||||
liblog.EnableColor()
|
||||
liblog.SetLevel(liblog.DebugLevel)
|
||||
liblog.AddGID(true)
|
||||
liblog.FileTrace(true)
|
||||
liblog.SetFormat(liblog.TextFormat)
|
||||
liblog.Timestamp(true)
|
||||
|
||||
liberr.SetModeReturnError(liberr.ErrorReturnCodeErrorTraceFull)
|
||||
|
||||
ctx, cnl = context.WithCancel(context.Background())
|
||||
|
||||
liblog.SetLevel(liblog.DebugLevel)
|
||||
if err := liblog.GetDefault().SetOptions(ctx, &liblog.Options{
|
||||
DisableStandard: false,
|
||||
DisableStack: false,
|
||||
DisableTimestamp: false,
|
||||
EnableTrace: true,
|
||||
TraceFilter: "",
|
||||
DisableColor: false,
|
||||
}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
cfgPool = libsrv.PoolServerConfig{cfgSrv01, cfgSrv02, cfgSrv03}
|
||||
cfgPool.MapUpdate(func(cfg libsrv.ServerConfig) libsrv.ServerConfig {
|
||||
cfg.SetParentContext(func() context.Context {
|
||||
|
||||
@@ -52,14 +52,21 @@ var (
|
||||
)
|
||||
|
||||
func init() {
|
||||
liblog.EnableColor()
|
||||
liblog.AddGID(true)
|
||||
liblog.FileTrace(true)
|
||||
liblog.SetFormat(liblog.TextFormat)
|
||||
liblog.SetLevel(liblog.DebugLevel)
|
||||
liberr.SetModeReturnError(liberr.ErrorReturnCodeErrorTraceFull)
|
||||
|
||||
ctx, cnl = context.WithCancel(context.TODO())
|
||||
|
||||
liblog.SetLevel(liblog.DebugLevel)
|
||||
if err := liblog.GetDefault().SetOptions(ctx, &liblog.Options{
|
||||
DisableStandard: false,
|
||||
DisableStack: false,
|
||||
DisableTimestamp: false,
|
||||
EnableTrace: true,
|
||||
TraceFilter: "",
|
||||
DisableColor: false,
|
||||
}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
@@ -30,7 +30,6 @@ package main
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
@@ -69,38 +68,11 @@ var (
|
||||
|
||||
func init() {
|
||||
liberr.SetModeReturnError(liberr.ErrorReturnCodeErrorTraceFull)
|
||||
liblog.SetLevel(liblog.InfoLevel)
|
||||
liblog.AddGID(true)
|
||||
liblog.EnableColor()
|
||||
liblog.FileTrace(true)
|
||||
liblog.Timestamp(true)
|
||||
}
|
||||
|
||||
type EmptyStruct struct{}
|
||||
|
||||
func main() {
|
||||
if _, err := os.Stat(LoggerFile); err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||
panic(err)
|
||||
} else if err == nil {
|
||||
if err = os.Remove(LoggerFile); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
//nolint #gosec
|
||||
/* #nosec */
|
||||
if file, err := os.OpenFile(LoggerFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
liblog.SetOutput(file)
|
||||
defer func() {
|
||||
if file != nil {
|
||||
liblog.SetOutput(os.Stdout)
|
||||
_ = file.Close()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
ctx, cnl := context.WithCancel(context.Background())
|
||||
defer func() {
|
||||
if cnl != nil {
|
||||
@@ -108,6 +80,44 @@ func main() {
|
||||
}
|
||||
}()
|
||||
|
||||
log := liblog.New()
|
||||
log.SetLevel(liblog.InfoLevel)
|
||||
if err := log.SetOptions(ctx, &liblog.Options{
|
||||
DisableStandard: true,
|
||||
DisableStack: false,
|
||||
DisableTimestamp: false,
|
||||
EnableTrace: false,
|
||||
TraceFilter: "",
|
||||
DisableColor: false,
|
||||
LogFile: []liblog.OptionsFile{
|
||||
{
|
||||
LogLevel: []string{
|
||||
"panic",
|
||||
"fatal",
|
||||
"error",
|
||||
"warning",
|
||||
"info",
|
||||
"debug",
|
||||
},
|
||||
Filepath: LoggerFile,
|
||||
Create: true,
|
||||
CreatePath: true,
|
||||
FileMode: 0644,
|
||||
PathMode: 0755,
|
||||
DisableStack: false,
|
||||
DisableTimestamp: false,
|
||||
EnableTrace: true,
|
||||
},
|
||||
},
|
||||
}); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
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()
|
||||
|
||||
Reference in New Issue
Block a user