Compare commits
No commits in common. "master" and "v1.2.0" have entirely different histories.
@ -1,127 +0,0 @@
|
||||
package bitmask
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"math/bits"
|
||||
)
|
||||
|
||||
// MaskBit is a flag container.
|
||||
type MaskBit uint
|
||||
|
||||
/*
|
||||
NewMaskBit is a convenience function.
|
||||
It will return a MaskBit with a (referenced) value of 0, so set your consts up accordingly.
|
||||
|
||||
It is highly recommended to set this default as a "None" flag (separate from your iotas!)
|
||||
as shown in the example.
|
||||
*/
|
||||
func NewMaskBit() (m *MaskBit) {
|
||||
|
||||
m = new(MaskBit)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// NewMaskBitExplicit is like NewMaskBit, but allows you to specify a non-zero (0x0) value.
|
||||
func NewMaskBitExplicit(value uint) (m *MaskBit) {
|
||||
|
||||
var v MaskBit = MaskBit(value)
|
||||
|
||||
m = &v
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// HasFlag is true if m has MaskBit flag set/enabled.
|
||||
func (m *MaskBit) HasFlag(flag MaskBit) (r bool) {
|
||||
|
||||
var b MaskBit = *m
|
||||
|
||||
if b&flag != 0 {
|
||||
r = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// AddFlag adds MaskBit flag to m.
|
||||
func (m *MaskBit) AddFlag(flag MaskBit) {
|
||||
|
||||
*m |= flag
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ClearFlag removes MaskBit flag from m.
|
||||
func (m *MaskBit) ClearFlag(flag MaskBit) {
|
||||
|
||||
*m &= flag
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// ToggleFlag switches MaskBit flag in m to its inverse; if true, it is now false and vice versa.
|
||||
func (m *MaskBit) ToggleFlag(flag MaskBit) {
|
||||
|
||||
*m ^= flag
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Bytes returns the current value of a MasBit as a byte slice (big-endian).
|
||||
|
||||
If trim is false, b will (probably) be 4 bytes long if you're on a 32-bit size system,
|
||||
and b will (probably) be 8 bytes long if you're on a 64-bit size system. You can determine
|
||||
the size of the resulting slice via (math/)bits.UintSize / 8.
|
||||
|
||||
If trim is true, it will trim leading null bytes (if any). This will lead to an unpredictable
|
||||
byte slice length in b, but is most likely preferred for byte operations.
|
||||
|
||||
*/
|
||||
func (m *MaskBit) Bytes(trim bool) (b []byte) {
|
||||
|
||||
var b2 []byte
|
||||
var size int = bits.UintSize / 8
|
||||
var err error
|
||||
|
||||
b2 = make([]byte, size)
|
||||
|
||||
switch s := bits.UintSize; s {
|
||||
case 32:
|
||||
binary.BigEndian.PutUint32(b2[:], uint32(*m))
|
||||
case 64:
|
||||
binary.BigEndian.PutUint64(b2[:], uint64(*m))
|
||||
default:
|
||||
err = errors.New("unsupported Uint/system bit size")
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if trim {
|
||||
b = bytes.TrimLeft(b2, "\x00")
|
||||
return
|
||||
} else {
|
||||
b = b2
|
||||
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.
|
||||
func (m *MaskBit) Value() (v uint) {
|
||||
|
||||
v = uint(*m)
|
||||
|
||||
return
|
||||
}
|
46
bitmask/bitmasks.go
Normal file
46
bitmask/bitmasks.go
Normal file
@ -0,0 +1,46 @@
|
||||
package bitmask
|
||||
|
||||
// MaskBit is a flag container.
|
||||
type MaskBit uint8
|
||||
|
||||
/*
|
||||
NewMaskBit is a convenience function.
|
||||
It will return a MaskBit with a (referenced) value of 0, so set your consts up accordingly.
|
||||
It is highly recommended to set this default as a "None" flag (separate from your iotas!)
|
||||
as shown in the example.
|
||||
*/
|
||||
func NewMaskBit() (m *MaskBit) {
|
||||
|
||||
m = new(MaskBit)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// HasFlag is true if m has MaskBit flag set/enabled.
|
||||
func (m *MaskBit) HasFlag(flag MaskBit) (r bool) {
|
||||
|
||||
var b MaskBit = *m
|
||||
|
||||
if b&flag != 0 {
|
||||
r = true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// AddFlag adds MaskBit flag to m.
|
||||
func (m *MaskBit) AddFlag(flag MaskBit) {
|
||||
*m |= flag
|
||||
return
|
||||
}
|
||||
|
||||
// ClearFlag removes MaskBit flag from m.
|
||||
func (m *MaskBit) ClearFlag(flag MaskBit) {
|
||||
*m &= flag
|
||||
return
|
||||
}
|
||||
|
||||
// ToggleFlag switches MaskBit flag in m to its inverse; if true, it is now false and vice versa.
|
||||
func (m *MaskBit) ToggleFlag(flag MaskBit) {
|
||||
*m ^= flag
|
||||
return
|
||||
}
|
@ -11,18 +11,18 @@ To use this, set constants like thus:
|
||||
"r00t2.io/goutils/bitmask"
|
||||
)
|
||||
|
||||
const OPTNONE bitmask.MaskBit = 0
|
||||
const OPTNONE types.MaskBit = 0
|
||||
const (
|
||||
OPT1 bitmask.MaskBit = 1 << iota
|
||||
OPT1 types.MaskBit = 1 << iota
|
||||
OPT2
|
||||
OPT3
|
||||
// ...
|
||||
)
|
||||
|
||||
var MyMask *bitmask.MaskBit
|
||||
var MyMask *MaskBit
|
||||
|
||||
func main() {
|
||||
MyMask = bitmask.NewMaskBit()
|
||||
MyMask = types.NewMaskBit
|
||||
|
||||
MyMask.AddFlag(OPT1)
|
||||
MyMask.AddFlag(OPT3)
|
||||
@ -41,13 +41,5 @@ As would this:
|
||||
But this would return false:
|
||||
|
||||
MyMask.HasFlag(OPT2)
|
||||
|
||||
If you need something with more flexibility (as always, at the cost of complexity),
|
||||
you may be interested in one of the following libraries:
|
||||
|
||||
. github.com/alvaroloes/enumer
|
||||
. github.com/abice/go-enum
|
||||
. github.com/jeffreyrichter/enum/enum
|
||||
|
||||
*/
|
||||
package bitmask
|
||||
|
@ -3,14 +3,9 @@
|
||||
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.
|
||||
|
||||
- StdLogger2; where stdout and stderr are both logged to depending on severity level.
|
||||
- make configurable via OR bitmask
|
||||
|
||||
- Suport remote loggers? (eventlog, syslog, systemd)
|
||||
|
||||
- JSON logger? YAML logger? XML logger?
|
||||
|
||||
- DOCS.
|
||||
-- Done, but flesh out.
|
||||
|
||||
- Implement io.Writer interfaces
|
||||
|
@ -12,16 +12,3 @@ const (
|
||||
// appendFlags are the flags used for testing the file (and opening/writing).
|
||||
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
|
||||
|
@ -3,19 +3,18 @@ Package logging implements and presents various loggers under a unified interfac
|
||||
|
||||
These particular loggers (logging.Logger) available are:
|
||||
|
||||
NullLogger
|
||||
StdLogger
|
||||
FileLogger
|
||||
SystemDLogger (Linux only)
|
||||
SyslogLogger (Linux only)
|
||||
WinLogger (Windows only)
|
||||
|
||||
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.
|
||||
There is a sixth type of logging.Logger, MultiLogger, that allows for multiple loggers to be written to with a single call.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Every logging.Logger type has the following methods that correspond to certain "levels".
|
||||
|
||||
Alert(s string, v ...interface{}) (err error)
|
||||
@ -37,7 +36,6 @@ 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:
|
||||
|
||||
DoDebug(d bool) (err error)
|
||||
GetDebug() (d bool)
|
||||
SetPrefix(p string) (err error)
|
||||
GetPrefix() (p string, err error)
|
||||
Setup() (err error)
|
||||
|
@ -1,12 +1,12 @@
|
||||
package logging
|
||||
|
||||
import (
|
||||
"errors"
|
||||
`errors`
|
||||
"fmt"
|
||||
"io/fs"
|
||||
`io/fs`
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
`strings`
|
||||
)
|
||||
|
||||
// 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.
|
||||
err will always be nil; it's there for interface-compat.
|
||||
GetPrefix returns the prefix used by this FileLogger.
|
||||
err will always be nil; it's there for interface-compat.
|
||||
*/
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
err will always be nil; it's there for interface-compat.
|
||||
*/
|
||||
func (l *FileLogger) DoDebug(d bool) (err error) {
|
||||
|
||||
@ -65,17 +65,9 @@ func (l *FileLogger) DoDebug(d bool) (err error) {
|
||||
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.
|
||||
err will always be nil; it's there for interface-compat.
|
||||
SetPrefix sets the prefix for this FileLogger.
|
||||
err will always be nil; it's there for interface-compat.
|
||||
*/
|
||||
func (l *FileLogger) SetPrefix(prefix string) (err error) {
|
||||
|
||||
@ -220,14 +212,6 @@ func (l *FileLogger) Warning(s string, v ...interface{}) (err error) {
|
||||
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.
|
||||
func (l *FileLogger) renderWrite(msg, prio string) {
|
||||
|
||||
|
@ -1,23 +0,0 @@
|
||||
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
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
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,12 +1,11 @@
|
||||
package logging
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
`log`
|
||||
"sync"
|
||||
`errors`
|
||||
`fmt`
|
||||
`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.
|
||||
@ -68,8 +67,8 @@ func (m *MultiLogger) Shutdown() (err error) {
|
||||
}
|
||||
|
||||
/*
|
||||
GetPrefix returns the prefix used by this MultiLogger (and all its MultiLogger.Loggers).
|
||||
err will always be nil; it's there for interface-compat.
|
||||
GetPrefix returns the prefix used by this MultiLogger (and all its MultiLogger.Loggers).
|
||||
err will always be nil; it's there for interface-compat.
|
||||
*/
|
||||
func (m *MultiLogger) GetPrefix() (prefix string, err error) {
|
||||
|
||||
@ -80,10 +79,10 @@ func (m *MultiLogger) GetPrefix() (prefix string, err error) {
|
||||
}
|
||||
|
||||
/*
|
||||
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.
|
||||
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.
|
||||
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) {
|
||||
|
||||
@ -115,18 +114,10 @@ func (m *MultiLogger) DoDebug(d bool) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// GetDebug returns the debug status of this MultiLogger.
|
||||
func (m *MultiLogger) GetDebug() (d bool) {
|
||||
|
||||
d = m.EnableDebug
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
SetPrefix sets the prefix for this MultiLogger (and all its MultiLogger.Loggers).
|
||||
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.
|
||||
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) {
|
||||
|
||||
@ -371,11 +362,3 @@ func (m *MultiLogger) Warning(s string, v ...interface{}) (err error) {
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
"path"
|
||||
`path`
|
||||
|
||||
"github.com/google/uuid"
|
||||
"r00t2.io/sysutils/paths"
|
||||
`github.com/google/uuid`
|
||||
`r00t2.io/sysutils/paths`
|
||||
)
|
||||
|
||||
/*
|
||||
@ -145,40 +145,6 @@ func (m *MultiLogger) AddFileLogger(identifier string, logFlags int, logfilePath
|
||||
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.
|
||||
func (m *MultiLogger) RemoveLogger(identifier string) (err error) {
|
||||
|
||||
|
@ -1,86 +0,0 @@
|
||||
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
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
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
|
||||
}
|
@ -2,15 +2,15 @@ package logging
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
`io`
|
||||
`log`
|
||||
`os`
|
||||
`strings`
|
||||
)
|
||||
|
||||
/*
|
||||
Setup sets up/configures a StdLogger and prepares it for use.
|
||||
err will always be nil; it's there for interface-compat.
|
||||
Setup sets up/configures a StdLogger and prepares it for use.
|
||||
err will always be nil; it's there for interface-compat.
|
||||
*/
|
||||
func (l *StdLogger) Setup() (err error) {
|
||||
|
||||
@ -47,8 +47,8 @@ func (l *StdLogger) Setup() (err error) {
|
||||
}
|
||||
|
||||
/*
|
||||
Shutdown cleanly shuts down a StdLogger.
|
||||
err will always be nil; it's there for interface-compat.
|
||||
Shutdown cleanly shuts down a StdLogger.
|
||||
err will always be nil; it's there for interface-compat.
|
||||
*/
|
||||
func (l *StdLogger) Shutdown() (err error) {
|
||||
|
||||
@ -58,8 +58,8 @@ func (l *StdLogger) Shutdown() (err error) {
|
||||
}
|
||||
|
||||
/*
|
||||
GetPrefix returns the prefix used by this StdLogger.
|
||||
err will always be nil; it's there for interface-compat.
|
||||
GetPrefix returns the prefix used by this StdLogger.
|
||||
err will always be nil; it's there for interface-compat.
|
||||
*/
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
err will always be nil; it's there for interface-compat.
|
||||
*/
|
||||
func (l *StdLogger) DoDebug(d bool) (err error) {
|
||||
|
||||
@ -80,17 +80,9 @@ func (l *StdLogger) DoDebug(d bool) (err error) {
|
||||
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.
|
||||
err will always be nil; it's there for interface-compat.
|
||||
SetPrefix sets the prefix for this StdLogger.
|
||||
err will always be nil; it's there for interface-compat.
|
||||
*/
|
||||
func (l *StdLogger) SetPrefix(prefix string) (err error) {
|
||||
|
||||
@ -244,11 +236,3 @@ func (l *StdLogger) renderWrite(msg, prio string) {
|
||||
|
||||
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.
|
||||
err will always be nil; it's there for interface-compat.
|
||||
Setup sets up/configures a SystemDLogger and prepares it for use.
|
||||
err will always be nil; it's there for interface-compat.
|
||||
*/
|
||||
func (l *SystemDLogger) Setup() (err error) {
|
||||
|
||||
@ -19,8 +19,8 @@ func (l *SystemDLogger) Setup() (err error) {
|
||||
}
|
||||
|
||||
/*
|
||||
Shutdown cleanly shuts down a SystemDLogger.
|
||||
err will always be nil; it's there for interface-compat.
|
||||
Shutdown cleanly shuts down a SystemDLogger.
|
||||
err will always be nil; it's there for interface-compat.
|
||||
*/
|
||||
func (l *SystemDLogger) Shutdown() (err error) {
|
||||
|
||||
@ -30,8 +30,8 @@ func (l *SystemDLogger) Shutdown() (err error) {
|
||||
}
|
||||
|
||||
/*
|
||||
GetPrefix returns the prefix used by this SystemDLogger.
|
||||
err will always be nil; it's there for interface-compat.
|
||||
GetPrefix returns the prefix used by this SystemDLogger.
|
||||
err will always be nil; it's there for interface-compat.
|
||||
*/
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
err will always be nil; it's there for interface-compat.
|
||||
*/
|
||||
func (l *SystemDLogger) DoDebug(d bool) (err error) {
|
||||
|
||||
@ -52,17 +52,9 @@ func (l *SystemDLogger) DoDebug(d bool) (err error) {
|
||||
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.
|
||||
err will always be nil; it's there for interface-compat.
|
||||
SetPrefix sets the prefix for this SystemDLogger.
|
||||
err will always be nil; it's there for interface-compat.
|
||||
*/
|
||||
func (l *SystemDLogger) SetPrefix(prefix string) (err error) {
|
||||
|
||||
@ -223,11 +215,3 @@ func (l *SystemDLogger) renderWrite(msg string, prio journal.Priority) {
|
||||
|
||||
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
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import (
|
||||
"log"
|
||||
"log/syslog"
|
||||
|
||||
"r00t2.io/goutils/multierr"
|
||||
`r00t2.io/goutils/multierr`
|
||||
)
|
||||
|
||||
// Setup sets up/configures a SyslogLogger and prepares it for use.
|
||||
@ -73,8 +73,8 @@ func (l *SyslogLogger) Shutdown() (err error) {
|
||||
}
|
||||
|
||||
/*
|
||||
GetPrefix returns the prefix used by this SyslogLogger.
|
||||
err will always be nil; it's there for interface-compat.
|
||||
GetPrefix returns the prefix used by this SyslogLogger.
|
||||
err will always be nil; it's there for interface-compat.
|
||||
*/
|
||||
func (l *SyslogLogger) GetPrefix() (prefix string, err error) {
|
||||
|
||||
@ -84,9 +84,9 @@ func (l *SyslogLogger) GetPrefix() (prefix string, err error) {
|
||||
}
|
||||
|
||||
/*
|
||||
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.
|
||||
err will always be nil; it's there for interface-compat.
|
||||
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.
|
||||
err will always be nil; it's there for interface-compat.
|
||||
*/
|
||||
func (l *SyslogLogger) DoDebug(d bool) (err error) {
|
||||
|
||||
@ -95,14 +95,6 @@ func (l *SyslogLogger) DoDebug(d bool) (err error) {
|
||||
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.
|
||||
func (l *SyslogLogger) SetPrefix(prefix string) (err error) {
|
||||
|
||||
@ -266,11 +258,3 @@ func (l *SyslogLogger) Warning(s string, v ...interface{}) (err error) {
|
||||
|
||||
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,27 +1,26 @@
|
||||
package logging
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
`log`
|
||||
"os"
|
||||
"os/exec"
|
||||
"syscall"
|
||||
`errors`
|
||||
`fmt`
|
||||
`os`
|
||||
`os/exec`
|
||||
`syscall`
|
||||
|
||||
"golang.org/x/sys/windows/registry"
|
||||
"golang.org/x/sys/windows/svc/eventlog"
|
||||
"r00t2.io/sysutils/paths"
|
||||
`golang.org/x/sys/windows/registry`
|
||||
`golang.org/x/sys/windows/svc/eventlog`
|
||||
`r00t2.io/sysutils/paths`
|
||||
)
|
||||
|
||||
/*
|
||||
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
|
||||
a registered Event Log source.
|
||||
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
|
||||
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 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).
|
||||
Otherwise eventlog.InstallAsEventCreate will be used.
|
||||
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),
|
||||
eventlog.Install will be used (with the WinLogger.ExpandKey field).
|
||||
Otherwise eventlog.InstallAsEventCreate will be used.
|
||||
*/
|
||||
func (l *WinLogger) Setup() (err error) {
|
||||
|
||||
@ -109,8 +108,8 @@ func (l *WinLogger) Remove() (err error) {
|
||||
}
|
||||
|
||||
/*
|
||||
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.
|
||||
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.
|
||||
*/
|
||||
func (l *WinLogger) Shutdown() (err error) {
|
||||
|
||||
@ -129,8 +128,8 @@ func (l *WinLogger) Shutdown() (err error) {
|
||||
}
|
||||
|
||||
/*
|
||||
GetPrefix returns the prefix used by this WinLogger.
|
||||
err will always be nil; it's there for interface-compat.
|
||||
GetPrefix returns the prefix used by this WinLogger.
|
||||
err will always be nil; it's there for interface-compat.
|
||||
*/
|
||||
func (l *WinLogger) GetPrefix() (prefix string, err error) {
|
||||
|
||||
@ -140,9 +139,9 @@ func (l *WinLogger) GetPrefix() (prefix string, err error) {
|
||||
}
|
||||
|
||||
/*
|
||||
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.
|
||||
err will always be nil; it's there for interface-compat.
|
||||
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.
|
||||
err will always be nil; it's there for interface-compat.
|
||||
*/
|
||||
func (l *WinLogger) DoDebug(d bool) (err error) {
|
||||
|
||||
@ -151,14 +150,6 @@ func (l *WinLogger) DoDebug(d bool) (err error) {
|
||||
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.
|
||||
func (l *WinLogger) SetPrefix(prefix string) (err error) {
|
||||
|
||||
@ -343,11 +334,3 @@ func (l *WinLogger) Warning(s string, v ...interface{}) (err error) {
|
||||
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,15 +2,11 @@ package logging
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
`r00t2.io/goutils/bitmask`
|
||||
`os`
|
||||
)
|
||||
|
||||
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 {
|
||||
Alert(s string, v ...interface{}) (err error)
|
||||
@ -22,17 +18,15 @@ type Logger interface {
|
||||
Notice(s string, v ...interface{}) (err error)
|
||||
Warning(s string, v ...interface{}) (err error)
|
||||
DoDebug(d bool) (err error)
|
||||
GetDebug() (d bool)
|
||||
SetPrefix(p string) (err error)
|
||||
GetPrefix() (p string, err error)
|
||||
Setup() (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.
|
||||
If you wish to modify the underling log.Logger object, you can access it directly via StdLogger.Logger.
|
||||
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.
|
||||
*/
|
||||
type StdLogger struct {
|
||||
// All log.Logger fields/methods are exposed.
|
||||
@ -77,11 +71,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
|
||||
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.)
|
||||
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.
|
||||
(Alternatively, run FileLogger.Shutdown and replace your logger with a new FileLogger.)
|
||||
*/
|
||||
type FileLogger struct {
|
||||
// StdLogger is used for the log formation and handling. See StdLogger for more details.
|
||||
@ -92,9 +86,6 @@ type FileLogger struct {
|
||||
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.
|
||||
type MultiLogger struct {
|
||||
/*
|
||||
@ -110,12 +101,3 @@ type MultiLogger struct {
|
||||
*/
|
||||
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,5 +0,0 @@
|
||||
package structutils
|
||||
|
||||
const (
|
||||
TagMapTrim tagMapOpt = iota
|
||||
)
|
@ -1,362 +0,0 @@
|
||||
/*
|
||||
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
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
package structutils
|
||||
|
||||
type (
|
||||
tagMapOpt uint8
|
||||
)
|
Loading…
Reference in New Issue
Block a user