Package Logger:

- Rework logger
- Remove deprecated functions
- Split Logger to sub package (fields, level, config, ...)
- Optimize dependencies
- Rework Hookfile: fix error like FD still opened
- Rework Hooksyslog: use same model like Hookfile, use network/protocol instead of self lib
- Rework HookStd: use independent hook for std out & std err
- Fix std config make generic options for files & syslog
- Apply formatter to hook instead of main logger entry
- optimize code

Package ioutils:
- rework PathCheckCreate funct: optimize code & fix some error

Package Network:
- create sub package protocol for all network protocl use
- add encode function

Package httpcli:
- remove file network
- use package network/protocol instead of network file

Package archive:
- apply change following rework of logger

Package aws:
- apply change following rework of logger

Package cluster:
- apply change following rework of logger

Package cobra:
- apply change following rework of logger

Package Config Component:
- apply change following rework of logger to component log
- fix logger for monitoring
- fix component following fix of package request / monitoring

Package context:
- apply change following rework of logger

Package database:
- apply change following rework of logger

Package httpserver:
- apply change following rework of logger

Package ldap:
- apply change following rework of logger

Package monitor:
- apply change following rework of logger
- fix logger for monitoring
- fix minor bugs

Package nats:
- apply change following rework of logger

Package nutsdb:
- apply change following rework of logger

Package request:
- apply change following rework of logger
- fix minor bug
- fix missing logger for monitoring
- add one line for healthcheck (info or error)

Package router:
- apply change following rework of logger

Package static:
- apply change following rework of logger

Package status:
- apply change following rework of logger
- fix bug with mandatory component

Package viper:
- apply change following rework of logger

Other:
- bump dependencies
- github action workflow fix
This commit is contained in:
nabbar
2023-06-19 15:53:42 +02:00
parent abe84d7498
commit f31950daef
117 changed files with 4178 additions and 2487 deletions

View File

@@ -1,9 +1,5 @@
name: Go name: Go
env:
GOPATH: "/go"
GO111MODULE: "on"
on: on:
push: push:
branches: [ master ] branches: [ master ]
@@ -13,7 +9,6 @@ on:
jobs: jobs:
build: build:
name: Build
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -21,10 +16,12 @@ jobs:
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Set up Go 1.x - name: Set up Go 1.x
uses: actions/setup-go@v2 uses: actions/setup-go@v4
with: with:
go-version: '>=1.18.0' go-version: '>=1.20'
check-latest: true
- name: Check Go Version
run: go version
- name: Link workspace with GOPATH - name: Link workspace with GOPATH
continue-on-error: false continue-on-error: false

View File

@@ -37,7 +37,6 @@ import (
libzip "github.com/nabbar/golib/archive/zip" libzip "github.com/nabbar/golib/archive/zip"
liberr "github.com/nabbar/golib/errors" liberr "github.com/nabbar/golib/errors"
libiot "github.com/nabbar/golib/ioutils" libiot "github.com/nabbar/golib/ioutils"
liblog "github.com/nabbar/golib/logger"
) )
type ArchiveType uint8 type ArchiveType uint8
@@ -125,33 +124,22 @@ func ExtractAll(src libiot.FileProgress, originalName, outputPath string, defaul
return ErrorFileOpen.Error(err) return ErrorFileOpen.Error(err)
} }
liblog.DebugLevel.Log("try BZ2...")
if err = libbz2.GetFile(src, tmp); err == nil { if err = libbz2.GetFile(src, tmp); err == nil {
liblog.DebugLevel.Log("try another archive...")
return ExtractAll(tmp, originalName, outputPath, defaultDirPerm) return ExtractAll(tmp, originalName, outputPath, defaultDirPerm)
} else if !err.IsCodeError(libbz2.ErrorIOCopy) { } else if !err.IsCodeError(libbz2.ErrorIOCopy) {
liblog.DebugLevel.Logf("error found on BZ2 : %v", err)
return err return err
} else {
liblog.DebugLevel.Logf("not a BZ2 : %v", err)
} }
liblog.DebugLevel.Log("try GZIP...")
if err = libgzp.GetFile(src, tmp); err == nil { if err = libgzp.GetFile(src, tmp); err == nil {
liblog.DebugLevel.Log("try another archive...")
return ExtractAll(tmp, originalName, outputPath, defaultDirPerm) return ExtractAll(tmp, originalName, outputPath, defaultDirPerm)
} else if !err.IsCodeError(libgzp.ErrorGZReader) { } else if !err.IsCodeError(libgzp.ErrorGZReader) {
liblog.DebugLevel.Logf("error found on GZIP : %v", err)
return err return err
} else {
liblog.DebugLevel.Logf("not a GZIP : %v", err)
} }
if tmp != nil { if tmp != nil {
_ = tmp.Close() _ = tmp.Close()
} }
liblog.DebugLevel.Log("prepare output...")
if i, e := os.Stat(outputPath); e != nil && os.IsNotExist(e) { if i, e := os.Stat(outputPath); e != nil && os.IsNotExist(e) {
//nolint #nosec //nolint #nosec
/* #nosec */ /* #nosec */
@@ -164,29 +152,18 @@ func ExtractAll(src libiot.FileProgress, originalName, outputPath string, defaul
return ErrorDirNotDir.Error(nil) return ErrorDirNotDir.Error(nil)
} }
liblog.DebugLevel.Log("try tar...")
if err = libtar.GetAll(src, outputPath, defaultDirPerm); err == nil { if err = libtar.GetAll(src, outputPath, defaultDirPerm); err == nil {
liblog.DebugLevel.Log("extracting TAR finished...")
return nil return nil
} else if !err.IsCodeError(libtar.ErrorTarNext) { } else if !err.IsCodeError(libtar.ErrorTarNext) {
liblog.DebugLevel.Logf("error found on TAR : %v", err)
return err return err
} else {
liblog.DebugLevel.Logf("not a TAR : %v", err)
} }
liblog.DebugLevel.Log("try zip...")
if err = libzip.GetAll(src, outputPath, defaultDirPerm); err == nil { if err = libzip.GetAll(src, outputPath, defaultDirPerm); err == nil {
liblog.DebugLevel.Log("extracting ZIP finished...")
return nil return nil
} else if !err.IsCodeError(libzip.ErrorZipOpen) { } else if !err.IsCodeError(libzip.ErrorZipOpen) {
liblog.DebugLevel.Logf("error found on ZIP : %v", err)
return err return err
} else {
liblog.DebugLevel.Logf("not a ZIP : %v", err)
} }
liblog.DebugLevel.Log("writing original file...")
if dst, err = src.NewFilePathWrite(filepath.Join(outputPath, originalName), true, true, 0664); err != nil { if dst, err = src.NewFilePathWrite(filepath.Join(outputPath, originalName), true, true, 0664); err != nil {
return ErrorFileOpen.Error(err) return ErrorFileOpen.Error(err)
} }

View File

@@ -31,7 +31,6 @@ import (
"crypto/rand" "crypto/rand"
"errors" "errors"
"fmt" "fmt"
libsiz "github.com/nabbar/golib/size"
"io/ioutil" "io/ioutil"
"net" "net"
"net/http" "net/http"
@@ -49,6 +48,7 @@ import (
"github.com/nabbar/golib/aws/configCustom" "github.com/nabbar/golib/aws/configCustom"
"github.com/nabbar/golib/httpcli" "github.com/nabbar/golib/httpcli"
"github.com/nabbar/golib/password" "github.com/nabbar/golib/password"
libsiz "github.com/nabbar/golib/size"
. "github.com/onsi/ginkgo/v2" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
) )

View File

@@ -32,13 +32,11 @@ import (
"net/url" "net/url"
"strings" "strings"
libreq "github.com/nabbar/golib/request"
sdkaws "github.com/aws/aws-sdk-go-v2/aws" sdkaws "github.com/aws/aws-sdk-go-v2/aws"
libval "github.com/go-playground/validator/v10" libval "github.com/go-playground/validator/v10"
liberr "github.com/nabbar/golib/errors" liberr "github.com/nabbar/golib/errors"
libhtc "github.com/nabbar/golib/httpcli" libhtc "github.com/nabbar/golib/httpcli"
liblog "github.com/nabbar/golib/logger" libreq "github.com/nabbar/golib/request"
) )
type Model struct { type Model struct {
@@ -247,7 +245,6 @@ func (c *awsModel) ResolveEndpointWithOptions(service, region string, options ..
}, nil }, nil
} }
liblog.DebugLevel.Logf("Called ResolveEndpoint for service '%s' / region '%s' with nil endpoint", service, region)
return sdkaws.Endpoint{}, ErrorEndpointInvalid.Error(nil) return sdkaws.Endpoint{}, ErrorEndpointInvalid.Error(nil)
} }

View File

@@ -31,15 +31,20 @@
package cluster package cluster
import ( import (
"context"
dgblog "github.com/lni/dragonboat/v3/logger" dgblog "github.com/lni/dragonboat/v3/logger"
liblog "github.com/nabbar/golib/logger" liblog "github.com/nabbar/golib/logger"
loglvl "github.com/nabbar/golib/logger/level"
) )
const LogLib = "DragonBoat" const LogLib = "DragonBoat"
func SetLoggerFactory(log liblog.FuncLog) { func SetLoggerFactory(log liblog.FuncLog) {
if log == nil { if log == nil {
log = liblog.GetDefault log = func() liblog.Logger {
return liblog.New(context.Background)
}
} }
dgblog.SetLoggerFactory(func(pkgName string) dgblog.ILogger { dgblog.SetLoggerFactory(func(pkgName string) dgblog.ILogger {
@@ -62,42 +67,44 @@ func (l *logDragonBoat) SetLevel(level dgblog.LogLevel) {
switch level { switch level {
case dgblog.CRITICAL: case dgblog.CRITICAL:
l.log().SetLevel(liblog.FatalLevel) l.log().SetLevel(loglvl.FatalLevel)
case dgblog.ERROR: case dgblog.ERROR:
l.log().SetLevel(liblog.ErrorLevel) l.log().SetLevel(loglvl.ErrorLevel)
case dgblog.WARNING: case dgblog.WARNING:
l.log().SetLevel(liblog.WarnLevel) l.log().SetLevel(loglvl.WarnLevel)
case dgblog.INFO: case dgblog.INFO:
l.log().SetLevel(liblog.InfoLevel) l.log().SetLevel(loglvl.InfoLevel)
case dgblog.DEBUG: case dgblog.DEBUG:
l.log().SetLevel(liblog.DebugLevel) l.log().SetLevel(loglvl.DebugLevel)
} }
} }
func (l *logDragonBoat) logMsg(lvl liblog.Level, message string, args ...interface{}) { func (l *logDragonBoat) logMsg(lvl loglvl.Level, message string, args ...interface{}) {
if l.log == nil { if l.log == nil {
l.log = liblog.GetDefault l.log = func() liblog.Logger {
return liblog.New(context.Background)
}
} }
l.log().Entry(lvl, message, args...).FieldAdd("lib", LogLib).FieldAdd("pkg", l.pkg).Log() l.log().Entry(lvl, message, args...).FieldAdd("lib", LogLib).FieldAdd("pkg", l.pkg).Log()
} }
func (l *logDragonBoat) Debugf(format string, args ...interface{}) { func (l *logDragonBoat) Debugf(format string, args ...interface{}) {
l.logMsg(liblog.DebugLevel, format, args...) l.logMsg(loglvl.DebugLevel, format, args...)
} }
func (l *logDragonBoat) Infof(format string, args ...interface{}) { func (l *logDragonBoat) Infof(format string, args ...interface{}) {
l.logMsg(liblog.InfoLevel, format, args...) l.logMsg(loglvl.InfoLevel, format, args...)
} }
func (l *logDragonBoat) Warningf(format string, args ...interface{}) { func (l *logDragonBoat) Warningf(format string, args ...interface{}) {
l.logMsg(liblog.WarnLevel, format, args...) l.logMsg(loglvl.WarnLevel, format, args...)
} }
func (l *logDragonBoat) Errorf(format string, args ...interface{}) { func (l *logDragonBoat) Errorf(format string, args ...interface{}) {
l.logMsg(liblog.ErrorLevel, format, args...) l.logMsg(loglvl.ErrorLevel, format, args...)
} }
func (l *logDragonBoat) Panicf(format string, args ...interface{}) { func (l *logDragonBoat) Panicf(format string, args ...interface{}) {
l.logMsg(liblog.FatalLevel, format, args...) l.logMsg(loglvl.FatalLevel, format, args...)
} }

View File

@@ -31,7 +31,7 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
liblog "github.com/nabbar/golib/logger" loglvl "github.com/nabbar/golib/logger/level"
spfcbr "github.com/spf13/cobra" spfcbr "github.com/spf13/cobra"
) )
@@ -57,37 +57,37 @@ func (c *cobra) AddCommandCompletion() {
var file string var file string
if len(args) < 1 { if len(args) < 1 {
c.getLog().CheckError(liblog.ErrorLevel, liblog.NilLevel, "missing args", cmd.Usage()) c.getLog().CheckError(loglvl.ErrorLevel, loglvl.NilLevel, "missing args", cmd.Usage())
os.Exit(1) os.Exit(1)
} else if len(args) >= 2 { } else if len(args) >= 2 {
file = filepath.Clean(args[1]) file = filepath.Clean(args[1])
c.getLog().CheckError(liblog.ErrorLevel, liblog.NilLevel, "create file path", os.MkdirAll(filepath.Dir(file), 0755)) c.getLog().CheckError(loglvl.ErrorLevel, loglvl.NilLevel, "create file path", os.MkdirAll(filepath.Dir(file), 0755))
} }
switch strings.ToLower(args[0]) { switch strings.ToLower(args[0]) {
case "bash": case "bash":
if file == "" { if file == "" {
c.getLog().CheckError(liblog.ErrorLevel, liblog.NilLevel, "generating bash completion", c.c.GenBashCompletionV2(os.Stdout, true)) c.getLog().CheckError(loglvl.ErrorLevel, loglvl.NilLevel, "generating bash completion", c.c.GenBashCompletionV2(os.Stdout, true))
} else { } else {
c.getLog().CheckError(liblog.ErrorLevel, liblog.NilLevel, "generating bash completion", c.c.GenBashCompletionFileV2(file, true)) c.getLog().CheckError(loglvl.ErrorLevel, loglvl.NilLevel, "generating bash completion", c.c.GenBashCompletionFileV2(file, true))
} }
case "fish": case "fish":
if file == "" { if file == "" {
c.getLog().CheckError(liblog.ErrorLevel, liblog.NilLevel, "generating bash completion", c.c.GenFishCompletion(os.Stdout, true)) c.getLog().CheckError(loglvl.ErrorLevel, loglvl.NilLevel, "generating bash completion", c.c.GenFishCompletion(os.Stdout, true))
} else { } else {
c.getLog().CheckError(liblog.ErrorLevel, liblog.NilLevel, "generating bash completion", c.c.GenFishCompletionFile(file, true)) c.getLog().CheckError(loglvl.ErrorLevel, loglvl.NilLevel, "generating bash completion", c.c.GenFishCompletionFile(file, true))
} }
case "powershell": case "powershell":
if file == "" { if file == "" {
c.getLog().CheckError(liblog.ErrorLevel, liblog.NilLevel, "generating bash completion", c.c.GenPowerShellCompletionWithDesc(os.Stdout)) c.getLog().CheckError(loglvl.ErrorLevel, loglvl.NilLevel, "generating bash completion", c.c.GenPowerShellCompletionWithDesc(os.Stdout))
} else { } else {
c.getLog().CheckError(liblog.ErrorLevel, liblog.NilLevel, "generating bash completion", c.c.GenPowerShellCompletionFileWithDesc(file)) c.getLog().CheckError(loglvl.ErrorLevel, loglvl.NilLevel, "generating bash completion", c.c.GenPowerShellCompletionFileWithDesc(file))
} }
case "zsh": case "zsh":
if file == "" { if file == "" {
c.getLog().CheckError(liblog.ErrorLevel, liblog.NilLevel, "generating bash completion", c.c.GenZshCompletion(os.Stdout)) c.getLog().CheckError(loglvl.ErrorLevel, loglvl.NilLevel, "generating bash completion", c.c.GenZshCompletion(os.Stdout))
} else { } else {
c.getLog().CheckError(liblog.ErrorLevel, liblog.NilLevel, "generating bash completion", c.c.GenZshCompletionFile(file)) c.getLog().CheckError(loglvl.ErrorLevel, loglvl.NilLevel, "generating bash completion", c.c.GenZshCompletionFile(file))
} }
} }
}, },

View File

@@ -36,7 +36,7 @@ import (
"strings" "strings"
"github.com/mitchellh/go-homedir" "github.com/mitchellh/go-homedir"
liblog "github.com/nabbar/golib/logger" loglvl "github.com/nabbar/golib/logger/level"
"github.com/pelletier/go-toml" "github.com/pelletier/go-toml"
spfcbr "github.com/spf13/cobra" spfcbr "github.com/spf13/cobra"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
@@ -49,7 +49,7 @@ func (c *cobra) getDefaultPath(baseName string) (string, error) {
// Find home directory. // Find home directory.
home, err := homedir.Dir() home, err := homedir.Dir()
c.getLog().CheckError(liblog.WarnLevel, liblog.InfoLevel, "Loading home dir", err) c.getLog().CheckError(loglvl.WarnLevel, loglvl.InfoLevel, "Loading home dir", err)
// set configname based on package name // set configname based on package name
if baseName == "" { if baseName == "" {

View File

@@ -27,6 +27,7 @@
package cobra package cobra
import ( import (
"context"
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
@@ -138,7 +139,7 @@ func (c *cobra) getLog() liblog.Logger {
return l return l
} }
return liblog.GetDefault() return liblog.New(context.Background)
} }
func (c *cobra) getPackageName() string { func (c *cobra) getPackageName() string {

View File

@@ -226,11 +226,10 @@ func (o *componentAws) _runCli() liberr.Error {
o.m.Unlock() o.m.Unlock()
if req != nil { if req != nil {
req.RegisterDefaultLogger(o.getLogger)
if req, e = opt.Update(o.x.GetContext, req); e != nil { if req, e = opt.Update(o.x.GetContext, req); e != nil {
return prt.ErrorParent(e) return prt.ErrorParent(e)
} }
} else if req, e = libreq.New(o.x.GetContext, opt); e != nil { } else if req, e = opt.New(o.x.GetContext); e != nil {
return prt.ErrorParent(e) return prt.ErrorParent(e)
} }

View File

@@ -113,6 +113,10 @@ func (o *componentAws) _registerMonitor(opt *libreq.OptionsHealth, aws libaws.Co
} }
} }
if opt.Monitor.Name != key {
opt.Monitor.Name = key
}
if e = mon.SetConfig(o.x.GetContext, opt.Monitor); e != nil { if e = mon.SetConfig(o.x.GetContext, opt.Monitor); e != nil {
return e return e
} }

View File

@@ -79,6 +79,10 @@ func (o *componentDatabase) _registerMonitor(cfg *libdbs.Config) error {
} }
} }
if cfg.Monitor.Name != key {
cfg.Monitor.Name = key
}
if e = mon.SetConfig(o.x.GetContext, cfg.Monitor); e != nil { if e = mon.SetConfig(o.x.GetContext, cfg.Monitor); e != nil {
return e return e
} }

View File

@@ -30,6 +30,7 @@ import (
cfgtps "github.com/nabbar/golib/config/types" cfgtps "github.com/nabbar/golib/config/types"
liberr "github.com/nabbar/golib/errors" liberr "github.com/nabbar/golib/errors"
liblog "github.com/nabbar/golib/logger" liblog "github.com/nabbar/golib/logger"
logcfg "github.com/nabbar/golib/logger/config"
libver "github.com/nabbar/golib/version" libver "github.com/nabbar/golib/version"
libvpr "github.com/nabbar/golib/viper" libvpr "github.com/nabbar/golib/viper"
spfvbr "github.com/spf13/viper" spfvbr "github.com/spf13/viper"
@@ -151,7 +152,7 @@ func (o *componentLog) _runCli() liberr.Error {
e error e error
err liberr.Error err liberr.Error
prt = ErrorReloadLog prt = ErrorReloadLog
cfg *liblog.Options cfg *logcfg.Options
) )
if !o.IsStarted() { if !o.IsStarted() {

View File

@@ -28,7 +28,7 @@ package log
import ( import (
liberr "github.com/nabbar/golib/errors" liberr "github.com/nabbar/golib/errors"
liblog "github.com/nabbar/golib/logger" logcfg "github.com/nabbar/golib/logger/config"
spfcbr "github.com/spf13/cobra" spfcbr "github.com/spf13/cobra"
spfvpr "github.com/spf13/viper" spfvpr "github.com/spf13/viper"
) )
@@ -70,10 +70,10 @@ func (o *componentLog) RegisterFlag(Command *spfcbr.Command) error {
return nil return nil
} }
func (o *componentLog) _getConfig() (*liblog.Options, liberr.Error) { func (o *componentLog) _getConfig() (*logcfg.Options, liberr.Error) {
var ( var (
key string key string
cfg liblog.Options cfg logcfg.Options
vpr *spfvpr.Viper vpr *spfvpr.Viper
err liberr.Error err liberr.Error
) )
@@ -88,20 +88,24 @@ func (o *componentLog) _getConfig() (*liblog.Options, liberr.Error) {
return nil, ErrorParamInvalid.ErrorParent(e) return nil, ErrorParamInvalid.ErrorParent(e)
} }
if cfg.Stdout == nil {
cfg.Stdout = &logcfg.OptionsStd{}
}
if val := vpr.GetBool(key + "disableStandard"); val { if val := vpr.GetBool(key + "disableStandard"); val {
cfg.DisableStandard = true cfg.Stdout.DisableStandard = true
} }
if val := vpr.GetBool(key + "disableStack"); val { if val := vpr.GetBool(key + "disableStack"); val {
cfg.DisableStack = true cfg.Stdout.DisableStack = true
} }
if val := vpr.GetBool(key + "disableTimestamp"); val { if val := vpr.GetBool(key + "disableTimestamp"); val {
cfg.DisableTimestamp = true cfg.Stdout.DisableTimestamp = true
} }
if val := vpr.GetBool(key + "enableTrace"); val { if val := vpr.GetBool(key + "enableTrace"); val {
cfg.EnableTrace = true cfg.Stdout.EnableTrace = true
} }
if val := vpr.GetString(key + "traceFilter"); val != "" { if val := vpr.GetString(key + "traceFilter"); val != "" {
@@ -109,7 +113,7 @@ func (o *componentLog) _getConfig() (*liblog.Options, liberr.Error) {
} }
if val := vpr.GetBool(key + "disableColor"); val { if val := vpr.GetBool(key + "disableColor"); val {
cfg.DisableColor = true cfg.Stdout.DisableColor = true
} }
if err = cfg.Validate(); err != nil { if err = cfg.Validate(); err != nil {

View File

@@ -27,9 +27,9 @@
package log package log
import ( import (
logdef "github.com/nabbar/golib/logger/config" logcfg "github.com/nabbar/golib/logger/config"
) )
func (o *componentLog) DefaultConfig(indent string) []byte { func (o *componentLog) DefaultConfig(indent string) []byte {
return logdef.DefaultConfig(indent) return logcfg.DefaultConfig(indent)
} }

View File

@@ -34,10 +34,13 @@ import (
libctx "github.com/nabbar/golib/context" libctx "github.com/nabbar/golib/context"
liberr "github.com/nabbar/golib/errors" liberr "github.com/nabbar/golib/errors"
liblog "github.com/nabbar/golib/logger" liblog "github.com/nabbar/golib/logger"
logcfg "github.com/nabbar/golib/logger/config"
logfld "github.com/nabbar/golib/logger/fields"
loglvl "github.com/nabbar/golib/logger/level"
) )
const ( const (
DefaultLevel = liblog.InfoLevel DefaultLevel = loglvl.InfoLevel
) )
type ComponentLog interface { type ComponentLog interface {
@@ -45,17 +48,17 @@ type ComponentLog interface {
Log() liblog.Logger Log() liblog.Logger
SetLevel(lvl liblog.Level) SetLevel(lvl loglvl.Level)
GetLevel() liblog.Level GetLevel() loglvl.Level
SetField(fields liblog.Fields) SetField(fields logfld.Fields)
GetField() liblog.Fields GetField() logfld.Fields
SetOptions(opt *liblog.Options) liberr.Error SetOptions(opt *logcfg.Options) liberr.Error
GetOptions() *liblog.Options GetOptions() *logcfg.Options
} }
func New(ctx libctx.FuncContext, lvl liblog.Level) ComponentLog { func New(ctx libctx.FuncContext, lvl loglvl.Level) ComponentLog {
return &componentLog{ return &componentLog{
m: sync.RWMutex{}, m: sync.RWMutex{},
x: libctx.NewConfig[uint8](ctx), x: libctx.NewConfig[uint8](ctx),
@@ -68,7 +71,7 @@ func Register(cfg libcfg.Config, key string, cpt ComponentLog) {
cfg.ComponentSet(key, cpt) cfg.ComponentSet(key, cpt)
} }
func RegisterNew(ctx libctx.FuncContext, cfg libcfg.Config, key string, lvl liblog.Level) { func RegisterNew(ctx libctx.FuncContext, cfg libcfg.Config, key string, lvl loglvl.Level) {
cfg.ComponentSet(key, New(ctx, lvl)) cfg.ComponentSet(key, New(ctx, lvl))
} }

View File

@@ -32,6 +32,9 @@ import (
libctx "github.com/nabbar/golib/context" libctx "github.com/nabbar/golib/context"
liberr "github.com/nabbar/golib/errors" liberr "github.com/nabbar/golib/errors"
liblog "github.com/nabbar/golib/logger" liblog "github.com/nabbar/golib/logger"
logcfg "github.com/nabbar/golib/logger/config"
logfld "github.com/nabbar/golib/logger/fields"
loglvl "github.com/nabbar/golib/logger/level"
) )
type componentLog struct { type componentLog struct {
@@ -39,7 +42,7 @@ type componentLog struct {
x libctx.Config[uint8] x libctx.Config[uint8]
l liblog.Logger l liblog.Logger
v liblog.Level v loglvl.Level
} }
func (o *componentLog) Log() liblog.Logger { func (o *componentLog) Log() liblog.Logger {
@@ -53,7 +56,7 @@ func (o *componentLog) Log() liblog.Logger {
return nil return nil
} }
func (o *componentLog) SetLevel(lvl liblog.Level) { func (o *componentLog) SetLevel(lvl loglvl.Level) {
o.m.Lock() o.m.Lock()
defer o.m.Unlock() defer o.m.Unlock()
@@ -66,14 +69,14 @@ func (o *componentLog) SetLevel(lvl liblog.Level) {
o.l.SetLevel(lvl) o.l.SetLevel(lvl)
} }
func (o *componentLog) GetLevel() liblog.Level { func (o *componentLog) GetLevel() loglvl.Level {
o.m.RLock() o.m.RLock()
defer o.m.RUnlock() defer o.m.RUnlock()
return o.v return o.v
} }
func (o *componentLog) SetField(fields liblog.Fields) { func (o *componentLog) SetField(fields logfld.Fields) {
o.m.Lock() o.m.Lock()
defer o.m.Unlock() defer o.m.Unlock()
@@ -84,7 +87,7 @@ func (o *componentLog) SetField(fields liblog.Fields) {
o.l.SetFields(fields) o.l.SetFields(fields)
} }
func (o *componentLog) GetField() liblog.Fields { func (o *componentLog) GetField() logfld.Fields {
o.m.RLock() o.m.RLock()
defer o.m.RUnlock() defer o.m.RUnlock()
@@ -95,7 +98,7 @@ func (o *componentLog) GetField() liblog.Fields {
return o.l.GetFields() return o.l.GetFields()
} }
func (o *componentLog) GetOptions() *liblog.Options { func (o *componentLog) GetOptions() *logcfg.Options {
o.m.RLock() o.m.RLock()
defer o.m.RUnlock() defer o.m.RUnlock()
@@ -106,7 +109,7 @@ func (o *componentLog) GetOptions() *liblog.Options {
return o.l.GetOptions() return o.l.GetOptions()
} }
func (o *componentLog) SetOptions(opt *liblog.Options) liberr.Error { func (o *componentLog) SetOptions(opt *logcfg.Options) liberr.Error {
o.m.Lock() o.m.Lock()
defer o.m.Unlock() defer o.m.Unlock()

View File

@@ -197,7 +197,6 @@ func (o *componentRequest) _runCli() liberr.Error {
cfg.SetDefaultLog(o.getLogger) cfg.SetDefaultLog(o.getLogger)
if req != nil { if req != nil {
req.RegisterDefaultLogger(o.getLogger)
if req, e = cfg.Update(o.x.GetContext, req); err != nil { if req, e = cfg.Update(o.x.GetContext, req); err != nil {
return prt.ErrorParent(e) return prt.ErrorParent(e)
} }

View File

@@ -89,6 +89,10 @@ func (o *componentRequest) _registerMonitor(cfg *libreq.Options) error {
mon.RegisterLoggerDefault(o.getLogger) mon.RegisterLoggerDefault(o.getLogger)
if cfg.Health.Monitor.Name != key {
cfg.Health.Monitor.Name = key
}
if e = mon.SetConfig(o.x.GetContext, cfg.Health.Monitor); e != nil { if e = mon.SetConfig(o.x.GetContext, cfg.Health.Monitor); e != nil {
return e return e
} }

View File

@@ -85,6 +85,10 @@ func (o *componentSmtp) _registerMonitor(cfg *montps.Config) error {
mon.RegisterLoggerDefault(o.getLogger) mon.RegisterLoggerDefault(o.getLogger)
if cfg.Name != key {
cfg.Name = key
}
if e = mon.SetConfig(o.x.GetContext, *cfg); e != nil { if e = mon.SetConfig(o.x.GetContext, *cfg); e != nil {
return e return e
} }

View File

@@ -30,6 +30,8 @@ import (
"os/signal" "os/signal"
"time" "time"
"github.com/nabbar/golib/logger/level"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
liblog "github.com/nabbar/golib/logger" liblog "github.com/nabbar/golib/logger"
) )
@@ -41,7 +43,7 @@ type ctxGinTonic struct {
c context.CancelFunc c context.CancelFunc
} }
func NewGinTonic(c *gin.Context) GinTonic { func NewGinTonic(c *gin.Context, log liblog.FuncLog) GinTonic {
if c == nil { if c == nil {
c = &gin.Context{ c = &gin.Context{
Request: nil, Request: nil,
@@ -65,7 +67,7 @@ func NewGinTonic(c *gin.Context) GinTonic {
} }
return &ctxGinTonic{ return &ctxGinTonic{
l: liblog.GetDefault, l: log,
g: c, g: c,
x: x, x: x,
c: l, c: l,
@@ -76,11 +78,15 @@ func (c *ctxGinTonic) SetLogger(fct liblog.FuncLog) {
c.l = fct c.l = fct
} }
func (c *ctxGinTonic) log(lvl liblog.Level, msg string, args ...interface{}) { func (c *ctxGinTonic) log(lvl level.Level, msg string, args ...interface{}) {
if c.l != nil { if c.l != nil {
c.l().Entry(lvl, msg, args...).Log() c.l().Entry(lvl, msg, args...).Log()
} else { } else {
liblog.GetDefault().Entry(lvl, msg, args...).Log() l := liblog.New(func() context.Context {
return c
})
l.Entry(lvl, msg, args...).Log()
} }
} }
@@ -91,11 +97,11 @@ func (c *ctxGinTonic) CancelOnSignal(s ...os.Signal) {
select { select {
case <-sc: case <-sc:
c.log(liblog.InfoLevel, "OS Signal received, calling context cancel !") c.log(level.InfoLevel, "OS Signal received, calling context cancel !")
c.c() c.c()
return return
case <-c.Done(): case <-c.Done():
c.log(liblog.InfoLevel, "Context has been closed !") c.log(level.InfoLevel, "Context has been closed !")
return return
} }
}() }()

View File

@@ -31,12 +31,12 @@ import (
"fmt" "fmt"
"time" "time"
moncfg "github.com/nabbar/golib/monitor/types"
libval "github.com/go-playground/validator/v10" libval "github.com/go-playground/validator/v10"
libctx "github.com/nabbar/golib/context" libctx "github.com/nabbar/golib/context"
liberr "github.com/nabbar/golib/errors" liberr "github.com/nabbar/golib/errors"
liblog "github.com/nabbar/golib/logger" liblog "github.com/nabbar/golib/logger"
loggrm "github.com/nabbar/golib/logger/gorm"
moncfg "github.com/nabbar/golib/monitor/types"
gormdb "gorm.io/gorm" gormdb "gorm.io/gorm"
gorcls "gorm.io/gorm/clause" gorcls "gorm.io/gorm/clause"
gorlog "gorm.io/gorm/logger" gorlog "gorm.io/gorm/logger"
@@ -131,7 +131,7 @@ func (c *Config) Validate() liberr.Error {
func (c *Config) RegisterLogger(fct func() liblog.Logger, ignoreRecordNotFoundError bool, slowThreshold time.Duration) { func (c *Config) RegisterLogger(fct func() liblog.Logger, ignoreRecordNotFoundError bool, slowThreshold time.Duration) {
c.flog = func() gorlog.Interface { c.flog = func() gorlog.Interface {
return liblog.NewGormLogger(fct, ignoreRecordNotFoundError, slowThreshold) return loggrm.New(fct, ignoreRecordNotFoundError, slowThreshold)
} }
} }

100
go.mod
View File

@@ -3,67 +3,67 @@ module github.com/nabbar/golib
go 1.20 go 1.20
require ( require (
github.com/aws/aws-sdk-go-v2 v1.18.0 github.com/aws/aws-sdk-go-v2 v1.18.1
github.com/aws/aws-sdk-go-v2/config v1.18.25 github.com/aws/aws-sdk-go-v2/config v1.18.27
github.com/aws/aws-sdk-go-v2/credentials v1.13.24 github.com/aws/aws-sdk-go-v2/credentials v1.13.26
github.com/aws/aws-sdk-go-v2/service/iam v1.19.12 github.com/aws/aws-sdk-go-v2/service/iam v1.20.3
github.com/aws/aws-sdk-go-v2/service/s3 v1.33.1 github.com/aws/aws-sdk-go-v2/service/s3 v1.35.0
github.com/bits-and-blooms/bitset v1.7.0 github.com/bits-and-blooms/bitset v1.8.0
github.com/c-bata/go-prompt v0.2.6 github.com/c-bata/go-prompt v0.2.6
github.com/fatih/color v1.15.0 github.com/fatih/color v1.15.0
github.com/fsnotify/fsnotify v1.6.0 github.com/fsnotify/fsnotify v1.6.0
github.com/fxamacker/cbor/v2 v2.4.0 github.com/fxamacker/cbor/v2 v2.4.0
github.com/gin-gonic/gin v1.9.1 github.com/gin-gonic/gin v1.9.1
github.com/go-ldap/ldap/v3 v3.4.4 github.com/go-ldap/ldap/v3 v3.4.5
github.com/go-playground/validator/v10 v10.14.0 github.com/go-playground/validator/v10 v10.14.1
github.com/google/go-github/v33 v33.0.0 github.com/google/go-github/v33 v33.0.0
github.com/hashicorp/go-hclog v1.5.0 github.com/hashicorp/go-hclog v1.5.0
github.com/hashicorp/go-retryablehttp v0.7.2 github.com/hashicorp/go-retryablehttp v0.7.4
github.com/hashicorp/go-uuid v1.0.3 github.com/hashicorp/go-uuid v1.0.3
github.com/hashicorp/go-version v1.6.0 github.com/hashicorp/go-version v1.6.0
github.com/jlaffaye/ftp v0.2.0 github.com/jlaffaye/ftp v0.2.0
github.com/lni/dragonboat/v3 v3.3.6 github.com/lni/dragonboat/v3 v3.3.7
github.com/matcornic/hermes/v2 v2.1.0 github.com/matcornic/hermes/v2 v2.1.0
github.com/mattn/go-colorable v0.1.13 github.com/mattn/go-colorable v0.1.13
github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/go-homedir v1.1.0
github.com/mitchellh/mapstructure v1.5.0 github.com/mitchellh/mapstructure v1.5.0
github.com/nats-io/jwt/v2 v2.4.1 github.com/nats-io/jwt/v2 v2.4.1
github.com/nats-io/nats-server/v2 v2.9.17 github.com/nats-io/nats-server/v2 v2.9.18
github.com/nats-io/nats.go v1.26.0 github.com/nats-io/nats.go v1.27.0
github.com/nutsdb/nutsdb v0.12.2 github.com/nutsdb/nutsdb v0.12.2
github.com/onsi/ginkgo/v2 v2.9.7 github.com/onsi/ginkgo/v2 v2.11.0
github.com/onsi/gomega v1.27.7 github.com/onsi/gomega v1.27.8
github.com/pelletier/go-toml v1.9.5 github.com/pelletier/go-toml v1.9.5
github.com/prometheus/client_golang v1.15.1 github.com/prometheus/client_golang v1.16.0
github.com/shirou/gopsutil v3.21.11+incompatible github.com/shirou/gopsutil v3.21.11+incompatible
github.com/sirupsen/logrus v1.9.2 github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.7.0 github.com/spf13/cobra v1.7.0
github.com/spf13/jwalterweatherman v1.1.0 github.com/spf13/jwalterweatherman v1.1.0
github.com/spf13/viper v1.16.0 github.com/spf13/viper v1.16.0
github.com/ugorji/go/codec v1.2.11 github.com/ugorji/go/codec v1.2.11
github.com/vbauerster/mpb/v5 v5.4.0 github.com/vbauerster/mpb/v5 v5.4.0
github.com/xanzy/go-gitlab v0.84.0 github.com/xanzy/go-gitlab v0.85.0
github.com/xhit/go-simple-mail v2.2.2+incompatible github.com/xhit/go-simple-mail v2.2.2+incompatible
github.com/xujiajun/utils v0.0.0-20220904132955-5f7c5b914235 github.com/xujiajun/utils v0.0.0-20220904132955-5f7c5b914235
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1
golang.org/x/net v0.10.0 golang.org/x/net v0.11.0
golang.org/x/oauth2 v0.8.0 golang.org/x/oauth2 v0.9.0
golang.org/x/sync v0.2.0 golang.org/x/sync v0.3.0
golang.org/x/sys v0.8.0 golang.org/x/sys v0.9.0
golang.org/x/term v0.8.0 golang.org/x/term v0.9.0
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
gorm.io/driver/clickhouse v0.5.1 gorm.io/driver/clickhouse v0.5.1
gorm.io/driver/mysql v1.5.1 gorm.io/driver/mysql v1.5.1
gorm.io/driver/postgres v1.5.2 gorm.io/driver/postgres v1.5.2
gorm.io/driver/sqlite v1.5.1 gorm.io/driver/sqlite v1.5.1
gorm.io/driver/sqlserver v1.5.0 gorm.io/driver/sqlserver v1.5.1
gorm.io/gorm v1.25.1 gorm.io/gorm v1.25.1
) )
require ( require (
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
github.com/ClickHouse/ch-go v0.56.0 // indirect github.com/ClickHouse/ch-go v0.56.1 // indirect
github.com/ClickHouse/clickhouse-go/v2 v2.10.0 // indirect github.com/ClickHouse/clickhouse-go/v2 v2.10.1 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver v1.5.0 // indirect github.com/Masterminds/semver v1.5.0 // indirect
github.com/Masterminds/sprig v2.22.0+incompatible // indirect github.com/Masterminds/sprig v2.22.0+incompatible // indirect
@@ -75,30 +75,30 @@ require (
github.com/andybalholm/cascadia v1.3.2 // indirect github.com/andybalholm/cascadia v1.3.2 // indirect
github.com/armon/go-metrics v0.4.1 // indirect github.com/armon/go-metrics v0.4.1 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.3 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.4 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.33 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.34 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.27 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.28 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.34 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.3.35 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.25 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.26 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.28 // indirect github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.29 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.27 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.28 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.2 // indirect github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.3 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.12.10 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.12.12 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.10 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.12 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.19.0 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.19.2 // indirect
github.com/aws/smithy-go v1.13.5 // indirect github.com/aws/smithy-go v1.13.5 // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/bwmarrin/snowflake v0.3.0 // indirect github.com/bwmarrin/snowflake v0.3.0 // indirect
github.com/bytedance/sonic v1.9.1 // indirect github.com/bytedance/sonic v1.9.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/cockroachdb/errors v1.9.1 // indirect github.com/cockroachdb/errors v1.10.0 // indirect
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
github.com/cockroachdb/pebble v0.0.0-20210331181633-27fc006b8bfb // indirect github.com/cockroachdb/pebble v0.0.0-20210331181633-27fc006b8bfb // indirect
github.com/cockroachdb/redact v1.1.4 // indirect github.com/cockroachdb/redact v1.1.5 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/getsentry/sentry-go v0.21.0 // indirect github.com/getsentry/sentry-go v0.22.0 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
github.com/go-faster/city v1.0.1 // indirect github.com/go-faster/city v1.0.1 // indirect
@@ -118,7 +118,7 @@ require (
github.com/google/btree v1.1.2 // indirect github.com/google/btree v1.1.2 // indirect
github.com/google/go-cmp v0.5.9 // indirect github.com/google/go-cmp v0.5.9 // indirect
github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-querystring v1.1.0 // indirect
github.com/google/pprof v0.0.0-20230602010524-ada837c32108 // indirect github.com/google/pprof v0.0.0-20230602150820-91b7bce49751 // indirect
github.com/google/uuid v1.3.0 // indirect github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/css v1.0.0 // indirect github.com/gorilla/css v1.0.0 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect
@@ -135,14 +135,14 @@ require (
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgx/v5 v5.3.1 // indirect github.com/jackc/pgx/v5 v5.4.1 // indirect
github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 // indirect github.com/jaytaylor/html2text v0.0.0-20230321000545-74c2419ad056 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect github.com/jinzhu/now v1.1.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/juju/ratelimit v1.0.2 // indirect github.com/juju/ratelimit v1.0.2 // indirect
github.com/klauspost/compress v1.16.5 // indirect github.com/klauspost/compress v1.16.6 // indirect
github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect
github.com/kr/pretty v0.3.1 // indirect github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect github.com/kr/text v0.2.0 // indirect
github.com/leodido/go-urn v1.2.4 // indirect github.com/leodido/go-urn v1.2.4 // indirect
@@ -154,7 +154,7 @@ require (
github.com/mattn/go-tty v0.0.5 // indirect github.com/mattn/go-tty v0.0.5 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/microsoft/go-mssqldb v1.1.0 // indirect github.com/microsoft/go-mssqldb v1.1.0 // indirect
github.com/miekg/dns v1.1.54 // indirect github.com/miekg/dns v1.1.55 // indirect
github.com/minio/highwayhash v1.0.2 // indirect github.com/minio/highwayhash v1.0.2 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect
@@ -165,12 +165,12 @@ require (
github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/paulmach/orb v0.9.2 // indirect github.com/paulmach/orb v0.9.2 // indirect
github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect
github.com/pierrec/lz4/v4 v4.1.17 // indirect github.com/pierrec/lz4/v4 v4.1.18 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pkg/term v1.2.0-beta.2 // indirect github.com/pkg/term v1.2.0-beta.2 // indirect
github.com/prometheus/client_model v0.4.0 // indirect github.com/prometheus/client_model v0.4.0 // indirect
github.com/prometheus/common v0.44.0 // indirect github.com/prometheus/common v0.44.0 // indirect
github.com/prometheus/procfs v0.10.1 // indirect github.com/prometheus/procfs v0.11.0 // indirect
github.com/rivo/uniseg v0.4.4 // indirect github.com/rivo/uniseg v0.4.4 // indirect
github.com/rogpeppe/go-internal v1.10.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
@@ -193,11 +193,11 @@ require (
go.opentelemetry.io/otel v1.16.0 // indirect go.opentelemetry.io/otel v1.16.0 // indirect
go.opentelemetry.io/otel/trace v1.16.0 // indirect go.opentelemetry.io/otel/trace v1.16.0 // indirect
golang.org/x/arch v0.3.0 // indirect golang.org/x/arch v0.3.0 // indirect
golang.org/x/crypto v0.9.0 // indirect golang.org/x/crypto v0.10.0 // indirect
golang.org/x/mod v0.10.0 // indirect golang.org/x/mod v0.11.0 // indirect
golang.org/x/text v0.9.0 // indirect golang.org/x/text v0.10.0 // indirect
golang.org/x/time v0.3.0 // indirect golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.9.3 // indirect golang.org/x/tools v0.10.0 // indirect
google.golang.org/appengine v1.6.7 // indirect google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.30.0 // indirect google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect

View File

@@ -33,6 +33,8 @@ import (
"net/url" "net/url"
"time" "time"
libptc "github.com/nabbar/golib/network/protocol"
"golang.org/x/net/http2" "golang.org/x/net/http2"
libtls "github.com/nabbar/golib/certificates" libtls "github.com/nabbar/golib/certificates"
@@ -97,7 +99,7 @@ func GetClientTls(serverName string, tls libtls.TLSConfig, http2Tr bool, GlobalT
return getclient(tr, http2Tr, GlobalTimeout) return getclient(tr, http2Tr, GlobalTimeout)
} }
func GetClientTlsForceIp(netw Network, ip string, serverName string, tls libtls.TLSConfig, http2Tr bool, GlobalTimeout time.Duration) (*http.Client, liberr.Error) { func GetClientTlsForceIp(netw libptc.NetworkProtocol, ip string, serverName string, tls libtls.TLSConfig, http2Tr bool, GlobalTimeout time.Duration) (*http.Client, liberr.Error) {
u := &url.URL{ u := &url.URL{
Host: ip, Host: ip,
} }

View File

@@ -1,63 +0,0 @@
/*
* 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 httpcli
import "strings"
type Network uint8
const (
NetworkTCP Network = iota
NetworkUDP
NetworkUnix
)
func GetNetworkFromString(str string) Network {
switch {
case strings.EqualFold(NetworkUDP.Code(), str):
return NetworkUDP
case strings.EqualFold(NetworkUnix.Code(), str):
return NetworkUnix
default:
return NetworkTCP
}
}
func (n Network) String() string {
switch n {
case NetworkUDP:
return "UDP"
case NetworkUnix:
return "unix"
default:
return "TCP"
}
}
func (n Network) Code() string {
return strings.ToLower(n.String())
}

View File

@@ -33,6 +33,8 @@ import (
"net/http" "net/http"
"time" "time"
libptc "github.com/nabbar/golib/network/protocol"
cmptls "github.com/nabbar/golib/config/components/tls" cmptls "github.com/nabbar/golib/config/components/tls"
cfgcst "github.com/nabbar/golib/config/const" cfgcst "github.com/nabbar/golib/config/const"
@@ -112,7 +114,7 @@ func (o Options) GetClient(def libtls.TLSConfig, servername string) (*http.Clien
} }
if o.ForceIP.Enable { if o.ForceIP.Enable {
return GetClientTlsForceIp(GetNetworkFromString(o.ForceIP.Net), o.ForceIP.IP, servername, tls, o.Http2, o.Timeout) return GetClientTlsForceIp(libptc.Parse(o.ForceIP.Net), o.ForceIP.IP, servername, tls, o.Http2, o.Timeout)
} else { } else {
return GetClientTls(servername, tls, o.Http2, o.Timeout) return GetClientTls(servername, tls, o.Http2, o.Timeout)
} }

View File

@@ -34,15 +34,14 @@ import (
"strings" "strings"
"time" "time"
srvtps "github.com/nabbar/golib/httpserver/types"
moncfg "github.com/nabbar/golib/monitor/types"
libval "github.com/go-playground/validator/v10" libval "github.com/go-playground/validator/v10"
libtls "github.com/nabbar/golib/certificates" libtls "github.com/nabbar/golib/certificates"
libctx "github.com/nabbar/golib/context" libctx "github.com/nabbar/golib/context"
liberr "github.com/nabbar/golib/errors" liberr "github.com/nabbar/golib/errors"
srvtps "github.com/nabbar/golib/httpserver/types"
liblog "github.com/nabbar/golib/logger" liblog "github.com/nabbar/golib/logger"
logcfg "github.com/nabbar/golib/logger/config"
moncfg "github.com/nabbar/golib/monitor/types"
) )
const ( const (
@@ -183,7 +182,7 @@ type Config struct {
DisableKeepAlive bool `mapstructure:"disable_keep_alive" json:"disable_keep_alive" yaml:"disable_keep_alive" toml:"disable_keep_alive"` DisableKeepAlive bool `mapstructure:"disable_keep_alive" json:"disable_keep_alive" yaml:"disable_keep_alive" toml:"disable_keep_alive"`
// Logger is used to define the logger options. // Logger is used to define the logger options.
Logger liblog.Options `mapstructure:"logger" json:"logger" yaml:"logger" toml:"logger"` Logger logcfg.Options `mapstructure:"logger" json:"logger" yaml:"logger" toml:"logger"`
} }
func (c *Config) Clone() Config { func (c *Config) Clone() Config {
@@ -414,11 +413,16 @@ func (o *srv) SetConfig(cfg Config, defLog liblog.FuncLog) error {
return nil return nil
} }
func (o *srv) setLogger(def liblog.FuncLog, opt liblog.Options) error { func (o *srv) setLogger(def liblog.FuncLog, opt logcfg.Options) error {
o.m.Lock() o.m.Lock()
defer o.m.Unlock() defer o.m.Unlock()
var l liblog.Logger var (
l liblog.Logger
f = func() liblog.Logger {
return liblog.New(o.c.GetContext)
}
)
if def != nil { if def != nil {
if n := def(); n != nil { if n := def(); n != nil {
@@ -427,7 +431,7 @@ func (o *srv) setLogger(def liblog.FuncLog, opt liblog.Options) error {
} }
if l == nil { if l == nil {
l = liblog.GetDefault() l = f()
} }
if e := l.SetOptions(&opt); e == nil { if e := l.SetOptions(&opt); e == nil {
@@ -436,7 +440,9 @@ func (o *srv) setLogger(def liblog.FuncLog, opt liblog.Options) error {
} }
return nil return nil
} else if o.l == nil { } else if o.l == nil {
o.l = liblog.GetDefault o.l = func() liblog.Logger {
return l
}
return e return e
} else { } else {
return e return e
@@ -451,10 +457,18 @@ func (o *srv) logger() liblog.Logger {
if o.l != nil { if o.l != nil {
log = o.l() log = o.l()
} else {
log = liblog.New(o.c.GetContext)
o.m.RUnlock()
o.m.Lock()
o.l = func() liblog.Logger {
return log
} }
if log == nil { o.m.Unlock()
log = liblog.GetDefault() o.m.RLock()
} }
log.SetFields(log.GetFields().Add("bind", o.GetBindable())) log.SetFields(log.GetFields().Add("bind", o.GetBindable()))

View File

@@ -59,6 +59,7 @@ type Server interface {
SetConfig(cfg Config, defLog liblog.FuncLog) error SetConfig(cfg Config, defLog liblog.FuncLog) error
Monitor(vrs libver.Version) (montps.Monitor, error) Monitor(vrs libver.Version) (montps.Monitor, error)
MonitorName() string
} }
func New(cfg Config, defLog liblog.FuncLog) (Server, error) { func New(cfg Config, defLog liblog.FuncLog) (Server, error) {

View File

@@ -32,6 +32,9 @@ import (
"fmt" "fmt"
"runtime" "runtime"
logent "github.com/nabbar/golib/logger/entry"
loglvl "github.com/nabbar/golib/logger/level"
libmon "github.com/nabbar/golib/monitor" libmon "github.com/nabbar/golib/monitor"
moninf "github.com/nabbar/golib/monitor/info" moninf "github.com/nabbar/golib/monitor/info"
montps "github.com/nabbar/golib/monitor/types" montps "github.com/nabbar/golib/monitor/types"
@@ -39,7 +42,7 @@ import (
) )
const ( const (
defaultNameMonitor = "HTTP Server" DefaultNameMonitor = "HTTP Server"
) )
var ( var (
@@ -47,16 +50,34 @@ var (
) )
func (o *srv) HealthCheck(ctx context.Context) error { func (o *srv) HealthCheck(ctx context.Context) error {
var ent logent.Entry
if l := o.logger(); l != nil {
ent = l.Entry(loglvl.ErrorLevel, "Healthcheck")
}
o.m.RLock() o.m.RLock()
defer o.m.RUnlock() defer o.m.RUnlock()
if o.r == nil { if o.r == nil {
if ent != nil {
ent.ErrorAdd(true, errNotRunning).Check(loglvl.InfoLevel)
}
return errNotRunning return errNotRunning
} else if e := o.runAndHealthy(ctx); e != nil { } else if e := o.runAndHealthy(ctx); e != nil {
if ent != nil {
ent.ErrorAdd(true, e).Check(loglvl.InfoLevel)
}
return e return e
} else if e = o.r.ErrorsLast(); e != nil { } else if e = o.r.ErrorsLast(); e != nil {
if ent != nil {
ent.ErrorAdd(true, e).Check(loglvl.InfoLevel)
}
return e return e
} else { } else {
if ent != nil {
ent.Check(loglvl.InfoLevel)
}
return nil return nil
} }
} }
@@ -74,6 +95,10 @@ func (o *srv) runAndHealthy(ctx context.Context) error {
return nil return nil
} }
func (o *srv) MonitorName() string {
return fmt.Sprintf("%s [%s]", DefaultNameMonitor, o.GetBindable())
}
func (o *srv) Monitor(vrs libver.Version) (montps.Monitor, error) { func (o *srv) Monitor(vrs libver.Version) (montps.Monitor, error) {
var ( var (
e error e error
@@ -93,11 +118,11 @@ func (o *srv) Monitor(vrs libver.Version) (montps.Monitor, error) {
res["date"] = vrs.GetDate() res["date"] = vrs.GetDate()
res["handler"] = o.HandlerGetValidKey() res["handler"] = o.HandlerGetValidKey()
if inf, e = moninf.New(defaultNameMonitor); e != nil { if inf, e = moninf.New(DefaultNameMonitor); e != nil {
return nil, e return nil, e
} else { } else {
inf.RegisterName(func() (string, error) { inf.RegisterName(func() (string, error) {
return fmt.Sprintf("%s [%s]", defaultNameMonitor, o.GetBindable()), nil return o.MonitorName(), nil
}) })
inf.RegisterInfo(func() (map[string]interface{}, error) { inf.RegisterInfo(func() (map[string]interface{}, error) {
return res, nil return res, nil

View File

@@ -54,6 +54,8 @@ type Manage interface {
StoreNew(cfg libhtp.Config, defLog liblog.FuncLog) error StoreNew(cfg libhtp.Config, defLog liblog.FuncLog) error
LoadAndDelete(bindAddress string) (val libhtp.Server, loaded bool) LoadAndDelete(bindAddress string) (val libhtp.Server, loaded bool)
MonitorNames() []string
} }
type Filter interface { type Filter interface {

View File

@@ -108,6 +108,17 @@ func (o *pool) context() context.Context {
return o.p.GetContext() return o.p.GetContext()
} }
func (o *pool) MonitorNames() []string {
var res = make([]string, 0)
o.Walk(func(bindAddress string, srv libhtp.Server) bool {
res = append(res, srv.MonitorName())
return true
})
return res
}
func (o *pool) Monitor(vrs libver.Version) ([]montps.Monitor, liberr.Error) { func (o *pool) Monitor(vrs libver.Version) ([]montps.Monitor, liberr.Error) {
var ( var (
res = make([]montps.Monitor, 0) res = make([]montps.Monitor, 0)

View File

@@ -33,7 +33,7 @@ import (
"net/http" "net/http"
srvtps "github.com/nabbar/golib/httpserver/types" srvtps "github.com/nabbar/golib/httpserver/types"
liblog "github.com/nabbar/golib/logger" loglvl "github.com/nabbar/golib/logger/level"
librun "github.com/nabbar/golib/server/runner/startStop" librun "github.com/nabbar/golib/server/runner/startStop"
) )
@@ -141,11 +141,11 @@ func (o *srv) runFuncStart(ctx context.Context) (err error) {
defer func() { defer func() {
if tls { if tls {
ent := o.logger().Entry(liblog.InfoLevel, "TLS HTTP Server stopped") ent := o.logger().Entry(loglvl.InfoLevel, "TLS HTTP Server stopped")
ent.ErrorAdd(true, err) ent.ErrorAdd(true, err)
ent.Log() ent.Log()
} else { } else {
ent := o.logger().Entry(liblog.InfoLevel, "HTTP Server stopped") ent := o.logger().Entry(loglvl.InfoLevel, "HTTP Server stopped")
ent.ErrorAdd(true, err) ent.ErrorAdd(true, err)
ent.Log() ent.Log()
} }
@@ -153,13 +153,13 @@ func (o *srv) runFuncStart(ctx context.Context) (err error) {
if ser = o.getServer(); ser == nil { if ser = o.getServer(); ser == nil {
if err = o.setServer(ctx); err != nil { if err = o.setServer(ctx); err != nil {
ent := o.logger().Entry(liblog.ErrorLevel, "starting http server") ent := o.logger().Entry(loglvl.ErrorLevel, "starting http server")
ent.ErrorAdd(true, err) ent.ErrorAdd(true, err)
ent.Log() ent.Log()
return err return err
} else if ser = o.getServer(); ser == nil { } else if ser = o.getServer(); ser == nil {
err = ErrorServerStart.ErrorParent(fmt.Errorf("cannot create new server, cannot retrieve server")) err = ErrorServerStart.ErrorParent(fmt.Errorf("cannot create new server, cannot retrieve server"))
ent := o.logger().Entry(liblog.ErrorLevel, "starting http server") ent := o.logger().Entry(loglvl.ErrorLevel, "starting http server")
ent.ErrorAdd(true, err) ent.ErrorAdd(true, err)
ent.Log() ent.Log()
return err return err
@@ -175,10 +175,10 @@ func (o *srv) runFuncStart(ctx context.Context) (err error) {
} }
if tls { if tls {
o.logger().Entry(liblog.InfoLevel, "TLS HTTP Server is starting").Log() o.logger().Entry(loglvl.InfoLevel, "TLS HTTP Server is starting").Log()
err = ser.ListenAndServeTLS("", "") err = ser.ListenAndServeTLS("", "")
} else { } else {
o.logger().Entry(liblog.InfoLevel, "HTTP Server is starting").Log() o.logger().Entry(loglvl.InfoLevel, "HTTP Server is starting").Log()
err = ser.ListenAndServe() err = ser.ListenAndServe()
} }
@@ -197,11 +197,11 @@ func (o *srv) runFuncStop(ctx context.Context) (err error) {
defer func() { defer func() {
o.delServer() o.delServer()
if tls { if tls {
ent := o.logger().Entry(liblog.InfoLevel, "Shutdown of TLS HTTP Server has been called") ent := o.logger().Entry(loglvl.InfoLevel, "Shutdown of TLS HTTP Server has been called")
ent.ErrorAdd(true, err) ent.ErrorAdd(true, err)
ent.Log() ent.Log()
} else { } else {
ent := o.logger().Entry(liblog.InfoLevel, "Shutdown of HTTP Server has been called") ent := o.logger().Entry(loglvl.InfoLevel, "Shutdown of HTTP Server has been called")
ent.ErrorAdd(true, err) ent.ErrorAdd(true, err)
ent.Log() ent.Log()
} }
@@ -209,7 +209,7 @@ func (o *srv) runFuncStop(ctx context.Context) (err error) {
if ser = o.getServer(); ser == nil { if ser = o.getServer(); ser == nil {
err = ErrorServerStart.ErrorParent(fmt.Errorf("cannot retrieve server")) err = ErrorServerStart.ErrorParent(fmt.Errorf("cannot retrieve server"))
ent := o.logger().Entry(liblog.ErrorLevel, "starting http server") ent := o.logger().Entry(loglvl.ErrorLevel, "starting http server")
ent.ErrorAdd(true, err) ent.ErrorAdd(true, err)
ent.Log() ent.Log()
return err return err
@@ -218,9 +218,9 @@ func (o *srv) runFuncStop(ctx context.Context) (err error) {
} }
if tls { if tls {
o.logger().Entry(liblog.InfoLevel, "Calling TLS HTTP Server shutdown").Log() o.logger().Entry(loglvl.InfoLevel, "Calling TLS HTTP Server shutdown").Log()
} else { } else {
o.logger().Entry(liblog.InfoLevel, "Calling HTTP Server shutdown").Log() o.logger().Entry(loglvl.InfoLevel, "Calling HTTP Server shutdown").Log()
} }
err = ser.Shutdown(x) err = ser.Shutdown(x)

View File

@@ -38,7 +38,7 @@ import (
liberr "github.com/nabbar/golib/errors" liberr "github.com/nabbar/golib/errors"
srvtps "github.com/nabbar/golib/httpserver/types" srvtps "github.com/nabbar/golib/httpserver/types"
liblog "github.com/nabbar/golib/logger" loglvl "github.com/nabbar/golib/logger/level"
libsrv "github.com/nabbar/golib/server" libsrv "github.com/nabbar/golib/server"
) )
@@ -83,7 +83,7 @@ func (o *srv) setServer(ctx context.Context) error {
if o.IsTLS() && ssl == nil { if o.IsTLS() && ssl == nil {
err := ErrorServerValidate.ErrorParent(fmt.Errorf("TLS Config is not well defined")) err := ErrorServerValidate.ErrorParent(fmt.Errorf("TLS Config is not well defined"))
ent := o.logger().Entry(liblog.ErrorLevel, "starting http server") ent := o.logger().Entry(loglvl.ErrorLevel, "starting http server")
ent.ErrorAdd(true, err) ent.ErrorAdd(true, err)
ent.Log() ent.Log()
return err return err
@@ -102,13 +102,13 @@ func (o *srv) setServer(ctx context.Context) error {
s.TLSConfig = ssl.TlsConfig("") s.TLSConfig = ssl.TlsConfig("")
stdlog.SetIOWriterFilter("http: TLS handshake error from 127.0.0.1") stdlog.SetIOWriterFilter("http: TLS handshake error from 127.0.0.1")
} else if e := o.cfgGetServer().initServer(s); e != nil { } else if e := o.cfgGetServer().initServer(s); e != nil {
ent := o.logger().Entry(liblog.ErrorLevel, "init http2 server") ent := o.logger().Entry(loglvl.ErrorLevel, "init http2 server")
ent.ErrorAdd(true, e) ent.ErrorAdd(true, e)
ent.Log() ent.Log()
return e return e
} }
s.ErrorLog = stdlog.GetStdLogger(liblog.ErrorLevel, log.LstdFlags|log.Lmicroseconds) s.ErrorLog = stdlog.GetStdLogger(loglvl.ErrorLevel, log.LstdFlags|log.Lmicroseconds)
if e := o.RunIfPortInUse(ctx, o.GetBindable(), 5, fctStop); e != nil { if e := o.RunIfPortInUse(ctx, o.GetBindable(), 5, fctStop); e != nil {
return e return e

View File

@@ -29,6 +29,7 @@ package ioutils
import ( import (
"errors" "errors"
"fmt"
"os" "os"
"path/filepath" "path/filepath"
) )
@@ -36,21 +37,28 @@ import (
func PathCheckCreate(isFile bool, path string, permFile os.FileMode, permDir os.FileMode) error { func PathCheckCreate(isFile bool, path string, permFile os.FileMode, permDir os.FileMode) error {
if inf, err := os.Stat(path); err != nil && !errors.Is(err, os.ErrNotExist) { if inf, err := os.Stat(path); err != nil && !errors.Is(err, os.ErrNotExist) {
return err return err
} else if err == nil { } else if err == nil && inf.IsDir() {
if inf.IsDir() { if isFile {
return fmt.Errorf("path '%s' still exising but is a directory", path)
}
if inf.Mode() != permDir {
_ = os.Chmod(path, permDir) _ = os.Chmod(path, permDir)
} else { }
return nil
} else if err == nil && !inf.IsDir() {
if !isFile {
return fmt.Errorf("path '%s' still exising but is not a directory", path)
}
if inf.Mode() != permFile {
_ = os.Chmod(path, permFile) _ = os.Chmod(path, permFile)
} }
return nil return nil
} } else if !isFile {
if !isFile {
return os.MkdirAll(path, permDir) return os.MkdirAll(path, permDir)
} else if e := PathCheckCreate(false, filepath.Dir(path), permFile, permDir); e != nil { } else if err = PathCheckCreate(false, filepath.Dir(path), permFile, permDir); err != nil {
return e
} else if hf, err := os.Create(path); err != nil {
return err return err
} else if hf, e := os.Create(path); e != nil {
return e
} else { } else {
_ = hf.Close() _ = hf.Close()
} }

View File

@@ -37,6 +37,8 @@ import (
libctx "github.com/nabbar/golib/context" libctx "github.com/nabbar/golib/context"
liberr "github.com/nabbar/golib/errors" liberr "github.com/nabbar/golib/errors"
liblog "github.com/nabbar/golib/logger" liblog "github.com/nabbar/golib/logger"
logent "github.com/nabbar/golib/logger/entry"
loglvl "github.com/nabbar/golib/logger/level"
) )
type FuncLogger liblog.FuncLog type FuncLogger liblog.FuncLog
@@ -75,29 +77,49 @@ func (lc *HelperLDAP) SetLogger(fct liblog.FuncLog) {
lc.log = fct lc.log = fct
} }
func (lc HelperLDAP) getLogEntry(lvl liblog.Level, msg string, args ...interface{}) *liblog.Entry { func (lc *HelperLDAP) getLogDefault() liblog.Logger {
return liblog.New(func() context.Context {
return lc.ctx
})
}
func (lc *HelperLDAP) getLogEntry(lvl loglvl.Level, msg string, args ...interface{}) logent.Entry {
var log liblog.Logger var log liblog.Logger
if lc.log == nil { if lc.log == nil {
log = liblog.GetDefault() log = lc.getLogDefault()
} else if l := lc.log(); l == nil { lc.log = func() liblog.Logger {
log = liblog.GetDefault() return log
} else { }
}
if l := lc.log(); l != nil {
log = l log = l
} }
if log == nil {
return logent.New(lvl)
}
return log.Entry(lvl, msg, args...).FieldAdd("ldap.host", lc.config.ServerAddr(lc.tlsMode == TLSModeTLS)).FieldAdd("ldap.tlsMode", lc.tlsMode.String()) 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 { func (lc *HelperLDAP) getLogEntryErr(lvlKO loglvl.Level, err error, msg string, args ...interface{}) logent.Entry {
var log liblog.Logger var log liblog.Logger
if lc.log == nil { if lc.log == nil {
log = liblog.GetDefault() log = lc.getLogDefault()
} else if l := lc.log(); l == nil { lc.log = func() liblog.Logger {
log = liblog.GetDefault() return log
} else { }
}
if l := lc.log(); l != nil {
log = l log = l
} }
if log == nil {
return logent.New(lvlKO).ErrorAdd(true, err)
}
return log.Entry(lvlKO, msg, args...).FieldAdd("ldap.host", lc.config.ServerAddr(lc.tlsMode == TLSModeTLS)).ErrorAdd(true, err) return log.Entry(lvlKO, msg, args...).FieldAdd("ldap.host", lc.config.ServerAddr(lc.tlsMode == TLSModeTLS)).ErrorAdd(true, err)
} }
@@ -227,7 +249,7 @@ func (lc *HelperLDAP) tryConnect() (TLSMode, liberr.Error) {
if lc.config.Portldaps != 0 { if lc.config.Portldaps != 0 {
l, err = lc.dialTLS() l, err = lc.dialTLS()
lc.getLogEntryErr(liblog.DebugLevel, err, "connecting ldap with tls mode '%s'", TLSModeTLS.String()).Check(liblog.DebugLevel) lc.getLogEntryErr(loglvl.DebugLevel, err, "connecting ldap with tls mode '%s'", TLSModeTLS.String()).Check(loglvl.DebugLevel)
if err == nil { if err == nil {
return TLSModeTLS, nil return TLSModeTLS, nil
@@ -239,14 +261,14 @@ func (lc *HelperLDAP) tryConnect() (TLSMode, liberr.Error) {
} }
l, err = lc.dial() l, err = lc.dial()
lc.getLogEntryErr(liblog.DebugLevel, err, "connecting ldap with tls mode '%s'", TLSModeNone.String()).Check(liblog.DebugLevel) lc.getLogEntryErr(loglvl.DebugLevel, err, "connecting ldap with tls mode '%s'", TLSModeNone.String()).Check(loglvl.DebugLevel)
if err != nil { if err != nil {
return _TLSModeInit, err return _TLSModeInit, err
} }
err = lc.starttls(l) err = lc.starttls(l)
lc.getLogEntryErr(liblog.DebugLevel, err, "connecting ldap with tls mode '%s'", TLSModeStarttls.String()).Check(liblog.DebugLevel) lc.getLogEntryErr(loglvl.DebugLevel, err, "connecting ldap with tls mode '%s'", TLSModeStarttls.String()).Check(loglvl.DebugLevel)
if err == nil { if err == nil {
return TLSModeStarttls, nil return TLSModeStarttls, nil
@@ -310,7 +332,7 @@ func (lc *HelperLDAP) connect() liberr.Error {
} }
} }
lc.getLogEntry(liblog.DebugLevel, "ldap connected").Log() lc.getLogEntry(loglvl.DebugLevel, "ldap connected").Log()
lc.conn = l lc.conn = l
} }
@@ -381,7 +403,7 @@ func (lc *HelperLDAP) Connect() liberr.Error {
return err return err
} }
lc.getLogEntry(liblog.DebugLevel, "ldap bind success").FieldAdd("bind.dn", lc.bindDN).Log() lc.getLogEntry(loglvl.DebugLevel, "ldap bind success").FieldAdd("bind.dn", lc.bindDN).Log()
return nil return nil
} }
@@ -411,7 +433,7 @@ func (lc *HelperLDAP) runSearch(filter string, attributes []string) (*ldap.Searc
return nil, ErrorLDAPSearch.ErrorParent(err) return nil, ErrorLDAPSearch.ErrorParent(err)
} }
lc.getLogEntry(liblog.DebugLevel, "ldap search success").FieldAdd("ldap.filter", filter).FieldAdd("ldap.attributes", attributes).Log() lc.getLogEntry(loglvl.DebugLevel, "ldap search success").FieldAdd("ldap.filter", filter).FieldAdd("ldap.attributes", attributes).Log()
return src, nil return src, nil
} }
@@ -480,7 +502,7 @@ func (lc *HelperLDAP) UserInfoByField(username string, fieldOfUnicValue string)
userRes["DN"] = src.Entries[0].DN userRes["DN"] = src.Entries[0].DN
} }
lc.getLogEntry(liblog.DebugLevel, "ldap user find success").FieldAdd("ldap.user", username).FieldAdd("ldap.map", userRes).Log() lc.getLogEntry(loglvl.DebugLevel, "ldap user find success").FieldAdd("ldap.user", username).FieldAdd("ldap.map", userRes).Log()
return userRes, nil return userRes, nil
} }
@@ -513,7 +535,7 @@ func (lc *HelperLDAP) GroupInfoByField(groupname string, fieldForUnicValue strin
} }
} }
lc.getLogEntry(liblog.DebugLevel, "ldap group find success").FieldAdd("ldap.group", groupname).FieldAdd("ldap.map", grpInfo).Log() lc.getLogEntry(loglvl.DebugLevel, "ldap group find success").FieldAdd("ldap.group", groupname).FieldAdd("ldap.map", grpInfo).Log()
return grpInfo, nil return grpInfo, nil
} }
@@ -538,13 +560,13 @@ func (lc *HelperLDAP) UserMemberOf(username string) ([]string, liberr.Error) {
for _, entry := range src.Entries { for _, entry := range src.Entries {
for _, mmb := range entry.GetAttributeValues("memberOf") { for _, mmb := range entry.GetAttributeValues("memberOf") {
lc.getLogEntry(liblog.DebugLevel, "ldap find user group list building").FieldAdd("ldap.user", username).FieldAdd("ldap.raw.groups", mmb).Log() lc.getLogEntry(loglvl.DebugLevel, "ldap find user group list building").FieldAdd("ldap.user", username).FieldAdd("ldap.raw.groups", mmb).Log()
mmo := lc.ParseEntries(mmb) mmo := lc.ParseEntries(mmb)
grp = append(grp, mmo["cn"]...) grp = append(grp, mmo["cn"]...)
} }
} }
lc.getLogEntry(liblog.DebugLevel, "ldap user group list success").FieldAdd("ldap.user", username).FieldAdd("ldap.grouplist", grp).Log() lc.getLogEntry(loglvl.DebugLevel, "ldap user group list success").FieldAdd("ldap.user", username).FieldAdd("ldap.grouplist", grp).Log()
return grp, nil return grp, nil
} }
@@ -594,12 +616,12 @@ func (lc *HelperLDAP) UsersOfGroup(groupname string) ([]string, liberr.Error) {
} }
} }
lc.getLogEntry(liblog.DebugLevel, "ldap group user list success").FieldAdd("ldap.group", groupname).FieldAdd("ldap.userlist", grp).Log() lc.getLogEntry(loglvl.DebugLevel, "ldap group user list success").FieldAdd("ldap.group", groupname).FieldAdd("ldap.userlist", grp).Log()
return grp, nil return grp, nil
} }
// ParseEntries used to clean attributes of an object class. // ParseEntries used to clean attributes of an object class.
func (lc HelperLDAP) ParseEntries(entry string) map[string][]string { func (lc *HelperLDAP) ParseEntries(entry string) map[string][]string {
var listEntries = make(map[string][]string) var listEntries = make(map[string][]string)
for _, ent := range strings.Split(entry, ",") { for _, ent := range strings.Split(entry, ",") {

View File

@@ -1,281 +0,0 @@
/***********************************************************************************************************************
*
* 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(context.Background)
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(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(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(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(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(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, "", err)
}
// 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(true, 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(true, 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(true, 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(true, err).Check(levelElse)
}

View File

@@ -1,7 +1,8 @@
/* /***********************************************************************************************************************
*
* MIT License * MIT License
* *
* Copyright (c) 2022 Nicolas JUHEL * Copyright (c) 2021 Nicolas JUHEL
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +23,7 @@
* SOFTWARE. * SOFTWARE.
* *
* *
*/ **********************************************************************************************************************/
package config package config
@@ -35,12 +36,15 @@ import (
var _defaultConfig = []byte(` var _defaultConfig = []byte(`
{ {
"inheritDefault": false,
"traceFilter":"",
"stdout":{
"disableStandard":false, "disableStandard":false,
"disableStack":false, "disableStack":false,
"disableTimestamp":false, "disableTimestamp":false,
"enableTrace":true, "enableTrace":true,
"traceFilter":"",
"disableColor":false, "disableColor":false,
},
"logFile":[ "logFile":[
{ {
"logLevel":[ "logLevel":[

57
logger/config/error.go Normal file
View File

@@ -0,0 +1,57 @@
/***********************************************************************************************************************
*
* 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 config
import (
"fmt"
liberr "github.com/nabbar/golib/errors"
)
const (
ErrorParamEmpty liberr.CodeError = iota + liberr.MinPkgLogger
ErrorValidatorError
)
func init() {
if liberr.ExistInMapMessage(ErrorParamEmpty) {
panic(fmt.Errorf("error code collision with package golib/logger"))
}
liberr.RegisterIdFctMessage(ErrorParamEmpty, getMessage)
}
func getMessage(code liberr.CodeError) (message string) {
switch code {
case ErrorParamEmpty:
return "given parameters is empty"
case ErrorValidatorError:
return "logger : invalid config"
}
return liberr.NullMessage
}

204
logger/config/model.go Normal file
View File

@@ -0,0 +1,204 @@
/***********************************************************************************************************************
*
* 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 config
import (
"fmt"
libval "github.com/go-playground/validator/v10"
liberr "github.com/nabbar/golib/errors"
)
type FuncOpt func() *Options
type Options struct {
// InheritDefault define if the current options will override a default options
InheritDefault bool `json:"inheritDefault" yaml:"inheritDefault" toml:"inheritDefault" mapstructure:"inheritDefault"`
// TraceFilter define the path to clean for trace.
TraceFilter string `json:"traceFilter,omitempty" yaml:"traceFilter,omitempty" toml:"traceFilter,omitempty" mapstructure:"traceFilter,omitempty"`
// Stdout define the options for stdout/stderr log.
Stdout *OptionsStd `json:"stdout,omitempty" yaml:"stdout,omitempty" toml:"stdout,omitempty" mapstructure:"stdout,omitempty"`
// LogFileExtend define if the logFile given is in addition of default LogFile or a replacement.
LogFileExtend bool `json:"logFileExtend,omitempty" yaml:"logFileExtend,omitempty" toml:"logFileExtend,omitempty" mapstructure:"logFileExtend,omitempty"`
// LogFile define a list of log file configuration to allow log to files.
LogFile OptionsFiles `json:"logFile,omitempty" yaml:"logFile,omitempty" toml:"logFile,omitempty" mapstructure:"logFile,omitempty"`
// LogSyslogExtend define if the logFile given is in addition of default LogSyslog or a replacement.
LogSyslogExtend bool `json:"logSyslogExtend,omitempty" yaml:"logSyslogExtend,omitempty" toml:"logSyslogExtend,omitempty" mapstructure:"logSyslogExtend,omitempty"`
// LogSyslog define a list of syslog configuration to allow log to syslog.
LogSyslog OptionsSyslogs `json:"logSyslog,omitempty" yaml:"logSyslog,omitempty" toml:"logSyslog,omitempty" mapstructure:"logSyslog,omitempty"`
// default options
opts FuncOpt
}
// RegisterDefaultFunc allow to register a function called to retrieve default options for inheritDefault.
// If not set, the previous options will be used as default options.
// To clean function, just call RegisterDefaultFunc with nil as param.
func (o *Options) RegisterDefaultFunc(fct FuncOpt) {
o.opts = fct
}
// Validate allow checking if the options' struct is valid with the awaiting model
func (o *Options) Validate() liberr.Error {
var e = ErrorValidatorError.Error(nil)
if err := libval.New().Struct(o); err != nil {
if er, ok := err.(*libval.InvalidValidationError); ok {
e.AddParent(er)
}
for _, er := range err.(libval.ValidationErrors) {
//nolint #goerr113
e.AddParent(fmt.Errorf("config field '%s' is not validated by constraint '%s'", er.Namespace(), er.ActualTag()))
}
}
if !e.HasParent() {
e = nil
}
return e
}
func (o *Options) Clone() Options {
var s *OptionsStd
if o.Stdout != nil {
s = o.Stdout.Clone()
}
return Options{
InheritDefault: o.InheritDefault,
TraceFilter: o.TraceFilter,
Stdout: s,
LogFile: o.LogFile.Clone(),
LogSyslog: o.LogSyslog.Clone(),
}
}
func (o *Options) Merge(opt *Options) {
if len(opt.TraceFilter) > 0 {
o.TraceFilter = opt.TraceFilter
}
if opt.Stdout != nil {
if o.Stdout == nil {
o.Stdout = &OptionsStd{}
}
if opt.Stdout.DisableStandard {
o.Stdout.DisableStandard = opt.Stdout.DisableStandard
}
if opt.Stdout.DisableColor {
o.Stdout.DisableColor = opt.Stdout.DisableColor
}
if opt.Stdout.DisableTimestamp {
o.Stdout.DisableTimestamp = opt.Stdout.DisableTimestamp
}
if opt.Stdout.DisableStack {
o.Stdout.DisableStack = opt.Stdout.DisableStack
}
if opt.Stdout.EnableTrace {
o.Stdout.EnableTrace = opt.Stdout.EnableTrace
}
if opt.Stdout.EnableAccessLog {
o.Stdout.EnableAccessLog = opt.Stdout.EnableAccessLog
}
}
if opt.LogFileExtend {
o.LogFile = append(o.LogFile, opt.LogFile...)
} else {
o.LogFile = opt.LogFile
}
if opt.LogSyslogExtend {
o.LogSyslog = append(o.LogSyslog, opt.LogSyslog...)
} else {
o.LogSyslog = opt.LogSyslog
}
if opt.opts != nil {
o.opts = opt.opts
}
}
func (o *Options) Options() *Options {
var no Options
if o.opts != nil && o.InheritDefault {
no = *o.opts()
}
if len(o.TraceFilter) > 0 {
no.TraceFilter = o.TraceFilter
}
if o.Stdout != nil {
if no.Stdout == nil {
no.Stdout = &OptionsStd{}
}
if o.Stdout.DisableStandard {
no.Stdout.DisableStandard = o.Stdout.DisableStandard
}
if o.Stdout.DisableColor {
no.Stdout.DisableColor = o.Stdout.DisableColor
}
if o.Stdout.DisableTimestamp {
no.Stdout.DisableTimestamp = o.Stdout.DisableTimestamp
}
if o.Stdout.DisableStack {
no.Stdout.DisableStack = o.Stdout.DisableStack
}
if o.Stdout.EnableTrace {
no.Stdout.EnableTrace = o.Stdout.EnableTrace
}
if o.Stdout.EnableAccessLog {
no.Stdout.EnableAccessLog = o.Stdout.EnableAccessLog
}
}
if o.LogFileExtend {
no.LogFile = append(no.LogFile, o.LogFile...)
} else {
no.LogFile = o.LogFile
}
if o.LogSyslogExtend {
no.LogSyslog = append(no.LogSyslog, o.LogSyslog...)
} else {
no.LogSyslog = o.LogSyslog
}
return &no
}

View File

@@ -0,0 +1,87 @@
/***********************************************************************************************************************
*
* 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 config
import "os"
type OptionsFile struct {
// LogLevel define the allowed level of log for this file.
LogLevel []string `json:"logLevel,omitempty" yaml:"logLevel,omitempty" toml:"logLevel,omitempty" mapstructure:"logLevel,omitempty"`
// Filepath define the file path for log to file.
Filepath string `json:"filepath,omitempty" yaml:"filepath,omitempty" toml:"filepath,omitempty" mapstructure:"filepath,omitempty"`
// Create define if the log file must exist or can create it.
Create bool `json:"create,omitempty" yaml:"create,omitempty" toml:"create,omitempty" mapstructure:"create,omitempty"`
// CreatePath define if the path of the log file must exist or can try to create it.
CreatePath bool `json:"createPath,omitempty" yaml:"createPath,omitempty" toml:"createPath,omitempty" mapstructure:"createPath,omitempty"`
// FileMode define mode to be used for the log file if the create it.
FileMode os.FileMode `json:"fileMode,omitempty" yaml:"fileMode,omitempty" toml:"fileMode,omitempty" mapstructure:"fileMode,omitempty"`
// PathMode define mode to be used for the path of the log file if create it.
PathMode os.FileMode `json:"pathMode,omitempty" yaml:"pathMode,omitempty" toml:"pathMode,omitempty" mapstructure:"pathMode,omitempty"`
// DisableStack allow to disable the goroutine id before each message.
DisableStack bool `json:"disableStack,omitempty" yaml:"disableStack,omitempty" toml:"disableStack,omitempty" mapstructure:"disableStack,omitempty"`
// DisableTimestamp allow to disable the timestamp before each message.
DisableTimestamp bool `json:"disableTimestamp,omitempty" yaml:"disableTimestamp,omitempty" toml:"disableTimestamp,omitempty" mapstructure:"disableTimestamp,omitempty"`
// EnableTrace allow to add the origin caller/file/line of each message.
EnableTrace bool `json:"enableTrace,omitempty" yaml:"enableTrace,omitempty" toml:"enableTrace,omitempty" mapstructure:"enableTrace,omitempty"`
// EnableAccessLog allow to add all message from api router for access log and error log.
EnableAccessLog bool `json:"enableAccessLog,omitempty" yaml:"enableAccessLog,omitempty" toml:"enableAccessLog,omitempty" mapstructure:"enableAccessLog,omitempty"`
}
type OptionsFiles []OptionsFile
func (o OptionsFile) Clone() OptionsFile {
return OptionsFile{
LogLevel: o.LogLevel,
Filepath: o.Filepath,
Create: o.Create,
CreatePath: o.CreatePath,
FileMode: o.FileMode,
PathMode: o.PathMode,
DisableStack: o.DisableStack,
DisableTimestamp: o.DisableTimestamp,
EnableTrace: o.EnableTrace,
EnableAccessLog: o.EnableAccessLog,
}
}
func (o OptionsFiles) Clone() OptionsFiles {
var c = make([]OptionsFile, 0)
for _, i := range o {
c = append(c, i.Clone())
}
return c
}

View File

@@ -0,0 +1,60 @@
/***********************************************************************************************************************
*
* 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 config
type OptionsStd struct {
// DisableStandard allow disabling to write log to standard output stdout/stderr.
DisableStandard bool `json:"disableStandard,omitempty" yaml:"disableStandard,omitempty" toml:"disableStandard,omitempty" mapstructure:"disableStandard,omitempty"`
// DisableStack allow to disable the goroutine id before each message.
DisableStack bool `json:"disableStack,omitempty" yaml:"disableStack,omitempty" toml:"disableStack,omitempty" mapstructure:"disableStack,omitempty"`
// DisableTimestamp allow to disable the timestamp before each message.
DisableTimestamp bool `json:"disableTimestamp,omitempty" yaml:"disableTimestamp,omitempty" toml:"disableTimestamp,omitempty" mapstructure:"disableTimestamp,omitempty"`
// EnableTrace allow to add the origin caller/file/line of each message.
EnableTrace bool `json:"enableTrace,omitempty" yaml:"enableTrace,omitempty" toml:"enableTrace,omitempty" mapstructure:"enableTrace,omitempty"`
// 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 `json:"disableColor,omitempty" yaml:"disableColor,omitempty" toml:"disableColor,omitempty" mapstructure:"disableColor,omitempty"`
// EnableAccessLog allow to add all message from api router for access log and error log.
EnableAccessLog bool `json:"enableAccessLog,omitempty" yaml:"enableAccessLog,omitempty" toml:"enableAccessLog,omitempty" mapstructure:"enableAccessLog,omitempty"`
}
func (o *OptionsStd) Clone() *OptionsStd {
return &OptionsStd{
DisableStandard: o.DisableStandard,
DisableStack: o.DisableStack,
DisableTimestamp: o.DisableTimestamp,
EnableTrace: o.EnableTrace,
DisableColor: o.DisableColor,
EnableAccessLog: o.EnableAccessLog,
}
}

View File

@@ -0,0 +1,86 @@
/***********************************************************************************************************************
*
* 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 config
type OptionsSyslog struct {
// LogLevel define the allowed level of log for this syslog.
LogLevel []string `json:"logLevel,omitempty" yaml:"logLevel,omitempty" toml:"logLevel,omitempty" mapstructure:"logLevel,omitempty"`
// Network define the network used to connect to this syslog (tcp, udp, or any other to a local connection).
Network string `json:"network,omitempty" yaml:"network,omitempty" toml:"network,omitempty" mapstructure:"network,omitempty"`
// Host define the remote syslog to use.
// If Host and Network are empty, local syslog will be used.
Host string `json:"host,omitempty" yaml:"host,omitempty" toml:"host,omitempty" mapstructure:"host,omitempty"`
/*
// Severity define the severity syslog to be used.
Severity string `json:"severity,omitempty" yaml:"severity,omitempty" toml:"severity,omitempty" mapstructure:"severity,omitempty"`
*/
// Facility define the facility syslog to be used.
Facility string `json:"facility,omitempty" yaml:"facility,omitempty" toml:"facility,omitempty" mapstructure:"facility,omitempty"`
// Tag define the syslog tag used in linux syslog system or name of logger for windows event logger.
// For window, this value must be unic for each syslog config
Tag string `json:"tag,omitempty" yaml:"tag,omitempty" toml:"tag,omitempty" mapstructure:"tag,omitempty"`
// DisableStack allow to disable the goroutine id before each message.
DisableStack bool `json:"disableStack,omitempty" yaml:"disableStack,omitempty" toml:"disableStack,omitempty" mapstructure:"disableStack,omitempty"`
// DisableTimestamp allow to disable the timestamp before each message.
DisableTimestamp bool `json:"disableTimestamp,omitempty" yaml:"disableTimestamp,omitempty" toml:"disableTimestamp,omitempty" mapstructure:"disableTimestamp,omitempty"`
// EnableTrace allow to add the origin caller/file/line of each message.
EnableTrace bool `json:"enableTrace,omitempty" yaml:"enableTrace,omitempty" toml:"enableTrace,omitempty" mapstructure:"enableTrace,omitempty"`
// EnableAccessLog allow to add all message from api router for access log and error log.
EnableAccessLog bool `json:"enableAccessLog,omitempty" yaml:"enableAccessLog,omitempty" toml:"enableAccessLog,omitempty" mapstructure:"enableAccessLog,omitempty"`
}
type OptionsSyslogs []OptionsSyslog
func (o OptionsSyslog) Clone() OptionsSyslog {
return OptionsSyslog{
LogLevel: o.LogLevel,
Network: o.Network,
Host: o.Host,
Facility: o.Facility,
Tag: o.Tag,
DisableStack: o.DisableStack,
DisableTimestamp: o.DisableTimestamp,
EnableTrace: o.EnableTrace,
EnableAccessLog: o.EnableAccessLog,
}
}
func (o OptionsSyslogs) Clone() OptionsSyslogs {
var c = make([]OptionsSyslog, 0)
for _, i := range o {
c = append(c, i.Clone())
}
return c
}

68
logger/entry/errors.go Normal file
View File

@@ -0,0 +1,68 @@
/***********************************************************************************************************************
*
* 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 entry
import (
liberr "github.com/nabbar/golib/errors"
)
func (e *entry) ErrorClean() Entry {
e.Error = make([]error, 0)
return e
}
func (e *entry) ErrorSet(err []error) Entry {
if len(err) < 1 {
err = make([]error, 0)
}
e.Error = err
return e
}
func (e *entry) ErrorAdd(cleanNil bool, err ...error) Entry {
if len(e.Error) < 1 {
e.Error = make([]error, 0)
}
for _, er := range err {
if cleanNil && er == nil {
continue
}
e.Error = append(e.Error, er)
}
return e
}
func (e *entry) ErrorAddLib(cleanNil bool, err ...liberr.Error) Entry {
for _, er := range err {
e.ErrorAdd(cleanNil, er.GetErrorSlice()...)
}
return e
}

58
logger/entry/field.go Normal file
View File

@@ -0,0 +1,58 @@
/***********************************************************************************************************************
*
* 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 entry
import (
logfld "github.com/nabbar/golib/logger/fields"
)
// 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 logfld.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 logfld.Fields) Entry {
e.Fields = fields
return e
}
func (e *entry) FieldClean(keys ...string) Entry {
for _, k := range keys {
e.Fields.Delete(k)
}
return e
}

73
logger/entry/interface.go Normal file
View File

@@ -0,0 +1,73 @@
/***********************************************************************************************************************
*
* 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 entry
import (
"time"
ginsdk "github.com/gin-gonic/gin"
liberr "github.com/nabbar/golib/errors"
logfld "github.com/nabbar/golib/logger/fields"
loglvl "github.com/nabbar/golib/logger/level"
"github.com/sirupsen/logrus"
)
type Entry interface {
SetLogger(fct func() *logrus.Logger) Entry
SetLevel(lvl loglvl.Level) Entry
SetMessageOnly(flag bool) Entry
SetEntryContext(etime time.Time, stack uint64, caller, file string, line uint64, msg string) Entry
SetGinContext(ctx *ginsdk.Context) Entry
DataSet(data interface{}) Entry
Check(lvlNoErr loglvl.Level) bool
Log()
FieldAdd(key string, val interface{}) Entry
FieldMerge(fields logfld.Fields) Entry
FieldSet(fields logfld.Fields) Entry
FieldClean(keys ...string) Entry
ErrorClean() Entry
ErrorSet(err []error) Entry
ErrorAdd(cleanNil bool, err ...error) Entry
ErrorAddLib(cleanNil bool, err ...liberr.Error) Entry
}
func New(lvl loglvl.Level) Entry {
return &entry{
log: nil,
gin: nil,
clean: false,
Level: lvl,
Time: time.Now(),
Error: make([]error, 0),
Data: nil,
Fields: nil,
}
}

View File

@@ -25,41 +25,30 @@
* *
**********************************************************************************************************************/ **********************************************************************************************************************/
package logger package entry
import ( import (
"os" "os"
"strings" "strings"
"time" "time"
"github.com/gin-gonic/gin" ginsdk "github.com/gin-gonic/gin"
logfld "github.com/nabbar/golib/logger/fields"
liberr "github.com/nabbar/golib/errors" loglvl "github.com/nabbar/golib/logger/level"
logtps "github.com/nabbar/golib/logger/types"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
const ( type entry struct {
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 log func() *logrus.Logger
gin *gin.Context gin *ginsdk.Context
clean bool clean bool
//Time is the time of the event (can be empty time if disabled timestamp) //Time is the time of the event (can be empty time if disabled timestamp)
Time time.Time `json:"time"` Time time.Time `json:"time"`
//Level define the level of the entry (cannot be empty or nil) //Level define the level of the entry (cannot be empty or nil)
Level Level `json:"level"` Level loglvl.Level `json:"level"`
//Stack define the process goroutine number (can be 0 if disabled) //Stack define the process goroutine number (can be 0 if disabled)
Stack uint64 `json:"stack"` Stack uint64 `json:"stack"`
@@ -71,7 +60,7 @@ type Entry struct {
File string `json:"file"` 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) //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"` Line uint64 `json:"line"`
//Message define the main message of the entry (can be empty) //Message define the main message of the entry (can be empty)
Message string `json:"message"` Message string `json:"message"`
@@ -83,74 +72,46 @@ type Entry struct {
Data interface{} `json:"data"` 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 are a list of custom information to add to log entry (can be nil or can overwrite Entry values)
Fields Fields `json:"fields"` Fields logfld.Fields `json:"fields"`
}
func (e *entry) SetEntryContext(etime time.Time, stack uint64, caller, file string, line uint64, msg string) Entry {
e.Time = etime
e.Stack = stack
e.Caller = caller
e.File = file
e.Line = line
e.Message = msg
return e
}
func (e *entry) SetMessageOnly(flag bool) Entry {
e.clean = flag
return e
}
func (e *entry) SetLevel(lvl loglvl.Level) Entry {
e.Level = lvl
return e
}
func (e *entry) SetLogger(fct func() *logrus.Logger) Entry {
e.log = fct
return e
} }
// SetGinContext allow to register a gin context pointer to register the errors of the current entry intro gin Context Error Slice. // 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 { func (e *entry) SetGinContext(ctx *ginsdk.Context) Entry {
e.gin = ctx e.gin = ctx
return e return e
} }
// FieldAdd allow to add one couple key/val as type string/interface into the custom field of the entry. func (e *entry) DataSet(data interface{}) 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 {
for _, k := range keys {
e.Fields.Delete(k)
}
return e
}
func (e *Entry) DataSet(data interface{}) *Entry {
e.Data = data e.Data = data
return e return e
} }
func (e *Entry) ErrorClean() *Entry { func (e *entry) Check(lvlNoErr loglvl.Level) bool {
e.Error = make([]error, 0)
return e
}
func (e *Entry) ErrorSet(err []error) *Entry {
e.Error = err
return e
}
func (e *Entry) ErrorAdd(cleanNil bool, err ...error) *Entry {
for _, er := range err {
if cleanNil && er == nil {
continue
}
e.Error = append(e.Error, er)
}
return e
}
func (e *Entry) ErrorAddLib(cleanNil bool, err ...liberr.Error) *Entry {
for _, er := range err {
e.ErrorAdd(cleanNil, er.GetErrorSlice()...)
}
return e
}
func (e *Entry) Check(lvlNoErr Level) bool {
var found = false var found = false
if len(e.Error) > 0 { if len(e.Error) > 0 {
for _, er := range e.Error { for _, er := range e.Error {
@@ -171,21 +132,7 @@ func (e *Entry) Check(lvlNoErr Level) bool {
return found return found
} }
func (e *Entry) _logClean() { func (e *entry) Log() {
var (
log *logrus.Logger
)
if e.log == nil {
return
} else if log = e.log(); log == nil {
return
} else {
log.Info(e.Message)
}
}
func (e *Entry) Log() {
if e == nil { if e == nil {
return return
} else if e.Fields == nil { } else if e.Fields == nil {
@@ -201,36 +148,36 @@ func (e *Entry) Log() {
} }
} }
if e.Level == NilLevel { if e.Level == loglvl.NilLevel {
return return
} }
var ( var (
ent *logrus.Entry ent *logrus.Entry
tag = NewFields(e.Fields.GetContext).Add(FieldLevel, e.Level.String()) tag = logfld.New(e.Fields.GetContext).Add(logtps.FieldLevel, e.Level.String())
log *logrus.Logger log *logrus.Logger
) )
if !e.Time.IsZero() { if !e.Time.IsZero() {
tag = tag.Add(FieldTime, e.Time.Format(time.RFC3339Nano)) tag = tag.Add(logtps.FieldTime, e.Time.Format(time.RFC3339Nano))
} }
if e.Stack > 0 { if e.Stack > 0 {
tag = tag.Add(FieldStack, e.Stack) tag = tag.Add(logtps.FieldStack, e.Stack)
} }
if e.Caller != "" { if e.Caller != "" {
tag = tag.Add(FieldCaller, e.Caller) tag = tag.Add(logtps.FieldCaller, e.Caller)
} else if e.File != "" { } else if e.File != "" {
tag = tag.Add(FieldFile, e.File) tag = tag.Add(logtps.FieldFile, e.File)
} }
if e.Line > 0 { if e.Line > 0 {
tag = tag.Add(FieldLine, e.Line) tag = tag.Add(logtps.FieldLine, e.Line)
} }
if e.Message != "" { if e.Message != "" {
tag = tag.Add(FieldMessage, e.Message) tag = tag.Add(logtps.FieldMessage, e.Message)
} }
if len(e.Error) > 0 { if len(e.Error) > 0 {
@@ -243,11 +190,11 @@ func (e *Entry) Log() {
msg = append(msg, er.Error()) msg = append(msg, er.Error())
} }
tag = tag.Add(FieldError, strings.Join(msg, ", ")) tag = tag.Add(logtps.FieldError, strings.Join(msg, ", "))
} }
if e.Data != nil { if e.Data != nil {
tag = tag.Add(FieldData, e.Data) tag = tag.Add(logtps.FieldData, e.Data)
} }
tag.Merge(e.Fields) tag.Merge(e.Fields)
@@ -262,7 +209,22 @@ func (e *Entry) Log() {
ent.Log(e.Level.Logrus()) ent.Log(e.Level.Logrus())
if e.Level <= FatalLevel { if e.Level <= loglvl.FatalLevel {
os.Exit(1) os.Exit(1)
} }
} }
func (e *entry) _logClean() {
var (
log *logrus.Logger
)
if e.log == nil {
return
} else if log = e.log(); log == nil {
return
} else {
//log.SetLevel(logrus.InfoLevel)
log.Info(e.Message)
}
}

View File

@@ -1,56 +0,0 @@
/*
* 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
import (
"fmt"
liberr "github.com/nabbar/golib/errors"
)
const (
ErrorParamEmpty liberr.CodeError = iota + liberr.MinPkgLogger
ErrorValidatorError
)
func init() {
if liberr.ExistInMapMessage(ErrorParamEmpty) {
panic(fmt.Errorf("error code collision with package golib/logger"))
}
liberr.RegisterIdFctMessage(ErrorParamEmpty, getMessage)
}
func getMessage(code liberr.CodeError) (message string) {
switch code {
case ErrorParamEmpty:
return "given parameters is empty"
case ErrorValidatorError:
return "logger : invalid config"
}
return liberr.NullMessage
}

View File

@@ -0,0 +1,53 @@
/***********************************************************************************************************************
*
* 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 fields
import (
"context"
"encoding/json"
libctx "github.com/nabbar/golib/context"
"github.com/sirupsen/logrus"
)
type Fields interface {
libctx.Config[string]
json.Marshaler
json.Unmarshaler
FieldsClone(ctx context.Context) Fields
Add(key string, val interface{}) Fields
Logrus() logrus.Fields
Map(fct func(key string, val interface{}) interface{}) Fields
}
func New(ctx libctx.FuncContext) Fields {
return &fldModel{
libctx.NewConfig[string](ctx),
}
}

View File

@@ -25,7 +25,7 @@
* *
**********************************************************************************************************************/ **********************************************************************************************************************/
package logger package fields
import ( import (
"context" "context"
@@ -35,23 +35,6 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
type Fields interface {
libctx.Config[string]
json.Marshaler
json.Unmarshaler
FieldsClone(ctx context.Context) Fields
Add(key string, val interface{}) Fields
Logrus() logrus.Fields
Map(fct func(key string, val interface{}) interface{}) Fields
}
func NewFields(ctx libctx.FuncContext) Fields {
return &fldModel{
libctx.NewConfig[string](ctx),
}
}
type fldModel struct { type fldModel struct {
libctx.Config[string] libctx.Config[string]
} }

View File

@@ -28,79 +28,19 @@
package logger package logger
import ( import (
"io"
"log" "log"
"github.com/hashicorp/go-hclog" loglvl "github.com/nabbar/golib/logger/level"
jww "github.com/spf13/jwalterweatherman"
) )
func (o *logger) GetStdLogger(lvl Level, logFlags int) *log.Logger { func (o *logger) GetStdLogger(lvl loglvl.Level, logFlags int) *log.Logger {
o.SetIOWriterLevel(lvl) o.SetIOWriterLevel(lvl)
return log.New(o, "", logFlags) return log.New(o, "", logFlags)
} }
func (o *logger) SetStdLogger(lvl Level, logFlags int) { func (o *logger) SetStdLogger(lvl loglvl.Level, logFlags int) {
o.SetIOWriterLevel(lvl) o.SetIOWriterLevel(lvl)
log.SetOutput(o) log.SetOutput(o)
log.SetPrefix("") log.SetPrefix("")
log.SetFlags(logFlags) log.SetFlags(logFlags)
} }
func (o *logger) SetSPF13Level(lvl Level, log *jww.Notepad) {
var (
fOutLog func(handle io.Writer)
fLvl func(threshold jww.Threshold)
)
if log == nil {
jww.SetStdoutOutput(io.Discard)
fOutLog = jww.SetLogOutput
fLvl = jww.SetLogThreshold
} else {
fOutLog = log.SetLogOutput
fLvl = log.SetLogThreshold
}
switch lvl {
case NilLevel:
fOutLog(io.Discard)
fLvl(jww.LevelCritical)
case DebugLevel:
fOutLog(o)
if opt := o.GetOptions(); opt.EnableTrace {
fLvl(jww.LevelTrace)
} else {
fLvl(jww.LevelDebug)
}
case InfoLevel:
fOutLog(o)
fLvl(jww.LevelInfo)
case WarnLevel:
fOutLog(o)
fLvl(jww.LevelWarn)
case ErrorLevel:
fOutLog(o)
fLvl(jww.LevelError)
case FatalLevel:
fOutLog(o)
fLvl(jww.LevelFatal)
case PanicLevel:
fOutLog(o)
fLvl(jww.LevelCritical)
}
}
func (o *logger) SetHashicorpHCLog() {
hclog.SetDefault(&_hclog{
l: o,
})
}
func (o *logger) NewHashicorpHCLog() hclog.Logger {
return &_hclog{
l: o,
}
}

View File

@@ -1,106 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2022 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"
"errors"
"fmt"
"time"
gorlog "gorm.io/gorm/logger"
)
type logGorm struct {
i bool
s time.Duration
l func() Logger
}
func NewGormLogger(fct func() Logger, ignoreRecordNotFoundError bool, slowThreshold time.Duration) gorlog.Interface {
return &logGorm{
i: ignoreRecordNotFoundError,
s: slowThreshold,
l: fct,
}
}
func (l *logGorm) LogMode(level gorlog.LogLevel) gorlog.Interface {
switch level {
case gorlog.Silent:
l.l().SetLevel(NilLevel)
case gorlog.Info:
l.l().SetLevel(InfoLevel)
case gorlog.Warn:
l.l().SetLevel(WarnLevel)
case gorlog.Error:
l.l().SetLevel(ErrorLevel)
}
return l
}
func (l *logGorm) Info(ctx context.Context, s string, i ...interface{}) {
l.l().Entry(InfoLevel, s, i...).Log()
}
func (l *logGorm) Warn(ctx context.Context, s string, i ...interface{}) {
l.l().Entry(WarnLevel, s, i...).Log()
}
func (l *logGorm) Error(ctx context.Context, s string, i ...interface{}) {
l.l().Entry(ErrorLevel, s, i...).Log()
}
func (l *logGorm) Trace(ctx context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error) {
var e *Entry
elapsed := time.Since(begin)
switch {
case err != nil && (!errors.Is(err, gorlog.ErrRecordNotFound) || !l.i):
e = l.l().Entry(ErrorLevel, "database error with trace")
e.ErrorAdd(true, err)
case elapsed > l.s && l.s != 0:
e = l.l().Entry(WarnLevel, "database warning with trace")
e.ErrorAdd(true, fmt.Errorf("SLOW Query >= %v", l.s))
default:
e = l.l().Entry(InfoLevel, "database trace")
}
e.FieldAdd("elapsed ms", float64(elapsed.Nanoseconds())/1e6)
sql, rows := fc()
if rows == -1 {
e.FieldAdd("rows", "-")
e.FieldAdd("query", sql)
} else {
e.FieldAdd("rows", rows)
e.FieldAdd("query", sql)
}
e.Log()
}

43
logger/gorm/interface.go Normal file
View File

@@ -0,0 +1,43 @@
/***********************************************************************************************************************
*
* 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 gorm
import (
"time"
liblog "github.com/nabbar/golib/logger"
gorlog "gorm.io/gorm/logger"
)
func New(fct func() liblog.Logger, ignoreRecordNotFoundError bool, slowThreshold time.Duration) gorlog.Interface {
return &logGorm{
i: ignoreRecordNotFoundError,
s: slowThreshold,
l: fct,
}
}

102
logger/gorm/model.go Normal file
View File

@@ -0,0 +1,102 @@
/***********************************************************************************************************************
*
* 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 gorm
import (
"context"
"errors"
"fmt"
"time"
liblog "github.com/nabbar/golib/logger"
logent "github.com/nabbar/golib/logger/entry"
loglvl "github.com/nabbar/golib/logger/level"
gorlog "gorm.io/gorm/logger"
)
type logGorm struct {
i bool
s time.Duration
l func() liblog.Logger
}
func (l *logGorm) LogMode(level gorlog.LogLevel) gorlog.Interface {
switch level {
case gorlog.Silent:
l.l().SetLevel(loglvl.NilLevel)
case gorlog.Info:
l.l().SetLevel(loglvl.InfoLevel)
case gorlog.Warn:
l.l().SetLevel(loglvl.WarnLevel)
case gorlog.Error:
l.l().SetLevel(loglvl.ErrorLevel)
}
return l
}
func (l *logGorm) Info(ctx context.Context, s string, i ...interface{}) {
l.l().Entry(loglvl.InfoLevel, s, i...).Log()
}
func (l *logGorm) Warn(ctx context.Context, s string, i ...interface{}) {
l.l().Entry(loglvl.WarnLevel, s, i...).Log()
}
func (l *logGorm) Error(ctx context.Context, s string, i ...interface{}) {
l.l().Entry(loglvl.ErrorLevel, s, i...).Log()
}
func (l *logGorm) Trace(ctx context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error) {
var e logent.Entry
elapsed := time.Since(begin)
switch {
case err != nil && (!errors.Is(err, gorlog.ErrRecordNotFound) || !l.i):
e = l.l().Entry(loglvl.ErrorLevel, "database error with trace")
e.ErrorAdd(true, err)
case elapsed > l.s && l.s != 0:
e = l.l().Entry(loglvl.WarnLevel, "database warning with trace")
e.ErrorAdd(true, fmt.Errorf("SLOW Query >= %v", l.s))
default:
e = l.l().Entry(loglvl.InfoLevel, "database trace")
}
e.FieldAdd("elapsed ms", float64(elapsed.Nanoseconds())/1e6)
sql, rows := fc()
if rows == -1 {
e.FieldAdd("rows", "-")
e.FieldAdd("query", sql)
} else {
e.FieldAdd("rows", rows)
e.FieldAdd("query", sql)
}
e.Log()
}

View File

@@ -0,0 +1,43 @@
/***********************************************************************************************************************
*
* 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 hashicorp
import (
"github.com/hashicorp/go-hclog"
liblog "github.com/nabbar/golib/logger"
)
func New(logger liblog.Logger) hclog.Logger {
return &_hclog{
l: logger,
}
}
func SetDefault(log liblog.Logger) {
hclog.SetDefault(New(log))
}

View File

@@ -25,13 +25,16 @@
* *
**********************************************************************************************************************/ **********************************************************************************************************************/
package logger package hashicorp
import ( import (
"io" "io"
"log" "log"
"github.com/hashicorp/go-hclog" "github.com/hashicorp/go-hclog"
liblog "github.com/nabbar/golib/logger"
logcfg "github.com/nabbar/golib/logger/config"
loglvl "github.com/nabbar/golib/logger/level"
) )
const ( const (
@@ -40,7 +43,7 @@ const (
) )
type _hclog struct { type _hclog struct {
l Logger l liblog.Logger
} }
func (o *_hclog) Log(level hclog.Level, msg string, args ...interface{}) { func (o *_hclog) Log(level hclog.Level, msg string, args ...interface{}) {
@@ -81,23 +84,29 @@ func (o *_hclog) Error(msg string, args ...interface{}) {
} }
func (o *_hclog) IsTrace() bool { func (o *_hclog) IsTrace() bool {
return o.l.GetOptions().EnableTrace if opt := o.l.GetOptions(); opt == nil {
return false
} else if opt.Stdout == nil {
return false
} else {
return opt.Stdout.EnableTrace
}
} }
func (o *_hclog) IsDebug() bool { func (o *_hclog) IsDebug() bool {
return o.l.GetLevel() >= DebugLevel return o.l.GetLevel() >= loglvl.DebugLevel
} }
func (o *_hclog) IsInfo() bool { func (o *_hclog) IsInfo() bool {
return o.l.GetLevel() >= InfoLevel return o.l.GetLevel() >= loglvl.InfoLevel
} }
func (o *_hclog) IsWarn() bool { func (o *_hclog) IsWarn() bool {
return o.l.GetLevel() >= WarnLevel return o.l.GetLevel() >= loglvl.WarnLevel
} }
func (o *_hclog) IsError() bool { func (o *_hclog) IsError() bool {
return o.l.GetLevel() >= ErrorLevel return o.l.GetLevel() >= loglvl.ErrorLevel
} }
func (o *_hclog) ImpliedArgs() []interface{} { func (o *_hclog) ImpliedArgs() []interface{} {
@@ -142,39 +151,41 @@ func (o *_hclog) ResetNamed(name string) hclog.Logger {
func (o *_hclog) SetLevel(level hclog.Level) { func (o *_hclog) SetLevel(level hclog.Level) {
switch level { switch level {
case hclog.NoLevel, hclog.Off: case hclog.NoLevel, hclog.Off:
o.l.SetLevel(NilLevel) o.l.SetLevel(loglvl.NilLevel)
case hclog.Trace: case hclog.Trace:
opt := o.l.GetOptions() opt := o.l.GetOptions()
opt.EnableTrace = true if opt.Stdout == nil {
opt.Stdout = &logcfg.OptionsStd{}
}
opt.Stdout.EnableTrace = true
_ = o.l.SetOptions(opt) _ = o.l.SetOptions(opt)
o.l.SetLevel(DebugLevel) o.l.SetLevel(loglvl.DebugLevel)
case hclog.Debug: case hclog.Debug:
o.l.SetLevel(DebugLevel) o.l.SetLevel(loglvl.DebugLevel)
case hclog.Info: case hclog.Info:
o.l.SetLevel(InfoLevel) o.l.SetLevel(loglvl.InfoLevel)
case hclog.Warn: case hclog.Warn:
o.l.SetLevel(WarnLevel) o.l.SetLevel(loglvl.WarnLevel)
case hclog.Error: case hclog.Error:
o.l.SetLevel(ErrorLevel) o.l.SetLevel(loglvl.ErrorLevel)
} }
} }
func (o *_hclog) GetLevel() hclog.Level { func (o *_hclog) GetLevel() hclog.Level {
switch o.l.GetLevel() { switch o.l.GetLevel() {
case NilLevel: case loglvl.NilLevel:
return hclog.NoLevel return hclog.NoLevel
case DebugLevel: case loglvl.DebugLevel:
opt := o.l.GetOptions() if o.IsTrace() {
if opt.EnableTrace {
return hclog.Trace return hclog.Trace
} else { } else {
return hclog.Debug return hclog.Debug
} }
case InfoLevel: case loglvl.InfoLevel:
return hclog.Info return hclog.Info
case WarnLevel: case loglvl.WarnLevel:
return hclog.Warn return hclog.Warn
case ErrorLevel: case loglvl.ErrorLevel:
return hclog.Error return hclog.Error
default: default:
return hclog.Off return hclog.Off
@@ -182,20 +193,20 @@ func (o *_hclog) GetLevel() hclog.Level {
} }
func (o *_hclog) StandardLogger(opts *hclog.StandardLoggerOptions) *log.Logger { func (o *_hclog) StandardLogger(opts *hclog.StandardLoggerOptions) *log.Logger {
var lvl Level var lvl loglvl.Level
switch opts.ForceLevel { switch opts.ForceLevel {
case hclog.NoLevel, hclog.Off: case hclog.NoLevel, hclog.Off:
lvl = NilLevel lvl = loglvl.NilLevel
case hclog.Trace: case hclog.Trace:
lvl = DebugLevel lvl = loglvl.DebugLevel
case hclog.Debug: case hclog.Debug:
lvl = DebugLevel lvl = loglvl.DebugLevel
case hclog.Info: case hclog.Info:
lvl = InfoLevel lvl = loglvl.InfoLevel
case hclog.Warn: case hclog.Warn:
lvl = WarnLevel lvl = loglvl.WarnLevel
case hclog.Error: case hclog.Error:
lvl = ErrorLevel lvl = loglvl.ErrorLevel
} }
return o.l.GetStdLogger(lvl, 0) return o.l.GetStdLogger(lvl, 0)

View File

@@ -1,308 +0,0 @@
/***********************************************************************************************************************
*
* 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"
"strings"
"sync"
"time"
"github.com/nabbar/golib/ioutils"
"github.com/sirupsen/logrus"
)
type HookFile interface {
logrus.Hook
io.WriteCloser
RegisterHook(log *logrus.Logger)
}
type _HookFile struct {
m sync.Mutex
h *os.File
w time.Time
r logrus.Formatter
l []logrus.Level
s bool
d bool
t bool
a bool
o _HookFileOptions
}
type _HookFileOptions struct {
Create bool
FilePath string
Flags int
ModeFile os.FileMode
ModePath os.FileMode
}
func NewHookFile(opt OptionsFile, format logrus.Formatter) (HookFile, error) {
if opt.Filepath == "" {
return nil, fmt.Errorf("missing file path")
}
var (
LVLs = make([]logrus.Level, 0)
flags = os.O_WRONLY | os.O_APPEND
)
if len(opt.LogLevel) > 0 {
for _, ls := range opt.LogLevel {
LVLs = append(LVLs, GetLevelString(ls).Logrus())
}
} else {
LVLs = logrus.AllLevels
}
if opt.Create {
flags = os.O_CREATE | flags
}
if opt.FileMode == 0 {
opt.FileMode = 0644
}
if opt.PathMode == 0 {
opt.PathMode = 0755
}
obj := &_HookFile{
m: sync.Mutex{},
h: nil,
w: time.Time{},
r: format,
l: LVLs,
s: opt.DisableStack,
d: opt.DisableTimestamp,
t: opt.EnableTrace,
a: opt.EnableAccessLog,
o: _HookFileOptions{
Create: opt.CreatePath,
FilePath: opt.Filepath,
Flags: flags,
ModeFile: opt.FileMode,
ModePath: opt.PathMode,
},
}
if h, e := obj.openCreate(); e != nil {
return nil, e
} else {
_ = h.Close()
}
return obj, nil
}
func (o *_HookFile) openCreate() (*os.File, error) {
var err error
if o.o.Create {
if err = ioutils.PathCheckCreate(true, o.o.FilePath, o.o.ModeFile, o.o.ModePath); err != nil {
return nil, err
}
}
if h, e := os.OpenFile(o.o.FilePath, o.o.Flags, o.o.ModeFile); e != nil {
return nil, e
} else if _, e = h.Seek(0, io.SeekEnd); e != nil {
return nil, e
} else {
return h, nil
}
}
func (o *_HookFile) isStack() bool {
o.m.Lock()
defer o.m.Unlock()
return o.s
}
func (o *_HookFile) isTimeStamp() bool {
o.m.Lock()
defer o.m.Unlock()
return o.d
}
func (o *_HookFile) isTrace() bool {
o.m.Lock()
defer o.m.Unlock()
return o.t
}
func (o *_HookFile) isAccessLog() bool {
o.m.Lock()
defer o.m.Unlock()
return o.a
}
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()
ent.Level = entry.Level
if o.isStack() {
ent.Data = o.filterKey(ent.Data, FieldStack)
}
if o.isTimeStamp() {
ent.Data = o.filterKey(ent.Data, FieldTime)
}
if !o.isTrace() {
ent.Data = o.filterKey(ent.Data, FieldCaller)
ent.Data = o.filterKey(ent.Data, FieldFile)
ent.Data = o.filterKey(ent.Data, FieldLine)
}
var (
p []byte
e error
)
if o.isAccessLog() {
if len(entry.Message) > 0 {
if !strings.HasSuffix(entry.Message, "\n") {
entry.Message += "\n"
}
p = []byte(entry.Message)
} else {
return nil
}
} else {
if len(ent.Data) < 1 {
return nil
} else if p, e = ent.Bytes(); e != nil {
return e
}
}
if _, e = o.Write(p); e != nil {
return e
}
return nil
}
func (o *_HookFile) write(p []byte) (n int, err error) {
o.m.Lock()
defer o.m.Unlock()
var e error
if o.h == nil {
if o.h, e = o.openCreate(); e != nil {
return 0, fmt.Errorf("logrus.hookfile: cannot open '%s': %v", o.o.FilePath, e)
}
} else if _, e = o.h.Seek(0, io.SeekEnd); e != nil {
return 0, fmt.Errorf("logrus.hookfile: cannot seek file '%s' to EOF: %v", o.o.FilePath, e)
}
return o.h.Write(p)
}
func (o *_HookFile) Write(p []byte) (n int, err error) {
if n, err = o.write(p); err != nil {
_ = o.Close()
n, err = o.write(p)
}
if err != nil {
return n, err
}
o.m.Lock()
defer o.m.Unlock()
if o.w.IsZero() {
_ = o.h.Sync()
o.w = time.Now()
return n, err
} else if time.Since(o.w) > 30*time.Second {
_ = o.h.Sync()
o.w = time.Now()
return n, err
}
return n, err
}
func (o *_HookFile) Close() error {
o.m.Lock()
defer o.m.Unlock()
if o.h != nil {
var e error
if er := o.h.Sync(); er != nil {
e = fmt.Errorf("logrus.hookfile: sync file error '%s': %v", o.o.FilePath, er)
}
if er := o.h.Close(); er != nil {
if e != nil {
e = fmt.Errorf("%v, close file error '%s': %v", e, o.o.FilePath, er)
} else {
e = fmt.Errorf("logrus.hookfile: close file error '%s': %v", o.o.FilePath, er)
}
}
o.h = nil
return e
}
return nil
}
func (o *_HookFile) filterKey(f logrus.Fields, key string) logrus.Fields {
if len(f) < 1 {
return f
}
if _, ok := f[key]; !ok {
return f
} else {
delete(f, key)
return f
}
}

View File

@@ -0,0 +1,63 @@
/***********************************************************************************************************************
*
* 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 hookfile
var (
closeStruct = make(chan struct{})
closeByte = make(chan []byte)
)
func init() {
close(closeStruct)
close(closeByte)
}
func (o *hkf) prepareChan() {
o.d.Store(make(chan []byte))
o.s.Store(make(chan struct{}))
}
func (o *hkf) Done() <-chan struct{} {
c := o.s.Load()
if c != nil {
return c.(chan struct{})
}
return closeStruct
}
func (o *hkf) Data() <-chan []byte {
c := o.d.Load()
if c != nil {
return c.(chan []byte)
}
return closeByte
}

35
logger/hookfile/errors.go Normal file
View File

@@ -0,0 +1,35 @@
/***********************************************************************************************************************
*
* 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 hookfile
import "fmt"
var (
errMissingFilePath = fmt.Errorf("missing file path")
errStreamClosed = fmt.Errorf("stream is closed")
)

View File

@@ -0,0 +1,112 @@
/***********************************************************************************************************************
*
* 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 hookfile
import (
"io"
"os"
"sync/atomic"
libiot "github.com/nabbar/golib/ioutils"
logcfg "github.com/nabbar/golib/logger/config"
loglvl "github.com/nabbar/golib/logger/level"
logtps "github.com/nabbar/golib/logger/types"
"github.com/sirupsen/logrus"
)
type HookFile interface {
logtps.Hook
Done() <-chan struct{}
}
func New(opt logcfg.OptionsFile, format logrus.Formatter) (HookFile, error) {
if opt.Filepath == "" {
return nil, errMissingFilePath
}
var (
LVLs = make([]logrus.Level, 0)
flags = os.O_WRONLY | os.O_APPEND
)
if len(opt.LogLevel) > 0 {
for _, ls := range opt.LogLevel {
LVLs = append(LVLs, loglvl.Parse(ls).Logrus())
}
} else {
LVLs = logrus.AllLevels
}
if opt.Create {
flags = os.O_CREATE | flags
}
if opt.FileMode == 0 {
opt.FileMode = 0644
}
if opt.PathMode == 0 {
opt.PathMode = 0755
}
n := &hkf{
s: new(atomic.Value),
d: new(atomic.Value),
o: ohkf{
format: format,
flags: flags,
levels: LVLs,
disableStack: opt.DisableStack,
disableTimestamp: opt.DisableTimestamp,
enableTrace: opt.EnableTrace,
enableAccessLog: opt.EnableAccessLog,
createPath: opt.CreatePath,
filepath: opt.Filepath,
fileMode: opt.FileMode,
pathMode: opt.PathMode,
},
}
if opt.CreatePath {
if e := libiot.PathCheckCreate(true, opt.Filepath, opt.FileMode, opt.PathMode); e != nil {
return nil, e
}
}
if h, e := os.OpenFile(opt.Filepath, flags, opt.FileMode); e != nil {
return nil, e
} else if _, e = h.Seek(0, io.SeekEnd); e != nil {
_ = h.Close()
return nil, e
} else if e = h.Close(); e != nil {
return nil, e
}
return n, nil
}

View File

@@ -0,0 +1,57 @@
/***********************************************************************************************************************
*
* 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 hookfile
import (
"fmt"
"time"
)
func (o *hkf) Write(p []byte) (n int, err error) {
c := o.d.Load()
if c != nil {
if c.(chan []byte) != closeByte {
c.(chan []byte) <- p
return len(p), nil
}
}
return 0, fmt.Errorf("%v, path: %s", errStreamClosed, o.getFilepath())
}
func (o *hkf) Close() error {
fmt.Printf("closing hook for log file '%s'\n", o.getFilepath())
o.d.Store(closeByte)
time.Sleep(10 * time.Millisecond)
o.s.Store(closeStruct)
return nil
}

133
logger/hookfile/model.go Normal file
View File

@@ -0,0 +1,133 @@
/***********************************************************************************************************************
*
* 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 hookfile
import (
"os"
"strings"
"sync/atomic"
logtps "github.com/nabbar/golib/logger/types"
"github.com/sirupsen/logrus"
)
type ohkf struct {
format logrus.Formatter
flags int
levels []logrus.Level
disableStack bool
disableTimestamp bool
enableTrace bool
enableAccessLog bool
createPath bool
filepath string
fileMode os.FileMode
pathMode os.FileMode
}
type hkf struct {
s *atomic.Value // channel stop struct{}
d *atomic.Value // channel data []byte
o ohkf // config data
}
func (o *hkf) Levels() []logrus.Level {
return o.getLevel()
}
func (o *hkf) RegisterHook(log *logrus.Logger) {
log.AddHook(o)
}
func (o *hkf) Fire(entry *logrus.Entry) error {
ent := entry.Dup()
ent.Level = entry.Level
if o.getDisableStack() {
ent.Data = o.filterKey(ent.Data, logtps.FieldStack)
}
if o.getDisableTimestamp() {
ent.Data = o.filterKey(ent.Data, logtps.FieldTime)
}
if !o.getEnableTrace() {
ent.Data = o.filterKey(ent.Data, logtps.FieldCaller)
ent.Data = o.filterKey(ent.Data, logtps.FieldFile)
ent.Data = o.filterKey(ent.Data, logtps.FieldLine)
}
var (
p []byte
e error
)
if o.getEnableAccessLog() {
if len(entry.Message) > 0 {
if !strings.HasSuffix(entry.Message, "\n") {
entry.Message += "\n"
}
p = []byte(entry.Message)
} else {
return nil
}
} else {
if len(ent.Data) < 1 {
return nil
}
if f := o.getFormatter(); f != nil {
p, e = f.Format(ent)
} else {
p, e = ent.Bytes()
}
if e != nil {
return e
}
}
if _, e = o.Write(p); e != nil {
return e
}
return nil
}
func (o *hkf) filterKey(f logrus.Fields, key string) logrus.Fields {
if len(f) < 1 {
return f
}
if _, ok := f[key]; !ok {
return f
} else {
delete(f, key)
return f
}
}

View File

@@ -0,0 +1,78 @@
/***********************************************************************************************************************
*
* 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 hookfile
import (
"os"
"github.com/sirupsen/logrus"
)
func (o *hkf) getFormatter() logrus.Formatter {
return o.o.format
}
func (o *hkf) getFlags() int {
return o.o.flags
}
func (o *hkf) getLevel() []logrus.Level {
return o.o.levels
}
func (o *hkf) getDisableStack() bool {
return o.o.disableStack
}
func (o *hkf) getDisableTimestamp() bool {
return o.o.disableTimestamp
}
func (o *hkf) getEnableTrace() bool {
return o.o.enableTrace
}
func (o *hkf) getEnableAccessLog() bool {
return o.o.enableAccessLog
}
func (o *hkf) getCreatePath() bool {
return o.o.createPath
}
func (o *hkf) getFilepath() string {
return o.o.filepath
}
func (o *hkf) getFileMode() os.FileMode {
return o.o.fileMode
}
func (o *hkf) getPathMode() os.FileMode {
return o.o.pathMode
}

134
logger/hookfile/system.go Normal file
View 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 hookfile
import (
"bytes"
"context"
"fmt"
"io"
"os"
"time"
libiot "github.com/nabbar/golib/ioutils"
)
const sizeBuffer = 32 * 1024
func (o *hkf) writeBuffer(buf *bytes.Buffer) error {
var (
e error
h *os.File
p = o.getFilepath()
m = o.getFileMode()
n = o.getPathMode()
f = o.getFlags()
)
if o.getCreatePath() {
if e = libiot.PathCheckCreate(true, p, m, n); e != nil {
return e
}
}
defer func() {
if h != nil {
_ = h.Close()
}
}()
if h, e = os.OpenFile(p, f, m); e != nil {
return e
} else if _, e = h.Seek(0, io.SeekEnd); e != nil {
return e
} else if _, e = h.Write(buf.Bytes()); e != nil {
return e
} else if e = h.Close(); e != nil {
h = nil
buf.Reset()
return e
} else {
h = nil
}
buf.Reset()
return nil
}
func (o *hkf) freeBuffer(buf *bytes.Buffer, size int) *bytes.Buffer {
var a = bytes.NewBuffer(buf.Bytes()[size:])
a.Grow(size)
return a
}
func (o *hkf) Run(ctx context.Context) {
var (
b = bytes.NewBuffer(make([]byte, sizeBuffer))
t = time.NewTicker(time.Second)
e error
)
defer func() {
//flush buffer before exit function
if b.Len() > 0 {
if e = o.writeBuffer(b); e != nil {
fmt.Println(e.Error())
}
b.Reset()
}
}()
o.prepareChan()
fmt.Printf("starting hook for log file '%s'\n", o.getFilepath())
for {
select {
case <-ctx.Done():
return
case <-o.Done():
return
case <-t.C:
if b.Len() < 1 {
continue
} else if e = o.writeBuffer(b); e != nil {
fmt.Println(e.Error())
}
case p := <-o.Data():
// prevent buffer overflow
if b.Len()+len(p) >= sizeBuffer {
b = o.freeBuffer(b, len(p))
b.Write(p)
} else {
_, _ = b.Write(p)
}
}
}
}

View File

@@ -0,0 +1,73 @@
/***********************************************************************************************************************
*
* 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 hookstderr
import (
"io"
"os"
"github.com/mattn/go-colorable"
logcfg "github.com/nabbar/golib/logger/config"
logtps "github.com/nabbar/golib/logger/types"
"github.com/sirupsen/logrus"
)
type HookStdErr interface {
logtps.Hook
}
func New(opt *logcfg.OptionsStd, lvls []logrus.Level, f logrus.Formatter) (HookStdErr, error) {
if opt == nil || opt.DisableStandard {
return nil, nil
}
if len(lvls) < 1 {
lvls = logrus.AllLevels
}
var w io.Writer
if opt.DisableColor {
w = os.Stderr
} else {
w = colorable.NewColorableStderr()
}
n := &hkerr{
w: w,
l: lvls,
f: f,
s: opt.DisableStack,
d: opt.DisableTimestamp,
t: opt.EnableTrace,
c: opt.DisableColor,
a: opt.EnableAccessLog,
}
return n, nil
}

View File

@@ -0,0 +1,44 @@
/***********************************************************************************************************************
*
* 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 hookstderr
import (
"fmt"
)
func (o *hkerr) 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 *hkerr) Close() error {
return nil
}

View File

@@ -25,98 +25,60 @@
* *
**********************************************************************************************************************/ **********************************************************************************************************************/
package logger package hookstderr
import ( import (
"fmt" "context"
"io" "io"
"os"
"strings" "strings"
"github.com/mattn/go-colorable" logtps "github.com/nabbar/golib/logger/types"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
type StdWriter uint8 type hkerr struct {
const (
StdOut StdWriter = iota
StdErr
)
type HookStandard interface {
logrus.Hook
io.WriteCloser
RegisterHook(log *logrus.Logger)
}
type _HookStd struct {
w io.Writer w io.Writer
l []logrus.Level l []logrus.Level
f logrus.Formatter
s bool // Disable Stack s bool // Disable Stack
d bool // Disable Timestamp d bool // Disable Timestamp
t bool // Disable Trace t bool // Disable Trace
c bool // Disable Color
a bool // Enable AccessLog a bool // Enable AccessLog
} }
func NewHookStandard(opt Options, s StdWriter, lvls []logrus.Level) HookStandard { func (o *hkerr) getFormatter() logrus.Formatter {
if len(lvls) < 1 { return o.f
lvls = logrus.AllLevels
} }
var w io.Writer func (o *hkerr) Run(ctx context.Context) {
return
if opt.DisableColor {
switch s {
case StdErr:
w = os.Stderr
default:
w = os.Stdout
}
} else {
switch s {
case StdErr:
w = colorable.NewColorableStderr()
default:
w = colorable.NewColorableStderr()
}
} }
return &_HookStd{ func (o *hkerr) Levels() []logrus.Level {
w: w,
l: lvls,
s: opt.DisableStack,
d: opt.DisableTimestamp,
t: opt.EnableTrace,
a: opt.EnableAccessLog,
}
}
func (o *_HookStd) RegisterHook(log *logrus.Logger) {
log.AddHook(o)
}
func (o *_HookStd) Levels() []logrus.Level {
return o.l return o.l
} }
func (o *_HookStd) Fire(entry *logrus.Entry) error { func (o *hkerr) RegisterHook(log *logrus.Logger) {
log.AddHook(o)
}
func (o *hkerr) Fire(entry *logrus.Entry) error {
ent := entry.Dup() ent := entry.Dup()
ent.Level = entry.Level ent.Level = entry.Level
if o.s { if o.s {
ent.Data = o.filterKey(ent.Data, FieldStack) ent.Data = o.filterKey(ent.Data, logtps.FieldStack)
} }
if o.d { if o.d {
ent.Data = o.filterKey(ent.Data, FieldTime) ent.Data = o.filterKey(ent.Data, logtps.FieldTime)
} }
if !o.t { if !o.t {
ent.Data = o.filterKey(ent.Data, FieldCaller) ent.Data = o.filterKey(ent.Data, logtps.FieldCaller)
ent.Data = o.filterKey(ent.Data, FieldFile) ent.Data = o.filterKey(ent.Data, logtps.FieldFile)
ent.Data = o.filterKey(ent.Data, FieldLine) ent.Data = o.filterKey(ent.Data, logtps.FieldLine)
} }
var ( var (
@@ -136,7 +98,15 @@ func (o *_HookStd) Fire(entry *logrus.Entry) error {
} else { } else {
if len(ent.Data) < 1 { if len(ent.Data) < 1 {
return nil return nil
} else if p, e = ent.Bytes(); e != nil { }
if f := o.getFormatter(); f != nil {
p, e = f.Format(ent)
} else {
p, e = ent.Bytes()
}
if e != nil {
return e return e
} }
} }
@@ -148,19 +118,7 @@ func (o *_HookStd) Fire(entry *logrus.Entry) error {
return nil return nil
} }
func (o *_HookStd) Write(p []byte) (n int, err error) { func (o *hkerr) filterKey(f logrus.Fields, key string) logrus.Fields {
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 { if len(f) < 1 {
return f return f
} }
@@ -171,16 +129,4 @@ func (o *_HookStd) filterKey(f logrus.Fields, key string) logrus.Fields {
delete(f, key) delete(f, key)
return f return f
} }
/*
var res = make(map[string]interface{}, 0)
for k, v := range f {
if k == key {
continue
}
res[k] = v
}
return res
*/
} }

View File

@@ -0,0 +1,73 @@
/***********************************************************************************************************************
*
* 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 hookstdout
import (
"io"
"os"
"github.com/mattn/go-colorable"
logcfg "github.com/nabbar/golib/logger/config"
logtps "github.com/nabbar/golib/logger/types"
"github.com/sirupsen/logrus"
)
type HookStdOut interface {
logtps.Hook
}
func New(opt *logcfg.OptionsStd, lvls []logrus.Level, f logrus.Formatter) (HookStdOut, error) {
if opt == nil || opt.DisableStandard {
return nil, nil
}
if len(lvls) < 1 {
lvls = logrus.AllLevels
}
var w io.Writer
if opt.DisableColor {
w = os.Stdout
} else {
w = colorable.NewColorableStdout()
}
n := &hkstd{
w: w,
l: lvls,
f: f,
s: opt.DisableStack,
d: opt.DisableTimestamp,
t: opt.EnableTrace,
c: opt.DisableColor,
a: opt.EnableAccessLog,
}
return n, nil
}

View File

@@ -0,0 +1,44 @@
/***********************************************************************************************************************
*
* 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 hookstdout
import (
"fmt"
)
func (o *hkstd) 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 *hkstd) Close() error {
return nil
}

132
logger/hookstdout/model.go Normal file
View File

@@ -0,0 +1,132 @@
/***********************************************************************************************************************
*
* 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 hookstdout
import (
"context"
"io"
"strings"
logtps "github.com/nabbar/golib/logger/types"
"github.com/sirupsen/logrus"
)
type hkstd struct {
w io.Writer
l []logrus.Level
f logrus.Formatter
s bool // Disable Stack
d bool // Disable Timestamp
t bool // Disable Trace
c bool // Disable Color
a bool // Enable AccessLog
}
func (o *hkstd) getFormatter() logrus.Formatter {
return o.f
}
func (o *hkstd) Run(ctx context.Context) {
return
}
func (o *hkstd) Levels() []logrus.Level {
return o.l
}
func (o *hkstd) RegisterHook(log *logrus.Logger) {
log.AddHook(o)
}
func (o *hkstd) Fire(entry *logrus.Entry) error {
ent := entry.Dup()
ent.Level = entry.Level
if o.s {
ent.Data = o.filterKey(ent.Data, logtps.FieldStack)
}
if o.d {
ent.Data = o.filterKey(ent.Data, logtps.FieldTime)
}
if !o.t {
ent.Data = o.filterKey(ent.Data, logtps.FieldCaller)
ent.Data = o.filterKey(ent.Data, logtps.FieldFile)
ent.Data = o.filterKey(ent.Data, logtps.FieldLine)
}
var (
p []byte
e error
)
if o.a {
if len(entry.Message) > 0 {
if !strings.HasSuffix(entry.Message, "\n") {
entry.Message += "\n"
}
p = []byte(entry.Message)
} else {
return nil
}
} else {
if len(ent.Data) < 1 {
return nil
}
if f := o.getFormatter(); f != nil {
p, e = f.Format(ent)
} else {
p, e = ent.Bytes()
}
if e != nil {
return e
}
}
if _, e = o.Write(p); e != nil {
return e
}
return nil
}
func (o *hkstd) filterKey(f logrus.Fields, key string) logrus.Fields {
if len(f) < 1 {
return f
}
if _, ok := f[key]; !ok {
return f
} else {
delete(f, key)
return f
}
}

View File

@@ -1,268 +0,0 @@
/***********************************************************************************************************************
*
* 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"
"strings"
"sync"
"github.com/sirupsen/logrus"
)
type HookSyslog interface {
logrus.Hook
io.WriteCloser
RegisterHook(log *logrus.Logger)
}
type syslogWrapper interface {
io.WriteCloser
Panic(p []byte) (n int, err error)
Fatal(p []byte) (n int, err error)
Error(p []byte) (n int, err error)
Warning(p []byte) (n int, err error)
Info(p []byte) (n int, err error)
Debug(p []byte) (n int, err error)
}
type FuncFormatter func() logrus.Formatter
type _HookSyslog struct {
m sync.Mutex
w syslogWrapper
f logrus.Formatter
l []logrus.Level
o _HookSyslogOptions
}
type _HookSyslogOptions struct {
Net NetworkType
Hst string
Tag string
// Sev SyslogSeverity
Fac SyslogFacility
Pid bool
Tms bool
Trc bool
Acc bool
}
func NewHookSyslog(opt OptionsSyslog, format logrus.Formatter) (HookSyslog, error) {
var (
LVLs = make([]logrus.Level, 0)
sys syslogWrapper
err error
)
if len(opt.LogLevel) > 0 {
for _, ls := range opt.LogLevel {
LVLs = append(LVLs, GetLevelString(ls).Logrus())
}
} else {
LVLs = logrus.AllLevels
}
obj := &_HookSyslog{
m: sync.Mutex{},
w: sys,
f: format,
l: LVLs,
o: _HookSyslogOptions{
Net: MakeNetwork(opt.Network),
Hst: opt.Host,
Tag: opt.Tag,
// Sev: MakeSeverity(opt.Severity),
Fac: MakeFacility(opt.Facility),
Pid: opt.DisableStack,
Tms: opt.DisableTimestamp,
Trc: opt.EnableTrace,
Acc: opt.EnableAccessLog,
},
}
if h, e := obj.openCreate(); e != nil {
return nil, e
} else {
_ = h.Close()
}
return obj, err
}
func (o *_HookSyslog) openCreate() (syslogWrapper, error) {
return newSyslog(o.o.Net, o.o.Hst, o.o.Tag, o.o.Fac)
//return newSyslog(o.o.Net, o.o.Hst, o.o.Tag, o.o.Sev, o.o.Fac)
}
func (o *_HookSyslog) isStack() bool {
o.m.Lock()
defer o.m.Unlock()
return o.o.Pid
}
func (o *_HookSyslog) isTimeStamp() bool {
o.m.Lock()
defer o.m.Unlock()
return o.o.Tms
}
func (o *_HookSyslog) isTrace() bool {
o.m.Lock()
defer o.m.Unlock()
return o.o.Trc
}
func (o *_HookSyslog) isAccessLog() bool {
o.m.Lock()
defer o.m.Unlock()
return o.o.Acc
}
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()
ent.Level = entry.Level
if o.isStack() {
ent.Data = o.filterKey(ent.Data, FieldStack)
}
if o.isTimeStamp() {
ent.Data = o.filterKey(ent.Data, FieldTime)
}
if !o.isTrace() {
ent.Data = o.filterKey(ent.Data, FieldCaller)
ent.Data = o.filterKey(ent.Data, FieldFile)
ent.Data = o.filterKey(ent.Data, FieldLine)
}
var (
p []byte
e error
)
if o.isAccessLog() {
if len(entry.Message) > 0 {
if !strings.HasSuffix(entry.Message, "\n") {
entry.Message += "\n"
}
p = []byte(entry.Message)
} else {
return nil
}
} else {
if len(ent.Data) < 1 {
return nil
} else if p, e = ent.Bytes(); e != nil {
return e
}
}
if _, e = o.writeLevel(ent.Level, p); e != nil {
_ = o.Close()
_, e = o.writeLevel(ent.Level, p)
}
return e
}
func (o *_HookSyslog) Write(p []byte) (n int, err error) {
return o.writeLevel(logrus.InfoLevel, p)
}
func (o *_HookSyslog) writeLevel(lvl logrus.Level, p []byte) (n int, err error) {
o.m.Lock()
defer o.m.Unlock()
if o.w == nil {
var e error
if o.w, e = o.openCreate(); e != nil {
return 0, fmt.Errorf("logrus.hooksyslog: %v", e)
}
}
switch lvl {
case logrus.PanicLevel:
return o.w.Panic(p)
case logrus.FatalLevel:
return o.w.Fatal(p)
case logrus.ErrorLevel:
return o.w.Error(p)
case logrus.WarnLevel:
return o.w.Warning(p)
case logrus.InfoLevel:
return o.w.Info(p)
case logrus.DebugLevel:
return o.w.Debug(p)
default:
return o.w.Write(p)
}
}
func (o *_HookSyslog) Close() error {
o.m.Lock()
defer o.m.Unlock()
var e error
if o.w != nil {
e = o.w.Close()
}
o.w = nil
return e
}
func (o *_HookSyslog) filterKey(f logrus.Fields, key string) logrus.Fields {
if len(f) < 1 {
return f
}
if _, ok := f[key]; !ok {
return f
} else {
delete(f, key)
return f
}
}

View File

@@ -0,0 +1,63 @@
/***********************************************************************************************************************
*
* 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 hooksyslog
var (
closeStruct = make(chan struct{})
closeByte = make(chan data)
)
func init() {
close(closeStruct)
close(closeByte)
}
func (o *hks) prepareChan() {
o.d.Store(make(chan data))
o.s.Store(make(chan struct{}))
}
func (o *hks) Done() <-chan struct{} {
c := o.s.Load()
if c != nil {
return c.(chan struct{})
}
return closeStruct
}
func (o *hks) Data() <-chan data {
c := o.d.Load()
if c != nil {
return c.(chan data)
}
return closeByte
}

42
logger/hooksyslog/data.go Normal file
View File

@@ -0,0 +1,42 @@
/***********************************************************************************************************************
*
* 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 hooksyslog
type data struct {
s SyslogSeverity
p []byte
}
type bufData []data
func newData(s SyslogSeverity, p []byte) data {
return data{
s: s,
p: p,
}
}

View File

@@ -0,0 +1,32 @@
/***********************************************************************************************************************
*
* 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 hooksyslog
import "fmt"
var errStreamClosed = fmt.Errorf("stream is closed")

View 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 hooksyslog
import (
"sync/atomic"
logcfg "github.com/nabbar/golib/logger/config"
loglvl "github.com/nabbar/golib/logger/level"
logtps "github.com/nabbar/golib/logger/types"
libptc "github.com/nabbar/golib/network/protocol"
"github.com/sirupsen/logrus"
)
type HookSyslog interface {
logtps.Hook
Done() <-chan struct{}
WriteSev(s SyslogSeverity, p []byte) (n int, err error)
}
func New(opt logcfg.OptionsSyslog, format logrus.Formatter) (HookSyslog, error) {
var (
LVLs = make([]logrus.Level, 0)
)
if len(opt.LogLevel) > 0 {
for _, ls := range opt.LogLevel {
LVLs = append(LVLs, loglvl.Parse(ls).Logrus())
}
} else {
LVLs = logrus.AllLevels
}
n := &hks{
s: new(atomic.Value),
d: new(atomic.Value),
o: ohks{
format: format,
levels: LVLs,
disableStack: opt.DisableStack,
disableTimestamp: opt.DisableTimestamp,
enableTrace: opt.EnableTrace,
enableAccessLog: opt.EnableAccessLog,
network: libptc.Parse(opt.Network),
endpoint: opt.Host,
tag: opt.Tag,
fac: MakeFacility(opt.Facility),
//sev : MakeSeverity(opt.Severity),
},
}
n.s.Store(make(chan struct{}))
n.d.Store(make(chan data))
if h, e := n.getSyslog(); e != nil {
return nil, e
} else {
_ = h.Close()
}
return n, nil
}

View File

@@ -0,0 +1,71 @@
/***********************************************************************************************************************
*
* 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 hooksyslog
import (
"fmt"
"time"
)
func (o *hks) Write(p []byte) (n int, err error) {
c := o.d.Load()
if c != nil {
if c.(chan data) != closeByte {
c.(chan data) <- newData(0, p)
return len(p), nil
}
}
return 0, errStreamClosed
}
func (o *hks) WriteSev(s SyslogSeverity, p []byte) (n int, err error) {
c := o.d.Load()
if c != nil {
if c.(chan data) != closeByte {
c.(chan data) <- newData(s, p)
return len(p), nil
}
}
return 0, fmt.Errorf("%v, path: %s", errStreamClosed, o.getSyslogInfo())
}
func (o *hks) Close() error {
fmt.Printf("closing hook for log syslog '%s'\n", o.getSyslogInfo())
o.d.Store(closeByte)
time.Sleep(10 * time.Millisecond)
o.s.Store(closeStruct)
return nil
}

153
logger/hooksyslog/model.go Normal file
View 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 hooksyslog
import (
"strings"
"sync/atomic"
libptc "github.com/nabbar/golib/network/protocol"
logtps "github.com/nabbar/golib/logger/types"
"github.com/sirupsen/logrus"
)
type ohks struct {
format logrus.Formatter
levels []logrus.Level
disableStack bool
disableTimestamp bool
enableTrace bool
enableAccessLog bool
network libptc.NetworkProtocol
endpoint string
tag string
fac SyslogFacility
// Sev SyslogSeverity
}
type hks struct {
s *atomic.Value // channel stop struct{}
d *atomic.Value // channel data []byte
o ohks // config data
}
func (o *hks) Levels() []logrus.Level {
return o.getLevel()
}
func (o *hks) RegisterHook(log *logrus.Logger) {
log.AddHook(o)
}
func (o *hks) Fire(entry *logrus.Entry) error {
ent := entry.Dup()
ent.Level = entry.Level
if o.getDisableStack() {
ent.Data = o.filterKey(ent.Data, logtps.FieldStack)
}
if o.getDisableTimestamp() {
ent.Data = o.filterKey(ent.Data, logtps.FieldTime)
}
if !o.getEnableTrace() {
ent.Data = o.filterKey(ent.Data, logtps.FieldCaller)
ent.Data = o.filterKey(ent.Data, logtps.FieldFile)
ent.Data = o.filterKey(ent.Data, logtps.FieldLine)
}
var (
p []byte
e error
)
if o.getEnableAccessLog() {
if len(entry.Message) > 0 {
if !strings.HasSuffix(entry.Message, "\n") {
entry.Message += "\n"
}
p = []byte(entry.Message)
} else {
return nil
}
} else {
if len(ent.Data) < 1 {
return nil
}
if f := o.getFormatter(); f != nil {
p, e = f.Format(ent)
} else {
p, e = ent.Bytes()
}
if e != nil {
return e
}
}
switch ent.Level {
case logrus.PanicLevel:
_, e = o.WriteSev(SyslogSeverityAlert, p)
case logrus.FatalLevel:
_, e = o.WriteSev(SyslogSeverityCrit, p)
case logrus.ErrorLevel:
_, e = o.WriteSev(SyslogSeverityErr, p)
case logrus.WarnLevel:
_, e = o.WriteSev(SyslogSeverityWarning, p)
case logrus.InfoLevel:
_, e = o.WriteSev(SyslogSeverityInfo, p)
case logrus.DebugLevel:
_, e = o.WriteSev(SyslogSeverityDebug, p)
default:
_, e = o.Write(p)
}
if e != nil {
return e
}
return nil
}
func (o *hks) filterKey(f logrus.Fields, key string) logrus.Fields {
if len(f) < 1 {
return f
}
if _, ok := f[key]; !ok {
return f
} else {
delete(f, key)
return f
}
}

View File

@@ -0,0 +1,66 @@
/***********************************************************************************************************************
*
* MIT License
*
* Copyright (c) 2021 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
**********************************************************************************************************************/
package hooksyslog
import (
"fmt"
"github.com/sirupsen/logrus"
)
func (o *hks) getFormatter() logrus.Formatter {
return o.o.format
}
func (o *hks) getLevel() []logrus.Level {
return o.o.levels
}
func (o *hks) getDisableStack() bool {
return o.o.disableStack
}
func (o *hks) getDisableTimestamp() bool {
return o.o.disableTimestamp
}
func (o *hks) getEnableTrace() bool {
return o.o.enableTrace
}
func (o *hks) getEnableAccessLog() bool {
return o.o.enableAccessLog
}
func (o *hks) getSyslog() (Wrapper, error) {
return newSyslog(o.o.network, o.o.endpoint, o.o.tag, o.o.fac)
}
func (o *hks) getSyslogInfo() string {
return fmt.Sprintf("syslog to '%s %s' with tag '%s'", o.o.network.Code(), o.o.endpoint, o.o.tag)
}

View File

@@ -25,7 +25,7 @@
* *
**********************************************************************************************************************/ **********************************************************************************************************************/
package logger package hooksyslog
import "strings" import "strings"

View File

@@ -28,11 +28,13 @@
* *
**********************************************************************************************************************/ **********************************************************************************************************************/
package logger package hooksyslog
import ( import (
"fmt" "fmt"
"log/syslog" "log/syslog"
libptc "github.com/nabbar/golib/network/protocol"
) )
func makePriority(severity SyslogSeverity, facility SyslogFacility) syslog.Priority { func makePriority(severity SyslogSeverity, facility SyslogFacility) syslog.Priority {
@@ -111,7 +113,7 @@ type _Syslog struct {
w *syslog.Writer w *syslog.Writer
} }
func newSyslog(net NetworkType, host, tag string, fac SyslogFacility) (syslogWrapper, error) { func newSyslog(net libptc.NetworkProtocol, host, tag string, fac SyslogFacility) (Wrapper, error) {
var ( var (
err error err error
) )
@@ -128,7 +130,7 @@ func newSyslog(net NetworkType, host, tag string, fac SyslogFacility) (syslogWra
return obj, nil return obj, nil
} }
func (o *_Syslog) openSyslogSev(net NetworkType, host, tag string, prio syslog.Priority) (*syslog.Writer, error) { func (o *_Syslog) openSyslogSev(net libptc.NetworkProtocol, host, tag string, prio syslog.Priority) (*syslog.Writer, error) {
return syslog.Dial(net.String(), host, prio, tag) return syslog.Dial(net.String(), host, prio, tag)
} }
@@ -138,7 +140,7 @@ func (o *_Syslog) Write(p []byte) (n int, err error) {
func (o *_Syslog) WriteSev(sev SyslogSeverity, p []byte) (n int, err error) { func (o *_Syslog) WriteSev(sev SyslogSeverity, p []byte) (n int, err error) {
if o.w == nil { if o.w == nil {
return 0, fmt.Errorf("logrus.hooksyslog: connection not setup") return 0, fmt.Errorf("hooksyslog: connection not setup")
} }
switch sev { switch sev {

View File

@@ -28,12 +28,14 @@
* *
**********************************************************************************************************************/ **********************************************************************************************************************/
package logger package hooksyslog
import ( import (
"sync/atomic" "sync/atomic"
"time" "time"
libptc "github.com/nabbar/golib/network/protocol"
"golang.org/x/sys/windows/svc/eventlog" "golang.org/x/sys/windows/svc/eventlog"
) )
@@ -125,13 +127,13 @@ type _WinLog struct {
w *eventlog.Log w *eventlog.Log
} }
func newSyslog(net NetworkType, host, tag string, facility SyslogFacility) (syslogWrapper, error) { func newSyslog(net libptc.NetworkProtocol, host, tag string, facility SyslogFacility) (Wrapper, error) {
var ( var (
sys *eventlog.Log sys *eventlog.Log
err error err error
) )
if net != NetworkEmpty { if net != libptc.NetworkEmpty {
sys, err = eventlog.OpenRemote(host, tag) sys, err = eventlog.OpenRemote(host, tag)
} else { } else {
if err = windowsRegister(tag); err != nil { if err = windowsRegister(tag); err != nil {
@@ -146,7 +148,7 @@ func newSyslog(net NetworkType, host, tag string, facility SyslogFacility) (sysl
} }
return &_WinLog{ return &_WinLog{
r: net != NetworkEmpty, r: net != libptc.NetworkEmpty,
s: tag, s: tag,
w: sys, w: sys,
}, nil }, nil

110
logger/hooksyslog/system.go Normal file
View File

@@ -0,0 +1,110 @@
/***********************************************************************************************************************
*
* 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 hooksyslog
import (
"context"
"fmt"
"sync"
"time"
)
func (o *hks) Run(ctx context.Context) {
var (
s Wrapper
w = sync.WaitGroup{}
e error
)
defer func() {
if s != nil {
w.Wait()
_ = s.Close()
}
}()
for {
if s, e = o.getSyslog(); e != nil {
fmt.Println(e.Error())
} else {
break
}
time.Sleep(time.Second)
}
o.prepareChan()
fmt.Printf("starting hook for log syslog '%s'\n", o.getSyslogInfo())
for {
select {
case <-ctx.Done():
return
case <-o.Done():
return
case i := <-o.Data():
w.Add(1)
go o.writeWrapper(s, i, w.Done)
}
}
}
func (o *hks) writeWrapper(w Wrapper, d data, done func()) {
var err error
defer done()
if w == nil {
return
} else if len(d.p) < 1 {
return
}
switch d.s {
case SyslogSeverityAlert:
_, err = w.Panic(d.p)
case SyslogSeverityCrit:
_, err = w.Fatal(d.p)
case SyslogSeverityErr:
_, err = w.Error(d.p)
case SyslogSeverityWarning:
_, err = w.Warning(d.p)
case SyslogSeverityInfo:
_, err = w.Info(d.p)
case SyslogSeverityDebug:
_, err = w.Debug(d.p)
default:
_, err = w.Write(d.p)
}
if err != nil {
fmt.Println(err.Error())
}
}

View File

@@ -0,0 +1,41 @@
/***********************************************************************************************************************
*
* 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 hooksyslog
import "io"
type Wrapper interface {
io.WriteCloser
Panic(p []byte) (n int, err error)
Fatal(p []byte) (n int, err error)
Error(p []byte) (n int, err error)
Warning(p []byte) (n int, err error)
Info(p []byte) (n int, err error)
Debug(p []byte) (n int, err error)
}

View File

@@ -31,68 +31,64 @@ import (
"io" "io"
"log" "log"
"sync" "sync"
"sync/atomic"
"time" "time"
libctx "github.com/nabbar/golib/context"
iotclo "github.com/nabbar/golib/ioutils/mapCloser" iotclo "github.com/nabbar/golib/ioutils/mapCloser"
"github.com/hashicorp/go-hclog" libctx "github.com/nabbar/golib/context"
logcfg "github.com/nabbar/golib/logger/config"
logent "github.com/nabbar/golib/logger/entry"
logfld "github.com/nabbar/golib/logger/fields"
loglvl "github.com/nabbar/golib/logger/level"
jww "github.com/spf13/jwalterweatherman" jww "github.com/spf13/jwalterweatherman"
) )
type FuncLog func() Logger type FuncLog func() Logger
type FuncOpt func() *Options
type Logger interface { type Logger interface {
io.WriteCloser io.WriteCloser
//SetLevel allow to change the minimal level of log message //SetLevel allow to change the minimal level of log message
SetLevel(lvl Level) SetLevel(lvl loglvl.Level)
//GetLevel return the minimal level of log message //GetLevel return the minimal level of log message
GetLevel() Level GetLevel() loglvl.Level
//SetIOWriterLevel allow to change the minimal level of log message for io.WriterCloser interface //SetIOWriterLevel allow to change the minimal level of log message for io.WriterCloser interface
SetIOWriterLevel(lvl Level) SetIOWriterLevel(lvl loglvl.Level)
//GetIOWriterLevel return the minimal level of log message for io.WriterCloser interface //GetIOWriterLevel return the minimal level of log message for io.WriterCloser interface
GetIOWriterLevel() Level GetIOWriterLevel() loglvl.Level
// SetIOWriterFilter allow to filter message that contained the given pattern. If the pattern is found, the log is drop. // SetIOWriterFilter allow to filter message that contained the given pattern. If the pattern is found, the log is drop.
SetIOWriterFilter(pattern string) SetIOWriterFilter(pattern string)
//SetOptions allow to set or update the options for the logger //SetOptions allow to set or update the options for the logger
SetOptions(opt *Options) error SetOptions(opt *logcfg.Options) error
//GetOptions return the options for the logger //GetOptions return the options for the logger
GetOptions() *Options GetOptions() *logcfg.Options
//SetFields allow to set or update the default fields for all logger entry //SetFields allow to set or update the default fields for all logger entry
// Fields are custom information added into log message // Fields are custom information added into log message
SetFields(field Fields) SetFields(field logfld.Fields)
//GetFields return the default fields for all logger entry //GetFields return the default fields for all logger entry
// Fields are custom information added into log message // Fields are custom information added into log message
GetFields() Fields GetFields() logfld.Fields
//Clone allow to duplicate the logger with a copy of the logger //Clone allow to duplicate the logger with a copy of the logger
Clone() Logger Clone() Logger
//SetSPF13Level allow to plus spf13 logger (jww) to this logger //SetSPF13Level allow to plus spf13 logger (jww) to this logger
SetSPF13Level(lvl Level, log *jww.Notepad) SetSPF13Level(lvl loglvl.Level, log *jww.Notepad)
//GetStdLogger return a golang log.logger instance linked with this main logger. //GetStdLogger return a golang log.logger instance linked with this main logger.
GetStdLogger(lvl Level, logFlags int) *log.Logger GetStdLogger(lvl loglvl.Level, logFlags int) *log.Logger
//SetStdLogger force the default golang log.logger instance linked with this main logger. //SetStdLogger force the default golang log.logger instance linked with this main logger.
SetStdLogger(lvl Level, logFlags int) SetStdLogger(lvl loglvl.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 add an entry with DebugLevel to the logger
Debug(message string, data interface{}, args ...interface{}) Debug(message string, data interface{}, args ...interface{})
@@ -115,17 +111,17 @@ type Logger interface {
Panic(message string, data interface{}, args ...interface{}) Panic(message string, data interface{}, args ...interface{})
//LogDetails add an entry to the logger //LogDetails add an entry to the logger
LogDetails(lvl Level, message string, data interface{}, err []error, fields Fields, args ...interface{}) LogDetails(lvl loglvl.Level, message string, data interface{}, err []error, fields logfld.Fields, args ...interface{})
//CheckError will check if a not nil error is given and if yes, will add an entry to the logger. //CheckError will check if a not nil error is given and if yes, will add an entry to the logger.
// Othwise if the lvlOK is given (and not NilLevel) the function will add entry and said ok // Othwise if the lvlOK is given (and not NilLevel) the function will add entry and said ok
CheckError(lvlKO, lvlOK Level, message string, err ...error) bool CheckError(lvlKO, lvlOK loglvl.Level, message string, err ...error) bool
//Entry will return an entry struct to manage it (set gin context, add fields, log the entry...) //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 Entry(lvl loglvl.Level, message string, args ...interface{}) logent.Entry
//Access will return an entry struct to store info level access log message //Access will return an entry struct to store info level access log message
Access(remoteAddr, remoteUser string, localtime time.Time, latency time.Duration, method, request, proto string, status int, size int64) *Entry Access(remoteAddr, remoteUser string, localtime time.Time, latency time.Duration, method, request, proto string, status int, size int64) logent.Entry
} }
// New return a new logger interface pointer // New return a new logger interface pointer
@@ -133,11 +129,12 @@ func New(ctx libctx.FuncContext) Logger {
l := &logger{ l := &logger{
m: sync.RWMutex{}, m: sync.RWMutex{},
x: libctx.NewConfig[uint8](ctx), x: libctx.NewConfig[uint8](ctx),
f: NewFields(ctx), f: logfld.New(ctx),
c: iotclo.New(ctx), c: new(atomic.Value),
} }
l.SetLevel(InfoLevel) l.c.Store(iotclo.New(ctx))
l.SetLevel(loglvl.InfoLevel)
return l return l
} }

View File

@@ -1,7 +1,8 @@
/* /***********************************************************************************************************************
*
* MIT License * MIT License
* *
* Copyright (c) 2020 Nicolas JUHEL * Copyright (c) 2021 Nicolas JUHEL
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -21,7 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. * SOFTWARE.
* *
*/ *
**********************************************************************************************************************/
package logger_test package logger_test
@@ -30,9 +32,11 @@ import (
"path/filepath" "path/filepath"
"time" "time"
liblog "github.com/nabbar/golib/logger"
logcfg "github.com/nabbar/golib/logger/config"
logfld "github.com/nabbar/golib/logger/fields"
loglvl "github.com/nabbar/golib/logger/level"
libsem "github.com/nabbar/golib/semaphore" libsem "github.com/nabbar/golib/semaphore"
"github.com/nabbar/golib/logger"
. "github.com/onsi/ginkgo/v2" . "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega" . "github.com/onsi/gomega"
) )
@@ -52,40 +56,58 @@ func getLogFileTemp() string {
var _ = Describe("Logger", func() { var _ = Describe("Logger", func() {
Context("Create New Logger with Default Config", func() { Context("Create New Logger with Default Config", func() {
It("Must succeed", func() { It("Must succeed", func() {
log := logger.New(GetContext) log := liblog.New(GetContext)
log.SetLevel(logger.DebugLevel) defer func() {
err := log.SetOptions(&logger.Options{}) Expect(log.Close()).ToNot(HaveOccurred())
}()
log.SetLevel(loglvl.DebugLevel)
err := log.SetOptions(&logcfg.Options{
Stdout: &logcfg.OptionsStd{},
})
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
log.LogDetails(logger.InfoLevel, "test logger", nil, nil, nil) log.LogDetails(loglvl.InfoLevel, "test logger", nil, nil, nil)
}) })
}) })
Context("Create New Logger with Default Config and trace", func() { Context("Create New Logger with Default Config and trace", func() {
It("Must succeed", func() { It("Must succeed", func() {
log := logger.New(GetContext) log := liblog.New(GetContext)
log.SetLevel(logger.DebugLevel) defer func() {
err := log.SetOptions(&logger.Options{ Expect(log.Close()).ToNot(HaveOccurred())
}()
log.SetLevel(loglvl.DebugLevel)
err := log.SetOptions(&logcfg.Options{
Stdout: &logcfg.OptionsStd{
EnableTrace: true, EnableTrace: true,
},
}) })
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
log.LogDetails(logger.InfoLevel, "test logger with trace", nil, nil, nil) log.LogDetails(loglvl.InfoLevel, "test logger with trace", nil, nil, nil)
}) })
}) })
Context("Create New Logger with field", func() { Context("Create New Logger with field", func() {
It("Must succeed", func() { It("Must succeed", func() {
log := logger.New(GetContext) log := liblog.New(GetContext)
log.SetLevel(logger.DebugLevel) defer func() {
err := log.SetOptions(&logger.Options{ Expect(log.Close()).ToNot(HaveOccurred())
}()
log.SetLevel(loglvl.DebugLevel)
err := log.SetOptions(&logcfg.Options{
Stdout: &logcfg.OptionsStd{
EnableTrace: true, EnableTrace: true,
},
}) })
log.SetFields(logger.NewFields(GetContext).Add("test-field", "ok")) log.SetFields(logfld.New(GetContext).Add("test-field", "ok"))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
log.LogDetails(logger.InfoLevel, "test logger with field", nil, nil, nil) log.LogDetails(loglvl.InfoLevel, "test logger with field", nil, nil, nil)
}) })
}) })
Context("Create New Logger with file", func() { Context("Create New Logger with file", func() {
It("Must succeed", func() { It("Must succeed", func() {
log := logger.New(GetContext) log := liblog.New(GetContext)
log.SetLevel(logger.DebugLevel) defer func() {
Expect(log.Close()).ToNot(HaveOccurred())
}()
log.SetLevel(loglvl.DebugLevel)
fsp, err := GetTempFile() fsp, err := GetTempFile()
@@ -96,16 +118,16 @@ var _ = Describe("Logger", func() {
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
err = log.SetOptions(&logger.Options{ err = log.SetOptions(&logcfg.Options{
Stdout: &logcfg.OptionsStd{
EnableTrace: true, EnableTrace: true,
LogFile: []logger.OptionsFile{ },
LogFile: []logcfg.OptionsFile{
{ {
LogLevel: nil, LogLevel: nil,
Filepath: fsp, Filepath: fsp,
Create: true, Create: true,
CreatePath: true, CreatePath: true,
//FileMode: 0644,
//PathMode: 0755,
DisableStack: false, DisableStack: false,
DisableTimestamp: false, DisableTimestamp: false,
EnableTrace: true, EnableTrace: true,
@@ -114,14 +136,17 @@ var _ = Describe("Logger", func() {
}) })
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
log.SetFields(logger.NewFields(GetContext).Add("test-field", "ok")) log.SetFields(logfld.New(GetContext).Add("test-field", "ok"))
log.LogDetails(logger.InfoLevel, "test logger with field", nil, nil, nil) log.LogDetails(loglvl.InfoLevel, "test logger with field", nil, nil, nil)
}) })
}) })
Context("Create New Logger with file in multithreading mode", func() { Context("Create New Logger with file in multithreading mode", func() {
It("Must succeed", func() { It("Must succeed", func() {
log := logger.New(GetContext) log := liblog.New(GetContext)
log.SetLevel(logger.DebugLevel) defer func() {
Expect(log.Close()).ToNot(HaveOccurred())
}()
log.SetLevel(loglvl.DebugLevel)
fsp, err := GetTempFile() fsp, err := GetTempFile()
@@ -132,16 +157,16 @@ var _ = Describe("Logger", func() {
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
err = log.SetOptions(&logger.Options{ err = log.SetOptions(&logcfg.Options{
Stdout: &logcfg.OptionsStd{
EnableTrace: true, EnableTrace: true,
LogFile: []logger.OptionsFile{ },
LogFile: []logcfg.OptionsFile{
{ {
LogLevel: nil, LogLevel: nil,
Filepath: fsp, Filepath: fsp,
Create: true, Create: true,
CreatePath: true, CreatePath: true,
//FileMode: 0644,
//PathMode: 0755,
DisableStack: false, DisableStack: false,
DisableTimestamp: false, DisableTimestamp: false,
EnableTrace: true, EnableTrace: true,
@@ -150,25 +175,25 @@ var _ = Describe("Logger", func() {
}) })
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
log.SetFields(logger.NewFields(GetContext).Add("test-field", "ok")) log.SetFields(logfld.New(GetContext).Add("test-field", "ok"))
log.LogDetails(logger.InfoLevel, "test logger with field", nil, nil, nil) log.LogDetails(loglvl.InfoLevel, "test logger with field", nil, nil, nil)
var sub logger.Logger var sub liblog.Logger
sub = log.Clone() sub = log.Clone()
go func(log logger.Logger) { go func(log liblog.Logger) {
defer func() { defer func() {
se := log.Close() se := log.Close()
Expect(se).ToNot(HaveOccurred()) Expect(se).ToNot(HaveOccurred())
}() }()
log.SetFields(logger.NewFields(GetContext).Add("logger", "sub")) log.SetFields(logfld.New(GetContext).Add("logger", "sub"))
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
log.Entry(logger.InfoLevel, "test multithreading logger").FieldAdd("id", i).Log() log.Entry(loglvl.InfoLevel, "test multithreading logger").FieldAdd("id", i).Log()
} }
}(sub) }(sub)
log.SetFields(logger.NewFields(GetContext).Add("logger", "main")) log.SetFields(logfld.New(GetContext).Add("logger", "main"))
sem := libsem.NewSemaphoreWithContext(context.Background(), 0) sem := libsem.NewSemaphoreWithContext(context.Background(), 0)
defer sem.DeferMain() defer sem.DeferMain()
@@ -177,7 +202,7 @@ var _ = Describe("Logger", func() {
go func(id int) { go func(id int) {
defer sem.DeferWorker() defer sem.DeferWorker()
ent := log.Entry(logger.InfoLevel, "test multithreading logger") ent := log.Entry(loglvl.InfoLevel, "test multithreading logger")
ent.FieldAdd("id", id) ent.FieldAdd("id", id)
ent.Log() ent.Log()
}(i) }(i)

View File

@@ -29,21 +29,13 @@ package logger
import ( import (
"bytes" "bytes"
"fmt"
"strings" "strings"
loglvl "github.com/nabbar/golib/logger/level"
) )
func (o *logger) Close() error { func (o *logger) Close() error {
if o == nil { return o.switchCloser(o.newCloser()).Close()
return fmt.Errorf("not initialized")
} else if o.c == nil {
return fmt.Errorf("not initialized")
}
_ = o.c.Close()
o.c.Clean()
return nil
} }
func (o *logger) Write(p []byte) (n int, err error) { func (o *logger) Write(p []byte) (n int, err error) {
@@ -63,7 +55,7 @@ func (o *logger) Write(p []byte) (n int, err error) {
return len(p), nil return len(p), nil
} }
func (o *logger) SetIOWriterLevel(lvl Level) { func (o *logger) SetIOWriterLevel(lvl loglvl.Level) {
if o == nil { if o == nil {
return return
} else if o.x == nil { } else if o.x == nil {
@@ -72,15 +64,15 @@ func (o *logger) SetIOWriterLevel(lvl Level) {
o.x.Store(keyWriter, lvl) o.x.Store(keyWriter, lvl)
} }
func (o *logger) GetIOWriterLevel() Level { func (o *logger) GetIOWriterLevel() loglvl.Level {
if o == nil { if o == nil {
return NilLevel return loglvl.NilLevel
} else if o.x == nil { } else if o.x == nil {
return NilLevel return loglvl.NilLevel
} else if i, l := o.x.Load(keyWriter); !l { } else if i, l := o.x.Load(keyWriter); !l {
return NilLevel return loglvl.NilLevel
} else if v, k := i.(Level); !k { } else if v, k := i.(loglvl.Level); !k {
return NilLevel return loglvl.NilLevel
} else { } else {
return v return v
} }

View File

@@ -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 (
"math"
"strings"
"github.com/sirupsen/logrus"
)
// Level a uint8 type customized with function to log message with the current log level.
type Level uint8
const (
// PanicLevel Panic level for entry log, will result on a Panic() call (trace + fatal).
PanicLevel Level = iota
// FatalLevel Fatal level for entry log, will result on os.Exit with error.
FatalLevel
// ErrorLevel Error level for entry log who's meaning the caller stop his process and return to the pre caller.
ErrorLevel
// WarnLevel Warning level for entry log who's meaning the caller don't stop his process and try to continue it.
WarnLevel
// InfoLevel Info level for entry log who's meaning it is just an information who's have no impact on caller's process but can be useful to inform human of a state, event, success, ...
InfoLevel
// DebugLevel Debug level for entry log who's meaning the caller has no problem and the information is only useful to identify a potential problem who's can arrive later.
DebugLevel
// NilLevel Nil level will never log anything and is used to completely disable current log entry. It cannot be used in the SetLogLevel function.
NilLevel
)
// GetLevelListString return a list ([]string) of all string loglevel available.
func GetLevelListString() []string {
return []string{
strings.ToLower(PanicLevel.String()),
strings.ToLower(FatalLevel.String()),
strings.ToLower(ErrorLevel.String()),
strings.ToLower(WarnLevel.String()),
strings.ToLower(InfoLevel.String()),
strings.ToLower(DebugLevel.String()),
}
}
// 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(l string) Level {
switch {
case strings.EqualFold(PanicLevel.String(), l):
return PanicLevel
case strings.EqualFold(FatalLevel.String(), l):
return FatalLevel
case strings.EqualFold(ErrorLevel.String(), l):
return ErrorLevel
case strings.EqualFold(WarnLevel.String(), l):
return WarnLevel
case strings.EqualFold(InfoLevel.String(), l):
return InfoLevel
case strings.EqualFold(DebugLevel.String(), l):
return DebugLevel
}
return InfoLevel
}
// Uint8 Convert the current Level type to a uint8 value. E.g. FatalLevel becomes 1.
func (l Level) Uint8() uint8 {
return uint8(l)
}
// String Convert the current Level type to a string. E.g. PanicLevel becomes "Critical Error".
func (l Level) String() string {
//nolint exhaustive
switch l {
case DebugLevel:
return "Debug"
case InfoLevel:
return "Info"
case WarnLevel:
return "Warning"
case ErrorLevel:
return "Error"
case FatalLevel:
return "Fatal"
case PanicLevel:
return "Critical"
case NilLevel:
return ""
}
return "unknown"
}
func (l Level) Logrus() logrus.Level {
switch l {
case DebugLevel:
return logrus.DebugLevel
case InfoLevel:
return logrus.InfoLevel
case WarnLevel:
return logrus.WarnLevel
case ErrorLevel:
return logrus.ErrorLevel
case FatalLevel:
return logrus.FatalLevel
case PanicLevel:
return logrus.PanicLevel
default:
return math.MaxInt32
}
}

93
logger/level/interface.go Normal file
View File

@@ -0,0 +1,93 @@
/***********************************************************************************************************************
*
* 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 level
import (
"strings"
)
// Level a uint8 type customized with function to log message with the current log level.
type Level uint8
const (
// PanicLevel Panic level for entry log, will result on a Panic() call (trace + fatal).
PanicLevel Level = iota
// FatalLevel Fatal level for entry log, will result on os.Exit with error.
FatalLevel
// ErrorLevel Error level for entry log who's meaning the caller stop his process and return to the pre caller.
ErrorLevel
// WarnLevel Warning level for entry log who's meaning the caller don't stop his process and try to continue it.
WarnLevel
// InfoLevel Info level for entry log who's meaning it is just an information who's have no impact on caller's process but can be useful to inform human of a state, event, success, ...
InfoLevel
// DebugLevel Debug level for entry log who's meaning the caller has no problem and the information is only useful to identify a potential problem who's can arrive later.
DebugLevel
// NilLevel Nil level will never log anything and is used to completely disable current log entry. It cannot be used in the SetLogLevel function.
NilLevel
)
// ListLevels return a list ([]string) of all string loglevel available.
func ListLevels() []string {
return []string{
strings.ToLower(PanicLevel.String()),
strings.ToLower(FatalLevel.String()),
strings.ToLower(ErrorLevel.String()),
strings.ToLower(WarnLevel.String()),
strings.ToLower(InfoLevel.String()),
strings.ToLower(DebugLevel.String()),
}
}
// Parse 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 Parse(l string) Level {
switch {
case strings.EqualFold(PanicLevel.String(), l):
return PanicLevel
case strings.EqualFold(FatalLevel.String(), l):
return FatalLevel
case strings.EqualFold(ErrorLevel.String(), l):
return ErrorLevel
case strings.EqualFold(WarnLevel.String(), l):
return WarnLevel
case strings.EqualFold(InfoLevel.String(), l):
return InfoLevel
case strings.EqualFold(DebugLevel.String(), l):
return DebugLevel
}
return InfoLevel
}

81
logger/level/model.go Normal file
View File

@@ -0,0 +1,81 @@
/***********************************************************************************************************************
*
* 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 level
import (
"math"
"github.com/sirupsen/logrus"
)
// Uint8 Convert the current Level type to a uint8 value. E.g. FatalLevel becomes 1.
func (l Level) Uint8() uint8 {
return uint8(l)
}
// String Convert the current Level type to a string. E.g. PanicLevel becomes "Critical Error".
func (l Level) String() string {
//nolint exhaustive
switch l {
case DebugLevel:
return "Debug"
case InfoLevel:
return "Info"
case WarnLevel:
return "Warning"
case ErrorLevel:
return "Error"
case FatalLevel:
return "Fatal"
case PanicLevel:
return "Critical"
case NilLevel:
return ""
}
return "unknown"
}
func (l Level) Logrus() logrus.Level {
switch l {
case DebugLevel:
return logrus.DebugLevel
case InfoLevel:
return logrus.InfoLevel
case WarnLevel:
return logrus.WarnLevel
case ErrorLevel:
return logrus.ErrorLevel
case FatalLevel:
return logrus.FatalLevel
case PanicLevel:
return logrus.PanicLevel
default:
return math.MaxInt32
}
}

View File

@@ -30,109 +30,70 @@ package logger
import ( import (
"fmt" "fmt"
"time" "time"
logent "github.com/nabbar/golib/logger/entry"
logfld "github.com/nabbar/golib/logger/fields"
loglvl "github.com/nabbar/golib/logger/level"
) )
func (o *logger) Debug(message string, data interface{}, args ...interface{}) { func (o *logger) Debug(message string, data interface{}, args ...interface{}) {
o.newEntry(DebugLevel, fmt.Sprintf(message, args...), nil, nil, data).Log() o.newEntry(loglvl.DebugLevel, fmt.Sprintf(message, args...), nil, nil, data).Log()
} }
func (o *logger) Info(message string, data interface{}, args ...interface{}) { func (o *logger) Info(message string, data interface{}, args ...interface{}) {
o.newEntry(InfoLevel, fmt.Sprintf(message, args...), nil, nil, data).Log() o.newEntry(loglvl.InfoLevel, fmt.Sprintf(message, args...), nil, nil, data).Log()
} }
func (o *logger) Warning(message string, data interface{}, args ...interface{}) { func (o *logger) Warning(message string, data interface{}, args ...interface{}) {
o.newEntry(WarnLevel, fmt.Sprintf(message, args...), nil, nil, data).Log() o.newEntry(loglvl.WarnLevel, fmt.Sprintf(message, args...), nil, nil, data).Log()
} }
func (o *logger) Error(message string, data interface{}, args ...interface{}) { func (o *logger) Error(message string, data interface{}, args ...interface{}) {
o.newEntry(ErrorLevel, fmt.Sprintf(message, args...), nil, nil, data).Log() o.newEntry(loglvl.ErrorLevel, fmt.Sprintf(message, args...), nil, nil, data).Log()
} }
func (o *logger) Fatal(message string, data interface{}, args ...interface{}) { func (o *logger) Fatal(message string, data interface{}, args ...interface{}) {
o.newEntry(FatalLevel, fmt.Sprintf(message, args...), nil, nil, data).Log() o.newEntry(loglvl.FatalLevel, fmt.Sprintf(message, args...), nil, nil, data).Log()
} }
func (o *logger) Panic(message string, data interface{}, args ...interface{}) { func (o *logger) Panic(message string, data interface{}, args ...interface{}) {
o.newEntry(PanicLevel, fmt.Sprintf(message, args...), nil, nil, data).Log() o.newEntry(loglvl.PanicLevel, fmt.Sprintf(message, args...), nil, nil, data).Log()
} }
func (o *logger) LogDetails(lvl Level, message string, data interface{}, err []error, fields Fields, args ...interface{}) { func (o *logger) LogDetails(lvl loglvl.Level, message string, data interface{}, err []error, fields logfld.Fields, args ...interface{}) {
o.newEntry(lvl, fmt.Sprintf(message, args...), err, fields, data).Log() o.newEntry(lvl, fmt.Sprintf(message, args...), err, fields, data).Log()
} }
func (o *logger) CheckError(lvlKO, lvlOK Level, message string, err ...error) bool { func (o *logger) CheckError(lvlKO, lvlOK loglvl.Level, message string, err ...error) bool {
ent := o.newEntry(lvlKO, message, err, nil, nil) ent := o.newEntry(lvlKO, message, err, nil, nil)
return ent.Check(lvlOK) return ent.Check(lvlOK)
} }
func (o *logger) Entry(lvl Level, message string, args ...interface{}) *Entry { func (o *logger) Entry(lvl loglvl.Level, message string, args ...interface{}) logent.Entry {
return o.newEntry(lvl, fmt.Sprintf(message, args...), nil, nil, nil) return o.newEntry(lvl, fmt.Sprintf(message, args...), nil, nil, nil)
} }
func (o *logger) Access(remoteAddr, remoteUser string, localtime time.Time, latency time.Duration, method, request, proto string, status int, size int64) *Entry { func (o *logger) Access(remoteAddr, remoteUser string, localtime time.Time, latency time.Duration, method, request, proto string, status int, size int64) logent.Entry {
return o.newEntryClean(fmt.Sprintf("%s - %s [%s] [%s] \"%s %s %s\" %d %d", remoteAddr, remoteUser, localtime.Format(time.RFC1123Z), latency.String(), method, request, proto, status, size)) var msg = fmt.Sprintf("%s - %s [%s] [%s] \"%s %s %s\" %d %d", remoteAddr, remoteUser, localtime.Format(time.RFC1123Z), latency.String(), method, request, proto, status, size)
return o.newEntryClean(msg)
} }
func (o *logger) newEntry(lvl Level, message string, err []error, fields Fields, data interface{}) *Entry { func (o *logger) newEntry(lvl loglvl.Level, message string, err []error, fields logfld.Fields, data interface{}) logent.Entry {
opt := o.GetOptions() var (
cLv := o.GetLevel() ent = logent.New(lvl)
frm = o.getCaller()
)
var ent = &Entry{ ent.ErrorSet(err)
clean: false, ent.FieldSet(o.GetFields().FieldsClone(nil))
Time: time.Time{}, ent.DataSet(data)
Level: lvl, ent.SetLogger(o.getLogrus)
Stack: 0, ent.SetEntryContext(time.Now(), o.getStack(), frm.Function, frm.File, uint64(frm.Line), message)
Caller: "", ent.FieldMerge(fields)
File: "",
Line: 0,
Error: err,
Fields: o.GetFields().FieldsClone(nil),
}
if cLv == NilLevel || lvl > cLv {
return ent
} else {
ent.log = o.getLogrus
ent.Message = message
ent.Data = data
}
ent.Fields.Merge(fields)
if !opt.DisableTimestamp {
ent.Time = time.Now()
}
if !opt.DisableStack {
ent.Stack = o.getStack()
}
if opt.EnableTrace {
frm := o.getCaller()
if frm.Function != "" {
ent.Caller = frm.Function
}
if frm.File != "" {
ent.File = o.filterPath(frm.File)
}
if frm.Line > 0 {
ent.Line = uint32(frm.Line)
}
}
return ent return ent
} }
func (o *logger) newEntryClean(message string) *Entry { func (o *logger) newEntryClean(message string) logent.Entry {
var ent = &Entry{ return o.newEntry(loglvl.InfoLevel, message, nil, nil, nil).SetMessageOnly(true)
log: o.getLogrus,
clean: true,
Message: message,
Fields: NewFields(o.x.GetContext),
}
return ent
} }

View File

@@ -1,7 +1,8 @@
/* /***********************************************************************************************************************
*
* MIT License * MIT License
* *
* Copyright (c) 2020 Nicolas JUHEL * Copyright (c) 2021 Nicolas JUHEL
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -21,7 +22,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. * SOFTWARE.
* *
*/ *
**********************************************************************************************************************/
package logger_test package logger_test

View File

@@ -31,51 +31,111 @@ import (
"context" "context"
"io" "io"
"sync" "sync"
"sync/atomic"
"time"
iotclo "github.com/nabbar/golib/ioutils/mapCloser" iotclo "github.com/nabbar/golib/ioutils/mapCloser"
logcfg "github.com/nabbar/golib/logger/config"
logfld "github.com/nabbar/golib/logger/fields"
logfil "github.com/nabbar/golib/logger/hookfile"
logerr "github.com/nabbar/golib/logger/hookstderr"
logout "github.com/nabbar/golib/logger/hookstdout"
logsys "github.com/nabbar/golib/logger/hooksyslog"
loglvl "github.com/nabbar/golib/logger/level"
logtps "github.com/nabbar/golib/logger/types"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
func (o *logger) getCloser() iotclo.Closer {
i := o.c.Load()
if c, k := i.(iotclo.Closer); k && c != nil {
return c
}
c := iotclo.New(o.x.GetContext)
o.c.Store(c)
return c
}
func (o *logger) switchCloser(c iotclo.Closer) iotclo.Closer {
b := o.getCloser()
o.c.Store(c)
return b
}
func (o *logger) newCloser() iotclo.Closer {
return iotclo.New(o.x.GetContext)
}
func (o *logger) Clone() Logger { func (o *logger) Clone() Logger {
if o == nil { if o == nil {
return nil return nil
} }
o.m.RLock() l := &logger{
defer o.m.RUnlock()
return &logger{
x: o.x.Clone(nil),
m: sync.RWMutex{}, m: sync.RWMutex{},
x: o.x.Clone(nil),
f: o.f.FieldsClone(nil), f: o.f.FieldsClone(nil),
c: o.c.Clone(), c: new(atomic.Value),
}
return l
}
func (o *logger) RegisterFuncUpdateLogger(fct func(log Logger)) {
o.x.Store(keyFctUpdLog, fct)
}
func (o *logger) runFuncUpdateLogger() {
if i, l := o.x.Load(keyFctUpdLog); !l {
return
} else if f, k := i.(func(log Logger)); !k {
return
} else if f == nil {
return
} else {
f(o)
} }
} }
func (o *logger) SetLevel(lvl Level) { func (o *logger) RegisterFuncUpdateLevel(fct func(log Logger)) {
o.x.Store(keyFctUpdLvl, fct)
}
func (o *logger) runFuncUpdateLevel() {
if i, l := o.x.Load(keyFctUpdLvl); !l {
return
} else if f, k := i.(func(log Logger)); !k {
return
} else if f == nil {
return
} else {
f(o)
}
}
func (o *logger) SetLevel(lvl loglvl.Level) {
o.x.Store(keyLevel, lvl) o.x.Store(keyLevel, lvl)
o.setLogrusLevel(o.GetLevel()) o.setLogrusLevel(o.GetLevel())
o.runFuncUpdateLevel()
if opt := o.GetOptions(); opt.change != nil {
opt.change(o)
}
} }
func (o *logger) GetLevel() Level { func (o *logger) GetLevel() loglvl.Level {
if o == nil { if o == nil {
return NilLevel return loglvl.NilLevel
} else if o.x == nil { } else if o.x == nil {
return NilLevel return loglvl.NilLevel
} else if i, l := o.x.Load(keyLevel); !l { } else if i, l := o.x.Load(keyLevel); !l {
return NilLevel return loglvl.NilLevel
} else if v, k := i.(Level); !k { } else if v, k := i.(loglvl.Level); !k {
return NilLevel return loglvl.NilLevel
} else { } else {
return v return v
} }
} }
func (o *logger) SetFields(field Fields) { func (o *logger) SetFields(field logfld.Fields) {
if o == nil { if o == nil {
return return
} }
@@ -87,9 +147,9 @@ func (o *logger) SetFields(field Fields) {
} }
} }
func (o *logger) GetFields() Fields { func (o *logger) GetFields() logfld.Fields {
if o == nil { if o == nil {
return NewFields(context.Background) return logfld.New(context.Background)
} }
o.m.RLock() o.m.RLock()
@@ -97,85 +157,97 @@ func (o *logger) GetFields() Fields {
return o.f.FieldsClone(nil) return o.f.FieldsClone(nil)
} }
func (o *logger) SetOptions(opt *Options) error { func (o *logger) SetOptions(opt *logcfg.Options) error {
var ( var (
ctx, cnl = context.WithCancel(o.x.GetContext())
lvl = o.GetLevel() lvl = o.GetLevel()
obj = logrus.New() obj = logrus.New()
hkl = make([]logtps.Hook, 0)
) )
defer cnl()
o.optionsMerge(opt) o.optionsMerge(opt)
obj.SetLevel(lvl.Logrus()) obj.SetLevel(lvl.Logrus())
obj.SetFormatter(o.defaultFormatter(opt)) obj.SetFormatter(o.defaultFormatter(nil))
obj.SetOutput(io.Discard) // Send all logs to nowhere by default obj.SetOutput(io.Discard) // Send all logs to nowhere by default
clo := iotclo.New(func() context.Context { if opt.Stdout != nil && !opt.Stdout.DisableStandard {
return ctx f := o.defaultFormatter(opt.Stdout)
}) l := []logrus.Level{
if !opt.DisableStandard {
obj.AddHook(NewHookStandard(*opt, StdOut, []logrus.Level{
logrus.InfoLevel, logrus.InfoLevel,
logrus.DebugLevel, logrus.DebugLevel,
logrus.TraceLevel, logrus.TraceLevel,
})) }
obj.AddHook(NewHookStandard(*opt, StdErr, []logrus.Level{ if h, e := logout.New(opt.Stdout, l, f); e != nil {
return e
} else {
hkl = append(hkl, h)
}
l = []logrus.Level{
logrus.PanicLevel, logrus.PanicLevel,
logrus.FatalLevel, logrus.FatalLevel,
logrus.ErrorLevel, logrus.ErrorLevel,
logrus.WarnLevel, logrus.WarnLevel,
})) }
if h, e := logerr.New(opt.Stdout, l, f); e != nil {
return e
} else {
hkl = append(hkl, h)
}
} }
if len(opt.LogFile) > 0 { if len(opt.LogFile) > 0 {
for _, fopt := range opt.LogFile { for _, f := range opt.LogFile {
if hook, err := NewHookFile(fopt, o.defaultFormatterNoColor()); err != nil { if h, e := logfil.New(f, o.defaultFormatterNoColor()); e != nil {
return err return e
} else { } else {
clo.Add(hook) hkl = append(hkl, h)
hook.RegisterHook(obj)
} }
} }
} }
if len(opt.LogSyslog) > 0 { if len(opt.LogSyslog) > 0 {
for _, lopt := range opt.LogSyslog { for _, s := range opt.LogSyslog {
if hook, err := NewHookSyslog(lopt, o.defaultFormatterNoColor()); err != nil { if h, e := logsys.New(s, o.defaultFormatterNoColor()); e != nil {
return err return e
} else { } else {
clo.Add(hook) hkl = append(hkl, h)
hook.RegisterHook(obj)
} }
} }
} }
var clo = o.newCloser()
for _, h := range hkl {
clo.Add(h)
h.RegisterHook(obj)
go h.Run(o.x.GetContext())
}
o.x.Store(keyOptions, opt) o.x.Store(keyOptions, opt)
o.x.Store(keyLogrus, obj) o.x.Store(keyLogrus, obj)
o.runFuncUpdateLogger()
_ = o.Close() clo = o.switchCloser(clo)
o.c.Add(clo.Get()...) go func(c iotclo.Closer) {
clo.Clean() time.Sleep(3 * time.Second)
_ = c.Close()
if opt.init != nil { }(clo)
opt.init(o)
}
return nil return nil
} }
func (o *logger) GetOptions() *Options { func (o *logger) GetOptions() *logcfg.Options {
if o == nil { if o == nil {
return &Options{} return &logcfg.Options{}
} else if o.x == nil { } else if o.x == nil {
return &Options{} return &logcfg.Options{}
} else if i, l := o.x.Load(keyOptions); !l { } else if i, l := o.x.Load(keyOptions); !l {
return &Options{} return &logcfg.Options{}
} else if v, k := i.(*Options); !k { } else if v, k := i.(*logcfg.Options); !k {
return &Options{} return &logcfg.Options{}
} else { } else {
return v return v
} }

View File

@@ -36,11 +36,14 @@ import (
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"sync/atomic"
"time" "time"
libctx "github.com/nabbar/golib/context" libctx "github.com/nabbar/golib/context"
liberr "github.com/nabbar/golib/errors" liberr "github.com/nabbar/golib/errors"
iotclo "github.com/nabbar/golib/ioutils/mapCloser" logcfg "github.com/nabbar/golib/logger/config"
logfld "github.com/nabbar/golib/logger/fields"
loglvl "github.com/nabbar/golib/logger/level"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@@ -52,6 +55,8 @@ const (
keyLogrus keyLogrus
keyWriter keyWriter
keyFilter keyFilter
keyFctUpdLog
keyFctUpdLvl
_TraceFilterMod = "/pkg/mod/" _TraceFilterMod = "/pkg/mod/"
_TraceFilterVendor = "/vendor/" _TraceFilterVendor = "/vendor/"
@@ -62,8 +67,8 @@ var _selfPackage = path.Base(reflect.TypeOf(logger{}).PkgPath())
type logger struct { type logger struct {
m sync.RWMutex m sync.RWMutex
x libctx.Config[uint8] // cf const key... x libctx.Config[uint8] // cf const key...
f Fields // fields map f logfld.Fields // fields map
c iotclo.Closer c *atomic.Value // closer
} }
func defaultFormatter() logrus.TextFormatter { func defaultFormatter() logrus.TextFormatter {
@@ -86,7 +91,7 @@ func defaultFormatter() logrus.TextFormatter {
} }
} }
func (o *logger) defaultFormatter(opt *Options) logrus.Formatter { func (o *logger) defaultFormatter(opt *logcfg.OptionsStd) logrus.Formatter {
f := defaultFormatter() f := defaultFormatter()
if opt != nil && opt.DisableColor { if opt != nil && opt.DisableColor {
@@ -128,69 +133,22 @@ func (o *logger) cancelCall() {
} }
} }
func (o *logger) optionsMerge(opt *Options) { func (o *logger) optionsMerge(opt *logcfg.Options) {
if !opt.InheritDefault { var oo logcfg.Options
if i, l := o.x.Load(keyOptions); !l {
return return
} } else if v, k := i.(*logcfg.Options); !k {
var no Options
if opt.opts != nil {
no = *opt.opts()
} else if i, l := o.x.Load(keyOptions); !l {
return return
} else if v, k := i.(*Options); !k {
return
} else if v.opts != nil {
no = *v.opts()
} else { } else {
no = *v oo = *v
} }
if opt.DisableStandard { oo.Merge(opt)
no.DisableStandard = true *opt = oo
} }
if opt.DisableStack { func (o *logger) setLogrusLevel(lvl loglvl.Level) {
no.DisableStack = true
}
if opt.DisableTimestamp {
no.DisableTimestamp = true
}
if opt.EnableTrace {
no.EnableTrace = true
}
if len(opt.TraceFilter) > 0 {
no.TraceFilter = opt.TraceFilter
}
if opt.DisableColor {
no.DisableColor = true
}
if opt.EnableAccessLog {
no.EnableAccessLog = true
}
if opt.LogFileExtend {
no.LogFile = append(no.LogFile, opt.LogFile...)
} else {
no.LogFile = opt.LogFile
}
if opt.LogSyslogExtend {
no.LogSyslog = append(no.LogSyslog, opt.LogSyslog...)
} else {
no.LogSyslog = opt.LogSyslog
}
*opt = no
}
func (o *logger) setLogrusLevel(lvl Level) {
if i, l := o.x.Load(keyLogrus); !l { if i, l := o.x.Load(keyLogrus); !l {
return return
} else if v, k := i.(*logrus.Logger); !k { } else if v, k := i.(*logrus.Logger); !k {

View File

@@ -1,286 +0,0 @@
/*
* 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"
"os"
"strings"
libval "github.com/go-playground/validator/v10"
liberr "github.com/nabbar/golib/errors"
)
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 ""
}
}
func MakeNetwork(net string) NetworkType {
switch strings.ToLower(net) {
case NetworkTCP.String():
return NetworkTCP
case NetworkUDP.String():
return NetworkUDP
default:
return NetworkEmpty
}
}
type OptionsFile struct {
// LogLevel define the allowed level of log for this file.
LogLevel []string `json:"logLevel,omitempty" yaml:"logLevel,omitempty" toml:"logLevel,omitempty" mapstructure:"logLevel,omitempty"`
// Filepath define the file path for log to file.
Filepath string `json:"filepath,omitempty" yaml:"filepath,omitempty" toml:"filepath,omitempty" mapstructure:"filepath,omitempty"`
// Create define if the log file must exist or can create it.
Create bool `json:"create,omitempty" yaml:"create,omitempty" toml:"create,omitempty" mapstructure:"create,omitempty"`
// CreatePath define if the path of the log file must exist or can try to create it.
CreatePath bool `json:"createPath,omitempty" yaml:"createPath,omitempty" toml:"createPath,omitempty" mapstructure:"createPath,omitempty"`
// FileMode define mode to be used for the log file if the create it.
FileMode os.FileMode `json:"fileMode,omitempty" yaml:"fileMode,omitempty" toml:"fileMode,omitempty" mapstructure:"fileMode,omitempty"`
// PathMode define mode to be used for the path of the log file if create it.
PathMode os.FileMode `json:"pathMode,omitempty" yaml:"pathMode,omitempty" toml:"pathMode,omitempty" mapstructure:"pathMode,omitempty"`
// DisableStack allow to disable the goroutine id before each message.
DisableStack bool `json:"disableStack,omitempty" yaml:"disableStack,omitempty" toml:"disableStack,omitempty" mapstructure:"disableStack,omitempty"`
// DisableTimestamp allow to disable the timestamp before each message.
DisableTimestamp bool `json:"disableTimestamp,omitempty" yaml:"disableTimestamp,omitempty" toml:"disableTimestamp,omitempty" mapstructure:"disableTimestamp,omitempty"`
// EnableTrace allow to add the origin caller/file/line of each message.
EnableTrace bool `json:"enableTrace,omitempty" yaml:"enableTrace,omitempty" toml:"enableTrace,omitempty" mapstructure:"enableTrace,omitempty"`
// EnableAccessLog allow to add all message from api router for access log and error log.
EnableAccessLog bool `json:"enableAccessLog,omitempty" yaml:"enableAccessLog,omitempty" toml:"enableAccessLog,omitempty" mapstructure:"enableAccessLog,omitempty"`
}
type OptionsFiles []OptionsFile
type OptionsSyslog struct {
// LogLevel define the allowed level of log for this syslog.
LogLevel []string `json:"logLevel,omitempty" yaml:"logLevel,omitempty" toml:"logLevel,omitempty" mapstructure:"logLevel,omitempty"`
// Network define the network used to connect to this syslog (tcp, udp, or any other to a local connection).
Network string `json:"network,omitempty" yaml:"network,omitempty" toml:"network,omitempty" mapstructure:"network,omitempty"`
// Host define the remote syslog to use.
// If Host and Network are empty, local syslog will be used.
Host string `json:"host,omitempty" yaml:"host,omitempty" toml:"host,omitempty" mapstructure:"host,omitempty"`
/*
// Severity define the severity syslog to be used.
Severity string `json:"severity,omitempty" yaml:"severity,omitempty" toml:"severity,omitempty" mapstructure:"severity,omitempty"`
*/
// Facility define the facility syslog to be used.
Facility string `json:"facility,omitempty" yaml:"facility,omitempty" toml:"facility,omitempty" mapstructure:"facility,omitempty"`
// Tag define the syslog tag used in linux syslog system or name of logger for windows event logger.
// For window, this value must be unic for each syslog config
Tag string `json:"tag,omitempty" yaml:"tag,omitempty" toml:"tag,omitempty" mapstructure:"tag,omitempty"`
// DisableStack allow to disable the goroutine id before each message.
DisableStack bool `json:"disableStack,omitempty" yaml:"disableStack,omitempty" toml:"disableStack,omitempty" mapstructure:"disableStack,omitempty"`
// DisableTimestamp allow to disable the timestamp before each message.
DisableTimestamp bool `json:"disableTimestamp,omitempty" yaml:"disableTimestamp,omitempty" toml:"disableTimestamp,omitempty" mapstructure:"disableTimestamp,omitempty"`
// EnableTrace allow to add the origin caller/file/line of each message.
EnableTrace bool `json:"enableTrace,omitempty" yaml:"enableTrace,omitempty" toml:"enableTrace,omitempty" mapstructure:"enableTrace,omitempty"`
// EnableAccessLog allow to add all message from api router for access log and error log.
EnableAccessLog bool `json:"enableAccessLog,omitempty" yaml:"enableAccessLog,omitempty" toml:"enableAccessLog,omitempty" mapstructure:"enableAccessLog,omitempty"`
}
type OptionsSyslogs []OptionsSyslog
type Options struct {
// InheritDefault define if the current options will override a default options
InheritDefault bool `json:"inheritDefault" yaml:"inheritDefault" toml:"inheritDefault" mapstructure:"inheritDefault"`
// DisableStandard allow disabling to write log to standard output stdout/stderr.
DisableStandard bool `json:"disableStandard,omitempty" yaml:"disableStandard,omitempty" toml:"disableStandard,omitempty" mapstructure:"disableStandard,omitempty"`
// DisableStack allow to disable the goroutine id before each message.
DisableStack bool `json:"disableStack,omitempty" yaml:"disableStack,omitempty" toml:"disableStack,omitempty" mapstructure:"disableStack,omitempty"`
// DisableTimestamp allow to disable the timestamp before each message.
DisableTimestamp bool `json:"disableTimestamp,omitempty" yaml:"disableTimestamp,omitempty" toml:"disableTimestamp,omitempty" mapstructure:"disableTimestamp,omitempty"`
// EnableTrace allow to add the origin caller/file/line of each message.
EnableTrace bool `json:"enableTrace,omitempty" yaml:"enableTrace,omitempty" toml:"enableTrace,omitempty" mapstructure:"enableTrace,omitempty"`
// TraceFilter define the path to clean for trace.
TraceFilter string `json:"traceFilter,omitempty" yaml:"traceFilter,omitempty" toml:"traceFilter,omitempty" mapstructure:"traceFilter,omitempty"`
// 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 `json:"disableColor,omitempty" yaml:"disableColor,omitempty" toml:"disableColor,omitempty" mapstructure:"disableColor,omitempty"`
// EnableAccessLog allow to add all message from api router for access log and error log.
EnableAccessLog bool `json:"enableAccessLog,omitempty" yaml:"enableAccessLog,omitempty" toml:"enableAccessLog,omitempty" mapstructure:"enableAccessLog,omitempty"`
// LogFileExtend define if the logFile given is in addition of default LogFile or a replacement.
LogFileExtend bool `json:"logFileExtend,omitempty" yaml:"logFileExtend,omitempty" toml:"logFileExtend,omitempty" mapstructure:"logFileExtend,omitempty"`
// LogFile define a list of log file configuration to allow log to files.
LogFile OptionsFiles `json:"logFile,omitempty" yaml:"logFile,omitempty" toml:"logFile,omitempty" mapstructure:"logFile,omitempty"`
// LogSyslogExtend define if the logFile given is in addition of default LogSyslog or a replacement.
LogSyslogExtend bool `json:"logSyslogExtend,omitempty" yaml:"logSyslogExtend,omitempty" toml:"logSyslogExtend,omitempty" mapstructure:"logSyslogExtend,omitempty"`
// LogSyslog define a list of syslog configuration to allow log to syslog.
LogSyslog OptionsSyslogs `json:"logSyslog,omitempty" yaml:"logSyslog,omitempty" toml:"logSyslog,omitempty" mapstructure:"logSyslog,omitempty"`
// custom function handler.
init FuncCustomConfig
change FuncCustomConfig
// default options
opts FuncOpt
}
// RegisterDefaultFunc allow to register a function called to retrieve default options for inheritDefault.
// If not set, the previous options will be used as default options.
// To clean function, just call RegisterDefaultFunc with nil as param.
func (o *Options) RegisterDefaultFunc(fct FuncOpt) {
o.opts = fct
}
// 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
}
// Validate allow checking if the options' struct is valid with the awaiting model
func (o *Options) Validate() liberr.Error {
var e = ErrorValidatorError.Error(nil)
if err := libval.New().Struct(o); err != nil {
if er, ok := err.(*libval.InvalidValidationError); ok {
e.AddParent(er)
}
for _, er := range err.(libval.ValidationErrors) {
//nolint #goerr113
e.AddParent(fmt.Errorf("config field '%s' is not validated by constraint '%s'", er.Namespace(), er.ActualTag()))
}
}
if !e.HasParent() {
e = nil
}
return e
}
func (o *Options) Clone() Options {
return Options{
DisableStandard: o.DisableStandard,
DisableStack: o.DisableStack,
DisableTimestamp: o.DisableTimestamp,
EnableTrace: o.EnableTrace,
TraceFilter: o.TraceFilter,
DisableColor: o.DisableColor,
EnableAccessLog: o.EnableAccessLog,
LogFile: o.LogFile.Clone(),
LogSyslog: o.LogSyslog.Clone(),
init: o.init,
change: o.change,
}
}
func (o OptionsFile) Clone() OptionsFile {
return OptionsFile{
LogLevel: o.LogLevel,
Filepath: o.Filepath,
Create: o.Create,
CreatePath: o.CreatePath,
FileMode: o.FileMode,
PathMode: o.PathMode,
DisableStack: o.DisableStack,
DisableTimestamp: o.DisableTimestamp,
EnableTrace: o.EnableTrace,
EnableAccessLog: o.EnableAccessLog,
}
}
func (o OptionsFiles) Clone() OptionsFiles {
var c = make([]OptionsFile, 0)
for _, i := range o {
c = append(c, i.Clone())
}
return c
}
func (o OptionsSyslog) Clone() OptionsSyslog {
return OptionsSyslog{
LogLevel: o.LogLevel,
Network: o.Network,
Host: o.Host,
Facility: o.Facility,
Tag: o.Tag,
DisableStack: o.DisableStack,
DisableTimestamp: o.DisableTimestamp,
EnableTrace: o.EnableTrace,
EnableAccessLog: o.EnableAccessLog,
}
}
func (o OptionsSyslogs) Clone() OptionsSyslogs {
var c = make([]OptionsSyslog, 0)
for _, i := range o {
c = append(c, i.Clone())
}
return c
}

67
logger/spf13.go Normal file
View File

@@ -0,0 +1,67 @@
/***********************************************************************************************************************
*
* 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"
loglvl "github.com/nabbar/golib/logger/level"
jww "github.com/spf13/jwalterweatherman"
)
func (o *logger) SetSPF13Level(lvl loglvl.Level, log *jww.Notepad) {
if log == nil {
jww.SetStdoutOutput(io.Discard)
} else {
jww.SetStdoutOutput(o)
}
switch lvl {
case loglvl.NilLevel:
jww.SetLogOutput(io.Discard)
jww.SetLogThreshold(jww.LevelCritical)
case loglvl.DebugLevel:
jww.SetLogOutput(o)
jww.SetLogThreshold(jww.LevelTrace)
case loglvl.InfoLevel:
jww.SetLogOutput(o)
jww.SetLogThreshold(jww.LevelInfo)
case loglvl.WarnLevel:
jww.SetLogOutput(o)
jww.SetLogThreshold(jww.LevelWarn)
case loglvl.ErrorLevel:
jww.SetLogOutput(o)
jww.SetLogThreshold(jww.LevelError)
case loglvl.FatalLevel:
jww.SetLogOutput(o)
jww.SetLogThreshold(jww.LevelFatal)
case loglvl.PanicLevel:
jww.SetLogOutput(o)
jww.SetLogThreshold(jww.LevelCritical)
}
}

40
logger/types/fields.go Normal file
View File

@@ -0,0 +1,40 @@
/***********************************************************************************************************************
*
* 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 types
const (
FieldTime = "time"
FieldLevel = "level"
FieldStack = "stack"
FieldCaller = "caller"
FieldFile = "file"
FieldLine = "line"
FieldMessage = "message"
FieldError = "error"
FieldData = "data"
)

42
logger/types/hook.go Normal file
View File

@@ -0,0 +1,42 @@
/***********************************************************************************************************************
*
* 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 types
import (
"context"
"io"
"github.com/sirupsen/logrus"
)
type Hook interface {
logrus.Hook
io.WriteCloser
RegisterHook(log *logrus.Logger)
Run(ctx context.Context)
}

View File

@@ -30,11 +30,10 @@ import (
"time" "time"
libctx "github.com/nabbar/golib/context" libctx "github.com/nabbar/golib/context"
"github.com/nabbar/golib/monitor/types"
liberr "github.com/nabbar/golib/errors" liberr "github.com/nabbar/golib/errors"
liblog "github.com/nabbar/golib/logger" liblog "github.com/nabbar/golib/logger"
logcfg "github.com/nabbar/golib/logger/config"
montps "github.com/nabbar/golib/monitor/types"
) )
type runCfg struct { type runCfg struct {
@@ -101,7 +100,7 @@ func (o *mon) getLoggerDefault() liblog.Logger {
} }
} }
func (o *mon) SetConfig(ctx libctx.FuncContext, cfg types.Config) liberr.Error { func (o *mon) SetConfig(ctx libctx.FuncContext, cfg montps.Config) liberr.Error {
if ctx == nil { if ctx == nil {
ctx = o.x.GetContext ctx = o.x.GetContext
} }
@@ -175,17 +174,12 @@ func (o *mon) SetConfig(ctx libctx.FuncContext, cfg types.Config) liberr.Error {
f := n.GetFields() f := n.GetFields()
n.SetFields(f.Add(LogFieldProcess, LogValueProcess).Add(LogFieldName, cfg.Name)) n.SetFields(f.Add(LogFieldProcess, LogValueProcess).Add(LogFieldName, cfg.Name))
n.SetLevel(liblog.GetCurrentLevel())
if l := o.getLog(); l != nil {
_ = l.Close()
}
o.x.Store(keyLogger, n) o.x.Store(keyLogger, n)
return nil return nil
} }
func (o *mon) GetConfig() types.Config { func (o *mon) GetConfig() montps.Config {
cfg := o.getCfg() cfg := o.getCfg()
if cfg == nil { if cfg == nil {
cfg = &runCfg{} cfg = &runCfg{}
@@ -193,10 +187,10 @@ func (o *mon) GetConfig() types.Config {
opt := o.getLogger().GetOptions() opt := o.getLogger().GetOptions()
if opt == nil { if opt == nil {
opt = &liblog.Options{} opt = &logcfg.Options{}
} }
return types.Config{ return montps.Config{
Name: o.getName(), Name: o.getName(),
CheckTimeout: cfg.checkTimeout, CheckTimeout: cfg.checkTimeout,
IntervalCheck: cfg.intervalCheck, IntervalCheck: cfg.intervalCheck,
@@ -244,16 +238,16 @@ func (o *mon) getLogger() liblog.Logger {
i := o.getLog() i := o.getLog()
if i == nil { if i == nil {
return liblog.GetDefault() return liblog.New(o.x.GetContext)
} else { } else {
return i return i
} }
} }
func (o *mon) getFct() types.HealthCheck { func (o *mon) getFct() montps.HealthCheck {
if i, l := o.x.Load(keyHealthCheck); !l { if i, l := o.x.Load(keyHealthCheck); !l {
return nil return nil
} else if v, k := i.(types.HealthCheck); !k { } else if v, k := i.(montps.HealthCheck); !k {
return nil return nil
} else { } else {
return v return v

View File

@@ -30,8 +30,7 @@ import (
"context" "context"
"strings" "strings"
liblog "github.com/nabbar/golib/logger" loglvl "github.com/nabbar/golib/logger/level"
montps "github.com/nabbar/golib/monitor/types" montps "github.com/nabbar/golib/monitor/types"
libprm "github.com/nabbar/golib/prometheus" libprm "github.com/nabbar/golib/prometheus"
libmet "github.com/nabbar/golib/prometheus/metrics" libmet "github.com/nabbar/golib/prometheus/metrics"
@@ -115,7 +114,7 @@ func (o *pool) collectMetricLatency(ctx context.Context, m libmet.Metric) {
o.MonitorWalk(func(name string, val montps.Monitor) bool { o.MonitorWalk(func(name string, val montps.Monitor) bool {
if e := m.Observe([]string{name}, val.CollectLatency().Seconds()); e != nil { if e := m.Observe([]string{name}, val.CollectLatency().Seconds()); e != nil {
ent := log.Entry(liblog.ErrorLevel, "failed to collect metrics", nil) ent := log.Entry(loglvl.ErrorLevel, "failed to collect metrics", nil)
ent.FieldAdd("monitor", name) ent.FieldAdd("monitor", name)
ent.FieldAdd("metric", val.Name()) ent.FieldAdd("metric", val.Name())
ent.ErrorAdd(true, e) ent.ErrorAdd(true, e)
@@ -151,7 +150,7 @@ func (o *pool) collectMetricUptime(ctx context.Context, m libmet.Metric) {
o.MonitorWalk(func(name string, val montps.Monitor) bool { o.MonitorWalk(func(name string, val montps.Monitor) bool {
if e := m.SetGaugeValue([]string{name}, val.CollectUpTime().Seconds()); e != nil { if e := m.SetGaugeValue([]string{name}, val.CollectUpTime().Seconds()); e != nil {
ent := log.Entry(liblog.ErrorLevel, "failed to collect metrics", nil) ent := log.Entry(loglvl.ErrorLevel, "failed to collect metrics", nil)
ent.FieldAdd("monitor", name) ent.FieldAdd("monitor", name)
ent.FieldAdd("metric", val.Name()) ent.FieldAdd("metric", val.Name())
ent.ErrorAdd(true, e) ent.ErrorAdd(true, e)
@@ -187,7 +186,7 @@ func (o *pool) collectMetricDowntime(ctx context.Context, m libmet.Metric) {
o.MonitorWalk(func(name string, val montps.Monitor) bool { o.MonitorWalk(func(name string, val montps.Monitor) bool {
if e := m.SetGaugeValue([]string{name}, val.CollectDownTime().Seconds()); e != nil { if e := m.SetGaugeValue([]string{name}, val.CollectDownTime().Seconds()); e != nil {
ent := log.Entry(liblog.ErrorLevel, "failed to collect metrics", nil) ent := log.Entry(loglvl.ErrorLevel, "failed to collect metrics", nil)
ent.FieldAdd("monitor", name) ent.FieldAdd("monitor", name)
ent.FieldAdd("metric", val.Name()) ent.FieldAdd("metric", val.Name())
ent.ErrorAdd(true, e) ent.ErrorAdd(true, e)
@@ -223,7 +222,7 @@ func (o *pool) collectMetricRiseTime(ctx context.Context, m libmet.Metric) {
o.MonitorWalk(func(name string, val montps.Monitor) bool { o.MonitorWalk(func(name string, val montps.Monitor) bool {
if e := m.SetGaugeValue([]string{name}, val.CollectRiseTime().Seconds()); e != nil { if e := m.SetGaugeValue([]string{name}, val.CollectRiseTime().Seconds()); e != nil {
ent := log.Entry(liblog.ErrorLevel, "failed to collect metrics", nil) ent := log.Entry(loglvl.ErrorLevel, "failed to collect metrics", nil)
ent.FieldAdd("monitor", name) ent.FieldAdd("monitor", name)
ent.FieldAdd("metric", val.Name()) ent.FieldAdd("metric", val.Name())
ent.ErrorAdd(true, e) ent.ErrorAdd(true, e)
@@ -259,7 +258,7 @@ func (o *pool) collectMetricFallTime(ctx context.Context, m libmet.Metric) {
o.MonitorWalk(func(name string, val montps.Monitor) bool { o.MonitorWalk(func(name string, val montps.Monitor) bool {
if e := m.SetGaugeValue([]string{name}, val.CollectFallTime().Seconds()); e != nil { if e := m.SetGaugeValue([]string{name}, val.CollectFallTime().Seconds()); e != nil {
ent := log.Entry(liblog.ErrorLevel, "failed to collect metrics", nil) ent := log.Entry(loglvl.ErrorLevel, "failed to collect metrics", nil)
ent.FieldAdd("monitor", name) ent.FieldAdd("monitor", name)
ent.FieldAdd("metric", val.Name()) ent.FieldAdd("metric", val.Name())
ent.ErrorAdd(true, e) ent.ErrorAdd(true, e)
@@ -299,7 +298,7 @@ func (o *pool) collectMetricStatus(ctx context.Context, m libmet.Metric) {
) )
if e := m.SetGaugeValue([]string{name}, s.Float()); e != nil { if e := m.SetGaugeValue([]string{name}, s.Float()); e != nil {
ent := log.Entry(liblog.ErrorLevel, "failed to collect metrics", nil) ent := log.Entry(loglvl.ErrorLevel, "failed to collect metrics", nil)
ent.FieldAdd("monitor", name) ent.FieldAdd("monitor", name)
ent.FieldAdd("metric", val.Name()) ent.FieldAdd("metric", val.Name())
ent.ErrorAdd(true, e) ent.ErrorAdd(true, e)
@@ -345,7 +344,7 @@ func (o *pool) collectMetricRising(ctx context.Context, m libmet.Metric) {
} }
if e := m.SetGaugeValue([]string{name}, s); e != nil { if e := m.SetGaugeValue([]string{name}, s); e != nil {
ent := log.Entry(liblog.ErrorLevel, "failed to collect metrics", nil) ent := log.Entry(loglvl.ErrorLevel, "failed to collect metrics", nil)
ent.FieldAdd("monitor", name) ent.FieldAdd("monitor", name)
ent.FieldAdd("metric", val.Name()) ent.FieldAdd("metric", val.Name())
ent.ErrorAdd(true, e) ent.ErrorAdd(true, e)
@@ -392,7 +391,7 @@ func (o *pool) collectMetricFalling(ctx context.Context, m libmet.Metric) {
} }
if e := m.SetGaugeValue([]string{name}, s); e != nil { if e := m.SetGaugeValue([]string{name}, s); e != nil {
ent := log.Entry(liblog.ErrorLevel, "failed to collect metrics", nil) ent := log.Entry(loglvl.ErrorLevel, "failed to collect metrics", nil)
ent.FieldAdd("monitor", name) ent.FieldAdd("monitor", name)
ent.FieldAdd("metric", val.Name()) ent.FieldAdd("metric", val.Name())
ent.ErrorAdd(true, e) ent.ErrorAdd(true, e)
@@ -462,7 +461,7 @@ func (o *pool) collectMetricSLis(ctx context.Context, m libmet.Metric) {
} }
if e := m.SetGaugeValue([]string{name}, cur); e != nil { if e := m.SetGaugeValue([]string{name}, cur); e != nil {
ent := log.Entry(liblog.ErrorLevel, "failed to collect metrics", nil) ent := log.Entry(loglvl.ErrorLevel, "failed to collect metrics", nil)
ent.FieldAdd("monitor", name) ent.FieldAdd("monitor", name)
ent.FieldAdd("metric", val.Name()) ent.FieldAdd("metric", val.Name())
ent.ErrorAdd(true, e) ent.ErrorAdd(true, e)
@@ -489,7 +488,7 @@ func (o *pool) collectMetricSLis(ctx context.Context, m libmet.Metric) {
} }
if e := m.SetGaugeValue([]string{monitorMeans}, mns); e != nil { if e := m.SetGaugeValue([]string{monitorMeans}, mns); e != nil {
ent := log.Entry(liblog.ErrorLevel, "failed to collect metrics", nil) ent := log.Entry(loglvl.ErrorLevel, "failed to collect metrics", nil)
ent.FieldAdd("monitor", monitorMeans) ent.FieldAdd("monitor", monitorMeans)
ent.FieldAdd("metric", metricSLis) ent.FieldAdd("metric", metricSLis)
ent.ErrorAdd(true, e) ent.ErrorAdd(true, e)
@@ -497,7 +496,7 @@ func (o *pool) collectMetricSLis(ctx context.Context, m libmet.Metric) {
} }
if e := m.SetGaugeValue([]string{monitorMin}, min); e != nil { if e := m.SetGaugeValue([]string{monitorMin}, min); e != nil {
ent := log.Entry(liblog.ErrorLevel, "failed to collect metrics", nil) ent := log.Entry(loglvl.ErrorLevel, "failed to collect metrics", nil)
ent.FieldAdd("monitor", monitorMin) ent.FieldAdd("monitor", monitorMin)
ent.FieldAdd("metric", metricSLis) ent.FieldAdd("metric", metricSLis)
ent.ErrorAdd(true, e) ent.ErrorAdd(true, e)
@@ -505,7 +504,7 @@ func (o *pool) collectMetricSLis(ctx context.Context, m libmet.Metric) {
} }
if e := m.SetGaugeValue([]string{monitorMax}, max); e != nil { if e := m.SetGaugeValue([]string{monitorMax}, max); e != nil {
ent := log.Entry(liblog.ErrorLevel, "failed to collect metrics", nil) ent := log.Entry(loglvl.ErrorLevel, "failed to collect metrics", nil)
ent.FieldAdd("monitor", monitorMax) ent.FieldAdd("monitor", monitorMax)
ent.FieldAdd("metric", metricSLis) ent.FieldAdd("metric", metricSLis)
ent.ErrorAdd(true, e) ent.ErrorAdd(true, e)

View File

@@ -31,9 +31,8 @@ import (
"sync" "sync"
"time" "time"
liblog "github.com/nabbar/golib/logger"
libctx "github.com/nabbar/golib/context" libctx "github.com/nabbar/golib/context"
liblog "github.com/nabbar/golib/logger"
libprm "github.com/nabbar/golib/prometheus" libprm "github.com/nabbar/golib/prometheus"
) )
@@ -44,17 +43,31 @@ type pool struct {
p libctx.Config[string] p libctx.Config[string]
} }
func (o *pool) setDefaultLog() {
o.m.Lock()
defer o.m.Unlock()
lg := liblog.New(o.p.GetContext)
o.fl = func() liblog.Logger {
return lg
}
}
func (o *pool) getLog() liblog.Logger { func (o *pool) getLog() liblog.Logger {
o.m.RLock() o.m.RLock()
defer o.m.RUnlock() defer o.m.RUnlock()
if o.fl == nil { if o.fl != nil {
return liblog.GetDefault() if l := o.fl(); l != nil {
} else if l := o.fl(); l != nil {
return l return l
} }
}
return liblog.GetDefault() o.m.RUnlock()
o.setDefaultLog()
o.m.RLock()
return o.fl()
} }
func (o *pool) InitMetrics(prm libprm.FuncGetPrometheus, log liblog.FuncLog) error { func (o *pool) InitMetrics(prm libprm.FuncGetPrometheus, log liblog.FuncLog) error {

View File

@@ -32,13 +32,10 @@ import (
"fmt" "fmt"
"time" "time"
cptlog "github.com/nabbar/golib/logger/config"
cfgtps "github.com/nabbar/golib/config/const"
libval "github.com/go-playground/validator/v10" libval "github.com/go-playground/validator/v10"
cfgtps "github.com/nabbar/golib/config/const"
liberr "github.com/nabbar/golib/errors" liberr "github.com/nabbar/golib/errors"
liblog "github.com/nabbar/golib/logger" logcfg "github.com/nabbar/golib/logger/config"
) )
var _defaultConfig = []byte(`{ var _defaultConfig = []byte(`{
@@ -51,7 +48,7 @@ var _defaultConfig = []byte(`{
"fall-count-warn": "", "fall-count-warn": "",
"rise-count-ko": "", "rise-count-ko": "",
"rise-count-warn": "", "rise-count-warn": "",
"logger": ` + string(cptlog.DefaultConfig(cfgtps.JSONIndent+cfgtps.JSONIndent)) + ` "logger": ` + string(logcfg.DefaultConfig(cfgtps.JSONIndent+cfgtps.JSONIndent)) + `
}`) }`)
func SetDefaultConfig(cfg []byte) { func SetDefaultConfig(cfg []byte) {
@@ -96,7 +93,7 @@ type Config struct {
RiseCountWarn uint8 `json:"rise-count-warn" yaml:"rise-count-warn" toml:"rise-count-warn" mapstructure:"rise-count-warn"` RiseCountWarn uint8 `json:"rise-count-warn" yaml:"rise-count-warn" toml:"rise-count-warn" mapstructure:"rise-count-warn"`
// Logger define the logger options for current monitor log // Logger define the logger options for current monitor log
Logger liblog.Options `json:"logger" yaml:"logger" toml:"logger" mapstructure:"logger"` Logger logcfg.Options `json:"logger" yaml:"logger" toml:"logger" mapstructure:"logger"`
} }
func (o Config) Validate() liberr.Error { func (o Config) Validate() liberr.Error {

View File

@@ -36,13 +36,13 @@ import (
"strings" "strings"
"time" "time"
moncfg "github.com/nabbar/golib/monitor/types"
libval "github.com/go-playground/validator/v10" libval "github.com/go-playground/validator/v10"
libtls "github.com/nabbar/golib/certificates" libtls "github.com/nabbar/golib/certificates"
liberr "github.com/nabbar/golib/errors" liberr "github.com/nabbar/golib/errors"
libiot "github.com/nabbar/golib/ioutils" libiot "github.com/nabbar/golib/ioutils"
liblog "github.com/nabbar/golib/logger" liblog "github.com/nabbar/golib/logger"
loglvl "github.com/nabbar/golib/logger/level"
moncfg "github.com/nabbar/golib/monitor/types"
natjwt "github.com/nats-io/jwt/v2" natjwt "github.com/nats-io/jwt/v2"
natsrv "github.com/nats-io/nats-server/v2/server" natsrv "github.com/nats-io/nats-server/v2/server"
) )
@@ -128,7 +128,7 @@ func (c Config) LogConfigJson() liberr.Error {
return nil return nil
} }
func (c Config) NatsOption(defaultTls libtls.TLSConfig) (*natsrv.Options, liberr.Error) { func (c Config) NatsOption(defaultTls libtls.TLSConfig, log liblog.Logger) (*natsrv.Options, liberr.Error) {
cfg := &natsrv.Options{ cfg := &natsrv.Options{
CheckConfig: false, CheckConfig: false,
} }
@@ -137,7 +137,7 @@ func (c Config) NatsOption(defaultTls libtls.TLSConfig) (*natsrv.Options, liberr
return nil, e return nil, e
} }
if e := c.Logs.makeOpt(cfg); e != nil { if e := c.Logs.makeOpt(log, cfg); e != nil {
return nil, e return nil, e
} }
@@ -472,7 +472,7 @@ func (c ConfigPermissionResponse) makeOpt() *natsrv.ResponsePermission {
return res return res
} }
func (c ConfigLogger) makeOpt(cfg *natsrv.Options) liberr.Error { func (c ConfigLogger) makeOpt(log liblog.Logger, cfg *natsrv.Options) liberr.Error {
if cfg == nil { if cfg == nil {
return ErrorParamsInvalid.Error(nil) return ErrorParamsInvalid.Error(nil)
} }
@@ -521,19 +521,14 @@ func (c ConfigLogger) makeOpt(cfg *natsrv.Options) liberr.Error {
cfg.ReconnectErrorReports = c.ReconnectErrorReports cfg.ReconnectErrorReports = c.ReconnectErrorReports
} }
if liblog.IsTimeStamp() {
cfg.Logtime = true cfg.Logtime = true
}
if liblog.IsFileTrace() {
cfg.Trace = true cfg.Trace = true
}
switch liblog.GetCurrentLevel() { switch log.GetLevel() {
case liblog.DebugLevel: case loglvl.DebugLevel:
cfg.Debug = true cfg.Debug = true
cfg.NoLog = false cfg.NoLog = false
case liblog.NilLevel: case loglvl.NilLevel:
cfg.Debug = false cfg.Debug = false
cfg.NoLog = true cfg.NoLog = true
default: default:

Some files were not shown because too many files have changed in this diff Show More