Compare commits
14 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
dc2ed32352 | ||
![]() |
e734e847c4 | ||
![]() |
2203de4e32 | ||
![]() |
a0c6df14aa | ||
![]() |
fd720f2b34 | ||
![]() |
3c543a05e7 | ||
![]() |
e5191383a7 | ||
![]() |
ae49f42c0c | ||
![]() |
b87934e8a9 | ||
70d6c2cbb3 | |||
a445a51c0d | |||
a2a849600b | |||
94145fb4c7 | |||
81a2d308f0 |
@ -2,8 +2,8 @@ package bitmask
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
"math/bits"
|
"math/bits"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ func (m *MaskBit) AddFlag(flag MaskBit) {
|
|||||||
// ClearFlag removes MaskBit flag from m.
|
// ClearFlag removes MaskBit flag from m.
|
||||||
func (m *MaskBit) ClearFlag(flag MaskBit) {
|
func (m *MaskBit) ClearFlag(flag MaskBit) {
|
||||||
|
|
||||||
*m &= flag
|
*m &^= flag
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -109,6 +109,15 @@ func (m *MaskBit) Bytes(trim bool) (b []byte) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copy returns a pointer to a (new) copy of a MaskBit.
|
||||||
|
func (m *MaskBit) Copy() (newM *MaskBit) {
|
||||||
|
|
||||||
|
newM = new(MaskBit)
|
||||||
|
*newM = *m
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Value returns the current raw uint value of a MaskBit.
|
// Value returns the current raw uint value of a MaskBit.
|
||||||
func (m *MaskBit) Value() (v uint) {
|
func (m *MaskBit) Value() (v uint) {
|
||||||
|
|
||||||
|
11
logging/TODO
11
logging/TODO
@ -1,11 +1,22 @@
|
|||||||
|
- macOS support beyond the legacy NIX stuff. it apparently uses something called "ULS", "Unified Logging System".
|
||||||
|
-- https://developer.apple.com/documentation/os/logging
|
||||||
|
-- https://developer.apple.com/documentation/os/generating-log-messages-from-your-code
|
||||||
|
-- no native Go support (yet)?
|
||||||
|
--- https://developer.apple.com/forums/thread/773369
|
||||||
|
|
||||||
- Implement code line/func/etc. (only for debug?):
|
- Implement code line/func/etc. (only for debug?):
|
||||||
https://stackoverflow.com/a/24809646
|
https://stackoverflow.com/a/24809646
|
||||||
https://golang.org/pkg/runtime/#Caller
|
https://golang.org/pkg/runtime/#Caller
|
||||||
-- log.LlongFile and log.Lshortfile flags don't currently work properly for StdLogger/FileLogger; they refer to the file in logging package rather than the caller.
|
-- log.LlongFile and log.Lshortfile flags don't currently work properly for StdLogger/FileLogger; they refer to the file in logging package rather than the caller.
|
||||||
|
|
||||||
|
- StdLogger2; where stdout and stderr are both logged to depending on severity level.
|
||||||
|
- make configurable via OR bitmask
|
||||||
|
|
||||||
- Suport remote loggers? (eventlog, syslog, systemd)
|
- Suport remote loggers? (eventlog, syslog, systemd)
|
||||||
|
|
||||||
- JSON logger? YAML logger? XML logger?
|
- JSON logger? YAML logger? XML logger?
|
||||||
|
|
||||||
- DOCS.
|
- DOCS.
|
||||||
-- Done, but flesh out.
|
-- Done, but flesh out.
|
||||||
|
|
||||||
|
- Implement io.Writer interfaces
|
||||||
|
@ -12,3 +12,16 @@ const (
|
|||||||
// appendFlags are the flags used for testing the file (and opening/writing).
|
// appendFlags are the flags used for testing the file (and opening/writing).
|
||||||
appendFlags int = os.O_APPEND | os.O_CREATE | os.O_WRONLY
|
appendFlags int = os.O_APPEND | os.O_CREATE | os.O_WRONLY
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const PriorityNone logPrio = 0
|
||||||
|
const (
|
||||||
|
PriorityEmergency logPrio = 1 << iota
|
||||||
|
PriorityAlert
|
||||||
|
PriorityCritical
|
||||||
|
PriorityError
|
||||||
|
PriorityWarning
|
||||||
|
PriorityNotice
|
||||||
|
PriorityInformational
|
||||||
|
PriorityDebug
|
||||||
|
)
|
||||||
|
const PriorityAll logPrio = PriorityEmergency | PriorityAlert | PriorityCritical | PriorityError | PriorityWarning | PriorityNotice | PriorityInformational | PriorityDebug
|
||||||
|
9
logging/consts_darwin.go
Normal file
9
logging/consts_darwin.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package logging
|
||||||
|
|
||||||
|
var (
|
||||||
|
// defLogPaths indicates default log paths.
|
||||||
|
defLogPaths = []string{
|
||||||
|
"/var/log/golang/program.log",
|
||||||
|
"~/Library/Logs/Golang/program.log",
|
||||||
|
}
|
||||||
|
)
|
@ -1,32 +1,5 @@
|
|||||||
package logging
|
package logging
|
||||||
|
|
||||||
import (
|
|
||||||
`log/syslog`
|
|
||||||
|
|
||||||
`r00t2.io/goutils/bitmask`
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// devlog is the path to the syslog char device.
|
|
||||||
devlog string = "/dev/log"
|
|
||||||
// syslogFacility is the facility to use; it's a little like a context or scope if you think of it in those terms.
|
|
||||||
syslogFacility syslog.Priority = syslog.LOG_USER
|
|
||||||
)
|
|
||||||
|
|
||||||
// Flags for logger configuration. These are used internally.
|
|
||||||
const (
|
|
||||||
// LogUndefined indicates an undefined Logger type.
|
|
||||||
LogUndefined bitmask.MaskBit = 1 << iota
|
|
||||||
// LogJournald flags a SystemDLogger Logger type.
|
|
||||||
LogJournald
|
|
||||||
// LogSyslog flags a SyslogLogger Logger type.
|
|
||||||
LogSyslog
|
|
||||||
// LogFile flags a FileLogger Logger type.
|
|
||||||
LogFile
|
|
||||||
// LogStdout flags a StdLogger Logger type.
|
|
||||||
LogStdout
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// defLogPaths indicates default log paths.
|
// defLogPaths indicates default log paths.
|
||||||
defLogPaths = []string{
|
defLogPaths = []string{
|
||||||
|
34
logging/consts_nix.go
Normal file
34
logging/consts_nix.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
//go:build !(windows || plan9 || wasip1 || js || ios)
|
||||||
|
// +build !windows,!plan9,!wasip1,!js,!ios
|
||||||
|
|
||||||
|
// I mean maybe it works for plan9 and ios, I don't know.
|
||||||
|
|
||||||
|
package logging
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log/syslog"
|
||||||
|
|
||||||
|
"r00t2.io/goutils/bitmask"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// devlog is the path to the syslog char device.
|
||||||
|
devlog string = "/dev/log"
|
||||||
|
// syslogFacility is the facility to use; it's a little like a context or scope if you think of it in those terms.
|
||||||
|
syslogFacility syslog.Priority = syslog.LOG_USER
|
||||||
|
)
|
||||||
|
|
||||||
|
// Flags for logger configuration. These are used internally.
|
||||||
|
|
||||||
|
// LogUndefined indicates an undefined Logger type.
|
||||||
|
const LogUndefined bitmask.MaskBit = iota
|
||||||
|
const (
|
||||||
|
// LogJournald flags a SystemDLogger Logger type.
|
||||||
|
LogJournald = 1 << iota
|
||||||
|
// LogSyslog flags a SyslogLogger Logger type.
|
||||||
|
LogSyslog
|
||||||
|
// LogFile flags a FileLogger Logger type.
|
||||||
|
LogFile
|
||||||
|
// LogStdout flags a StdLogger Logger type.
|
||||||
|
LogStdout
|
||||||
|
)
|
@ -3,18 +3,19 @@ Package logging implements and presents various loggers under a unified interfac
|
|||||||
|
|
||||||
These particular loggers (logging.Logger) available are:
|
These particular loggers (logging.Logger) available are:
|
||||||
|
|
||||||
|
NullLogger
|
||||||
StdLogger
|
StdLogger
|
||||||
FileLogger
|
FileLogger
|
||||||
SystemDLogger (Linux only)
|
SystemDLogger (Linux only)
|
||||||
SyslogLogger (Linux only)
|
SyslogLogger (Linux/macOS/other *NIX-like only)
|
||||||
WinLogger (Windows only)
|
WinLogger (Windows only)
|
||||||
|
|
||||||
There is a sixth type of logging.Logger, MultiLogger, that allows for multiple loggers to be written to with a single call.
|
There is a seventh type of logging.Logger, MultiLogger, that allows for multiple loggers to be written to with a single call.
|
||||||
|
As you may have guessed, NullLogger doesn't actually log anything but is fully "functional" as a logging.Logger.
|
||||||
|
|
||||||
Note that for some Loggers, the prefix may be modified - "literal" loggers (StdLogger and FileLogger) will append a space to the end of the prefix.
|
Note that for some Loggers, the prefix may be modified - "literal" loggers (StdLogger and FileLogger) will append a space to the end of the prefix.
|
||||||
If this is undesired (unlikely), you will need to modify (Logger).Prefix and run (Logger).Logger.SetPrefix(yourPrefixHere) for the respective logger.
|
If this is undesired (unlikely), you will need to modify (Logger).Prefix and run (Logger).Logger.SetPrefix(yourPrefixHere) for the respective logger.
|
||||||
|
|
||||||
|
|
||||||
Every logging.Logger type has the following methods that correspond to certain "levels".
|
Every logging.Logger type has the following methods that correspond to certain "levels".
|
||||||
|
|
||||||
Alert(s string, v ...interface{}) (err error)
|
Alert(s string, v ...interface{}) (err error)
|
||||||
@ -36,6 +37,7 @@ Note that in the case of a MultiLogger, err (if not nil) will be a (r00t2.io/gou
|
|||||||
logging.Logger types also have the following methods:
|
logging.Logger types also have the following methods:
|
||||||
|
|
||||||
DoDebug(d bool) (err error)
|
DoDebug(d bool) (err error)
|
||||||
|
GetDebug() (d bool)
|
||||||
SetPrefix(p string) (err error)
|
SetPrefix(p string) (err error)
|
||||||
GetPrefix() (p string, err error)
|
GetPrefix() (p string, err error)
|
||||||
Setup() (err error)
|
Setup() (err error)
|
||||||
|
@ -1,18 +1,10 @@
|
|||||||
package logging
|
package logging
|
||||||
|
|
||||||
import (
|
import (
|
||||||
`errors`
|
"errors"
|
||||||
`fmt`
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// ErrNoSysD indicates that the user attempted to add a SystemDLogger to a MultiLogger but systemd is unavailable.
|
// ErrNoSysD indicates that the user attempted to add a SystemDLogger to a MultiLogger but systemd is unavailable.
|
||||||
ErrNoSysD error = errors.New("a systemd (journald) Logger was requested but systemd is unavailable on this system")
|
ErrNoSysD error = errors.New("a systemd (journald) Logger was requested but systemd is unavailable on this system")
|
||||||
// ErrNoSyslog indicates that the user attempted to add a SyslogLogger to a MultiLogger but syslog's logger device is unavailable.
|
|
||||||
ErrNoSyslog error = errors.New("a Syslog Logger was requested but Syslog is unavailable on this system")
|
|
||||||
/*
|
|
||||||
ErrInvalidDevLog indicates that the user attempted to add a SyslogLogger to a MultiLogger but
|
|
||||||
the Syslog char device file is... not actually a char device file.
|
|
||||||
*/
|
|
||||||
ErrInvalidDevLog error = errors.New(fmt.Sprintf("a Syslog Logger was requested but %v is not a valid logger handle", devlog))
|
|
||||||
)
|
)
|
||||||
|
19
logging/errs_nix.go
Normal file
19
logging/errs_nix.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
//go:build !(windows || plan9 || wasip1 || js || ios)
|
||||||
|
// +build !windows,!plan9,!wasip1,!js,!ios
|
||||||
|
|
||||||
|
package logging
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrNoSyslog indicates that the user attempted to add a SyslogLogger to a MultiLogger but syslog's logger device is unavailable.
|
||||||
|
ErrNoSyslog error = errors.New("a Syslog Logger was requested but Syslog is unavailable on this system")
|
||||||
|
/*
|
||||||
|
ErrInvalidDevLog indicates that the user attempted to add a SyslogLogger to a MultiLogger but
|
||||||
|
the Syslog char device file is... not actually a char device file.
|
||||||
|
*/
|
||||||
|
ErrInvalidDevLog error = errors.New(fmt.Sprintf("a Syslog Logger was requested but %v is not a valid logger handle", devlog))
|
||||||
|
)
|
@ -1,12 +1,12 @@
|
|||||||
package logging
|
package logging
|
||||||
|
|
||||||
import (
|
import (
|
||||||
`errors`
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
`io/fs`
|
"io/fs"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
`strings`
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Setup sets up/configures a FileLogger and prepares it for use.
|
// Setup sets up/configures a FileLogger and prepares it for use.
|
||||||
@ -43,8 +43,8 @@ func (l *FileLogger) Shutdown() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
GetPrefix returns the prefix used by this FileLogger.
|
GetPrefix returns the prefix used by this FileLogger.
|
||||||
err will always be nil; it's there for interface-compat.
|
err will always be nil; it's there for interface-compat.
|
||||||
*/
|
*/
|
||||||
func (l *FileLogger) GetPrefix() (prefix string, err error) {
|
func (l *FileLogger) GetPrefix() (prefix string, err error) {
|
||||||
|
|
||||||
@ -54,9 +54,9 @@ func (l *FileLogger) GetPrefix() (prefix string, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
DoDebug sets the debug state of this FileLogger.
|
DoDebug sets the debug state of this FileLogger.
|
||||||
Note that this merely acts as a *safety filter* for debug messages to avoid sensitive information being written to the log.
|
Note that this merely acts as a *safety filter* for debug messages to avoid sensitive information being written to the log.
|
||||||
err will always be nil; it's there for interface-compat.
|
err will always be nil; it's there for interface-compat.
|
||||||
*/
|
*/
|
||||||
func (l *FileLogger) DoDebug(d bool) (err error) {
|
func (l *FileLogger) DoDebug(d bool) (err error) {
|
||||||
|
|
||||||
@ -65,9 +65,17 @@ func (l *FileLogger) DoDebug(d bool) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetDebug returns the debug status of this FileLogger.
|
||||||
|
func (l *FileLogger) GetDebug() (d bool) {
|
||||||
|
|
||||||
|
d = l.EnableDebug
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
SetPrefix sets the prefix for this FileLogger.
|
SetPrefix sets the prefix for this FileLogger.
|
||||||
err will always be nil; it's there for interface-compat.
|
err will always be nil; it's there for interface-compat.
|
||||||
*/
|
*/
|
||||||
func (l *FileLogger) SetPrefix(prefix string) (err error) {
|
func (l *FileLogger) SetPrefix(prefix string) (err error) {
|
||||||
|
|
||||||
@ -212,6 +220,14 @@ func (l *FileLogger) Warning(s string, v ...interface{}) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToLogger returns a stdlib log.Logger.
|
||||||
|
func (l *FileLogger) ToLogger(prio logPrio) (stdLibLog *log.Logger) {
|
||||||
|
|
||||||
|
stdLibLog = log.New(&logWriter{backend: l, prio: prio}, "", 0)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// renderWrite prepares/formats a log message to be written to this FileLogger.
|
// renderWrite prepares/formats a log message to be written to this FileLogger.
|
||||||
func (l *FileLogger) renderWrite(msg, prio string) {
|
func (l *FileLogger) renderWrite(msg, prio string) {
|
||||||
|
|
||||||
|
23
logging/funcs_logprio.go
Normal file
23
logging/funcs_logprio.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package logging
|
||||||
|
|
||||||
|
import (
|
||||||
|
`r00t2.io/goutils/bitmask`
|
||||||
|
)
|
||||||
|
|
||||||
|
// HasFlag provides a wrapper for functionality to the underlying bitmask.MaskBit.
|
||||||
|
func (l *logPrio) HasFlag(prio logPrio) (hasFlag bool) {
|
||||||
|
|
||||||
|
var m *bitmask.MaskBit
|
||||||
|
var p *bitmask.MaskBit
|
||||||
|
|
||||||
|
if l == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
m = bitmask.NewMaskBitExplicit(uint(*l))
|
||||||
|
p = bitmask.NewMaskBitExplicit(uint(prio))
|
||||||
|
|
||||||
|
hasFlag = m.HasFlag(*p)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
74
logging/funcs_logwriter.go
Normal file
74
logging/funcs_logwriter.go
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
package logging
|
||||||
|
|
||||||
|
import (
|
||||||
|
`r00t2.io/goutils/multierr`
|
||||||
|
)
|
||||||
|
|
||||||
|
// Write writes bytes b to the underlying Logger's priority level if the logWriter's priority level(s) match.
|
||||||
|
func (l *logWriter) Write(b []byte) (n int, err error) {
|
||||||
|
|
||||||
|
var s string
|
||||||
|
var mErr *multierr.MultiError = multierr.NewMultiError(nil)
|
||||||
|
|
||||||
|
if b == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
s = string(b)
|
||||||
|
|
||||||
|
if l.prio.HasFlag(PriorityEmergency) {
|
||||||
|
if err = l.backend.Emerg(s); err != nil {
|
||||||
|
mErr.AddError(err)
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if l.prio.HasFlag(PriorityAlert) {
|
||||||
|
if err = l.backend.Alert(s); err != nil {
|
||||||
|
mErr.AddError(err)
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if l.prio.HasFlag(PriorityCritical) {
|
||||||
|
if err = l.backend.Crit(s); err != nil {
|
||||||
|
mErr.AddError(err)
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if l.prio.HasFlag(PriorityError) {
|
||||||
|
if err = l.backend.Err(s); err != nil {
|
||||||
|
mErr.AddError(err)
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if l.prio.HasFlag(PriorityWarning) {
|
||||||
|
if err = l.backend.Warning(s); err != nil {
|
||||||
|
mErr.AddError(err)
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if l.prio.HasFlag(PriorityNotice) {
|
||||||
|
if err = l.backend.Notice(s); err != nil {
|
||||||
|
mErr.AddError(err)
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if l.prio.HasFlag(PriorityInformational) {
|
||||||
|
if err = l.backend.Info(s); err != nil {
|
||||||
|
mErr.AddError(err)
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if l.prio.HasFlag(PriorityDebug) {
|
||||||
|
if err = l.backend.Debug(s); err != nil {
|
||||||
|
mErr.AddError(err)
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !mErr.IsEmpty() {
|
||||||
|
err = mErr
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
@ -1,11 +1,12 @@
|
|||||||
package logging
|
package logging
|
||||||
|
|
||||||
import (
|
import (
|
||||||
`errors`
|
"errors"
|
||||||
`fmt`
|
"fmt"
|
||||||
`sync`
|
`log`
|
||||||
|
"sync"
|
||||||
|
|
||||||
`r00t2.io/goutils/multierr`
|
"r00t2.io/goutils/multierr"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Setup sets up/configures a MultiLogger (and all its MultiLogger.Loggers) and prepares it for use.
|
// Setup sets up/configures a MultiLogger (and all its MultiLogger.Loggers) and prepares it for use.
|
||||||
@ -67,8 +68,8 @@ func (m *MultiLogger) Shutdown() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
GetPrefix returns the prefix used by this MultiLogger (and all its MultiLogger.Loggers).
|
GetPrefix returns the prefix used by this MultiLogger (and all its MultiLogger.Loggers).
|
||||||
err will always be nil; it's there for interface-compat.
|
err will always be nil; it's there for interface-compat.
|
||||||
*/
|
*/
|
||||||
func (m *MultiLogger) GetPrefix() (prefix string, err error) {
|
func (m *MultiLogger) GetPrefix() (prefix string, err error) {
|
||||||
|
|
||||||
@ -79,10 +80,10 @@ func (m *MultiLogger) GetPrefix() (prefix string, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
DoDebug sets the debug state of this MultiLogger (and all its MultiLogger.Loggers).
|
DoDebug sets the debug state of this MultiLogger (and all its MultiLogger.Loggers).
|
||||||
Note that this merely acts as a *safety filter* for debug messages to avoid sensitive information being written to the log.
|
Note that this merely acts as a *safety filter* for debug messages to avoid sensitive information being written to the log.
|
||||||
|
|
||||||
If you had a logger-specific EnableDebug set, you will need to re-set it to your desired state after running this method.
|
If you had a logger-specific EnableDebug set, you will need to re-set it to your desired state after running this method.
|
||||||
*/
|
*/
|
||||||
func (m *MultiLogger) DoDebug(d bool) (err error) {
|
func (m *MultiLogger) DoDebug(d bool) (err error) {
|
||||||
|
|
||||||
@ -114,10 +115,18 @@ func (m *MultiLogger) DoDebug(d bool) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// GetDebug returns the debug status of this MultiLogger.
|
||||||
SetPrefix sets the prefix for this MultiLogger (and all its MultiLogger.Loggers).
|
func (m *MultiLogger) GetDebug() (d bool) {
|
||||||
|
|
||||||
If you had a logger-specific Prefix set, you will need to re-set it to your desired prefix after running this method.
|
d = m.EnableDebug
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
SetPrefix sets the prefix for this MultiLogger (and all its MultiLogger.Loggers).
|
||||||
|
|
||||||
|
If you had a logger-specific Prefix set, you will need to re-set it to your desired prefix after running this method.
|
||||||
*/
|
*/
|
||||||
func (m *MultiLogger) SetPrefix(prefix string) (err error) {
|
func (m *MultiLogger) SetPrefix(prefix string) (err error) {
|
||||||
|
|
||||||
@ -362,3 +371,11 @@ func (m *MultiLogger) Warning(s string, v ...interface{}) (err error) {
|
|||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToLogger returns a stdlib log.Logger.
|
||||||
|
func (m *MultiLogger) ToLogger(prio logPrio) (stdLibLog *log.Logger) {
|
||||||
|
|
||||||
|
stdLibLog = log.New(&logWriter{backend: m, prio: prio}, "", 0)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package logging
|
package logging
|
||||||
|
|
||||||
import (
|
import (
|
||||||
`path`
|
"path"
|
||||||
|
|
||||||
`github.com/google/uuid`
|
"github.com/google/uuid"
|
||||||
`r00t2.io/sysutils/paths`
|
"r00t2.io/sysutils/paths"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -145,6 +145,40 @@ func (m *MultiLogger) AddFileLogger(identifier string, logFlags int, logfilePath
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
AddNullLogger adds a NullLogger to a MultiLogger.
|
||||||
|
|
||||||
|
identifier is a string to use to identify the added NullLogger in MultiLogger.Loggers.
|
||||||
|
If empty, one will be automatically generated.
|
||||||
|
*/
|
||||||
|
func (m *MultiLogger) AddNullLogger(identifier string) (err error) {
|
||||||
|
|
||||||
|
var exists bool
|
||||||
|
var prefix string
|
||||||
|
|
||||||
|
if identifier == "" {
|
||||||
|
identifier = uuid.New().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, exists = m.Loggers[identifier]; exists {
|
||||||
|
err = ErrExistingLogger
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
m.Loggers[identifier] = &NullLogger{}
|
||||||
|
if err = m.Loggers[identifier].Setup(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if prefix, err = m.Loggers[identifier].GetPrefix(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
m.Loggers[identifier].Debug("logger initialized of type %T with prefix %v", m.Loggers[identifier], prefix)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// RemoveLogger will let you remove a Logger from MultiLogger.Loggers.
|
// RemoveLogger will let you remove a Logger from MultiLogger.Loggers.
|
||||||
func (m *MultiLogger) RemoveLogger(identifier string) (err error) {
|
func (m *MultiLogger) RemoveLogger(identifier string) (err error) {
|
||||||
|
|
||||||
|
@ -1,20 +1,17 @@
|
|||||||
package logging
|
package logging
|
||||||
|
|
||||||
import (
|
import (
|
||||||
`os`
|
sysd "github.com/coreos/go-systemd/journal"
|
||||||
|
"github.com/google/uuid"
|
||||||
sysd `github.com/coreos/go-systemd/journal`
|
|
||||||
`github.com/google/uuid`
|
|
||||||
`r00t2.io/sysutils/paths`
|
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
AddDefaultLogger adds a default Logger (as would be determined by GetLogger) to a MultiLogger.
|
AddDefaultLogger adds a default Logger (as would be determined by GetLogger) to a MultiLogger.
|
||||||
|
|
||||||
identifier is a string to use to identify the added Logger in MultiLogger.Loggers.
|
identifier is a string to use to identify the added Logger in MultiLogger.Loggers.
|
||||||
If empty, one will be automatically generated.
|
If empty, one will be automatically generated.
|
||||||
|
|
||||||
See the documentation for GetLogger for details on other arguments.
|
See the documentation for GetLogger for details on other arguments.
|
||||||
*/
|
*/
|
||||||
func (m *MultiLogger) AddDefaultLogger(identifier string, logFlags int, logPaths ...string) (err error) {
|
func (m *MultiLogger) AddDefaultLogger(identifier string, logFlags int, logPaths ...string) (err error) {
|
||||||
|
|
||||||
@ -40,10 +37,10 @@ func (m *MultiLogger) AddDefaultLogger(identifier string, logFlags int, logPaths
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
AddSysdLogger adds a SystemDLogger to a MultiLogger.
|
AddSysdLogger adds a SystemDLogger to a MultiLogger.
|
||||||
|
|
||||||
identifier is a string to use to identify the added SystemDLogger in MultiLogger.Loggers.
|
identifier is a string to use to identify the added SystemDLogger in MultiLogger.Loggers.
|
||||||
If empty, one will be automatically generated.
|
If empty, one will be automatically generated.
|
||||||
*/
|
*/
|
||||||
func (m *MultiLogger) AddSysdLogger(identifier string) (err error) {
|
func (m *MultiLogger) AddSysdLogger(identifier string) (err error) {
|
||||||
|
|
||||||
@ -80,55 +77,3 @@ func (m *MultiLogger) AddSysdLogger(identifier string) (err error) {
|
|||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
AddSyslogLogger adds a SyslogLogger to a MultiLogger.
|
|
||||||
|
|
||||||
identifier is a string to use to identify the added SyslogLogger in MultiLogger.Loggers.
|
|
||||||
If empty, one will be automatically generated.
|
|
||||||
*/
|
|
||||||
func (m *MultiLogger) AddSyslogLogger(identifier string) (err error) {
|
|
||||||
|
|
||||||
var exists bool
|
|
||||||
var hasSyslog bool
|
|
||||||
var stat os.FileInfo
|
|
||||||
var devlogPath string = devlog
|
|
||||||
var prefix string
|
|
||||||
|
|
||||||
if identifier == "" {
|
|
||||||
identifier = uuid.New().String()
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, exists = m.Loggers[identifier]; exists {
|
|
||||||
err = ErrExistingLogger
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if hasSyslog, stat, err = paths.RealPathExistsStat(&devlogPath); hasSyslog && err != nil {
|
|
||||||
return
|
|
||||||
} else if !hasSyslog {
|
|
||||||
err = ErrNoSyslog
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if stat.Mode().IsRegular() {
|
|
||||||
err = ErrInvalidDevLog
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
m.Loggers[identifier] = &SyslogLogger{
|
|
||||||
EnableDebug: m.EnableDebug,
|
|
||||||
Prefix: m.Prefix,
|
|
||||||
}
|
|
||||||
if err = m.Loggers[identifier].Setup(); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if prefix, err = m.Loggers[identifier].GetPrefix(); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
m.Loggers[identifier].Debug("logger initialized of type %T with prefix %v", m.Loggers[identifier], prefix)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
63
logging/funcs_multilogger_mgr_nix.go
Normal file
63
logging/funcs_multilogger_mgr_nix.go
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
//go:build !(windows || plan9 || wasip1 || js || ios)
|
||||||
|
// +build !windows,!plan9,!wasip1,!js,!ios
|
||||||
|
|
||||||
|
package logging
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"r00t2.io/sysutils/paths"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
AddSyslogLogger adds a SyslogLogger to a MultiLogger.
|
||||||
|
|
||||||
|
identifier is a string to use to identify the added SyslogLogger in MultiLogger.Loggers.
|
||||||
|
If empty, one will be automatically generated.
|
||||||
|
*/
|
||||||
|
func (m *MultiLogger) AddSyslogLogger(identifier string) (err error) {
|
||||||
|
|
||||||
|
var exists bool
|
||||||
|
var hasSyslog bool
|
||||||
|
var stat os.FileInfo
|
||||||
|
var devlogPath string = devlog
|
||||||
|
var prefix string
|
||||||
|
|
||||||
|
if identifier == "" {
|
||||||
|
identifier = uuid.New().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, exists = m.Loggers[identifier]; exists {
|
||||||
|
err = ErrExistingLogger
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if hasSyslog, stat, err = paths.RealPathExistsStat(&devlogPath); hasSyslog && err != nil {
|
||||||
|
return
|
||||||
|
} else if !hasSyslog {
|
||||||
|
err = ErrNoSyslog
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if stat.Mode().IsRegular() {
|
||||||
|
err = ErrInvalidDevLog
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
m.Loggers[identifier] = &SyslogLogger{
|
||||||
|
EnableDebug: m.EnableDebug,
|
||||||
|
Prefix: m.Prefix,
|
||||||
|
}
|
||||||
|
if err = m.Loggers[identifier].Setup(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if prefix, err = m.Loggers[identifier].GetPrefix(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
m.Loggers[identifier].Debug("logger initialized of type %T with prefix %v", m.Loggers[identifier], prefix)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
41
logging/funcs_multilogger_mgr_oldnix.go
Normal file
41
logging/funcs_multilogger_mgr_oldnix.go
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
//go:build !(windows || plan9 || wasip1 || js || ios || linux)
|
||||||
|
// +build !windows,!plan9,!wasip1,!js,!ios,!linux
|
||||||
|
|
||||||
|
// Linux is excluded because it has its own.
|
||||||
|
|
||||||
|
package logging
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
AddDefaultLogger adds a default Logger (as would be determined by GetLogger) to a MultiLogger.
|
||||||
|
|
||||||
|
identifier is a string to use to identify the added Logger in MultiLogger.Loggers.
|
||||||
|
If empty, one will be automatically generated.
|
||||||
|
|
||||||
|
See the documentation for GetLogger for details on other arguments.
|
||||||
|
*/
|
||||||
|
func (m *MultiLogger) AddDefaultLogger(identifier string, logFlags int, logPaths ...string) (err error) {
|
||||||
|
|
||||||
|
var l Logger
|
||||||
|
var exists bool
|
||||||
|
|
||||||
|
if identifier == "" {
|
||||||
|
identifier = uuid.New().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, exists = m.Loggers[identifier]; exists {
|
||||||
|
err = ErrExistingLogger
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if l, err = GetLogger(m.EnableDebug, m.Prefix, logFlags, logPaths...); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
m.Loggers[identifier] = l
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
86
logging/funcs_nulllogger.go
Normal file
86
logging/funcs_nulllogger.go
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
package logging
|
||||||
|
|
||||||
|
import (
|
||||||
|
`log`
|
||||||
|
)
|
||||||
|
|
||||||
|
// Setup does nothing at all; it's here for interface compat. 🙃
|
||||||
|
func (l *NullLogger) Setup() (err error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// DoDebug does nothing at all; it's here for interface compat. 🙃
|
||||||
|
func (l *NullLogger) DoDebug(d bool) (err error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDebug returns the debug status of this NullLogger. It will always return true. 🙃
|
||||||
|
func (n *NullLogger) GetDebug() (d bool) {
|
||||||
|
|
||||||
|
d = true
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetPrefix does nothing at all; it's here for interface compat. 🙃
|
||||||
|
func (l *NullLogger) SetPrefix(p string) (err error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPrefix does nothing at all; it's here for interface compat. 🙃
|
||||||
|
func (l *NullLogger) GetPrefix() (p string, err error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shutdown does nothing at all; it's here for interface compat. 🙃
|
||||||
|
func (l *NullLogger) Shutdown() (err error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alert does nothing at all; it's here for interface compat. 🙃
|
||||||
|
func (l *NullLogger) Alert(s string, v ...interface{}) (err error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Crit does nothing at all; it's here for interface compat. 🙃
|
||||||
|
func (l *NullLogger) Crit(s string, v ...interface{}) (err error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug does nothing at all; it's here for interface compat. 🙃
|
||||||
|
func (l *NullLogger) Debug(s string, v ...interface{}) (err error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emerg does nothing at all; it's here for interface compat. 🙃
|
||||||
|
func (l *NullLogger) Emerg(s string, v ...interface{}) (err error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Err does nothing at all; it's here for interface compat. 🙃
|
||||||
|
func (l *NullLogger) Err(s string, v ...interface{}) (err error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Info does nothing at all; it's here for interface compat. 🙃
|
||||||
|
func (l *NullLogger) Info(s string, v ...interface{}) (err error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notice does nothing at all; it's here for interface compat. 🙃
|
||||||
|
func (l *NullLogger) Notice(s string, v ...interface{}) (err error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warning does nothing at all; it's here for interface compat. 🙃
|
||||||
|
func (l *NullLogger) Warning(s string, v ...interface{}) (err error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToLogger returns a stdlib log.Logger (that doesn't actually write to anything).
|
||||||
|
func (l *NullLogger) ToLogger(prio logPrio) (stdLibLog *log.Logger) {
|
||||||
|
|
||||||
|
stdLibLog = log.New(&nullWriter{}, "", 0)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
12
logging/funcs_nullwriter.go
Normal file
12
logging/funcs_nullwriter.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package logging
|
||||||
|
|
||||||
|
// nulLWriter writes... nothing. To avoid errors, however, in downstream code it pretends it does (n will *always* == len(b)).
|
||||||
|
func (nw *nullWriter) Write(b []byte) (n int, err error) {
|
||||||
|
|
||||||
|
if b == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
n = len(b)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
138
logging/funcs_oldnix.go
Normal file
138
logging/funcs_oldnix.go
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
//go:build !(windows || plan9 || wasip1 || js || ios || linux)
|
||||||
|
// +build !windows,!plan9,!wasip1,!js,!ios,!linux
|
||||||
|
|
||||||
|
// Linux is excluded because it has its own.
|
||||||
|
|
||||||
|
package logging
|
||||||
|
|
||||||
|
import (
|
||||||
|
native "log"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
|
||||||
|
"r00t2.io/goutils/bitmask"
|
||||||
|
"r00t2.io/sysutils/paths"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
_ = native.Logger{}
|
||||||
|
_ = os.Interrupt
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
GetLogger returns an instance of Logger that best suits your system's capabilities.
|
||||||
|
|
||||||
|
If enableDebug is true, debug messages (which according to your program may or may not contain sensitive data) are rendered and written.
|
||||||
|
|
||||||
|
If prefix is "\x00" (a null byte), then the default logging prefix will be used. If anything else, even an empty string,
|
||||||
|
is specified then that will be used instead for the prefix.
|
||||||
|
|
||||||
|
logConfigFlags is the corresponding flag(s) OR'd for StdLogger.LogFlags / FileLogger.StdLogger.LogFlags if either is selected. See StdLogger.LogFlags and
|
||||||
|
https://pkg.go.dev/log#pkg-constants for details.
|
||||||
|
|
||||||
|
logPaths is an (optional) list of strings to use as paths to test for writing. If the file can be created/written to,
|
||||||
|
it will be used (assuming you have no higher-level loggers available). Only the first logPaths entry that "works" will be used, later entries will be ignored.
|
||||||
|
If you want to log to multiple files simultaneously, use a MultiLogger instead.
|
||||||
|
|
||||||
|
If you call GetLogger, you will only get a single ("best") logger your system supports.
|
||||||
|
If you want to log to multiple Logger destinations at once (or want to log to an explicit Logger type),
|
||||||
|
use GetMultiLogger.
|
||||||
|
*/
|
||||||
|
func GetLogger(enableDebug bool, prefix string, logConfigFlags int, logPaths ...string) (logger Logger, err error) {
|
||||||
|
|
||||||
|
var logPath string
|
||||||
|
var logFlags bitmask.MaskBit
|
||||||
|
var currentPrefix string
|
||||||
|
|
||||||
|
// Configure system-supported logger(s).
|
||||||
|
|
||||||
|
// If we can detect syslog, use that. If not, try to use a file logger (+ stdout).
|
||||||
|
// Last ditch, stdout.
|
||||||
|
var hasSyslog bool
|
||||||
|
var stat os.FileInfo
|
||||||
|
var devlogPath string = devlog
|
||||||
|
|
||||||
|
if hasSyslog, stat, err = paths.RealPathExistsStat(&devlogPath); hasSyslog && err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if hasSyslog && !stat.Mode().IsRegular() {
|
||||||
|
logFlags.AddFlag(LogSyslog)
|
||||||
|
} else {
|
||||||
|
var exists bool
|
||||||
|
var success bool
|
||||||
|
var ckLogPaths []string
|
||||||
|
|
||||||
|
logFlags.AddFlag(LogStdout)
|
||||||
|
ckLogPaths = defLogPaths
|
||||||
|
if logPaths != nil {
|
||||||
|
ckLogPaths = logPaths
|
||||||
|
}
|
||||||
|
for _, p := range ckLogPaths {
|
||||||
|
if exists, _ = paths.RealPathExists(&p); exists {
|
||||||
|
if success, err = testOpen(p); err != nil {
|
||||||
|
continue
|
||||||
|
} else if !success {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
logFlags.AddFlag(LogFile)
|
||||||
|
logPath = p
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
dirPath := path.Dir(p)
|
||||||
|
if err = paths.MakeDirIfNotExist(dirPath); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if success, err = testOpen(p); err != nil {
|
||||||
|
continue
|
||||||
|
} else if !success {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
logFlags.AddFlag(LogFile)
|
||||||
|
logPath = p
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if logFlags.HasFlag(LogSyslog) {
|
||||||
|
logger = &SyslogLogger{
|
||||||
|
Prefix: logPrefix,
|
||||||
|
EnableDebug: enableDebug,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if logFlags.HasFlag(LogFile) {
|
||||||
|
logger = &FileLogger{
|
||||||
|
StdLogger: StdLogger{
|
||||||
|
Prefix: logPrefix,
|
||||||
|
EnableDebug: enableDebug,
|
||||||
|
LogFlags: logConfigFlags,
|
||||||
|
},
|
||||||
|
Path: logPath,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger = &StdLogger{
|
||||||
|
Prefix: logPrefix,
|
||||||
|
EnableDebug: enableDebug,
|
||||||
|
LogFlags: logConfigFlags,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if prefix != "\x00" {
|
||||||
|
if err = logger.SetPrefix(prefix); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err = logger.Setup(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if currentPrefix, err = logger.GetPrefix(); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Debug("logger initialized of type %T with prefix %v", logger, currentPrefix)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
@ -2,15 +2,15 @@ package logging
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
`io`
|
"io"
|
||||||
`log`
|
"log"
|
||||||
`os`
|
"os"
|
||||||
`strings`
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Setup sets up/configures a StdLogger and prepares it for use.
|
Setup sets up/configures a StdLogger and prepares it for use.
|
||||||
err will always be nil; it's there for interface-compat.
|
err will always be nil; it's there for interface-compat.
|
||||||
*/
|
*/
|
||||||
func (l *StdLogger) Setup() (err error) {
|
func (l *StdLogger) Setup() (err error) {
|
||||||
|
|
||||||
@ -47,8 +47,8 @@ func (l *StdLogger) Setup() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Shutdown cleanly shuts down a StdLogger.
|
Shutdown cleanly shuts down a StdLogger.
|
||||||
err will always be nil; it's there for interface-compat.
|
err will always be nil; it's there for interface-compat.
|
||||||
*/
|
*/
|
||||||
func (l *StdLogger) Shutdown() (err error) {
|
func (l *StdLogger) Shutdown() (err error) {
|
||||||
|
|
||||||
@ -58,8 +58,8 @@ func (l *StdLogger) Shutdown() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
GetPrefix returns the prefix used by this StdLogger.
|
GetPrefix returns the prefix used by this StdLogger.
|
||||||
err will always be nil; it's there for interface-compat.
|
err will always be nil; it's there for interface-compat.
|
||||||
*/
|
*/
|
||||||
func (l *StdLogger) GetPrefix() (prefix string, err error) {
|
func (l *StdLogger) GetPrefix() (prefix string, err error) {
|
||||||
|
|
||||||
@ -69,9 +69,9 @@ func (l *StdLogger) GetPrefix() (prefix string, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
DoDebug sets the debug state of this StdLogger.
|
DoDebug sets the debug state of this StdLogger.
|
||||||
Note that this merely acts as a *safety filter* for debug messages to avoid sensitive information being written to the log.
|
Note that this merely acts as a *safety filter* for debug messages to avoid sensitive information being written to the log.
|
||||||
err will always be nil; it's there for interface-compat.
|
err will always be nil; it's there for interface-compat.
|
||||||
*/
|
*/
|
||||||
func (l *StdLogger) DoDebug(d bool) (err error) {
|
func (l *StdLogger) DoDebug(d bool) (err error) {
|
||||||
|
|
||||||
@ -80,9 +80,17 @@ func (l *StdLogger) DoDebug(d bool) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetDebug returns the debug status of this StdLogger.
|
||||||
|
func (l *StdLogger) GetDebug() (d bool) {
|
||||||
|
|
||||||
|
d = l.EnableDebug
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
SetPrefix sets the prefix for this StdLogger.
|
SetPrefix sets the prefix for this StdLogger.
|
||||||
err will always be nil; it's there for interface-compat.
|
err will always be nil; it's there for interface-compat.
|
||||||
*/
|
*/
|
||||||
func (l *StdLogger) SetPrefix(prefix string) (err error) {
|
func (l *StdLogger) SetPrefix(prefix string) (err error) {
|
||||||
|
|
||||||
@ -236,3 +244,11 @@ func (l *StdLogger) renderWrite(msg, prio string) {
|
|||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToLogger returns a stdlib log.Logger.
|
||||||
|
func (l *StdLogger) ToLogger(prio logPrio) (stdLibLog *log.Logger) {
|
||||||
|
|
||||||
|
stdLibLog = log.New(&logWriter{backend: l, prio: prio}, "", 0)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
@ -8,8 +8,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Setup sets up/configures a SystemDLogger and prepares it for use.
|
Setup sets up/configures a SystemDLogger and prepares it for use.
|
||||||
err will always be nil; it's there for interface-compat.
|
err will always be nil; it's there for interface-compat.
|
||||||
*/
|
*/
|
||||||
func (l *SystemDLogger) Setup() (err error) {
|
func (l *SystemDLogger) Setup() (err error) {
|
||||||
|
|
||||||
@ -19,8 +19,8 @@ func (l *SystemDLogger) Setup() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Shutdown cleanly shuts down a SystemDLogger.
|
Shutdown cleanly shuts down a SystemDLogger.
|
||||||
err will always be nil; it's there for interface-compat.
|
err will always be nil; it's there for interface-compat.
|
||||||
*/
|
*/
|
||||||
func (l *SystemDLogger) Shutdown() (err error) {
|
func (l *SystemDLogger) Shutdown() (err error) {
|
||||||
|
|
||||||
@ -30,8 +30,8 @@ func (l *SystemDLogger) Shutdown() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
GetPrefix returns the prefix used by this SystemDLogger.
|
GetPrefix returns the prefix used by this SystemDLogger.
|
||||||
err will always be nil; it's there for interface-compat.
|
err will always be nil; it's there for interface-compat.
|
||||||
*/
|
*/
|
||||||
func (l *SystemDLogger) GetPrefix() (prefix string, err error) {
|
func (l *SystemDLogger) GetPrefix() (prefix string, err error) {
|
||||||
|
|
||||||
@ -41,9 +41,9 @@ func (l *SystemDLogger) GetPrefix() (prefix string, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
DoDebug sets the debug state of this SystemDLogger.
|
DoDebug sets the debug state of this SystemDLogger.
|
||||||
Note that this merely acts as a *safety filter* for debug messages to avoid sensitive information being written to the log.
|
Note that this merely acts as a *safety filter* for debug messages to avoid sensitive information being written to the log.
|
||||||
err will always be nil; it's there for interface-compat.
|
err will always be nil; it's there for interface-compat.
|
||||||
*/
|
*/
|
||||||
func (l *SystemDLogger) DoDebug(d bool) (err error) {
|
func (l *SystemDLogger) DoDebug(d bool) (err error) {
|
||||||
|
|
||||||
@ -52,9 +52,17 @@ func (l *SystemDLogger) DoDebug(d bool) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetDebug returns the debug status of this SystemDLogger.
|
||||||
|
func (l *SystemDLogger) GetDebug() (d bool) {
|
||||||
|
|
||||||
|
d = l.EnableDebug
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
SetPrefix sets the prefix for this SystemDLogger.
|
SetPrefix sets the prefix for this SystemDLogger.
|
||||||
err will always be nil; it's there for interface-compat.
|
err will always be nil; it's there for interface-compat.
|
||||||
*/
|
*/
|
||||||
func (l *SystemDLogger) SetPrefix(prefix string) (err error) {
|
func (l *SystemDLogger) SetPrefix(prefix string) (err error) {
|
||||||
|
|
||||||
@ -215,3 +223,11 @@ func (l *SystemDLogger) renderWrite(msg string, prio journal.Priority) {
|
|||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToLogger returns a stdlib log.Logger.
|
||||||
|
func (l *SystemDLogger) ToLogger(prio logPrio) (stdLibLog *log.Logger) {
|
||||||
|
|
||||||
|
stdLibLog = log.New(&logWriter{backend: l, prio: prio}, "", 0)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
//go:build !(windows || plan9 || wasip1 || js || ios)
|
||||||
|
// +build !windows,!plan9,!wasip1,!js,!ios
|
||||||
|
|
||||||
package logging
|
package logging
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -5,7 +8,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"log/syslog"
|
"log/syslog"
|
||||||
|
|
||||||
`r00t2.io/goutils/multierr`
|
"r00t2.io/goutils/multierr"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Setup sets up/configures a SyslogLogger and prepares it for use.
|
// Setup sets up/configures a SyslogLogger and prepares it for use.
|
||||||
@ -73,8 +76,8 @@ func (l *SyslogLogger) Shutdown() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
GetPrefix returns the prefix used by this SyslogLogger.
|
GetPrefix returns the prefix used by this SyslogLogger.
|
||||||
err will always be nil; it's there for interface-compat.
|
err will always be nil; it's there for interface-compat.
|
||||||
*/
|
*/
|
||||||
func (l *SyslogLogger) GetPrefix() (prefix string, err error) {
|
func (l *SyslogLogger) GetPrefix() (prefix string, err error) {
|
||||||
|
|
||||||
@ -84,9 +87,9 @@ func (l *SyslogLogger) GetPrefix() (prefix string, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
DoDebug sets the debug state of this SyslogLogger.
|
DoDebug sets the debug state of this SyslogLogger.
|
||||||
Note that this merely acts as a *safety filter* for debug messages to avoid sensitive information being written to the log.
|
Note that this merely acts as a *safety filter* for debug messages to avoid sensitive information being written to the log.
|
||||||
err will always be nil; it's there for interface-compat.
|
err will always be nil; it's there for interface-compat.
|
||||||
*/
|
*/
|
||||||
func (l *SyslogLogger) DoDebug(d bool) (err error) {
|
func (l *SyslogLogger) DoDebug(d bool) (err error) {
|
||||||
|
|
||||||
@ -95,6 +98,14 @@ func (l *SyslogLogger) DoDebug(d bool) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetDebug returns the debug status of this SyslogLogger.
|
||||||
|
func (l *SyslogLogger) GetDebug() (d bool) {
|
||||||
|
|
||||||
|
d = l.EnableDebug
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// SetPrefix sets the prefix for this SyslogLogger.
|
// SetPrefix sets the prefix for this SyslogLogger.
|
||||||
func (l *SyslogLogger) SetPrefix(prefix string) (err error) {
|
func (l *SyslogLogger) SetPrefix(prefix string) (err error) {
|
||||||
|
|
||||||
@ -258,3 +269,11 @@ func (l *SyslogLogger) Warning(s string, v ...interface{}) (err error) {
|
|||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToLogger returns a stdlib log.Logger.
|
||||||
|
func (l *SyslogLogger) ToLogger(prio logPrio) (stdLibLog *log.Logger) {
|
||||||
|
|
||||||
|
stdLibLog = log.New(&logWriter{backend: l, prio: prio}, "", 0)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
@ -1,26 +1,27 @@
|
|||||||
package logging
|
package logging
|
||||||
|
|
||||||
import (
|
import (
|
||||||
`errors`
|
"errors"
|
||||||
`fmt`
|
"fmt"
|
||||||
`os`
|
`log`
|
||||||
`os/exec`
|
"os"
|
||||||
`syscall`
|
"os/exec"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
`golang.org/x/sys/windows/registry`
|
"golang.org/x/sys/windows/registry"
|
||||||
`golang.org/x/sys/windows/svc/eventlog`
|
"golang.org/x/sys/windows/svc/eventlog"
|
||||||
`r00t2.io/sysutils/paths`
|
"r00t2.io/sysutils/paths"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Setup sets up/configures a WinLogger and prepares it for use.
|
Setup sets up/configures a WinLogger and prepares it for use.
|
||||||
This will fail with an Access Denied (the first time, at least) unless running with elevated permissions unless WinLogger.Prefix is
|
This will fail with an Access Denied (the first time, at least) unless running with elevated permissions unless WinLogger.Prefix is
|
||||||
a registered Event Log source.
|
a registered Event Log source.
|
||||||
|
|
||||||
If a failure occurs while trying to open the log with the given WinLogger.Prefix ("source"), a new Event Log source will be registered.
|
If a failure occurs while trying to open the log with the given WinLogger.Prefix ("source"), a new Event Log source will be registered.
|
||||||
If WinLogger.Executable is not empty at the time of calling WinLogger.Setup (or WinLogger.ForceService is true),
|
If WinLogger.Executable is not empty at the time of calling WinLogger.Setup (or WinLogger.ForceService is true),
|
||||||
eventlog.Install will be used (with the WinLogger.ExpandKey field).
|
eventlog.Install will be used (with the WinLogger.ExpandKey field).
|
||||||
Otherwise eventlog.InstallAsEventCreate will be used.
|
Otherwise eventlog.InstallAsEventCreate will be used.
|
||||||
*/
|
*/
|
||||||
func (l *WinLogger) Setup() (err error) {
|
func (l *WinLogger) Setup() (err error) {
|
||||||
|
|
||||||
@ -108,8 +109,8 @@ func (l *WinLogger) Remove() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Shutdown cleanly shuts down a WinLogger but keep the source registered. Use WinLogger.Remove
|
Shutdown cleanly shuts down a WinLogger but keep the source registered. Use WinLogger.Remove
|
||||||
(or set WinLogger.RemoveOnClose to true before calling WinLogger.Shutdown) to remove the registered source.
|
(or set WinLogger.RemoveOnClose to true before calling WinLogger.Shutdown) to remove the registered source.
|
||||||
*/
|
*/
|
||||||
func (l *WinLogger) Shutdown() (err error) {
|
func (l *WinLogger) Shutdown() (err error) {
|
||||||
|
|
||||||
@ -128,8 +129,8 @@ func (l *WinLogger) Shutdown() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
GetPrefix returns the prefix used by this WinLogger.
|
GetPrefix returns the prefix used by this WinLogger.
|
||||||
err will always be nil; it's there for interface-compat.
|
err will always be nil; it's there for interface-compat.
|
||||||
*/
|
*/
|
||||||
func (l *WinLogger) GetPrefix() (prefix string, err error) {
|
func (l *WinLogger) GetPrefix() (prefix string, err error) {
|
||||||
|
|
||||||
@ -139,9 +140,9 @@ func (l *WinLogger) GetPrefix() (prefix string, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
DoDebug sets the debug state of this WinLogger.
|
DoDebug sets the debug state of this WinLogger.
|
||||||
Note that this merely acts as a *safety filter* for debug messages to avoid sensitive information being written to the log.
|
Note that this merely acts as a *safety filter* for debug messages to avoid sensitive information being written to the log.
|
||||||
err will always be nil; it's there for interface-compat.
|
err will always be nil; it's there for interface-compat.
|
||||||
*/
|
*/
|
||||||
func (l *WinLogger) DoDebug(d bool) (err error) {
|
func (l *WinLogger) DoDebug(d bool) (err error) {
|
||||||
|
|
||||||
@ -150,6 +151,14 @@ func (l *WinLogger) DoDebug(d bool) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetDebug returns the debug status of this WinLogger.
|
||||||
|
func (l *WinLogger) GetDebug() (d bool) {
|
||||||
|
|
||||||
|
d = l.EnableDebug
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// SetPrefix sets the prefix for this WinLogger.
|
// SetPrefix sets the prefix for this WinLogger.
|
||||||
func (l *WinLogger) SetPrefix(prefix string) (err error) {
|
func (l *WinLogger) SetPrefix(prefix string) (err error) {
|
||||||
|
|
||||||
@ -334,3 +343,11 @@ func (l *WinLogger) Warning(s string, v ...interface{}) (err error) {
|
|||||||
return
|
return
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ToLogger returns a stdlib log.Logger.
|
||||||
|
func (l *WinLogger) ToLogger(prio logPrio) (stdLibLog *log.Logger) {
|
||||||
|
|
||||||
|
stdLibLog = log.New(&logWriter{backend: l, prio: prio}, "", 0)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
@ -2,11 +2,15 @@ package logging
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
`os`
|
"os"
|
||||||
|
|
||||||
|
`r00t2.io/goutils/bitmask`
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type logPrio bitmask.MaskBit
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Logger is one of the various loggers offered by this module.
|
Logger is one of the various loggers offered by this module.
|
||||||
*/
|
*/
|
||||||
type Logger interface {
|
type Logger interface {
|
||||||
Alert(s string, v ...interface{}) (err error)
|
Alert(s string, v ...interface{}) (err error)
|
||||||
@ -18,15 +22,17 @@ type Logger interface {
|
|||||||
Notice(s string, v ...interface{}) (err error)
|
Notice(s string, v ...interface{}) (err error)
|
||||||
Warning(s string, v ...interface{}) (err error)
|
Warning(s string, v ...interface{}) (err error)
|
||||||
DoDebug(d bool) (err error)
|
DoDebug(d bool) (err error)
|
||||||
|
GetDebug() (d bool)
|
||||||
SetPrefix(p string) (err error)
|
SetPrefix(p string) (err error)
|
||||||
GetPrefix() (p string, err error)
|
GetPrefix() (p string, err error)
|
||||||
Setup() (err error)
|
Setup() (err error)
|
||||||
Shutdown() (err error)
|
Shutdown() (err error)
|
||||||
|
ToLogger(prio logPrio) (stdLibLog *log.Logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
StdLogger uses the log package in stdlib to perform all logging. The default is to write to STDOUT.
|
StdLogger uses the log package in stdlib to perform all logging. The default is to write to STDOUT.
|
||||||
If you wish to modify the underling log.Logger object, you can access it directly via StdLogger.Logger.
|
If you wish to modify the underling log.Logger object, you can access it directly via StdLogger.Logger.
|
||||||
*/
|
*/
|
||||||
type StdLogger struct {
|
type StdLogger struct {
|
||||||
// All log.Logger fields/methods are exposed.
|
// All log.Logger fields/methods are exposed.
|
||||||
@ -71,11 +77,11 @@ type StdLogger struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
FileLogger uses a StdLogger with a file handle writer to write to the file given at Path.
|
FileLogger uses a StdLogger with a file handle writer to write to the file given at Path.
|
||||||
|
|
||||||
NOTE: If you wish to change the FileLogger.StdLogger.LogFlags, do *not* run FileLogger.StdLogger.Setup after doing so as this
|
NOTE: If you wish to change the FileLogger.StdLogger.LogFlags, do *not* run FileLogger.StdLogger.Setup after doing so as this
|
||||||
will instead create a logger detached from the file handler. Instead, be sure to call FileLogger.Setup.
|
will instead create a logger detached from the file handler. Instead, be sure to call FileLogger.Setup.
|
||||||
(Alternatively, run FileLogger.Shutdown and replace your logger with a new FileLogger.)
|
(Alternatively, run FileLogger.Shutdown and replace your logger with a new FileLogger.)
|
||||||
*/
|
*/
|
||||||
type FileLogger struct {
|
type FileLogger struct {
|
||||||
// StdLogger is used for the log formation and handling. See StdLogger for more details.
|
// StdLogger is used for the log formation and handling. See StdLogger for more details.
|
||||||
@ -86,6 +92,9 @@ type FileLogger struct {
|
|||||||
writer *os.File
|
writer *os.File
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NullLogger is used mainly for test implementations, mockup code, etc. It does absolutely nothing with all messages sent to it.
|
||||||
|
type NullLogger struct{}
|
||||||
|
|
||||||
// MultiLogger is used to contain one or more Loggers and present them all as a single Logger.
|
// MultiLogger is used to contain one or more Loggers and present them all as a single Logger.
|
||||||
type MultiLogger struct {
|
type MultiLogger struct {
|
||||||
/*
|
/*
|
||||||
@ -101,3 +110,12 @@ type MultiLogger struct {
|
|||||||
*/
|
*/
|
||||||
Loggers map[string]Logger
|
Loggers map[string]Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// logWriter is used as a log.Logger and is returned by <Logger>.ToLogger.
|
||||||
|
type logWriter struct {
|
||||||
|
backend Logger
|
||||||
|
prio logPrio
|
||||||
|
}
|
||||||
|
|
||||||
|
// nullWriter is used as a shortcut by NullLogger.ToLogger.
|
||||||
|
type nullWriter struct{}
|
||||||
|
@ -1,27 +1,9 @@
|
|||||||
package logging
|
package logging
|
||||||
|
|
||||||
import (
|
|
||||||
`log/syslog`
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
SystemDLogger (yes, I'm aware it's actually written as "systemd") writes to journald on systemd-enabled systems.
|
SystemDLogger (yes, I'm aware it's actually written as "systemd") writes to journald on systemd-enabled systems.
|
||||||
*/
|
*/
|
||||||
type SystemDLogger struct {
|
type SystemDLogger struct {
|
||||||
EnableDebug bool
|
EnableDebug bool
|
||||||
Prefix string
|
Prefix string
|
||||||
}
|
}
|
||||||
|
|
||||||
// SyslogLogger writes to syslog on syslog-enabled systems.
|
|
||||||
type SyslogLogger struct {
|
|
||||||
EnableDebug bool
|
|
||||||
Prefix string
|
|
||||||
alert,
|
|
||||||
crit,
|
|
||||||
debug,
|
|
||||||
emerg,
|
|
||||||
err,
|
|
||||||
info,
|
|
||||||
notice,
|
|
||||||
warning *syslog.Writer
|
|
||||||
}
|
|
||||||
|
22
logging/types_nix.go
Normal file
22
logging/types_nix.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
//go:build !(windows || plan9 || wasip1 || js || ios)
|
||||||
|
// +build !windows,!plan9,!wasip1,!js,!ios
|
||||||
|
|
||||||
|
package logging
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log/syslog"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SyslogLogger writes to syslog on syslog-enabled systems.
|
||||||
|
type SyslogLogger struct {
|
||||||
|
EnableDebug bool
|
||||||
|
Prefix string
|
||||||
|
alert,
|
||||||
|
crit,
|
||||||
|
debug,
|
||||||
|
emerg,
|
||||||
|
err,
|
||||||
|
info,
|
||||||
|
notice,
|
||||||
|
warning *syslog.Writer
|
||||||
|
}
|
@ -69,6 +69,9 @@ func (e *MultiError) Error() (errStr string) {
|
|||||||
numErrs = len(e.Errors)
|
numErrs = len(e.Errors)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
e.lock.Lock()
|
||||||
|
defer e.lock.Unlock()
|
||||||
|
|
||||||
for idx, err := range e.Errors {
|
for idx, err := range e.Errors {
|
||||||
if (idx + 1) < numErrs {
|
if (idx + 1) < numErrs {
|
||||||
errStr += fmt.Sprintf("%v%v", err.Error(), e.ErrorSep)
|
errStr += fmt.Sprintf("%v%v", err.Error(), e.ErrorSep)
|
||||||
@ -87,6 +90,9 @@ func (e *MultiError) AddError(err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
e.lock.Lock()
|
||||||
|
defer e.lock.Unlock()
|
||||||
|
|
||||||
e.Errors = append(e.Errors, err)
|
e.Errors = append(e.Errors, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,14 @@
|
|||||||
package multierr
|
package multierr
|
||||||
|
|
||||||
|
import (
|
||||||
|
`sync`
|
||||||
|
)
|
||||||
|
|
||||||
// MultiError is a type of error.Error that can contain multiple errors.
|
// MultiError is a type of error.Error that can contain multiple errors.
|
||||||
type MultiError struct {
|
type MultiError struct {
|
||||||
// Errors is a slice of errors to combine/concatenate when .Error() is called.
|
// Errors is a slice of errors to combine/concatenate when .Error() is called.
|
||||||
Errors []error `json:"errors"`
|
Errors []error `json:"errors"`
|
||||||
// ErrorSep is a string to use to separate errors for .Error(). The default is "\n".
|
// ErrorSep is a string to use to separate errors for .Error(). The default is "\n".
|
||||||
ErrorSep string `json:"separator"`
|
ErrorSep string `json:"separator"`
|
||||||
|
lock sync.Mutex
|
||||||
}
|
}
|
||||||
|
5
structutils/consts.go
Normal file
5
structutils/consts.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package structutils
|
||||||
|
|
||||||
|
const (
|
||||||
|
TagMapTrim tagMapOpt = iota
|
||||||
|
)
|
362
structutils/funcs.go
Normal file
362
structutils/funcs.go
Normal file
@ -0,0 +1,362 @@
|
|||||||
|
/*
|
||||||
|
GoUtils - a library to assist with various Golang-related functions
|
||||||
|
Copyright (C) 2020 Brent Saner
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package structutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
`reflect`
|
||||||
|
`strings`
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
TagToBoolMap takes struct field `field` and tag name `tagName`,
|
||||||
|
optionally with options `opts`, and returns a map of the tag values.
|
||||||
|
The tag value string is assumed to be in the form of:
|
||||||
|
option[,option,option...]
|
||||||
|
and returns a map[string]bool (map[option]true).
|
||||||
|
|
||||||
|
If field does not have tag tagName, m will be nil.
|
||||||
|
|
||||||
|
See the TagMap* constants for opts.
|
||||||
|
*/
|
||||||
|
func TagToBoolMap(field reflect.StructField, tagName string, opts ...tagMapOpt) (m map[string]bool) {
|
||||||
|
|
||||||
|
var s string
|
||||||
|
var optSplit []string
|
||||||
|
var tagOpts map[tagMapOpt]bool = getTagMapOpts(opts)
|
||||||
|
|
||||||
|
s = field.Tag.Get(tagName)
|
||||||
|
|
||||||
|
if strings.TrimSpace(s) == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
optSplit = strings.Split(s, ",")
|
||||||
|
if optSplit == nil || len(optSplit) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m = make(map[string]bool)
|
||||||
|
for _, o := range optSplit {
|
||||||
|
if tagOpts[TagMapTrim] {
|
||||||
|
o = strings.TrimSpace(o)
|
||||||
|
}
|
||||||
|
m[o] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
TagToBoolMapWithValue is like TagToBoolMap but additionally assumes the first value is an "identifier".
|
||||||
|
The tag value string is assumed to be in the form of:
|
||||||
|
value,option[,option,option...]
|
||||||
|
and returns a map[string]bool (map[option]true) with the value.
|
||||||
|
*/
|
||||||
|
func TagToBoolMapWithValue(field reflect.StructField, tagName string, opts ...tagMapOpt) (value string, m map[string]bool) {
|
||||||
|
|
||||||
|
var s string
|
||||||
|
var optSplit []string
|
||||||
|
var tagOpts map[tagMapOpt]bool = getTagMapOpts(opts)
|
||||||
|
|
||||||
|
s = field.Tag.Get(tagName)
|
||||||
|
|
||||||
|
if strings.TrimSpace(s) == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
optSplit = strings.Split(s, ",")
|
||||||
|
if optSplit == nil || len(optSplit) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m = make(map[string]bool)
|
||||||
|
for idx, o := range optSplit {
|
||||||
|
if idx == 0 {
|
||||||
|
if tagOpts[TagMapTrim] {
|
||||||
|
o = strings.TrimSpace(o)
|
||||||
|
}
|
||||||
|
value = o
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if tagOpts[TagMapTrim] {
|
||||||
|
o = strings.TrimSpace(o)
|
||||||
|
}
|
||||||
|
m[o] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
TagToMixedMap combines TagToBoolMap and TagToStringMap.
|
||||||
|
It takes struct field `field` and tag name `tagName`,
|
||||||
|
and returns all single-value options in mapBool, and all key/value options in mapString.
|
||||||
|
|
||||||
|
If field does not have tag tagName, m will be nil.
|
||||||
|
|
||||||
|
See the TagMap* constants for opts.
|
||||||
|
*/
|
||||||
|
func TagToMixedMap(field reflect.StructField, tagName string, opts ...tagMapOpt) (mapBool map[string]bool, mapString map[string]string) {
|
||||||
|
|
||||||
|
var s string
|
||||||
|
var valStr string
|
||||||
|
var split []string
|
||||||
|
var kvSplit []string
|
||||||
|
var valSplit []string
|
||||||
|
var k string
|
||||||
|
var v string
|
||||||
|
var tagOpts map[tagMapOpt]bool = getTagMapOpts(opts)
|
||||||
|
|
||||||
|
s = field.Tag.Get(tagName)
|
||||||
|
|
||||||
|
if strings.TrimSpace(s) == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
split = strings.Split(s, ",")
|
||||||
|
if split == nil || len(split) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mapBool = make(map[string]bool)
|
||||||
|
mapString = make(map[string]string)
|
||||||
|
for _, valStr = range split {
|
||||||
|
if strings.Contains(valStr, "=") {
|
||||||
|
kvSplit = strings.SplitN(valStr, "=", 2)
|
||||||
|
if kvSplit == nil || len(kvSplit) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
k = valSplit[0]
|
||||||
|
switch len(valSplit) {
|
||||||
|
case 1:
|
||||||
|
v = ""
|
||||||
|
case 2:
|
||||||
|
v = kvSplit[1]
|
||||||
|
}
|
||||||
|
if tagOpts[TagMapTrim] {
|
||||||
|
k = strings.TrimSpace(k)
|
||||||
|
v = strings.TrimSpace(v)
|
||||||
|
}
|
||||||
|
mapString[k] = v
|
||||||
|
} else {
|
||||||
|
if tagOpts[TagMapTrim] {
|
||||||
|
valStr = strings.TrimSpace(valStr)
|
||||||
|
}
|
||||||
|
mapBool[valStr] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
TagToMixedMapWithValue combines TagToBoolMapWithValue and TagToStringMapWithValue.
|
||||||
|
It takes struct field `field` and tag name `tagName`,
|
||||||
|
and returns all single-value options in mapBool, and all key/value options in mapString
|
||||||
|
along with the first single-value option as value..
|
||||||
|
|
||||||
|
If field does not have tag tagName, m will be nil.
|
||||||
|
|
||||||
|
See the TagMap* constants for opts.
|
||||||
|
*/
|
||||||
|
func TagToMixedMapWithValue(field reflect.StructField, tagName string, opts ...tagMapOpt) (value string, mapBool map[string]bool, mapString map[string]string) {
|
||||||
|
|
||||||
|
var s string
|
||||||
|
var idx int
|
||||||
|
var valStr string
|
||||||
|
var split []string
|
||||||
|
var kvSplit []string
|
||||||
|
var valSplit []string
|
||||||
|
var k string
|
||||||
|
var v string
|
||||||
|
var tagOpts map[tagMapOpt]bool = getTagMapOpts(opts)
|
||||||
|
|
||||||
|
s = field.Tag.Get(tagName)
|
||||||
|
|
||||||
|
if strings.TrimSpace(s) == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
split = strings.Split(s, ",")
|
||||||
|
if split == nil || len(split) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mapBool = make(map[string]bool)
|
||||||
|
mapString = make(map[string]string)
|
||||||
|
for idx, valStr = range split {
|
||||||
|
if idx == 0 {
|
||||||
|
if tagOpts[TagMapTrim] {
|
||||||
|
valStr = strings.TrimSpace(valStr)
|
||||||
|
}
|
||||||
|
value = valStr
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.Contains(valStr, "=") {
|
||||||
|
kvSplit = strings.SplitN(valStr, "=", 2)
|
||||||
|
if kvSplit == nil || len(kvSplit) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
k = valSplit[0]
|
||||||
|
switch len(valSplit) {
|
||||||
|
case 1:
|
||||||
|
v = ""
|
||||||
|
case 2:
|
||||||
|
v = kvSplit[1]
|
||||||
|
}
|
||||||
|
if tagOpts[TagMapTrim] {
|
||||||
|
k = strings.TrimSpace(k)
|
||||||
|
v = strings.TrimSpace(v)
|
||||||
|
}
|
||||||
|
mapString[k] = v
|
||||||
|
} else {
|
||||||
|
if tagOpts[TagMapTrim] {
|
||||||
|
valStr = strings.TrimSpace(valStr)
|
||||||
|
}
|
||||||
|
mapBool[valStr] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
TagToStringMap takes struct field `field` and tag name `tagName`,
|
||||||
|
optionally with options `opts`, and returns a map of the tag values.
|
||||||
|
The tag value string is assumed to be in the form of:
|
||||||
|
key=value[,key=value,key=value...]
|
||||||
|
and returns a map[string]string (map[key]value).
|
||||||
|
It is proccessed in order; later duplicate keys overwrite previous ones.
|
||||||
|
|
||||||
|
If field does not have tag tagName, m will be nil.
|
||||||
|
|
||||||
|
If only a key is provided with no value, the value in the map will be an empty string.
|
||||||
|
(e.g. "foo,bar=baz" => map[string]string{"foo": "", "bar: "baz"}
|
||||||
|
|
||||||
|
See the TagMap* constants for opts.
|
||||||
|
*/
|
||||||
|
func TagToStringMap(field reflect.StructField, tagName string, opts ...tagMapOpt) (m map[string]string) {
|
||||||
|
|
||||||
|
var s string
|
||||||
|
var kvSplit []string
|
||||||
|
var valSplit []string
|
||||||
|
var k string
|
||||||
|
var v string
|
||||||
|
var tagOpts map[tagMapOpt]bool = getTagMapOpts(opts)
|
||||||
|
|
||||||
|
s = field.Tag.Get(tagName)
|
||||||
|
|
||||||
|
if strings.TrimSpace(s) == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
kvSplit = strings.Split(s, ",")
|
||||||
|
if kvSplit == nil || len(kvSplit) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, kv := range kvSplit {
|
||||||
|
valSplit = strings.SplitN(kv, "=", 2)
|
||||||
|
if valSplit == nil || len(valSplit) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
k = valSplit[0]
|
||||||
|
switch len(valSplit) {
|
||||||
|
case 1:
|
||||||
|
v = ""
|
||||||
|
case 2:
|
||||||
|
v = valSplit[1]
|
||||||
|
// It's not possible to have more than 2.
|
||||||
|
}
|
||||||
|
if m == nil {
|
||||||
|
m = make(map[string]string)
|
||||||
|
}
|
||||||
|
if tagOpts[TagMapTrim] {
|
||||||
|
k = strings.TrimSpace(k)
|
||||||
|
v = strings.TrimSpace(v)
|
||||||
|
}
|
||||||
|
m[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
TagToStringMapWithValue is like TagToStringMap but additionally assumes the first value is an "identifier".
|
||||||
|
The tag value string is assumed to be in the form of:
|
||||||
|
value,key=value[,key=value,key=value...]
|
||||||
|
and returns a map[string]string (map[key]value) with the value.
|
||||||
|
*/
|
||||||
|
func TagToStringMapWithValue(field reflect.StructField, tagName string, opts ...tagMapOpt) (value string, m map[string]string) {
|
||||||
|
|
||||||
|
var s string
|
||||||
|
var kvSplit []string
|
||||||
|
var valSplit []string
|
||||||
|
var k string
|
||||||
|
var v string
|
||||||
|
var tagOpts map[tagMapOpt]bool = getTagMapOpts(opts)
|
||||||
|
|
||||||
|
s = field.Tag.Get(tagName)
|
||||||
|
|
||||||
|
if strings.TrimSpace(s) == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
kvSplit = strings.Split(s, ",")
|
||||||
|
if kvSplit == nil || len(kvSplit) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for idx, kv := range kvSplit {
|
||||||
|
if idx == 0 {
|
||||||
|
if tagOpts[TagMapTrim] {
|
||||||
|
kv = strings.TrimSpace(kv)
|
||||||
|
}
|
||||||
|
value = kv
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
valSplit = strings.SplitN(kv, "=", 2)
|
||||||
|
if valSplit == nil || len(valSplit) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
k = valSplit[0]
|
||||||
|
switch len(valSplit) {
|
||||||
|
case 1:
|
||||||
|
v = ""
|
||||||
|
case 2:
|
||||||
|
v = valSplit[1]
|
||||||
|
// It's not possible to have more than 2.
|
||||||
|
}
|
||||||
|
if m == nil {
|
||||||
|
m = make(map[string]string)
|
||||||
|
}
|
||||||
|
if tagOpts[TagMapTrim] {
|
||||||
|
k = strings.TrimSpace(k)
|
||||||
|
v = strings.TrimSpace(v)
|
||||||
|
}
|
||||||
|
m[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTagMapOpts(opts []tagMapOpt) (optMap map[tagMapOpt]bool) {
|
||||||
|
|
||||||
|
optMap = make(map[tagMapOpt]bool)
|
||||||
|
|
||||||
|
if opts == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
5
structutils/types.go
Normal file
5
structutils/types.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package structutils
|
||||||
|
|
||||||
|
type (
|
||||||
|
tagMapOpt uint8
|
||||||
|
)
|
Loading…
x
Reference in New Issue
Block a user