finalizing logging and multierror
This commit is contained in:
parent
3975f8b11f
commit
0e01306637
4
go.mod
4
go.mod
@ -4,5 +4,7 @@ go 1.16
|
||||
|
||||
require (
|
||||
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf
|
||||
r00t2.io/sysutils v0.0.0-20210224054841-55ac47c86928
|
||||
github.com/google/uuid v1.3.0
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e
|
||||
r00t2.io/sysutils v1.1.1
|
||||
)
|
||||
|
9
go.sum
9
go.sum
@ -1,5 +1,8 @@
|
||||
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf h1:iW4rZ826su+pqaw19uhpSCzhj44qo35pNgKFGqzDKkU=
|
||||
github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/jszwec/csvutil v1.5.0/go.mod h1:Rpu7Uu9giO9subDyMCIQfHVDuLrcaC36UA4YcJjGBkg=
|
||||
r00t2.io/sysutils v0.0.0-20210224054841-55ac47c86928 h1:aYEn20eguqsmqT3J9VjkzdhyPwmOVDGzzffcEfV18a4=
|
||||
r00t2.io/sysutils v0.0.0-20210224054841-55ac47c86928/go.mod h1:XzJkBF6SHAODEszJlOcjtGoTHwYnZZNmseA6PyOujes=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
r00t2.io/sysutils v1.1.1 h1:q2P5u50HIIRk6muCPo1Gpapy6sNT4oaB1l2O/C/mi3A=
|
||||
r00t2.io/sysutils v1.1.1/go.mod h1:Wlfi1rrJpoKBOjWiYM9rw2FaiZqraD6VpXyiHgoDo/o=
|
||||
|
@ -5,7 +5,10 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
// logPerm is the octal mode to use for testing the file.
|
||||
logPerm os.FileMode = 0600
|
||||
// logPrefix is the default log prefix.
|
||||
logPrefix string = "GOLANG PROGRAM"
|
||||
appendFlags int = os.O_APPEND|os.O_CREATE|os.O_WRONLY
|
||||
// appendFlags are the flags used for testing the file (and opening/writing).
|
||||
appendFlags int = os.O_APPEND | os.O_CREATE | os.O_WRONLY
|
||||
)
|
||||
|
@ -7,20 +7,28 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
devlog string = "/dev/log"
|
||||
// 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
|
||||
// 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 (
|
||||
// defLogPaths indicates default log paths.
|
||||
defLogPaths = []string{
|
||||
"/var/log/golang/program.log",
|
||||
"~/.local/log/golang/program.log",
|
||||
|
@ -6,24 +6,30 @@ import (
|
||||
`regexp`
|
||||
)
|
||||
|
||||
// Flags for logger configuration
|
||||
// Flags for logger configuration. These are used internally.
|
||||
const (
|
||||
// LogUndefined indicates an undefined Logger type.
|
||||
LogUndefined types.MaskBit = 1 << iota
|
||||
// LogWinLogger indicates a WinLogger Logger type (Event Log).
|
||||
LogWinLogger
|
||||
// LogFile flags a FileLogger Logger type.
|
||||
LogFile
|
||||
// LogStdout flags a StdLogger Logger type.
|
||||
LogStdout
|
||||
)
|
||||
|
||||
var (
|
||||
// defLogPaths indicates default log paths.
|
||||
defLogPaths = []string{
|
||||
filepath.Join(os.Getenv("ALLUSERSPROFILE"), "golang", "program.log"), // C:\ProgramData\log\golang\program.log
|
||||
filepath.Join(os.Getenv("LOCALAPPDATA"), "log", "golang", "program.log"), // C:\Users\<username>\AppData\Local\log\golang\program.log
|
||||
}
|
||||
)
|
||||
|
||||
// ptrnSourceExists is a regex pattern to check for a registry entry (Event Log entry) already existing.
|
||||
var ptrnSourceExists *regexp.Regexp = regexp.MustCompile(`registry\skey\salready\sexists$`)
|
||||
|
||||
// Default WinEventID
|
||||
// Default WinEventID, (can be) used in GetLogger and MultiLogger.AddWinLogger.
|
||||
var DefaultEventID *WinEventID = &WinEventID{
|
||||
Alert: EventAlert,
|
||||
Crit: EventCrit,
|
||||
|
43
logging/doc.go
Normal file
43
logging/doc.go
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
Package logging implements and presents various loggers under a unified interface, making them completely swappable.
|
||||
|
||||
These particular loggers (logging.Logger) available are:
|
||||
|
||||
StdLogger
|
||||
FileLogger
|
||||
SystemDLogger (Linux only)
|
||||
SyslogLogger (Linux 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.
|
||||
|
||||
Every logging.Logger type has the following methods that correspond to certain "levels".
|
||||
|
||||
Alert(s string, v ...interface{}) (err error)
|
||||
Crit(s string, v ...interface{}) (err error)
|
||||
Debug(s string, v ...interface{}) (err error)
|
||||
Emerg(s string, v ...interface{}) (err error)
|
||||
Err(s string, v ...interface{}) (err error)
|
||||
Info(s string, v ...interface{}) (err error)
|
||||
Notice(s string, v ...interface{}) (err error)
|
||||
Warning(s string, v ...interface{}) (err error)
|
||||
|
||||
Not all loggers implement the concept of levels, so approximations are made when/where possible.
|
||||
|
||||
In each of the above methods, s is the message that is optionally in a fmt.Sprintf-compatible format.
|
||||
If it is, the values to fmt.Sprintf can be passed as v.
|
||||
|
||||
Note that in the case of a MultiLogger, err (if not nil) will be a (r00t2.io/goutils/)multierr.MultiError.
|
||||
|
||||
logging.Logger types also have the following methods:
|
||||
|
||||
DoDebug(d bool)
|
||||
SetPrefix(p string)
|
||||
GetPrefix() (p string)
|
||||
Setup()
|
||||
Shutdown()
|
||||
|
||||
In some cases, Logger.Setup and Logger.Shutdown are no-ops. In other cases, they perform necessary initialization/cleanup and closing of the logger.
|
||||
It is recommended to *always* run Setup and Shutdown before and after using, respectively, regardless of the actual logging.Logger type.
|
||||
*/
|
||||
package logging
|
17
logging/errs.go
Normal file
17
logging/errs.go
Normal file
@ -0,0 +1,17 @@
|
||||
package logging
|
||||
|
||||
import (
|
||||
`errors`
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrExistingLogger indicates that the user attempted to add a Logger to a MultiLogger using an already-existing identifier.
|
||||
ErrExistingLogger error = errors.New("a Logger with that identifier already exists; please remove it first")
|
||||
/*
|
||||
ErrInvalidFile indicates that the user attempted to add a FileLogger to a MultiLogger but the file doesn't exist,
|
||||
exists with too restrictive perms to write/append to, and/or could not be created.
|
||||
*/
|
||||
ErrInvalidFile error = errors.New("a FileLogger was requested but the file does not exist and cannot be created")
|
||||
// ErrNoEntry indicates that the user attempted to MultiLogger.RemoveLogger a Logger but one by that identifier does not exist.
|
||||
ErrNoEntry error = errors.New("the Logger specified to be removed does not exist")
|
||||
)
|
18
logging/errs_linux.go
Normal file
18
logging/errs_linux.go
Normal file
@ -0,0 +1,18 @@
|
||||
package logging
|
||||
|
||||
import (
|
||||
`errors`
|
||||
`fmt`
|
||||
)
|
||||
|
||||
var (
|
||||
// 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")
|
||||
// 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))
|
||||
)
|
@ -4,6 +4,7 @@ import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// testOpen attempts to open a file for writing to test for suitability as a LogFile path.
|
||||
func testOpen(path string) (success bool, err error) {
|
||||
var f *os.File
|
||||
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// Setup sets up/configures a FileLogger and prepares it for use.
|
||||
func (l *FileLogger) Setup() {
|
||||
|
||||
var err error
|
||||
@ -21,6 +22,7 @@ func (l *FileLogger) Setup() {
|
||||
l.Logger.SetOutput(multi)
|
||||
}
|
||||
|
||||
// Shutdown cleanly shuts down a FileLogger.
|
||||
func (l *FileLogger) Shutdown() {
|
||||
|
||||
var err error
|
||||
@ -31,19 +33,26 @@ func (l *FileLogger) Shutdown() {
|
||||
|
||||
}
|
||||
|
||||
// GetPrefix returns the prefix used by this FileLogger.
|
||||
func (l *FileLogger) GetPrefix() string {
|
||||
return l.Prefix
|
||||
}
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
func (l *FileLogger) DoDebug(d bool) {
|
||||
l.EnableDebug = d
|
||||
}
|
||||
|
||||
// SetPrefix sets the prefix for this FileLogger.
|
||||
func (l *FileLogger) SetPrefix(prefix string) {
|
||||
l.Prefix = prefix
|
||||
l.Logger.SetPrefix(prefix)
|
||||
}
|
||||
|
||||
// Alert writes an ALERT-level message to this FileLogger.
|
||||
func (l *FileLogger) Alert(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
@ -59,6 +68,7 @@ func (l *FileLogger) Alert(s string, v ...interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Crit writes an CRITICAL-level message to this FileLogger.
|
||||
func (l *FileLogger) Crit(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
@ -74,6 +84,7 @@ func (l *FileLogger) Crit(s string, v ...interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Debug writes a DEBUG-level message to this FileLogger.
|
||||
func (l *FileLogger) Debug(s string, v ...interface{}) (err error) {
|
||||
|
||||
if !l.EnableDebug {
|
||||
@ -93,6 +104,7 @@ func (l *FileLogger) Debug(s string, v ...interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Emerg writes an EMERGENCY-level message to this FileLogger.
|
||||
func (l *FileLogger) Emerg(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
@ -108,6 +120,7 @@ func (l *FileLogger) Emerg(s string, v ...interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Err writes an ERROR-level message to this FileLogger.
|
||||
func (l *FileLogger) Err(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
@ -123,6 +136,7 @@ func (l *FileLogger) Err(s string, v ...interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Info writes an INFO-level message to this FileLogger.
|
||||
func (l *FileLogger) Info(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
@ -138,6 +152,7 @@ func (l *FileLogger) Info(s string, v ...interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Notice writes a NOTICE-level message to this FileLogger.
|
||||
func (l *FileLogger) Notice(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
@ -153,6 +168,7 @@ func (l *FileLogger) Notice(s string, v ...interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Warning writes a WARNING/WARN-level message to this FileLogger.
|
||||
func (l *FileLogger) Warning(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
@ -168,6 +184,7 @@ func (l *FileLogger) Warning(s string, v ...interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// renderWrite prepares/formats a log message to be written to this FileLogger.
|
||||
func (l *FileLogger) renderWrite(msg, prio string) {
|
||||
|
||||
s := fmt.Sprintf("[%v] %v", prio, msg)
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
`path`
|
||||
|
||||
sysd `github.com/coreos/go-systemd/journal`
|
||||
`r00t2.io/goutils/bitmask`
|
||||
`r00t2.io/sysutils/paths`
|
||||
)
|
||||
|
||||
@ -17,16 +18,24 @@ var (
|
||||
|
||||
/*
|
||||
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.
|
||||
|
||||
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, logPaths ...string) (logger Logger, err error) {
|
||||
|
||||
var logPath string
|
||||
var logFlags types.MaskBit
|
||||
var logFlags bitmask.MaskBit
|
||||
|
||||
// Configure system-supported logger(s).
|
||||
if sysd.Enabled() {
|
||||
@ -67,7 +76,7 @@ func GetLogger(enableDebug bool, prefix string, logPaths ...string) (logger Logg
|
||||
break
|
||||
} else {
|
||||
dirPath := path.Dir(p)
|
||||
if err = paths.MakeDirIfNotExist(&dirPath); err != nil {
|
||||
if err = paths.MakeDirIfNotExist(dirPath); err != nil {
|
||||
continue
|
||||
}
|
||||
if success, err = testOpen(p); err != nil {
|
||||
|
275
logging/funcs_multilogger.go
Normal file
275
logging/funcs_multilogger.go
Normal file
@ -0,0 +1,275 @@
|
||||
package logging
|
||||
|
||||
import (
|
||||
`sync`
|
||||
|
||||
`r00t2.io/goutils/multierr`
|
||||
)
|
||||
|
||||
// Setup sets up/configures a MultiLogger (and all its MultiLogger.Loggers) and prepares it for use.
|
||||
func (m *MultiLogger) Setup() {
|
||||
|
||||
var wg sync.WaitGroup
|
||||
|
||||
for _, l := range m.Loggers {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
l.Setup()
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
// Shutdown cleanly shuts down a MultiLogger (and all its MultiLogger.Loggers).
|
||||
func (m *MultiLogger) Shutdown() {
|
||||
|
||||
var wg sync.WaitGroup
|
||||
|
||||
for _, l := range m.Loggers {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
l.Shutdown()
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
// GetPrefix returns the prefix used by this MultiLogger (and all its MultiLogger.Loggers).
|
||||
func (m *MultiLogger) GetPrefix() string {
|
||||
|
||||
return m.Prefix
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
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.
|
||||
|
||||
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) {
|
||||
|
||||
var wg sync.WaitGroup
|
||||
|
||||
m.EnableDebug = d
|
||||
|
||||
for _, l := range m.Loggers {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
l.DoDebug(d)
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
/*
|
||||
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) {
|
||||
|
||||
var wg sync.WaitGroup
|
||||
|
||||
m.Prefix = prefix
|
||||
|
||||
for _, l := range m.Loggers {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
l.SetPrefix(prefix)
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
// Alert writes an ALERT-level message to this MultiLogger (and all its MultiLogger.Loggers).
|
||||
func (m *MultiLogger) Alert(s string, v ...interface{}) (err error) {
|
||||
|
||||
var wg sync.WaitGroup
|
||||
var e *multierr.MultiError = multierr.NewMultiError(nil)
|
||||
|
||||
for _, l := range m.Loggers {
|
||||
wg.Add(1)
|
||||
go func(logObj Logger, msg string, rplc ...interface{}) {
|
||||
if err = logObj.Alert(msg, rplc...); err != nil {
|
||||
e.AddError(err)
|
||||
err = nil
|
||||
}
|
||||
}(l, s, v)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
err = e
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Crit writes an CRITICAL-level message to this MultiLogger (and all its MultiLogger.Loggers).
|
||||
func (m *MultiLogger) Crit(s string, v ...interface{}) (err error) {
|
||||
|
||||
var wg sync.WaitGroup
|
||||
var e *multierr.MultiError = multierr.NewMultiError(nil)
|
||||
|
||||
for _, l := range m.Loggers {
|
||||
wg.Add(1)
|
||||
go func(logObj Logger, msg string, rplc ...interface{}) {
|
||||
if err = logObj.Crit(msg, rplc...); err != nil {
|
||||
e.AddError(err)
|
||||
err = nil
|
||||
}
|
||||
}(l, s, v)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
err = e
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Debug writes a DEBUG-level message to this MultiLogger (and all its MultiLogger.Loggers).
|
||||
func (m *MultiLogger) Debug(s string, v ...interface{}) (err error) {
|
||||
|
||||
var wg sync.WaitGroup
|
||||
var e *multierr.MultiError = multierr.NewMultiError(nil)
|
||||
|
||||
for _, l := range m.Loggers {
|
||||
wg.Add(1)
|
||||
go func(logObj Logger, msg string, rplc ...interface{}) {
|
||||
if err = logObj.Debug(msg, rplc...); err != nil {
|
||||
e.AddError(err)
|
||||
err = nil
|
||||
}
|
||||
}(l, s, v)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
err = e
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Emerg writes an EMERGENCY-level message to this MultiLogger (and all its MultiLogger.Loggers).
|
||||
func (m *MultiLogger) Emerg(s string, v ...interface{}) (err error) {
|
||||
|
||||
var wg sync.WaitGroup
|
||||
var e *multierr.MultiError = multierr.NewMultiError(nil)
|
||||
|
||||
for _, l := range m.Loggers {
|
||||
wg.Add(1)
|
||||
go func(logObj Logger, msg string, rplc ...interface{}) {
|
||||
if err = logObj.Emerg(msg, rplc...); err != nil {
|
||||
e.AddError(err)
|
||||
err = nil
|
||||
}
|
||||
}(l, s, v)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
err = e
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Err writes an ERROR-level message to this MultiLogger (and all its MultiLogger.Loggers).
|
||||
func (m *MultiLogger) Err(s string, v ...interface{}) (err error) {
|
||||
|
||||
var wg sync.WaitGroup
|
||||
var e *multierr.MultiError = multierr.NewMultiError(nil)
|
||||
|
||||
for _, l := range m.Loggers {
|
||||
wg.Add(1)
|
||||
go func(logObj Logger, msg string, rplc ...interface{}) {
|
||||
if err = logObj.Err(msg, rplc...); err != nil {
|
||||
e.AddError(err)
|
||||
err = nil
|
||||
}
|
||||
}(l, s, v)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
err = e
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Info writes an INFO-level message to this MultiLogger (and all its MultiLogger.Loggers).
|
||||
func (m *MultiLogger) Info(s string, v ...interface{}) (err error) {
|
||||
|
||||
var wg sync.WaitGroup
|
||||
var e *multierr.MultiError = multierr.NewMultiError(nil)
|
||||
|
||||
for _, l := range m.Loggers {
|
||||
wg.Add(1)
|
||||
go func(logObj Logger, msg string, rplc ...interface{}) {
|
||||
if err = logObj.Info(msg, rplc...); err != nil {
|
||||
e.AddError(err)
|
||||
err = nil
|
||||
}
|
||||
}(l, s, v)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
err = e
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Notice writes a NOTICE-level message to this MultiLogger (and all its MultiLogger.Loggers).
|
||||
func (m *MultiLogger) Notice(s string, v ...interface{}) (err error) {
|
||||
|
||||
var wg sync.WaitGroup
|
||||
var e *multierr.MultiError = multierr.NewMultiError(nil)
|
||||
|
||||
for _, l := range m.Loggers {
|
||||
wg.Add(1)
|
||||
go func(logObj Logger, msg string, rplc ...interface{}) {
|
||||
if err = logObj.Notice(msg, rplc...); err != nil {
|
||||
e.AddError(err)
|
||||
err = nil
|
||||
}
|
||||
}(l, s, v)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
err = e
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Warning writes a WARNING/WARN-level message to this MultiLogger (and all its MultiLogger.Loggers).
|
||||
func (m *MultiLogger) Warning(s string, v ...interface{}) (err error) {
|
||||
|
||||
var wg sync.WaitGroup
|
||||
var e *multierr.MultiError = multierr.NewMultiError(nil)
|
||||
|
||||
for _, l := range m.Loggers {
|
||||
wg.Add(1)
|
||||
go func(logObj Logger, msg string, rplc ...interface{}) {
|
||||
if err = logObj.Warning(msg, rplc...); err != nil {
|
||||
e.AddError(err)
|
||||
err = nil
|
||||
}
|
||||
}(l, s, v)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
err = e
|
||||
|
||||
return
|
||||
}
|
133
logging/funcs_multilogger_mgr.go
Normal file
133
logging/funcs_multilogger_mgr.go
Normal file
@ -0,0 +1,133 @@
|
||||
package logging
|
||||
|
||||
import (
|
||||
`path`
|
||||
|
||||
`github.com/google/uuid`
|
||||
`r00t2.io/sysutils/paths`
|
||||
)
|
||||
|
||||
/*
|
||||
GetMultiLogger returns a MultiLogger.
|
||||
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.
|
||||
|
||||
Remember to add at least one Logger (e.g. MultiLogger.AddStdLogger), otherwise no entries will actually be logged.
|
||||
|
||||
If you want to modify e.g. if debug is enabled for a specific Logger, reference the Logger directly (e.g. MultiLogger.Loggers[identifier].SetDebug(false)).
|
||||
*/
|
||||
func GetMultiLogger(enableDebug bool, prefix string) (m *MultiLogger) {
|
||||
|
||||
m = &MultiLogger{
|
||||
EnableDebug: enableDebug,
|
||||
Prefix: "",
|
||||
Loggers: make(map[string]Logger),
|
||||
}
|
||||
if prefix != "\x00" {
|
||||
m.Prefix = prefix
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
AddStdLogger adds a StdLogger to a MultiLogger.
|
||||
|
||||
identifier is a string to use to identify the added StdLogger in MultiLogger.Loggers.
|
||||
If empty, one will be automatically generated.
|
||||
*/
|
||||
func (m *MultiLogger) AddStdLogger(identifier string) (err error) {
|
||||
|
||||
var exists bool
|
||||
|
||||
if identifier == "" {
|
||||
identifier = uuid.New().String()
|
||||
}
|
||||
|
||||
if _, exists = m.Loggers[identifier]; exists {
|
||||
err = ErrExistingLogger
|
||||
return
|
||||
}
|
||||
|
||||
m.Loggers[identifier] = &StdLogger{
|
||||
Logger: nil,
|
||||
EnableDebug: m.EnableDebug,
|
||||
Prefix: m.Prefix,
|
||||
}
|
||||
m.Loggers[identifier].Setup()
|
||||
|
||||
m.Loggers[identifier].Info("logger initialized of type %T with prefix %v", m.Loggers[identifier], m.Loggers[identifier].GetPrefix())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
AddFileLogger adds a FileLogger to a MultiLogger.
|
||||
|
||||
identifier is a string to use to identify the added FileLogger in MultiLogger.Loggers.
|
||||
If empty, one will be automatically generated.
|
||||
|
||||
logfilePath is a string for the path to the desired logfile.
|
||||
*/
|
||||
func (m *MultiLogger) AddFileLogger(identifier, logfilePath string) (err error) {
|
||||
|
||||
var exists bool
|
||||
var success bool
|
||||
var dirPath string
|
||||
|
||||
if identifier == "" {
|
||||
identifier = uuid.New().String()
|
||||
}
|
||||
|
||||
if _, exists = m.Loggers[identifier]; exists {
|
||||
err = ErrExistingLogger
|
||||
return
|
||||
}
|
||||
|
||||
if exists, _ = paths.RealPathExists(&logfilePath); !exists {
|
||||
if success, err = testOpen(logfilePath); err != nil {
|
||||
return
|
||||
} else if !success {
|
||||
dirPath = path.Dir(logfilePath)
|
||||
if err = paths.MakeDirIfNotExist(dirPath); err != nil {
|
||||
return
|
||||
}
|
||||
if success, err = testOpen(dirPath); err != nil {
|
||||
return
|
||||
} else if !success {
|
||||
err = ErrInvalidFile
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m.Loggers[identifier] = &FileLogger{
|
||||
StdLogger: StdLogger{
|
||||
Logger: nil,
|
||||
EnableDebug: m.EnableDebug,
|
||||
Prefix: m.Prefix,
|
||||
},
|
||||
Path: logfilePath,
|
||||
}
|
||||
m.Loggers[identifier].Setup()
|
||||
|
||||
m.Loggers[identifier].Info("logger initialized of type %T with prefix %v", m.Loggers[identifier], m.Loggers[identifier].GetPrefix())
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// RemoveLogger will let you remove a Logger from MultiLogger.Loggers.
|
||||
func (m *MultiLogger) RemoveLogger(identifier string) (err error) {
|
||||
|
||||
var exists bool
|
||||
|
||||
if _, exists = m.Loggers[identifier]; !exists {
|
||||
err = ErrNoEntry
|
||||
return
|
||||
}
|
||||
|
||||
delete(m.Loggers, identifier)
|
||||
|
||||
return
|
||||
}
|
118
logging/funcs_multilogger_mgr_linux.go
Normal file
118
logging/funcs_multilogger_mgr_linux.go
Normal file
@ -0,0 +1,118 @@
|
||||
package logging
|
||||
|
||||
import (
|
||||
`os`
|
||||
|
||||
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.
|
||||
|
||||
identifier is a string to use to identify the added Logger in MultiLogger.Loggers.
|
||||
If empty, one will be automatically generated.
|
||||
*/
|
||||
func (m *MultiLogger) AddDefaultLogger(identifier string, 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, logPaths...); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
m.Loggers[identifier] = l
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
AddSysdLogger adds a SystemDLogger to a MultiLogger.
|
||||
|
||||
identifier is a string to use to identify the added SystemDLogger in MultiLogger.Loggers.
|
||||
If empty, one will be automatically generated.
|
||||
*/
|
||||
func (m *MultiLogger) AddSysdLogger(identifier string) (err error) {
|
||||
|
||||
var exists bool
|
||||
|
||||
if identifier == "" {
|
||||
identifier = uuid.New().String()
|
||||
}
|
||||
|
||||
if _, exists = m.Loggers[identifier]; exists {
|
||||
err = ErrExistingLogger
|
||||
return
|
||||
}
|
||||
|
||||
if !sysd.Enabled() {
|
||||
err = ErrNoSysD
|
||||
return
|
||||
}
|
||||
|
||||
m.Loggers[identifier] = &SystemDLogger{
|
||||
EnableDebug: m.EnableDebug,
|
||||
Prefix: m.Prefix,
|
||||
}
|
||||
m.Loggers[identifier].Setup()
|
||||
|
||||
m.Loggers[identifier].Info("logger initialized of type %T with prefix %v", m.Loggers[identifier], m.Loggers[identifier].GetPrefix())
|
||||
|
||||
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
|
||||
|
||||
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,
|
||||
}
|
||||
m.Loggers[identifier].Setup()
|
||||
|
||||
m.Loggers[identifier].Info("logger initialized of type %T with prefix %v", m.Loggers[identifier], m.Loggers[identifier].GetPrefix())
|
||||
|
||||
return
|
||||
}
|
84
logging/funcs_multilogger_mgr_windows.go
Normal file
84
logging/funcs_multilogger_mgr_windows.go
Normal file
@ -0,0 +1,84 @@
|
||||
package logging
|
||||
|
||||
/*
|
||||
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.
|
||||
|
||||
A pointer to a WinEventID struct may be specified for eventIDs to map extended logging levels (as Windows only supports three levels natively).
|
||||
If it is nil, a default one (DefaultEventID) will be used.
|
||||
|
||||
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.
|
||||
Currently this will almost always return a WinLogger.
|
||||
*/
|
||||
func (m *MultiLogger) AddDefaultLogger(identifier string, eventIDs *WinEventID) (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, eventIDs, logPaths...); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
m.Loggers[identifier] = l
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
AddWinLogger adds a WinLogger to a MultiLogger. Note that this is a VERY generalized interface to the Windows Event Log.
|
||||
|
||||
If you require more robust logging capabilities (e.g. custom event IDs per uniquely identifiable event),
|
||||
you will want to set up your own logger (golang.org/x/sys/windows/svc/eventlog).
|
||||
|
||||
identifier is a string to use to identify the added WinLogger in MultiLogger.Loggers.
|
||||
If empty, one will be automatically generated.
|
||||
|
||||
A blank source will return an error as it's used as the source name. Other functions, struct fields, etc. will refer to this as the "prefix".
|
||||
|
||||
A pointer to a WinEventID struct may be specified for eventIDs to map extended logging levels (as Windows only supports three levels natively).
|
||||
If it is nil, a default one (DefaultEventID) will be used.
|
||||
|
||||
See GetLogger for details.
|
||||
*/
|
||||
func (m *MultiLogger) AddWinLogger(identifier, source string, eventIDs *WinEventID) (err error) {
|
||||
|
||||
var exists bool
|
||||
|
||||
if identifier == "" {
|
||||
identifier = uuid.New().String()
|
||||
}
|
||||
|
||||
if _, exists = m.Loggers[identifier]; exists {
|
||||
err = ErrExistingLogger
|
||||
return
|
||||
}
|
||||
|
||||
if eventIDs == nil {
|
||||
eventIDs = DefaultEventID
|
||||
}
|
||||
|
||||
m.Loggers[identifier] = &WinLogger{
|
||||
Prefix: source,
|
||||
EnableDebug: m.EnableDebug,
|
||||
eids: eventIDs,
|
||||
}
|
||||
m.Loggers[identifier].Setup()
|
||||
|
||||
m.Loggers[identifier].Info("logger initialized of type %T with prefix %v", m.Loggers[identifier], m.Loggers[identifier].GetPrefix())
|
||||
|
||||
return
|
||||
}
|
@ -5,12 +5,14 @@ import (
|
||||
"log"
|
||||
)
|
||||
|
||||
// Setup sets up/configures a StdLogger and prepares it for use.
|
||||
func (l *StdLogger) Setup() {
|
||||
|
||||
l.Logger = log.Default()
|
||||
l.Logger.SetPrefix(l.Prefix)
|
||||
}
|
||||
|
||||
// Shutdown cleanly shuts down a StdLogger.
|
||||
func (l *StdLogger) Shutdown() {
|
||||
|
||||
// NOOP
|
||||
@ -18,15 +20,7 @@ func (l *StdLogger) Shutdown() {
|
||||
|
||||
}
|
||||
|
||||
func (l *StdLogger) DoDebug(d bool) {
|
||||
l.EnableDebug = d
|
||||
}
|
||||
|
||||
func (l *StdLogger) SetPrefix(prefix string) {
|
||||
l.Prefix = prefix
|
||||
l.Logger.SetPrefix(prefix)
|
||||
}
|
||||
|
||||
// GetPrefix returns the prefix used by this StdLogger.
|
||||
func (l *StdLogger) GetPrefix() (prefix string) {
|
||||
|
||||
prefix = l.Prefix
|
||||
@ -34,6 +28,21 @@ func (l *StdLogger) GetPrefix() (prefix string) {
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
func (l *StdLogger) DoDebug(d bool) {
|
||||
l.EnableDebug = d
|
||||
}
|
||||
|
||||
// SetPrefix sets the prefix for this StdLogger.
|
||||
func (l *StdLogger) SetPrefix(prefix string) {
|
||||
l.Prefix = prefix
|
||||
l.Logger.SetPrefix(prefix)
|
||||
}
|
||||
|
||||
// Alert writes an ALERT-level message to this StdLogger.
|
||||
func (l *StdLogger) Alert(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
@ -49,6 +58,7 @@ func (l *StdLogger) Alert(s string, v ...interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Crit writes an CRITICAL-level message to this StdLogger.
|
||||
func (l *StdLogger) Crit(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
@ -64,6 +74,7 @@ func (l *StdLogger) Crit(s string, v ...interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Debug writes a DEBUG-level message to this StdLogger.
|
||||
func (l *StdLogger) Debug(s string, v ...interface{}) (err error) {
|
||||
|
||||
if !l.EnableDebug {
|
||||
@ -83,6 +94,7 @@ func (l *StdLogger) Debug(s string, v ...interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Emerg writes an EMERGENCY-level message to this StdLogger.
|
||||
func (l *StdLogger) Emerg(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
@ -98,6 +110,7 @@ func (l *StdLogger) Emerg(s string, v ...interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Err writes an ERROR-level message to this StdLogger.
|
||||
func (l *StdLogger) Err(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
@ -113,6 +126,7 @@ func (l *StdLogger) Err(s string, v ...interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Info writes an INFO-level message to this StdLogger.
|
||||
func (l *StdLogger) Info(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
@ -128,6 +142,7 @@ func (l *StdLogger) Info(s string, v ...interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Notice writes a NOTICE-level message to this StdLogger.
|
||||
func (l *StdLogger) Notice(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
@ -143,6 +158,7 @@ func (l *StdLogger) Notice(s string, v ...interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Warning writes a WARNING/WARN-level message to this StdLogger.
|
||||
func (l *StdLogger) Warning(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
@ -158,6 +174,7 @@ func (l *StdLogger) Warning(s string, v ...interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// renderWrite prepares/formats a log message to be written to this StdLogger.
|
||||
func (l *StdLogger) renderWrite(msg, prio string) {
|
||||
|
||||
s := fmt.Sprintf("[%v] %v", prio, msg)
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"github.com/coreos/go-systemd/journal"
|
||||
)
|
||||
|
||||
// Setup sets up/configures a SystemDLogger and prepares it for use.
|
||||
func (l *SystemDLogger) Setup() {
|
||||
|
||||
// NOOP
|
||||
@ -14,6 +15,7 @@ func (l *SystemDLogger) Setup() {
|
||||
|
||||
}
|
||||
|
||||
// Shutdown cleanly shuts down a SystemDLogger.
|
||||
func (l *SystemDLogger) Shutdown() {
|
||||
|
||||
// NOOP
|
||||
@ -21,14 +23,7 @@ func (l *SystemDLogger) Shutdown() {
|
||||
|
||||
}
|
||||
|
||||
func (l *SystemDLogger) DoDebug(d bool) {
|
||||
l.EnableDebug = d
|
||||
}
|
||||
|
||||
func (l *SystemDLogger) SetPrefix(prefix string) {
|
||||
l.Prefix = prefix
|
||||
}
|
||||
|
||||
// GetPrefix returns the prefix used by this SystemDLogger.
|
||||
func (l *SystemDLogger) GetPrefix() (prefix string) {
|
||||
|
||||
prefix = l.Prefix
|
||||
@ -36,6 +31,20 @@ func (l *SystemDLogger) GetPrefix() (prefix string) {
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
func (l *SystemDLogger) DoDebug(d bool) {
|
||||
l.EnableDebug = d
|
||||
}
|
||||
|
||||
// SetPrefix sets the prefix for this SystemDLogger.
|
||||
func (l *SystemDLogger) SetPrefix(prefix string) {
|
||||
l.Prefix = prefix
|
||||
}
|
||||
|
||||
// Alert writes an ALERT-level message to this SystemDLogger.
|
||||
func (l *SystemDLogger) Alert(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
@ -51,6 +60,7 @@ func (l *SystemDLogger) Alert(s string, v ...interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Crit writes an CRITICAL-level message to this SystemDLogger.
|
||||
func (l *SystemDLogger) Crit(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
@ -66,6 +76,7 @@ func (l *SystemDLogger) Crit(s string, v ...interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Debug writes a DEBUG-level message to this SystemDLogger.
|
||||
func (l *SystemDLogger) Debug(s string, v ...interface{}) (err error) {
|
||||
|
||||
if !l.EnableDebug {
|
||||
@ -85,6 +96,7 @@ func (l *SystemDLogger) Debug(s string, v ...interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Emerg writes an EMERGENCY-level message to this SystemDLogger.
|
||||
func (l *SystemDLogger) Emerg(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
@ -100,6 +112,7 @@ func (l *SystemDLogger) Emerg(s string, v ...interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Err writes an ERROR-level message to this SystemDLogger.
|
||||
func (l *SystemDLogger) Err(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
@ -115,6 +128,7 @@ func (l *SystemDLogger) Err(s string, v ...interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Info writes an INFO-level message to this SystemDLogger.
|
||||
func (l *SystemDLogger) Info(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
@ -130,6 +144,7 @@ func (l *SystemDLogger) Info(s string, v ...interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Notice writes a NOTICE-level message to this SystemDLogger.
|
||||
func (l *SystemDLogger) Notice(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
@ -145,6 +160,7 @@ func (l *SystemDLogger) Notice(s string, v ...interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Warning writes a WARNING/WARN-level message to this SystemDLogger.
|
||||
func (l *SystemDLogger) Warning(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
@ -160,6 +176,7 @@ func (l *SystemDLogger) Warning(s string, v ...interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// renderWrite prepares/formats a log message to be written to this SystemDLogger.
|
||||
func (l *SystemDLogger) renderWrite(msg string, prio journal.Priority) {
|
||||
|
||||
// TODO: implement code line, etc.
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"log/syslog"
|
||||
)
|
||||
|
||||
// Setup sets up/configures a SyslogLogger and prepares it for use.
|
||||
func (l *SyslogLogger) Setup() {
|
||||
|
||||
var err error
|
||||
@ -37,6 +38,7 @@ func (l *SyslogLogger) Setup() {
|
||||
|
||||
}
|
||||
|
||||
// Shutdown cleanly shuts down a SyslogLogger.
|
||||
func (l *SyslogLogger) Shutdown() {
|
||||
|
||||
var err error
|
||||
@ -49,15 +51,7 @@ func (l *SyslogLogger) Shutdown() {
|
||||
|
||||
}
|
||||
|
||||
func (l *SyslogLogger) DoDebug(d bool) {
|
||||
l.EnableDebug = d
|
||||
}
|
||||
|
||||
func (l *SyslogLogger) SetPrefix(prefix string) {
|
||||
l.Prefix = prefix
|
||||
l.Setup()
|
||||
}
|
||||
|
||||
// GetPrefix returns the prefix used by this SyslogLogger.
|
||||
func (l *SyslogLogger) GetPrefix() (prefix string) {
|
||||
|
||||
prefix = l.Prefix
|
||||
@ -65,6 +59,21 @@ func (l *SyslogLogger) GetPrefix() (prefix string) {
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
func (l *SyslogLogger) DoDebug(d bool) {
|
||||
l.EnableDebug = d
|
||||
}
|
||||
|
||||
// SetPrefix sets the prefix for this SyslogLogger.
|
||||
func (l *SyslogLogger) SetPrefix(prefix string) {
|
||||
l.Prefix = prefix
|
||||
l.Setup()
|
||||
}
|
||||
|
||||
// Alert writes an ALERT-level message to this SyslogLogger.
|
||||
func (l *SyslogLogger) Alert(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
@ -82,6 +91,7 @@ func (l *SyslogLogger) Alert(s string, v ...interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Crit writes an CRITICAL-level message to this SyslogLogger.
|
||||
func (l *SyslogLogger) Crit(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
@ -99,6 +109,7 @@ func (l *SyslogLogger) Crit(s string, v ...interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Debug writes a DEBUG-level message to this SyslogLogger.
|
||||
func (l *SyslogLogger) Debug(s string, v ...interface{}) (err error) {
|
||||
|
||||
if !l.EnableDebug {
|
||||
@ -120,6 +131,7 @@ func (l *SyslogLogger) Debug(s string, v ...interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Emerg writes an EMERGENCY-level message to this SyslogLogger.
|
||||
func (l *SyslogLogger) Emerg(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
@ -137,6 +149,7 @@ func (l *SyslogLogger) Emerg(s string, v ...interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Err writes an ERROR-level message to this SyslogLogger.
|
||||
func (l *SyslogLogger) Err(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
@ -154,6 +167,7 @@ func (l *SyslogLogger) Err(s string, v ...interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Info writes an INFO-level message to this SyslogLogger.
|
||||
func (l *SyslogLogger) Info(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
@ -171,6 +185,7 @@ func (l *SyslogLogger) Info(s string, v ...interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Notice writes a NOTICE-level message to this SyslogLogger.
|
||||
func (l *SyslogLogger) Notice(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
@ -188,6 +203,7 @@ func (l *SyslogLogger) Notice(s string, v ...interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Warning writes a WARNING/WARN-level message to this SyslogLogger.
|
||||
func (l *SyslogLogger) Warning(s string, v ...interface{}) (err error) {
|
||||
var msg string
|
||||
|
||||
|
@ -7,21 +7,31 @@ import (
|
||||
|
||||
/*
|
||||
GetLogger returns an instance of Logger that best suits your system's capabilities. Note that this is a VERY generalized interface to the Windows Event Log.
|
||||
|
||||
If you require more robust logging capabilities (e.g. custom event IDs per uniquely identifiable event),
|
||||
you will want to set up your own logger (golang.org/x/sys/windows/svc/eventlog).
|
||||
|
||||
If enableDebug is true, debug messages (which according to your program may or may not contain sensitive data) are rendered and written (otherwise they are ignored).
|
||||
|
||||
A blank source will return an error as it's used as the source name. Other functions, struct fields, etc. will refer to this as the "prefix".
|
||||
|
||||
A pointer to a WinEventID struct may be specified for eventIDs to map extended logging levels (as Windows only supports three levels natively).
|
||||
If it is nil, a default one (DefaultEventID) will be used.
|
||||
|
||||
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.
|
||||
Currently this will almost always return a WinLogger until multiple logging destination support is added.
|
||||
Currently this will almost always return a WinLogger.
|
||||
|
||||
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, source string, eventIDs *WinEventID, logPaths ...string) (logger Logger, err error) {
|
||||
|
||||
var logPath string
|
||||
var logFlags types.MaskBit
|
||||
var logFlags bitmask.MaskBit
|
||||
var exists bool
|
||||
var success bool
|
||||
var ckLogPaths []string
|
||||
@ -53,7 +63,7 @@ func GetLogger(enableDebug bool, source string, eventIDs *WinEventID, logPaths .
|
||||
break
|
||||
} else {
|
||||
dirPath := path.Dir(p)
|
||||
if err = paths.MakeDirIfNotExist(&dirPath); err != nil {
|
||||
if err = paths.MakeDirIfNotExist(dirPath); err != nil {
|
||||
continue
|
||||
}
|
||||
if success, err = testOpen(p); err != nil {
|
||||
|
@ -2,8 +2,11 @@ package logging
|
||||
|
||||
import (
|
||||
`errors`
|
||||
|
||||
`golang.org/x/sys/windows/svc/eventlog`
|
||||
)
|
||||
|
||||
// Setup sets up/configures a WinLogger and prepares it for use.
|
||||
func (l *WinLogger) Setup() {
|
||||
|
||||
var err error
|
||||
@ -44,6 +47,7 @@ func (l *WinLogger) Setup() {
|
||||
|
||||
}
|
||||
|
||||
// Shutdown cleanly shuts down a WinLogger.
|
||||
func (l *WinLogger) Shutdown() {
|
||||
|
||||
var err error
|
||||
@ -58,12 +62,25 @@ func (l *WinLogger) Shutdown() {
|
||||
|
||||
}
|
||||
|
||||
// GetPrefix returns the prefix used by this WinLogger.
|
||||
func (l *WinLogger) GetPrefix() (prefix string) {
|
||||
|
||||
prefix = l.Prefix
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
func (l *WinLogger) DoDebug(d bool) {
|
||||
|
||||
l.EnableDebug = d
|
||||
|
||||
}
|
||||
|
||||
// SetPrefix sets the prefix for this WinLogger.
|
||||
func (l *WinLogger) SetPrefix(prefix string) {
|
||||
|
||||
var err error
|
||||
@ -95,13 +112,7 @@ func (l *WinLogger) SetPrefix(prefix string) {
|
||||
|
||||
}
|
||||
|
||||
func (l *WinLogger) GetPrefix() (prefix string) {
|
||||
|
||||
prefix = l.Prefix
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Alert writes an ALERT-level message to this WinLogger.
|
||||
func (l *WinLogger) Alert(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
@ -118,6 +129,7 @@ func (l *WinLogger) Alert(s string, v ...interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Crit writes an CRITICAL-level message to this WinLogger.
|
||||
func (l *WinLogger) Crit(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
@ -134,6 +146,7 @@ func (l *WinLogger) Crit(s string, v ...interface{}) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Debug writes a DEBUG-level message to this WinLogger.
|
||||
func (l *WinLogger) Debug(s string, v ...interface{}) (err error) {
|
||||
|
||||
if !l.EnableDebug {
|
||||
@ -155,6 +168,7 @@ func (l *WinLogger) Debug(s string, v ...interface{}) (err error) {
|
||||
|
||||
}
|
||||
|
||||
// Emerg writes an EMERGENCY-level message to this WinLogger.
|
||||
func (l *WinLogger) Emerg(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
@ -172,6 +186,7 @@ func (l *WinLogger) Emerg(s string, v ...interface{}) (err error) {
|
||||
|
||||
}
|
||||
|
||||
// Err writes an ERROR-level message to this WinLogger.
|
||||
func (l *WinLogger) Err(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
@ -188,6 +203,7 @@ func (l *WinLogger) Err(s string, v ...interface{}) (err error) {
|
||||
|
||||
}
|
||||
|
||||
// Info writes an INFO-level message to this WinLogger.
|
||||
func (l *WinLogger) Info(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
@ -204,6 +220,7 @@ func (l *WinLogger) Info(s string, v ...interface{}) (err error) {
|
||||
|
||||
}
|
||||
|
||||
// Notice writes a NOTICE-level message to this WinLogger.
|
||||
func (l *WinLogger) Notice(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
@ -221,6 +238,7 @@ func (l *WinLogger) Notice(s string, v ...interface{}) (err error) {
|
||||
|
||||
}
|
||||
|
||||
// Warning writes a WARNING/WARN-level message to this WinLogger.
|
||||
func (l *WinLogger) Warning(s string, v ...interface{}) (err error) {
|
||||
|
||||
var msg string
|
||||
|
@ -5,30 +5,60 @@ import (
|
||||
"os"
|
||||
)
|
||||
|
||||
/*
|
||||
Logger is one of the various loggers offered by this module.
|
||||
*/
|
||||
type Logger interface {
|
||||
Alert(string, ...interface{}) error
|
||||
Crit(string, ...interface{}) error
|
||||
Debug(string, ...interface{}) error
|
||||
Emerg(string, ...interface{}) error
|
||||
Err(string, ...interface{}) error
|
||||
Info(string, ...interface{}) error
|
||||
Notice(string, ...interface{}) error
|
||||
Warning(string, ...interface{}) error
|
||||
DoDebug(bool)
|
||||
SetPrefix(string)
|
||||
GetPrefix() string
|
||||
Alert(s string, v ...interface{}) (err error)
|
||||
Crit(s string, v ...interface{}) (err error)
|
||||
Debug(s string, v ...interface{}) (err error)
|
||||
Emerg(s string, v ...interface{}) (err error)
|
||||
Err(s string, v ...interface{}) (err error)
|
||||
Info(s string, v ...interface{}) (err error)
|
||||
Notice(s string, v ...interface{}) (err error)
|
||||
Warning(s string, v ...interface{}) (err error)
|
||||
DoDebug(d bool)
|
||||
SetPrefix(p string)
|
||||
GetPrefix() (p string)
|
||||
Setup()
|
||||
Shutdown()
|
||||
}
|
||||
|
||||
// StdLogger uses the log package in stdlib to perform all logging.
|
||||
type StdLogger struct {
|
||||
// All log.Logger fields/methods are exposed.
|
||||
*log.Logger
|
||||
/*
|
||||
EnableDebug indicates if the debug filter should be disabled (true) or if the filter should be enabled (false).
|
||||
This prevents potential data leak of sensitive information, as some loggers (e.g. FileLogger) will otherwise write all messages.
|
||||
*/
|
||||
EnableDebug bool
|
||||
Prefix string
|
||||
// Prefix indicates the prefix for log entries; in shared logs, this helps differentiate the source.
|
||||
Prefix string
|
||||
}
|
||||
|
||||
// FileLogger uses a StdLogger with a file handle writer to write to the file given at Path.
|
||||
type FileLogger struct {
|
||||
// StdLogger is used for the log formation and handling.
|
||||
StdLogger
|
||||
Path string
|
||||
// Path is the path to the logfile.
|
||||
Path string
|
||||
// writer is used for the writing out of the log file.
|
||||
writer *os.File
|
||||
}
|
||||
|
||||
// MultiLogger is used to contain one or more Loggers and present them all as a single Logger.
|
||||
type MultiLogger struct {
|
||||
/*
|
||||
EnableDebug indicates if the debug filter should be disabled (true) or if the filter should be enabled (false).
|
||||
This prevents potential data leak of sensitive information, as some loggers (e.g. FileLogger) will otherwise write all messages.
|
||||
*/
|
||||
EnableDebug bool
|
||||
// Prefix indicates the prefix for log entries; in shared logs, this helps differentiate the source.
|
||||
Prefix string
|
||||
/*
|
||||
Loggers contains a map of map[logname]Logger. It can be used to set log-specific options, or replace a Logger
|
||||
with one of a different type or options.
|
||||
*/
|
||||
Loggers map[string]Logger
|
||||
}
|
||||
|
58
multierr/doc.go
Normal file
58
multierr/doc.go
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
Package multierr provides a simple way of handling multiple errors and consolidating them into a single error.
|
||||
|
||||
Example:
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
`r00t2.io/goutils/multierr`
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
var err error
|
||||
var errs []error
|
||||
|
||||
errs = make([]error, 0)
|
||||
|
||||
for _, i := range someSlice {
|
||||
go func() {
|
||||
if err = i.DoSomething(); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
if errs != nil && len(errs) != 0 {
|
||||
// err now contains multiple errors presented as a single error.
|
||||
err = multierr.NewErrors(errs...)
|
||||
}
|
||||
}
|
||||
|
||||
MultiError also has a shorthand, making the above much less verbose:
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
`r00t2.io/goutils/multierr`
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
var err error
|
||||
var multierror *multierr.MultiError = multierr.NewMultiError(nil)
|
||||
|
||||
for _, i := range someSlice {
|
||||
go func() {
|
||||
if err = i.DoSomething(); err != nil {
|
||||
multierror.AddError(err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
// multierror now contains any/all errors above.
|
||||
}
|
||||
|
||||
In the above, the multierror assignment can still be used as an error.
|
||||
*/
|
||||
package multierr
|
85
multierr/funcs.go
Normal file
85
multierr/funcs.go
Normal file
@ -0,0 +1,85 @@
|
||||
package multierr
|
||||
|
||||
import (
|
||||
`fmt`
|
||||
)
|
||||
|
||||
/*
|
||||
NewErrors returns a new MultiError (as an error) based on/initialized with a slice of error.Error (errs).
|
||||
Any nil errors are trimmed.
|
||||
If there are no actual errors after trimming, err will be nil.
|
||||
*/
|
||||
func NewErrors(errs ...error) (err error) {
|
||||
|
||||
if errs == nil || len(errs) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
var realErrs []error = make([]error, 0)
|
||||
|
||||
for _, e := range errs {
|
||||
if e == nil {
|
||||
continue
|
||||
}
|
||||
realErrs = append(realErrs, e)
|
||||
}
|
||||
|
||||
if len(realErrs) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
err = &MultiError{
|
||||
Errors: realErrs,
|
||||
ErrorSep: "\n",
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// NewMultiError will provide a MultiError (true type), optionally initialized with errors.
|
||||
func NewMultiError(errs ...error) (m *MultiError) {
|
||||
|
||||
if errs == nil {
|
||||
errs = make([]error, 0)
|
||||
}
|
||||
|
||||
m = &MultiError{
|
||||
Errors: errs,
|
||||
ErrorSep: "\n",
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Error returns a string representation of a MultiError (to conform with the error interface).
|
||||
func (e *MultiError) Error() (errStr string) {
|
||||
|
||||
var numErrs int
|
||||
|
||||
if e == nil || len(e.Errors) == 0 {
|
||||
return
|
||||
} else {
|
||||
numErrs = len(e.Errors)
|
||||
}
|
||||
|
||||
for idx, err := range e.Errors {
|
||||
if (idx + 1) < numErrs {
|
||||
errStr += fmt.Sprintf("%v%v", err.Error(), e.ErrorSep)
|
||||
} else {
|
||||
errStr += err.Error()
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// AddError is a shorthand way of adding an error to a MultiError.
|
||||
func (e *MultiError) AddError(err error) {
|
||||
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
|
||||
e.Errors = append(e.Errors, err)
|
||||
|
||||
}
|
9
multierr/types.go
Normal file
9
multierr/types.go
Normal file
@ -0,0 +1,9 @@
|
||||
package multierr
|
||||
|
||||
// MultiError is a type of error.Error that can contain multiple errors.
|
||||
type MultiError struct {
|
||||
// Errors is a slice of errors to combine/concatenate when .Error() is called.
|
||||
Errors []error `json:"errors"`
|
||||
// ErrorSep is a string to use to separate errors for .Error(). The default is "\n".
|
||||
ErrorSep string `json:"separator"`
|
||||
}
|
Loading…
Reference in New Issue
Block a user