Fix logger :

- issue #106
- fix bug with color linux / win
- fix bug with color between std, file and syslog
This commit is contained in:
Nicolas JUHEL
2021-06-07 13:53:15 +02:00
parent c4fe18dad5
commit 00a825bea5
9 changed files with 893 additions and 43 deletions

View File

@@ -44,13 +44,14 @@ type HookFile interface {
type _HookFile struct {
f *os.File
r logrus.Formatter
l []logrus.Level
s bool
d bool
t bool
}
func NewHookFile(opt OptionsFile) (HookFile, error) {
func NewHookFile(opt OptionsFile, format logrus.Formatter) (HookFile, error) {
if opt.Filepath == "" {
return nil, fmt.Errorf("missing file path")
}
@@ -92,6 +93,7 @@ func NewHookFile(opt OptionsFile) (HookFile, error) {
return &_HookFile{
f: hdl,
r: format,
l: LVLs,
s: opt.DisableStack,
d: opt.DisableTimestamp,
@@ -125,7 +127,7 @@ func (o *_HookFile) Fire(entry *logrus.Entry) error {
ent.Data = o.filterKey(ent.Data, FieldLine)
}
if p, err := ent.Bytes(); err != nil {
if p, err := o.r.Format(ent); err != nil {
return err
} else if _, err = o.Write(p); err != nil {
return err

View File

@@ -30,10 +30,20 @@ package logger
import (
"fmt"
"io"
"os"
"github.com/mattn/go-colorable"
"github.com/sirupsen/logrus"
)
type StdWriter uint8
const (
StdOut StdWriter = iota
StdErr
)
type HookStandard interface {
logrus.Hook
io.WriteCloser
@@ -48,11 +58,29 @@ type _HookStd struct {
t bool // Disable Trace
}
func NewHookStandard(opt Options, w io.Writer, lvls []logrus.Level) HookFile {
func NewHookStandard(opt Options, s StdWriter, lvls []logrus.Level) HookFile {
if len(lvls) < 1 {
lvls = logrus.AllLevels
}
var w io.Writer
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{
w: w,
l: lvls,

View File

@@ -30,7 +30,6 @@ package logger
import (
"fmt"
"io"
"log/syslog"
"github.com/sirupsen/logrus"
)
@@ -41,18 +40,32 @@ type HookSyslog interface {
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 {
w *syslog.Writer
w syslogWrapper
f logrus.Formatter
l []logrus.Level
s bool
d bool
t bool
}
func NewHookSyslog(opt OptionsSyslog) (HookSyslog, error) {
func NewHookSyslog(opt OptionsSyslog, format logrus.Formatter) (HookSyslog, error) {
var (
LVLs = make([]logrus.Level, 0)
sys *syslog.Writer
sys syslogWrapper
err error
)
@@ -64,12 +77,13 @@ func NewHookSyslog(opt OptionsSyslog) (HookSyslog, error) {
LVLs = logrus.AllLevels
}
if sys, err = syslog.Dial(opt.Network.String(), opt.Host, opt.Priority, opt.Tag); err != nil {
if sys, err = newSyslog(MakeNetwork(opt.Network), opt.Host, opt.Tag, MakeSeverity(opt.Severity), MakeFacility(opt.Facility)); err != nil {
return nil, err
}
return &_HookSyslog{
w: sys,
f: format,
l: LVLs,
s: opt.DisableStack,
d: opt.DisableTimestamp,
@@ -103,13 +117,28 @@ func (o *_HookSyslog) Fire(entry *logrus.Entry) error {
ent.Data = o.filterKey(ent.Data, FieldLine)
}
if p, err := ent.Bytes(); err != nil {
return err
} else if _, err = o.Write(p); err != nil {
if p, err := o.f.Format(ent); err != nil {
return err
} else {
switch ent.Level {
case logrus.PanicLevel:
_, err = o.w.Panic(p)
case logrus.FatalLevel:
_, err = o.w.Fatal(p)
case logrus.ErrorLevel:
_, err = o.w.Error(p)
case logrus.WarnLevel:
_, err = o.w.Warning(p)
case logrus.InfoLevel:
_, err = o.w.Info(p)
case logrus.DebugLevel:
_, err = o.w.Debug(p)
default:
return nil
}
return nil
return err
}
}
func (o *_HookSyslog) Write(p []byte) (n int, err error) {

View File

@@ -32,7 +32,6 @@ import (
"context"
"io"
"io/ioutil"
"os"
"path"
"reflect"
"runtime"
@@ -42,8 +41,6 @@ import (
"sync/atomic"
"time"
"github.com/mattn/go-colorable"
"github.com/sirupsen/logrus"
)
@@ -66,14 +63,10 @@ type logger struct {
c *atomic.Value
}
func (l *logger) defaultFormatter(opt *Options) *logrus.TextFormatter {
if opt == nil {
opt = &Options{}
}
return &logrus.TextFormatter{
ForceColors: true,
DisableColors: opt.DisableColor,
func defaultFormatter() logrus.TextFormatter {
return logrus.TextFormatter{
ForceColors: false,
DisableColors: false,
ForceQuote: false,
DisableQuote: false,
EnvironmentOverrideColors: false,
@@ -90,6 +83,29 @@ func (l *logger) defaultFormatter(opt *Options) *logrus.TextFormatter {
}
}
func (l *logger) defaultFormatter(opt *Options) logrus.Formatter {
f := defaultFormatter()
if opt != nil && opt.DisableColor {
f.ForceColors = false
f.EnvironmentOverrideColors = false
f.DisableColors = true
} else {
f.ForceColors = true
f.DisableColors = false
}
return &f
}
func (l *logger) defaultFormatterNoColor() logrus.Formatter {
f := defaultFormatter()
f.ForceColors = false
f.EnvironmentOverrideColors = false
f.DisableColors = true
return &f
}
func (l *logger) closeAdd(clo io.Closer) {
lst := append(l.closeGet(), clo)
@@ -259,23 +275,13 @@ func (l *logger) setOptionsMutex(ctx context.Context, opt *Options) error {
obj.SetOutput(ioutil.Discard) // Send all logs to nowhere by default
if !opt.DisableStandard {
var (
o io.Writer = os.Stdout
e io.Writer = os.Stderr
)
if opt.DisableColor {
o = colorable.NewColorableStdout()
e = colorable.NewColorableStderr()
}
obj.AddHook(NewHookStandard(*opt, o, []logrus.Level{
obj.AddHook(NewHookStandard(*opt, StdOut, []logrus.Level{
logrus.InfoLevel,
logrus.DebugLevel,
logrus.TraceLevel,
}))
obj.AddHook(NewHookStandard(*opt, e, []logrus.Level{
obj.AddHook(NewHookStandard(*opt, StdErr, []logrus.Level{
logrus.PanicLevel,
logrus.FatalLevel,
logrus.ErrorLevel,
@@ -285,7 +291,7 @@ func (l *logger) setOptionsMutex(ctx context.Context, opt *Options) error {
if len(opt.LogFile) > 0 {
for _, fopt := range opt.LogFile {
if hook, err := NewHookFile(fopt); err != nil {
if hook, err := NewHookFile(fopt, l.defaultFormatterNoColor()); err != nil {
return err
} else {
l.closeAdd(hook)
@@ -296,7 +302,7 @@ func (l *logger) setOptionsMutex(ctx context.Context, opt *Options) error {
if len(opt.LogSyslog) > 0 {
for _, lopt := range opt.LogSyslog {
if hook, err := NewHookSyslog(lopt); err != nil {
if hook, err := NewHookSyslog(lopt, l.defaultFormatterNoColor()); err != nil {
return err
} else {
l.closeAdd(hook)

View File

@@ -28,8 +28,8 @@
package logger
import (
"log/syslog"
"os"
"strings"
)
type FuncCustomConfig func(log Logger)
@@ -53,6 +53,17 @@ func (n NetworkType) String() string {
}
}
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
@@ -86,17 +97,21 @@ type OptionsSyslog struct {
// LogLevel define the allowed level of log for this syslog.
LogLevel []string
// Network define the network used to connect to this syslog.
Network NetworkType
// Network define the network used to connect to this syslog (tcp, udp, or any other to a local connection).
Network string
// Host define the remote syslog to use.
// If Host and Network are empty, local syslog will be used.
Host string
// Priority define the priority used for this syslog.
Priority syslog.Priority
// Severity define the severity syslog to be used.
Severity string
// Tag define the syslog tag used for log message.
// Facility define the facility syslog to be used.
Facility string
// 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
// DisableStack allow to disable the goroutine id before each message.

208
logger/sys_priority.go Normal file
View File

@@ -0,0 +1,208 @@
/***********************************************************************************************************************
*
* 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 "strings"
type SyslogSeverity uint8
const (
SyslogSeverityEmerg SyslogSeverity = iota + 1
SyslogSeverityAlert
SyslogSeverityCrit
SyslogSeverityErr
SyslogSeverityWarning
SyslogSeverityNotice
SyslogSeverityInfo
SyslogSeverityDebug
)
func (s SyslogSeverity) String() string {
switch s {
case SyslogSeverityEmerg:
return "EMERG"
case SyslogSeverityAlert:
return "ALERT"
case SyslogSeverityCrit:
return "CRIT"
case SyslogSeverityErr:
return "ERR"
case SyslogSeverityWarning:
return "WARNING"
case SyslogSeverityNotice:
return "NOTICE"
case SyslogSeverityInfo:
return "INFO"
case SyslogSeverityDebug:
return "DEBUG"
}
return ""
}
func MakeSeverity(severity string) SyslogSeverity {
switch strings.ToUpper(severity) {
case SyslogSeverityEmerg.String():
return SyslogSeverityEmerg
case SyslogSeverityAlert.String():
return SyslogSeverityAlert
case SyslogSeverityCrit.String():
return SyslogSeverityCrit
case SyslogSeverityErr.String():
return SyslogSeverityErr
case SyslogSeverityWarning.String():
return SyslogSeverityWarning
case SyslogSeverityNotice.String():
return SyslogSeverityNotice
case SyslogSeverityInfo.String():
return SyslogSeverityInfo
case SyslogSeverityDebug.String():
return SyslogSeverityDebug
}
return 0
}
type SyslogFacility uint8
const (
SyslogFacilityKern SyslogFacility = iota + 1
SyslogFacilityUser
SyslogFacilityMail
SyslogFacilityDaemon
SyslogFacilityAuth
SyslogFacilitySyslog
SyslogFacilityLpr
SyslogFacilityNews
SyslogFacilityUucp
SyslogFacilityCron
SyslogFacilityAuthPriv
SyslogFacilityFTP
SyslogFacilityLocal0
SyslogFacilityLocal1
SyslogFacilityLocal2
SyslogFacilityLocal3
SyslogFacilityLocal4
SyslogFacilityLocal5
SyslogFacilityLocal6
SyslogFacilityLocal7
)
func (s SyslogFacility) String() string {
switch s {
case SyslogFacilityKern:
return "KERN"
case SyslogFacilityUser:
return "USER"
case SyslogFacilityMail:
return "MAIL"
case SyslogFacilityDaemon:
return "DAEMON"
case SyslogFacilityAuth:
return "AUTH"
case SyslogFacilitySyslog:
return "SYSLOG"
case SyslogFacilityLpr:
return "LPR"
case SyslogFacilityNews:
return "NEWS"
case SyslogFacilityUucp:
return "UUCP"
case SyslogFacilityCron:
return "CRON"
case SyslogFacilityAuthPriv:
return "AUTHPRIV"
case SyslogFacilityFTP:
return "FTP"
case SyslogFacilityLocal0:
return "LOCAL0"
case SyslogFacilityLocal1:
return "LOCAL1"
case SyslogFacilityLocal2:
return "LOCAL2"
case SyslogFacilityLocal3:
return "LOCAL3"
case SyslogFacilityLocal4:
return "LOCAL4"
case SyslogFacilityLocal5:
return "LOCAL5"
case SyslogFacilityLocal6:
return "LOCAL6"
case SyslogFacilityLocal7:
return "LOCAL7"
}
return ""
}
func MakeFacility(facility string) SyslogFacility {
switch strings.ToUpper(facility) {
case SyslogFacilityKern.String():
return SyslogFacilityKern
case SyslogFacilityUser.String():
return SyslogFacilityUser
case SyslogFacilityMail.String():
return SyslogFacilityMail
case SyslogFacilityDaemon.String():
return SyslogFacilityDaemon
case SyslogFacilityAuth.String():
return SyslogFacilityAuth
case SyslogFacilitySyslog.String():
return SyslogFacilitySyslog
case SyslogFacilityLpr.String():
return SyslogFacilityLpr
case SyslogFacilityNews.String():
return SyslogFacilityNews
case SyslogFacilityUucp.String():
return SyslogFacilityUucp
case SyslogFacilityCron.String():
return SyslogFacilityCron
case SyslogFacilityAuthPriv.String():
return SyslogFacilityAuthPriv
case SyslogFacilityFTP.String():
return SyslogFacilityFTP
case SyslogFacilityLocal0.String():
return SyslogFacilityLocal0
case SyslogFacilityLocal1.String():
return SyslogFacilityLocal1
case SyslogFacilityLocal2.String():
return SyslogFacilityLocal2
case SyslogFacilityLocal3.String():
return SyslogFacilityLocal3
case SyslogFacilityLocal4.String():
return SyslogFacilityLocal4
case SyslogFacilityLocal5.String():
return SyslogFacilityLocal5
case SyslogFacilityLocal6.String():
return SyslogFacilityLocal6
case SyslogFacilityLocal7.String():
return SyslogFacilityLocal7
}
return 0
}

164
logger/sys_syslog.go Normal file
View File

@@ -0,0 +1,164 @@
// +build !windows
/***********************************************************************************************************************
*
* 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"
"log/syslog"
)
func makePriority(severity SyslogSeverity, facility SyslogFacility) syslog.Priority {
return makePriorotySeverity(severity) | makePriorotyFacility(facility)
}
func makePriorotySeverity(sev SyslogSeverity) syslog.Priority {
switch sev {
case SyslogSeverityEmerg:
return syslog.LOG_EMERG
case SyslogSeverityAlert:
return syslog.LOG_ALERT
case SyslogSeverityCrit:
return syslog.LOG_CRIT
case SyslogSeverityErr:
return syslog.LOG_ERR
case SyslogSeverityWarning:
return syslog.LOG_WARNING
case SyslogSeverityNotice:
return syslog.LOG_NOTICE
case SyslogSeverityInfo:
return syslog.LOG_INFO
case SyslogSeverityDebug:
return syslog.LOG_DEBUG
}
return 0
}
func makePriorotyFacility(fac SyslogFacility) syslog.Priority {
switch fac {
case SyslogFacilityKern:
return syslog.LOG_KERN
case SyslogFacilityUser:
return syslog.LOG_USER
case SyslogFacilityMail:
return syslog.LOG_MAIL
case SyslogFacilityDaemon:
return syslog.LOG_DAEMON
case SyslogFacilityAuth:
return syslog.LOG_AUTH
case SyslogFacilitySyslog:
return syslog.LOG_SYSLOG
case SyslogFacilityLpr:
return syslog.LOG_LPR
case SyslogFacilityNews:
return syslog.LOG_NEWS
case SyslogFacilityUucp:
return syslog.LOG_UUCP
case SyslogFacilityCron:
return syslog.LOG_CRON
case SyslogFacilityAuthPriv:
return syslog.LOG_AUTHPRIV
case SyslogFacilityFTP:
return syslog.LOG_FTP
case SyslogFacilityLocal0:
return syslog.LOG_LOCAL0
case SyslogFacilityLocal1:
return syslog.LOG_LOCAL1
case SyslogFacilityLocal2:
return syslog.LOG_LOCAL2
case SyslogFacilityLocal3:
return syslog.LOG_LOCAL3
case SyslogFacilityLocal4:
return syslog.LOG_LOCAL4
case SyslogFacilityLocal5:
return syslog.LOG_LOCAL5
case SyslogFacilityLocal6:
return syslog.LOG_LOCAL6
case SyslogFacilityLocal7:
return syslog.LOG_LOCAL7
}
return 0
}
type _Syslog struct {
w *syslog.Writer
}
func newSyslog(net NetworkType, host, tag string, severity SyslogSeverity, facility SyslogFacility) (syslogWrapper, error) {
var (
sys *syslog.Writer
err error
)
if sys, err = syslog.Dial(net.String(), host, makePriority(severity, facility), tag); err != nil {
return nil, err
}
return &_Syslog{
w: sys,
}, nil
}
func (o *_Syslog) Write(p []byte) (n int, err error) {
if o.w == nil {
return 0, fmt.Errorf("logrus.hooksyslog: connection not setup")
}
return o.w.Write(p)
}
func (o *_Syslog) Close() error {
err := o.w.Close()
o.w = nil
return err
}
func (o *_Syslog) Panic(p []byte) (n int, err error) {
return o.Write(p)
}
func (o *_Syslog) Fatal(p []byte) (n int, err error) {
return o.Write(p)
}
func (o *_Syslog) Error(p []byte) (n int, err error) {
return o.Write(p)
}
func (o *_Syslog) Warning(p []byte) (n int, err error) {
return o.Write(p)
}
func (o *_Syslog) Info(p []byte) (n int, err error) {
return o.Write(p)
}
func (o *_Syslog) Debug(p []byte) (n int, err error) {
return o.Write(p)
}

196
logger/sys_winlog.go Normal file
View File

@@ -0,0 +1,196 @@
// +build windows
/***********************************************************************************************************************
*
* MIT License
*
* Copyright (c) 2021 Nicolas JUHEL
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*
**********************************************************************************************************************/
package logger
import (
"sync/atomic"
"time"
"golang.org/x/sys/windows/svc/eventlog"
)
var _registred *atomic.Value
func init() {
// register a function to clean event on stopping application to clean Windows Registry Database
go func() {
// clean all registered event
defer func() {
if _registred == nil {
_registred = new(atomic.Value)
}
var (
i interface{}
o []string
ok bool
)
if i = _registred.Load(); i == nil {
i = make([]string, 0)
}
if o, ok = i.([]string); !ok {
o = make([]string, 0)
}
_registred.Store(make([]string, 0))
for _, s := range o {
if err := eventlog.Remove(s); err != nil {
println(err)
}
}
}()
for {
// only wait the stopping process
time.Sleep(200 * time.Millisecond)
}
}()
}
func windowsRegister(source string) error {
if _registred == nil {
_registred = new(atomic.Value)
}
var (
i interface{}
o []string
ok bool
)
if i = _registred.Load(); i == nil {
i = make([]string, 0)
}
if o, ok = i.([]string); !ok {
o = make([]string, 0)
}
for _, s := range o {
if s == source {
return nil
}
}
if err := eventlog.InstallAsEventCreate(source, eventlog.Error|eventlog.Warning|eventlog.Info); err != nil {
return err
}
o = append(o, source)
_registred.Store(o)
return nil
}
const (
_ErrorId uint32 = iota + 1
_WarningId
_InfoId
)
type _WinLog struct {
r bool
s string
w *eventlog.Log
}
func newSyslog(net NetworkType, host, tag string, severity SyslogSeverity, facility SyslogFacility) (syslogWrapper, error) {
var (
sys *eventlog.Log
err error
)
if net != NetworkEmpty {
sys, err = eventlog.OpenRemote(host, tag)
} else {
if err = windowsRegister(tag); err != nil {
println(err.Error())
}
sys, err = eventlog.Open(tag)
}
if err != nil {
return nil, err
}
return &_WinLog{
r: net != NetworkEmpty,
s: tag,
w: sys,
}, nil
}
func (o *_WinLog) Close() error {
var err error
err = o.w.Close()
o.w = nil
if err != nil {
return err
}
return nil
}
func (o *_WinLog) Write(p []byte) (n int, err error) {
return o.Info(p)
}
func (o *_WinLog) Panic(p []byte) (n int, err error) {
return o.Error(p)
}
func (o *_WinLog) Fatal(p []byte) (n int, err error) {
return o.Error(p)
}
func (o *_WinLog) Error(p []byte) (n int, err error) {
err = o.w.Error(_ErrorId*100, string(p))
return len(p), err
}
func (o *_WinLog) Warning(p []byte) (n int, err error) {
err = o.w.Warning(_WarningId*100, string(p))
return len(p), err
}
func (o *_WinLog) Info(p []byte) (n int, err error) {
err = o.w.Info(_InfoId*100, string(p))
return len(p), err
}
func (o *_WinLog) Debug(p []byte) (n int, err error) {
return o.Info(p)
}

View File

@@ -0,0 +1,202 @@
/***********************************************************************************************************************
*
* 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 main
import (
"context"
"fmt"
"net/http"
"time"
liblog "github.com/nabbar/golib/logger"
libtls "github.com/nabbar/golib/certificates"
liberr "github.com/nabbar/golib/errors"
libsrv "github.com/nabbar/golib/httpserver"
)
var tlsConfigSrv = libtls.Config{
InheritDefault: true,
VersionMin: "1.2",
}
var cfgSrv01 = libsrv.ServerConfig{
Name: "test-01",
Listen: "0.0.0.0:61001",
Expose: "0.0.0.0:61000",
TLSMandatory: false,
TLS: tlsConfigSrv,
}
var cfgSrv02 = libsrv.ServerConfig{
Name: "test-02",
Listen: "0.0.0.0:61002",
Expose: "0.0.0.0:61000",
TLSMandatory: false,
TLS: tlsConfigSrv,
}
var cfgSrv03 = libsrv.ServerConfig{
Name: "test-03",
Listen: "0.0.0.0:61003",
Expose: "0.0.0.0:61000",
TLSMandatory: true,
TLS: tlsConfigSrv,
}
var (
cfgPool libsrv.PoolServerConfig
ctx context.Context
cnl context.CancelFunc
log = liblog.New()
)
func init() {
liberr.SetModeReturnError(liberr.ErrorReturnCodeErrorTraceFull)
ctx, cnl = context.WithCancel(context.Background())
log.SetLevel(liblog.DebugLevel)
if err := log.SetOptions(ctx, &liblog.Options{
DisableStandard: false,
DisableStack: false,
DisableTimestamp: false,
EnableTrace: true,
TraceFilter: "",
DisableColor: false,
LogSyslog: []liblog.OptionsSyslog{
{
LogLevel: nil,
Network: "",
Host: "",
Severity: "",
Facility: "USER",
Tag: "test-http-server",
DisableStack: false,
DisableTimestamp: false,
EnableTrace: true,
},
},
}); err != nil {
panic(err)
}
cfgPool = libsrv.PoolServerConfig{cfgSrv01, cfgSrv02, cfgSrv03}
cfgPool.MapUpdate(func(cfg libsrv.ServerConfig) libsrv.ServerConfig {
cfg.SetParentContext(func() context.Context {
return ctx
})
return cfg
})
}
func main() {
var (
pool libsrv.PoolServer
lerr liberr.Error
)
if pool, lerr = cfgPool.PoolServer(); lerr != nil {
panic(lerr)
} else {
pool.SetLogger(getLogger)
}
mux := http.NewServeMux()
mux.HandleFunc("/hello", hello)
mux.HandleFunc("/headers", headers)
if lerr = pool.Listen(mux); lerr != nil {
panic(lerr)
}
defer func() {
pool.Shutdown()
cnl()
}()
go pool.WaitNotify(ctx, cnl)
go func() {
l := getLogger()
for {
time.Sleep(5 * time.Second)
if ctx.Err() != nil {
return
}
pool.MapRun(func(srv libsrv.Server) {
n, v, _ := srv.StatusInfo()
e := l.Entry(liblog.ErrorLevel, "status message")
e = e.FieldAdd("server_name", n).FieldAdd("server_release", v)
e.ErrorAdd(true, srv.StatusHealth())
e.Check(liblog.InfoLevel)
})
}
}()
var i = 0
for {
l := getLogger()
time.Sleep(5 * time.Second)
if ctx.Err() != nil {
return
}
i++
if i%3 == 0 {
for s := range pool.List(libsrv.FieldBind, libsrv.FieldName, "", ".*") {
l.Entry(liblog.InfoLevel, "Restarting server...").FieldAdd("server_name", s).Log()
}
pool.Restart()
i = 0
}
}
}
func hello(w http.ResponseWriter, req *http.Request) {
_, _ = fmt.Fprintf(w, "hello\n")
}
func headers(w http.ResponseWriter, req *http.Request) {
for name, headers := range req.Header {
for _, h := range headers {
_, _ = fmt.Fprintf(w, "%v: %v\n", name, h)
}
}
}
func getLogger() liblog.Logger {
l, _ := log.Clone(ctx)
return l
}