mirror of
https://github.com/nabbar/golib.git
synced 2025-10-26 01:00:23 +08:00
Fix logger :
- issue #106 - fix bug with color linux / win - fix bug with color between std, file and syslog
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
208
logger/sys_priority.go
Normal 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
164
logger/sys_syslog.go
Normal 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
196
logger/sys_winlog.go
Normal 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)
|
||||
}
|
||||
202
test/test-httpserver-syslog/main.go
Normal file
202
test/test-httpserver-syslog/main.go
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user