4 Commits

Author SHA1 Message Date
brent saner
fd720f2b34 v1.7.2
FIXED:
* multierr race condition fix/now fully supports multithreading
2025-01-04 02:29:49 -05:00
brent saner
3c543a05e7 v1.7.1
FIXED:
* bitmask.MaskBit.ClearFlag now works properly. Whoooops, how long was
  that typo there?
2024-11-07 03:44:54 -05:00
brent saner
e5191383a7 v1.7.0
ADDED:
* logging.Logger objects now are able to return a stdlib *log.Logger.
2024-06-19 18:57:26 -04:00
brent saner
ae49f42c0c v1.6.0
Added bitmask/MaskBit.Copy()
2024-04-14 01:54:59 -04:00
15 changed files with 220 additions and 2 deletions

View File

@@ -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) {

View File

@@ -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

View File

@@ -220,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
View 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
}

View 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
}

View File

@@ -3,6 +3,7 @@ package logging
import ( import (
"errors" "errors"
"fmt" "fmt"
`log`
"sync" "sync"
"r00t2.io/goutils/multierr" "r00t2.io/goutils/multierr"
@@ -370,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
}

View File

@@ -1,5 +1,9 @@
package logging package logging
import (
`log`
)
// Setup does nothing at all; it's here for interface compat. 🙃 // Setup does nothing at all; it's here for interface compat. 🙃
func (l *NullLogger) Setup() (err error) { func (l *NullLogger) Setup() (err error) {
return return
@@ -72,3 +76,11 @@ func (l *NullLogger) Notice(s string, v ...interface{}) (err error) {
func (l *NullLogger) Warning(s string, v ...interface{}) (err error) { func (l *NullLogger) Warning(s string, v ...interface{}) (err error) {
return 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
}

View 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
}

View File

@@ -244,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
}

View File

@@ -223,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
}

View File

@@ -266,3 +266,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
}

View File

@@ -3,6 +3,7 @@ package logging
import ( import (
"errors" "errors"
"fmt" "fmt"
`log`
"os" "os"
"os/exec" "os/exec"
"syscall" "syscall"
@@ -342,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
}

View File

@@ -3,8 +3,12 @@ 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.
*/ */
@@ -23,6 +27,7 @@ type Logger interface {
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)
} }
/* /*
@@ -105,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{}

View File

@@ -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)
} }

View File

@@ -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
} }