Finalizing for 1.2.0

This commit is contained in:
brent s. 2022-01-16 06:55:29 -05:00
parent 39e0a1fd43
commit d98363c0d7
Signed by: bts
GPG Key ID: 8C004C2F93481F6B
22 changed files with 1106 additions and 110 deletions

1
.gitignore vendored
View File

@ -31,6 +31,7 @@
# But DO include the actual tests.
!_test.go
!*_test.go
!*_test_*.go
!*_test/

# Output of the go coverage tool, specifically when used with LiteIDE

View File

@ -1,10 +1,11 @@
- Implement code line/func/etc. (only for debug?):
https://stackoverflow.com/a/24809646
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.

- Suport remote loggers? (eventlog, syslog, systemd)

- JSON logger? YAML logger? XML logger?

- DOCS.
-- Done, but flesh out.

- Unit/Integration tests.

39
logging/consts_test.go Normal file
View File

@ -0,0 +1,39 @@
package logging

import (
`log`
)

/*
The following are strings written to the Logger in the various tests.
The %v is populated with the name of the type of Logger.
*/
const (
testAlert string = "This is a test ALERT-priority log message for logger %v."
testCrit string = "This is a test CRITICAL-priority (CRIT) log message for logger %v."
testDebug string = "This is a test DEBUG-priority log message for logger %v."
testEmerg string = "This is a test EMERGENCY-priority (EMERG) log message for logger %v."
testErr string = "This is a test ERROR-priority (ERR) log message for logger %v."
testInfo string = "This is a test INFO-priority log message for logger %v."
testNotice string = "This is a test NOTICE-priority log message for logger %v."
testWarning string = "This is a test WARNING-priority log message for logger %v."
)

// Prefixes to use for tests.
const (
// TestLogPrefix is used as the initial prefix.
TestLogPrefix string = "LOGGING_TESTRUN"
// TestLogAltPrefix is used as the alternative prefix to Logger.SetPrefix.
TestLogAltPrefix string = "LOGGING_TESTRUN_ALT"
)

const (
// EnvVarKeepLog is the env var key/var name to use to suppress removal of FileLogger.Path after tests complete.
EnvVarKeepLog string = "LOGGING_KEEP_TEMPLOG"
)

const (
// logFlags are used to set the log flags for StdLogger (and FileLogger.StdLogger).
// logFlags int = log.Ldate | log.Lmicroseconds | log.Llongfile | log.LUTC
logFlags int = log.Ldate | log.Lmicroseconds | log.Lshortfile | log.LUTC
)

View File

@ -55,7 +55,7 @@ var DefaultEventID *WinEventID = &WinEventID{
Warning: EventWarning,
}

// Default Event IDs for WinEventID.
// Default Event IDs for WinEventID (DefaultEventID, specifically).
const (
EventAlert uint32 = 1 << iota
EventCrit

View File

@ -35,11 +35,11 @@ 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)
SetPrefix(p string)
GetPrefix() (p string)
Setup()
Shutdown()
DoDebug(d bool) (err error)
SetPrefix(p string) (err error)
GetPrefix() (p string, err error)
Setup() (err error)
Shutdown() (err error)

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.

View File

@ -6,7 +6,10 @@ import (
)

var (
// ErrBadBinPath is returned if installing a binary-registered Event Log source instead of using EventCreate.exe.
ErrBadBinPath error = errors.New("evaluated binary path does not actually exist")
ErrBadPerms error = errors.New("access denied when attempting to register Event Log source")
ErrBadEid error = errors.New(fmt.Sprintf("event IDs must be between %v and %v inclusive", EIDMin, EIDMax))
// ErrBadPerms is returned if an access denied error is received when attempting to register, write to, close, etc. a source without proper perms.
ErrBadPerms error = errors.New("access denied when attempting to register Event Log source")
// ErrBadEid is returned if an event ID is within an invalid range.
ErrBadEid error = errors.New(fmt.Sprintf("event IDs must be between %v and %v inclusive", EIDMin, EIDMax))
)

View File

@ -6,13 +6,16 @@ import (

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

// Example #2, https://golang.org/pkg/os/#OpenFile
if f, err = os.OpenFile(path, appendFlags, logPerm); err != nil {
return
}
defer f.Close()
if err = f.Close(); err != nil {
return
}

success = true


View File

@ -3,7 +3,6 @@ package logging
import (
`errors`
"fmt"
"io"
`io/fs`
"log"
"os"
@ -13,8 +12,6 @@ import (
// Setup sets up/configures a FileLogger and prepares it for use.
func (l *FileLogger) Setup() (err error) {

var multi io.Writer

// This uses a shared handle across the import. We don't want that.
// l.Logger = log.Default()
if l.Prefix != "" {
@ -25,19 +22,7 @@ func (l *FileLogger) Setup() (err error) {
return
}

// https://stackoverflow.com/a/36719588/733214
switch {
case l.EnableStdErr && l.EnableStdOut:
multi = io.MultiWriter(os.Stdout, os.Stderr, l.writer)
case l.EnableStdErr:
multi = io.MultiWriter(os.Stderr, l.writer)
case l.EnableStdOut:
multi = io.MultiWriter(os.Stdout, l.writer)
default:
multi = l.writer
}

l.Logger = log.New(multi, l.Prefix, l.LogFlags)
l.Logger = log.New(l.writer, l.Prefix, l.LogFlags)
// l.Logger.SetOutput(multi)

return
@ -50,6 +35,8 @@ func (l *FileLogger) Shutdown() (err error) {
if !errors.Is(err, fs.ErrClosed) {
return
}
err = nil
return err
}

return

270
logging/funcs_linux_test.go Normal file
View File

@ -0,0 +1,270 @@
package logging

import (
`fmt`
`os`
`testing`
)

/*
TestSysDLogger tests functionality for SystemDLogger.
*/
func TestSysDLogger(t *testing.T) {

var l *SystemDLogger
var ltype string = "SystemDLogger"
var prefix string
var err error

l = &SystemDLogger{
EnableDebug: true,
Prefix: TestLogPrefix,
}

if err = l.Setup(); err != nil {
t.Fatalf("error when running Setup: %v", err.Error())
}

t.Logf("Logger %v passed Setup. Logger: %#v", ltype, l)

if err = l.Alert(testAlert, ltype); err != nil {
t.Fatalf("error for Alert: %v", err.Error())
}

if err = l.Crit(testCrit, ltype); err != nil {
t.Fatalf("error for Crit: %v", err.Error())
}

if err = l.Debug(testDebug, ltype); err != nil {
t.Fatalf("error for Debug: %v", err.Error())
}

if err = l.Emerg(testEmerg, ltype); err != nil {
t.Fatalf("error for Emerg: %v", err.Error())
}

if err = l.Err(testErr, ltype); err != nil {
t.Fatalf("error for Err: %v", err.Error())
}

if err = l.Info(testInfo, ltype); err != nil {
t.Fatalf("error for Alert: %v", err.Error())
}

if err = l.Notice(testNotice, ltype); err != nil {
t.Fatalf("error for Notice: %v", err.Error())
}

if err = l.Warning(testWarning, ltype); err != nil {
t.Fatalf("error for Warning: %v", err.Error())
}

if prefix, err = l.GetPrefix(); err != nil {
t.Fatalf("error when fetching prefix: %v", err.Error())
}

if prefix != TestLogPrefix {
t.Fatalf("true prefix ('%v') does not match TestLogPrefix ('%v')", prefix, TestLogPrefix)
}
if err = l.SetPrefix(TestLogAltPrefix); err != nil {
t.Fatalf("error when setting prefix to %v: %v", TestLogAltPrefix, err.Error())
} else {
_ = l.SetPrefix(TestLogPrefix)
}

if err = l.DoDebug(false); err != nil {
t.Fatalf("error when changing debug to false: %v", err.Error())
} else if l.EnableDebug {
t.Fatalf("did not properly set Debug filter state")
} else {
_ = l.DoDebug(true)
}

if err = l.Shutdown(); err != nil {
t.Fatalf("Error when running Shutdown: %v", err.Error())
}

t.Logf("Logger %v passed all logging targets.", ltype)
}

/*
TestSyslogLogger tests functionality for SyslogLogger.
*/
func TestSyslogLogger(t *testing.T) {

var l *SyslogLogger
var ltype string = "SyslogLogger"
var prefix string
var err error

l = &SyslogLogger{
EnableDebug: true,
Prefix: TestLogPrefix,
}

if err = l.Setup(); err != nil {
t.Fatalf("error when running Setup: %v", err.Error())
}

t.Logf("Logger %v passed Setup. Logger: %#v", ltype, l)

if err = l.Alert(testAlert, ltype); err != nil {
t.Fatalf("error for Alert: %v", err.Error())
}

if err = l.Crit(testCrit, ltype); err != nil {
t.Fatalf("error for Crit: %v", err.Error())
}

if err = l.Debug(testDebug, ltype); err != nil {
t.Fatalf("error for Debug: %v", err.Error())
}

if err = l.Emerg(testEmerg, ltype); err != nil {
t.Fatalf("error for Emerg: %v", err.Error())
}

if err = l.Err(testErr, ltype); err != nil {
t.Fatalf("error for Err: %v", err.Error())
}

if err = l.Info(testInfo, ltype); err != nil {
t.Fatalf("error for Alert: %v", err.Error())
}

if err = l.Notice(testNotice, ltype); err != nil {
t.Fatalf("error for Notice: %v", err.Error())
}

if err = l.Warning(testWarning, ltype); err != nil {
t.Fatalf("error for Warning: %v", err.Error())
}

if prefix, err = l.GetPrefix(); err != nil {
t.Fatalf("error when fetching prefix: %v", err.Error())
}

if prefix != TestLogPrefix {
t.Fatalf("true prefix ('%v') does not match TestLogPrefix ('%v')", prefix, TestLogPrefix)
}
if err = l.SetPrefix(TestLogAltPrefix); err != nil {
t.Fatalf("error when setting prefix to %v: %v", TestLogAltPrefix, err.Error())
} else {
_ = l.SetPrefix(TestLogPrefix)
}

if err = l.DoDebug(false); err != nil {
t.Fatalf("error when changing debug to false: %v", err.Error())
} else if l.EnableDebug {
t.Fatalf("did not properly set Debug filter state")
} else {
_ = l.DoDebug(true)
}

if err = l.Shutdown(); err != nil {
t.Fatalf("Error when running Shutdown: %v", err.Error())
}

t.Logf("Logger %v passed all logging targets.", ltype)
}

// TestDefaultLogger tests GetLogger.
func TestDefaultLogger(t *testing.T) {

var l Logger
var tempfile *os.File
var tempfilePath string
var keepLog bool
var ltype string
var prefix string
var testPrefix string
var err error

if tempfile, err = os.CreateTemp("", ".LOGGINGTEST_*"); err != nil {
t.Fatalf("error when creating temporary log file '%v': %v", tempfile.Name(), err.Error())
}
tempfilePath = tempfile.Name()
// We can close the handler immediately; we don't need it since the FileLogger opens its own.
if err = tempfile.Close(); err != nil {
t.Fatalf("error when closing handler for temporary log file '%v': %v", tempfile.Name(), err.Error())
}

if l, err = GetLogger(true, TestLogPrefix, logFlags, tempfilePath); err != nil {
t.Fatalf("error when spawning default Linux logger via GetLogger: %v", err.Error())
}

ltype = fmt.Sprintf("%T", l)

t.Logf("Logger %v passed Setup. Logger: %#v", ltype, l)

if err = l.Alert(testAlert, ltype); err != nil {
t.Fatalf("error for Alert: %v", err.Error())
}

if err = l.Crit(testCrit, ltype); err != nil {
t.Fatalf("error for Crit: %v", err.Error())
}

if err = l.Debug(testDebug, ltype); err != nil {
t.Fatalf("error for Debug: %v", err.Error())
}

if err = l.Emerg(testEmerg, ltype); err != nil {
t.Fatalf("error for Emerg: %v", err.Error())
}

if err = l.Err(testErr, ltype); err != nil {
t.Fatalf("error for Err: %v", err.Error())
}

if err = l.Info(testInfo, ltype); err != nil {
t.Fatalf("error for Alert: %v", err.Error())
}

if err = l.Notice(testNotice, ltype); err != nil {
t.Fatalf("error for Notice: %v", err.Error())
}

if err = l.Warning(testWarning, ltype); err != nil {
t.Fatalf("error for Warning: %v", err.Error())
}

if prefix, err = l.GetPrefix(); err != nil {
t.Fatalf("error when fetching prefix: %v", err.Error())
}

if ltype == "StdLogger" || ltype == "FileLogger" { // StdLogger (and thus FileLogger) adds a space at the end.
testPrefix = TestLogPrefix + " "
} else {
testPrefix = TestLogPrefix
}

if prefix != testPrefix {
t.Fatalf("true prefix ('%v') does not match TestLogPrefix ('%v')", prefix, TestLogPrefix)
}
if err = l.SetPrefix(TestLogAltPrefix); err != nil {
t.Fatalf("error when setting prefix to %v: %v", TestLogAltPrefix, err.Error())
} else {
_ = l.SetPrefix(TestLogPrefix)
}

if err = l.DoDebug(false); err != nil {
t.Fatalf("error when changing debug to false: %v", err.Error())
} else {
_ = l.DoDebug(true)
}

if err = l.Shutdown(); err != nil {
t.Fatalf("Error when running Shutdown: %v", err.Error())
}

_, keepLog = os.LookupEnv(EnvVarKeepLog)

if !keepLog {
if err = os.Remove(tempfilePath); err != nil {
t.Fatalf("error when removing temporary log file '%v': %v", tempfilePath, err.Error())
}
}

t.Logf("Logger %v passed all logging targets.", ltype)
}

View File

@ -1,6 +1,8 @@
package logging

import (
`errors`
`fmt`
`sync`

`r00t2.io/goutils/multierr`
@ -12,16 +14,17 @@ func (m *MultiLogger) Setup() (err error) {
var wg sync.WaitGroup
var errs *multierr.MultiError = multierr.NewMultiError(nil)

for _, l := range m.Loggers {
for logName, l := range m.Loggers {
wg.Add(1)
go func() {
go func(logger Logger, lName string) {
var err2 error
defer wg.Done()
if err2 = l.Setup(); err2 != nil {
if err2 = logger.Setup(); err2 != nil {
errs.AddError(errors.New(fmt.Sprintf("error on Setup for logger %v; follows (may be out of order):", lName)))
errs.AddError(err2)
err2 = nil
}
}()
}(l, logName)
}

wg.Wait()
@ -40,16 +43,17 @@ func (m *MultiLogger) Shutdown() (err error) {
var wg sync.WaitGroup
var errs *multierr.MultiError = multierr.NewMultiError(nil)

for _, l := range m.Loggers {
for logName, l := range m.Loggers {
wg.Add(1)
go func() {
go func(logger Logger, lName string) {
var err2 error
defer wg.Done()
if err2 = l.Shutdown(); err2 != nil {
if err2 = logger.Shutdown(); err2 != nil {
errs.AddError(errors.New(fmt.Sprintf("error on Shutdown for logger %v; follows (may be out of order):", lName)))
errs.AddError(err2)
err2 = nil
}
}()
}(l, logName)
}

wg.Wait()
@ -87,16 +91,17 @@ func (m *MultiLogger) DoDebug(d bool) (err error) {

m.EnableDebug = d

for _, l := range m.Loggers {
for logName, l := range m.Loggers {
wg.Add(1)
go func() {
go func(logger Logger, lName string) {
var err2 error
defer wg.Done()
if err2 = l.DoDebug(d); err2 != nil {
errs.AddError(errors.New(fmt.Sprintf("error on DoDebug for logger %v; follows (may be out of order):", lName)))
errs.AddError(err2)
err2 = nil
}
}()
}(l, logName)
}

wg.Wait()
@ -121,16 +126,17 @@ func (m *MultiLogger) SetPrefix(prefix string) (err error) {

m.Prefix = prefix

for _, l := range m.Loggers {
for logName, l := range m.Loggers {
wg.Add(1)
go func() {
go func(logger Logger, lName string) {
var err2 error
defer wg.Done()
if err2 = l.SetPrefix(prefix); err != nil {
errs.AddError(errors.New(fmt.Sprintf("error on SetPrefix for logger %v; follows (may be out of order):", lName)))
errs.AddError(err2)
err2 = nil
}
}()
}(l, logName)
}

wg.Wait()
@ -149,15 +155,16 @@ 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 {
for logName, l := range m.Loggers {
wg.Add(1)
go func(logObj Logger, msg string, rplc ...interface{}) {
go func(logObj Logger, msg, lName string, rplc ...interface{}) {
defer wg.Done()
if err = logObj.Alert(msg, rplc...); err != nil {
e.AddError(errors.New(fmt.Sprintf("error on Alert for logger %v; follows (may be out of order):", lName)))
e.AddError(err)
err = nil
}
}(l, s, v...)
}(l, s, logName, v...)
}

wg.Wait()
@ -175,15 +182,16 @@ 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 {
for logName, l := range m.Loggers {
wg.Add(1)
go func(logObj Logger, msg string, rplc ...interface{}) {
go func(logObj Logger, msg, lName string, rplc ...interface{}) {
defer wg.Done()
if err = logObj.Crit(msg, rplc...); err != nil {
e.AddError(errors.New(fmt.Sprintf("error on Crit for logger %v; follows (may be out of order):", lName)))
e.AddError(err)
err = nil
}
}(l, s, v...)
}(l, s, logName, v...)
}

wg.Wait()
@ -201,15 +209,16 @@ 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 {
for logName, l := range m.Loggers {
wg.Add(1)
go func(logObj Logger, msg string, rplc ...interface{}) {
go func(logObj Logger, msg, lName string, rplc ...interface{}) {
defer wg.Done()
if err = logObj.Debug(msg, rplc...); err != nil {
e.AddError(errors.New(fmt.Sprintf("error on Debug for logger %v; follows (may be out of order):", lName)))
e.AddError(err)
err = nil
}
}(l, s, v...)
}(l, s, logName, v...)
}

wg.Wait()
@ -226,15 +235,16 @@ 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 {
for logName, l := range m.Loggers {
wg.Add(1)
go func(logObj Logger, msg string, rplc ...interface{}) {
go func(logObj Logger, msg, lName string, rplc ...interface{}) {
defer wg.Done()
if err = logObj.Emerg(msg, rplc...); err != nil {
e.AddError(errors.New(fmt.Sprintf("error on Emerg for logger %v; follows (may be out of order):", lName)))
e.AddError(err)
err = nil
}
}(l, s, v...)
}(l, s, logName, v...)
}

wg.Wait()
@ -251,15 +261,16 @@ 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 {
for logName, l := range m.Loggers {
wg.Add(1)
go func(logObj Logger, msg string, rplc ...interface{}) {
go func(logObj Logger, msg, lName string, rplc ...interface{}) {
defer wg.Done()
if err = logObj.Err(msg, rplc...); err != nil {
e.AddError(errors.New(fmt.Sprintf("error on Err for logger %v; follows (may be out of order):", lName)))
e.AddError(err)
err = nil
}
}(l, s, v...)
}(l, s, logName, v...)
}

wg.Wait()
@ -277,15 +288,16 @@ 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 {
for logName, l := range m.Loggers {
wg.Add(1)
go func(logObj Logger, msg string, rplc ...interface{}) {
go func(logObj Logger, msg, lName string, rplc ...interface{}) {
defer wg.Done()
if err = logObj.Info(msg, rplc...); err != nil {
e.AddError(errors.New(fmt.Sprintf("error on Info for logger %v; follows (may be out of order):", lName)))
e.AddError(err)
err = nil
}
}(l, s, v...)
}(l, s, logName, v...)
}

wg.Wait()
@ -303,15 +315,16 @@ 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 {
for logName, l := range m.Loggers {
wg.Add(1)
go func(logObj Logger, msg string, rplc ...interface{}) {
go func(logObj Logger, msg, lName string, rplc ...interface{}) {
defer wg.Done()
if err = logObj.Notice(msg, rplc...); err != nil {
e.AddError(errors.New(fmt.Sprintf("error on Notice for logger %v; follows (may be out of order):", lName)))
e.AddError(err)
err = nil
}
}(l, s, v...)
}(l, s, logName, v...)
}

wg.Wait()
@ -329,15 +342,16 @@ 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 {
for logName, l := range m.Loggers {
wg.Add(1)
go func(logObj Logger, msg string, rplc ...interface{}) {
go func(logObj Logger, msg, lName string, rplc ...interface{}) {
defer wg.Done()
if err = logObj.Warning(msg, rplc...); err != nil {
e.AddError(errors.New(fmt.Sprintf("error on Warning for logger %v; follows (may be out of order):", lName)))
e.AddError(err)
err = nil
}
}(l, s, v...)
}(l, s, logName, v...)
}

wg.Wait()

View File

@ -37,9 +37,15 @@ func GetMultiLogger(enableDebug bool, prefix string) (m *MultiLogger) {
identifier is a string to use to identify the added StdLogger in MultiLogger.Loggers.
If empty, one will be automatically generated.

enableStdOut indicates that messages should be logged to STDOUT;
it is *strongly encouraged* to set at least one of enableStdOut or enableStdErr to true.

enableStdErr indicates that messages should be logged to STDERR;
it is *strongly encouraged* to set at least one of enableStdErr or enableStdOut to true.

See GetLogger's logConfigFlags argument and StdLogger.LogFlags for details on logFlags.
*/
func (m *MultiLogger) AddStdLogger(identifier string, logFlags int) (err error) {
func (m *MultiLogger) AddStdLogger(identifier string, enableStdOut, enableStdErr bool, logFlags int) (err error) {

var exists bool
var prefix string
@ -54,10 +60,12 @@ func (m *MultiLogger) AddStdLogger(identifier string, logFlags int) (err error)
}

m.Loggers[identifier] = &StdLogger{
Logger: nil,
EnableDebug: m.EnableDebug,
Prefix: m.Prefix,
LogFlags: logFlags,
Logger: nil,
EnableDebug: m.EnableDebug,
Prefix: m.Prefix,
LogFlags: logFlags,
EnableStdOut: enableStdOut,
EnableStdErr: enableStdErr,
}
if err = m.Loggers[identifier].Setup(); err != nil {
return
@ -80,7 +88,7 @@ func (m *MultiLogger) AddStdLogger(identifier string, logFlags int) (err error)

logfilePath is a string for the path to the desired logfile.
*/
func (m *MultiLogger) AddFileLogger(identifier string, enableStdOut, enableStdErr bool, logFlags int, logfilePath string) (err error) {
func (m *MultiLogger) AddFileLogger(identifier string, logFlags int, logfilePath string) (err error) {

var exists bool
var success bool
@ -122,9 +130,7 @@ func (m *MultiLogger) AddFileLogger(identifier string, enableStdOut, enableStdEr
Prefix: m.Prefix,
LogFlags: logFlags,
},
Path: logfilePath,
EnableStdOut: enableStdOut,
EnableStdErr: enableStdErr,
Path: logfilePath,
}
if err = m.Loggers[identifier].Setup(); err != nil {
return

View File

@ -65,7 +65,7 @@ func (m *MultiLogger) AddDefaultLogger(identifier string, eventIDs *WinEventID,

See GetLogger for details.
*/
func (m *MultiLogger) AddWinLogger(identifier, source string, eventIDs *WinEventID) (err error) {
func (m *MultiLogger) AddWinLogger(identifier string, eventIDs *WinEventID) (err error) {

var exists bool
var prefix string
@ -84,9 +84,9 @@ func (m *MultiLogger) AddWinLogger(identifier, source string, eventIDs *WinEvent
}

m.Loggers[identifier] = &WinLogger{
Prefix: source,
Prefix: m.Prefix,
EnableDebug: m.EnableDebug,
eids: eventIDs,
EIDs: eventIDs,
}
if err = m.Loggers[identifier].Setup(); err != nil {
return

View File

@ -2,6 +2,7 @@ package logging

import (
"fmt"
`io`
`log`
`os`
`strings`
@ -13,14 +14,34 @@ import (
*/
func (l *StdLogger) Setup() (err error) {

var multi io.Writer

// This uses a shared handle across the import. We don't want that.
// l.Logger = log.Default()
if l.Prefix != "" {
l.Prefix = strings.TrimRight(l.Prefix, " ") + " "
// l.Logger.SetPrefix(l.Prefix)
}
// (stdlib).log.std is returned by log.Default(), which uses os.Stderr.
l.Logger = log.New(os.Stderr, l.Prefix, l.LogFlags)
// (stdlib).log.std is returned by log.Default(), which uses os.Stderr but we have flags for that.
// https://stackoverflow.com/a/36719588/733214
switch {
case l.EnableStdErr && l.EnableStdOut:
multi = io.MultiWriter(os.Stdout, os.Stderr)
case l.EnableStdErr:
multi = os.Stderr
case l.EnableStdOut:
multi = os.Stdout
default:
multi = nil
}
if multi != nil {
l.Logger = log.New(multi, l.Prefix, l.LogFlags)
} else {
// This honestly should throw an error.
l.Logger = &log.Logger{}
l.Logger.SetPrefix(l.Prefix)
l.Logger.SetFlags(l.LogFlags)
}

return
}

View File

@ -1 +1,196 @@
package logging

import (
`os`
`testing`
)

/*
TestStdLogger tests functionality for StdLogger.
*/
func TestStdLogger(t *testing.T) {

var l *StdLogger
var ltype string = "StdLogger"
var prefix string
var err error

l = &StdLogger{
EnableDebug: true,
Prefix: TestLogPrefix,
LogFlags: logFlags,
EnableStdOut: false,
EnableStdErr: true,
}

if err = l.Setup(); err != nil {
t.Fatalf("error when running Setup: %v", err.Error())
}

t.Logf("Logger %v passed Setup. Logger: %#v", ltype, l)

if err = l.Alert(testAlert, ltype); err != nil {
t.Fatalf("error for Alert: %v", err.Error())
}

if err = l.Crit(testCrit, ltype); err != nil {
t.Fatalf("error for Crit: %v", err.Error())
}

if err = l.Debug(testDebug, ltype); err != nil {
t.Fatalf("error for Debug: %v", err.Error())
}

if err = l.Emerg(testEmerg, ltype); err != nil {
t.Fatalf("error for Emerg: %v", err.Error())
}

if err = l.Err(testErr, ltype); err != nil {
t.Fatalf("error for Err: %v", err.Error())
}

if err = l.Info(testInfo, ltype); err != nil {
t.Fatalf("error for Alert: %v", err.Error())
}

if err = l.Notice(testNotice, ltype); err != nil {
t.Fatalf("error for Notice: %v", err.Error())
}

if err = l.Warning(testWarning, ltype); err != nil {
t.Fatalf("error for Warning: %v", err.Error())
}

if prefix, err = l.GetPrefix(); err != nil {
t.Fatalf("error when fetching prefix: %v", err.Error())
}

if prefix != (TestLogPrefix + " ") { // StdLogger adds a space at the end.
t.Fatalf("true prefix ('%v') does not match TestLogPrefix ('%v')", prefix, TestLogPrefix)
}
if err = l.SetPrefix(TestLogAltPrefix); err != nil {
t.Fatalf("error when setting prefix to %v: %v", TestLogAltPrefix, err.Error())
} else {
_ = l.SetPrefix(TestLogPrefix)
}

if err = l.DoDebug(false); err != nil {
t.Fatalf("error when changing debug to false: %v", err.Error())
} else if l.EnableDebug {
t.Fatalf("did not properly set Debug filter state")
} else {
_ = l.DoDebug(true)
}

if err = l.Shutdown(); err != nil {
t.Fatalf("Error when running Shutdown: %v", err.Error())
}

t.Logf("Logger %v passed all logging targets.", ltype)
}

/*
TestFileLogger tests functionality for FileLogger.
If the appropriate env var is set (see the EnvVarKeepLog constant), the temporary log file that is created will not be cleaned up.
*/
func TestFileLogger(t *testing.T) {

var l *FileLogger
var ltype string = "FileLogger"
var prefix string
var tempfile *os.File
var tempfilePath string
var keepLog bool
var err error

if tempfile, err = os.CreateTemp("", ".LOGGINGTEST_*"); err != nil {
t.Fatalf("error when creating temporary log file '%v': %v", tempfile.Name(), err.Error())
}
tempfilePath = tempfile.Name()
// We can close the handler immediately; we don't need it since the FileLogger opens its own.
if err = tempfile.Close(); err != nil {
t.Fatalf("error when closing handler for temporary log file '%v': %v", tempfile.Name(), err.Error())
}

l = &FileLogger{
StdLogger: StdLogger{
EnableDebug: true,
Prefix: TestLogPrefix,
LogFlags: logFlags,
},
Path: tempfilePath,
}

if err = l.Setup(); err != nil {
t.Fatalf("error when running Setup: %v", err.Error())
}

t.Logf("Logger %v passed Setup. Logger: %#v", ltype, l)

if err = l.Alert(testAlert, ltype); err != nil {
t.Fatalf("error for Alert: %v", err.Error())
}

if err = l.Crit(testCrit, ltype); err != nil {
t.Fatalf("error for Crit: %v", err.Error())
}

if err = l.Debug(testDebug, ltype); err != nil {
t.Fatalf("error for Debug: %v", err.Error())
}

if err = l.Emerg(testEmerg, ltype); err != nil {
t.Fatalf("error for Emerg: %v", err.Error())
}

if err = l.Err(testErr, ltype); err != nil {
t.Fatalf("error for Err: %v", err.Error())
}

if err = l.Info(testInfo, ltype); err != nil {
t.Fatalf("error for Alert: %v", err.Error())
}

if err = l.Notice(testNotice, ltype); err != nil {
t.Fatalf("error for Notice: %v", err.Error())
}

if err = l.Warning(testWarning, ltype); err != nil {
t.Fatalf("error for Warning: %v", err.Error())
}

if prefix, err = l.GetPrefix(); err != nil {
t.Fatalf("error when fetching prefix: %v", err.Error())
}

if prefix != (TestLogPrefix + " ") { // StdLogger (and thus FileLogger) adds a space at the end.
t.Fatalf("true prefix ('%v') does not match TestLogPrefix ('%v')", prefix, TestLogPrefix)
}
if err = l.SetPrefix(TestLogAltPrefix); err != nil {
t.Fatalf("error when setting prefix to %v: %v", TestLogAltPrefix, err.Error())
} else {
_ = l.SetPrefix(TestLogPrefix)
}

if err = l.DoDebug(false); err != nil {
t.Fatalf("error when changing debug to false: %v", err.Error())
} else if l.EnableDebug {
t.Fatalf("did not properly set Debug filter state")
} else {
_ = l.DoDebug(true)
}

if err = l.Shutdown(); err != nil {
t.Fatalf("Error when running Shutdown: %v", err.Error())
}

_, keepLog = os.LookupEnv(EnvVarKeepLog)

if !keepLog {
if err = os.Remove(tempfilePath); err != nil {
t.Fatalf("error when removing temporary log file '%v': %v", tempfilePath, err.Error())
}
}

t.Logf("Logger %v passed all logging targets.", ltype)
}

View File

@ -90,7 +90,7 @@ func GetLogger(enableDebug bool, source string, eventIDs *WinEventID, logConfigF
logger = &WinLogger{
Prefix: source,
EnableDebug: enableDebug,
eids: eventIDs,
EIDs: eventIDs,
}
} else {
if logFlags.HasFlag(LogFile) {

View File

@ -0,0 +1,205 @@
package logging

import (
`fmt`
`os`
`testing`
)

/*
TestWinLogger tests functionality for WinLogger.
You will probably need to run it with an Administrator shell.
*/
func TestWinLogger(t *testing.T) {

var l *WinLogger
var ltype string = "WinLogger"
var prefix string
var exists bool
var err error

l = &WinLogger{
EnableDebug: true,
Prefix: TestLogPrefix,
RemoveOnClose: true,
EIDs: DefaultEventID,
}

if exists, err = l.Exists(); err != nil {
t.Fatalf("error when checking for existence of registered Event Log source '%v': %v", TestLogPrefix, err.Error())
} else {
t.Logf("Prefix (source) '%v' exists before setup: %v", TestLogPrefix, exists)
}

if err = l.Setup(); err != nil {
t.Fatalf("error when running Setup: %v", err.Error())
}

if exists, err = l.Exists(); err != nil {
t.Fatalf("error when checking for existence of registered Event Log source '%v': %v", TestLogPrefix, err.Error())
} else {
t.Logf("Prefix (source) '%v' exists after setup: %v", TestLogPrefix, exists)
}

t.Logf("Logger %v passed Setup. Logger: %#v", ltype, l)

if err = l.Alert(testAlert, ltype); err != nil {
t.Fatalf("error for Alert: %v", err.Error())
}

if err = l.Crit(testCrit, ltype); err != nil {
t.Fatalf("error for Crit: %v", err.Error())
}

if err = l.Debug(testDebug, ltype); err != nil {
t.Fatalf("error for Debug: %v", err.Error())
}

if err = l.Emerg(testEmerg, ltype); err != nil {
t.Fatalf("error for Emerg: %v", err.Error())
}

if err = l.Err(testErr, ltype); err != nil {
t.Fatalf("error for Err: %v", err.Error())
}

if err = l.Info(testInfo, ltype); err != nil {
t.Fatalf("error for Alert: %v", err.Error())
}

if err = l.Notice(testNotice, ltype); err != nil {
t.Fatalf("error for Notice: %v", err.Error())
}

if err = l.Warning(testWarning, ltype); err != nil {
t.Fatalf("error for Warning: %v", err.Error())
}

if prefix, err = l.GetPrefix(); err != nil {
t.Fatalf("error when fetching prefix: %v", err.Error())
}

if prefix != TestLogPrefix {
t.Fatalf("true prefix ('%v') does not match TestLogPrefix ('%v')", prefix, TestLogPrefix)
}
if err = l.SetPrefix(TestLogAltPrefix); err != nil {
t.Fatalf("error when setting prefix to %v: %v", TestLogAltPrefix, err.Error())
} else {
_ = l.SetPrefix(TestLogPrefix)
}

if err = l.DoDebug(false); err != nil {
t.Fatalf("error when changing debug to false: %v", err.Error())
} else if l.EnableDebug {
t.Fatalf("did not properly set Debug filter state")
} else {
_ = l.DoDebug(true)
}

if err = l.Shutdown(); err != nil {
t.Fatalf("Error when running Shutdown: %v", err.Error())
}

t.Logf("Logger %v passed all logging targets.", ltype)
}

// TestDefaultLogger tests GetLogger.
func TestDefaultLogger(t *testing.T) {

var l Logger
var tempfile *os.File
var tempfilePath string
var keepLog bool
var ltype string
var prefix string
var testPrefix string
var err error

if tempfile, err = os.CreateTemp("", ".LOGGINGTEST_*"); err != nil {
t.Fatalf("error when creating temporary log file '%v': %v", tempfile.Name(), err.Error())
}
tempfilePath = tempfile.Name()
// We can close the handler immediately; we don't need it since the FileLogger opens its own.
if err = tempfile.Close(); err != nil {
t.Fatalf("error when closing handler for temporary log file '%v': %v", tempfile.Name(), err.Error())
}

if l, err = GetLogger(true, TestLogPrefix, DefaultEventID, logFlags, tempfilePath); err != nil {
t.Fatalf("error when spawning default Windows logger via GetLogger: %v", err.Error())
}

ltype = fmt.Sprintf("%T", l)

t.Logf("Logger %v passed Setup. Logger: %#v", ltype, l)

if err = l.Alert(testAlert, ltype); err != nil {
t.Fatalf("error for Alert: %v", err.Error())
}

if err = l.Crit(testCrit, ltype); err != nil {
t.Fatalf("error for Crit: %v", err.Error())
}

if err = l.Debug(testDebug, ltype); err != nil {
t.Fatalf("error for Debug: %v", err.Error())
}

if err = l.Emerg(testEmerg, ltype); err != nil {
t.Fatalf("error for Emerg: %v", err.Error())
}

if err = l.Err(testErr, ltype); err != nil {
t.Fatalf("error for Err: %v", err.Error())
}

if err = l.Info(testInfo, ltype); err != nil {
t.Fatalf("error for Alert: %v", err.Error())
}

if err = l.Notice(testNotice, ltype); err != nil {
t.Fatalf("error for Notice: %v", err.Error())
}

if err = l.Warning(testWarning, ltype); err != nil {
t.Fatalf("error for Warning: %v", err.Error())
}

if prefix, err = l.GetPrefix(); err != nil {
t.Fatalf("error when fetching prefix: %v", err.Error())
}

if ltype == "StdLogger" || ltype == "FileLogger" { // StdLogger (and thus FileLogger) adds a space at the end.
testPrefix = TestLogPrefix + " "
} else {
testPrefix = TestLogPrefix
}

if prefix != testPrefix {
t.Fatalf("true prefix ('%v') does not match TestLogPrefix ('%v')", prefix, TestLogPrefix)
}
if err = l.SetPrefix(TestLogAltPrefix); err != nil {
t.Fatalf("error when setting prefix to %v: %v", TestLogAltPrefix, err.Error())
} else {
_ = l.SetPrefix(TestLogPrefix)
}

if err = l.DoDebug(false); err != nil {
t.Fatalf("error when changing debug to false: %v", err.Error())
} else {
_ = l.DoDebug(true)
}

if err = l.Shutdown(); err != nil {
t.Fatalf("Error when running Shutdown: %v", err.Error())
}

_, keepLog = os.LookupEnv(EnvVarKeepLog)

if !keepLog {
if err = os.Remove(tempfilePath); err != nil {
t.Fatalf("error when removing temporary log file '%v': %v", tempfilePath, err.Error())
}
}

t.Logf("Logger %v passed all logging targets.", ltype)
}

View File

@ -29,14 +29,14 @@ func (l *WinLogger) Setup() (err error) {
Since we use eventcreate, all Event IDs must be 1 <= eid <= 1000.
*/
for _, eid := range []uint32{
l.eids.Alert,
l.eids.Crit,
l.eids.Debug,
l.eids.Emerg,
l.eids.Err,
l.eids.Info,
l.eids.Notice,
l.eids.Warning,
l.EIDs.Alert,
l.EIDs.Crit,
l.EIDs.Debug,
l.EIDs.Emerg,
l.EIDs.Err,
l.EIDs.Info,
l.EIDs.Notice,
l.EIDs.Warning,
} {
if !((eid <= EIDMax) && (EIDMin <= eid)) {
err = ErrBadEid
@ -204,7 +204,7 @@ func (l *WinLogger) Alert(s string, v ...interface{}) (err error) {
}

// Treat ALERT as Warning
err = l.elog.Warning(l.eids.Alert, msg)
err = l.elog.Warning(l.EIDs.Alert, msg)

return
}
@ -221,7 +221,7 @@ func (l *WinLogger) Crit(s string, v ...interface{}) (err error) {
}

// Treat CRIT as Error
err = l.elog.Error(l.eids.Crit, msg)
err = l.elog.Error(l.EIDs.Crit, msg)

return
}
@ -242,7 +242,7 @@ func (l *WinLogger) Debug(s string, v ...interface{}) (err error) {
}

// Treat DEBUG as Info
err = l.elog.Info(l.eids.Debug, msg)
err = l.elog.Info(l.EIDs.Debug, msg)

return

@ -260,7 +260,7 @@ func (l *WinLogger) Emerg(s string, v ...interface{}) (err error) {
}

// Treat EMERG as Error
err = l.elog.Error(l.eids.Emerg, msg)
err = l.elog.Error(l.EIDs.Emerg, msg)

return

@ -277,7 +277,7 @@ func (l *WinLogger) Err(s string, v ...interface{}) (err error) {
msg = s
}

err = l.elog.Error(l.eids.Err, msg)
err = l.elog.Error(l.EIDs.Err, msg)

return

@ -294,7 +294,7 @@ func (l *WinLogger) Info(s string, v ...interface{}) (err error) {
msg = s
}

err = l.elog.Info(l.eids.Info, msg)
err = l.elog.Info(l.EIDs.Info, msg)

return

@ -312,7 +312,7 @@ func (l *WinLogger) Notice(s string, v ...interface{}) (err error) {
}

// Treat NOTICE as Info
err = l.elog.Info(l.eids.Notice, msg)
err = l.elog.Info(l.EIDs.Notice, msg)

return

@ -329,7 +329,7 @@ func (l *WinLogger) Warning(s string, v ...interface{}) (err error) {
msg = s
}

err = l.elog.Warning(l.eids.Warning, msg)
err = l.elog.Warning(l.EIDs.Warning, msg)

return


View File

@ -0,0 +1,121 @@
package logging

import (
`os`
`testing`
)

// TestMultiLogger tests GetMultiLogger and MultiLogger methods.
func TestMultiLogger(t *testing.T) {

var l *MultiLogger
var tempfile *os.File
var tempfilePath string
var keepLog bool
var ltype string = "MultiLogger"
var prefix string
var testPrefix string
var err error

if tempfile, err = os.CreateTemp("", ".LOGGINGTEST_*"); err != nil {
t.Fatalf("error when creating temporary log file '%v': %v", tempfile.Name(), err.Error())
}
tempfilePath = tempfile.Name()
// We can close the handler immediately; we don't need it since the FileLogger opens its own.
if err = tempfile.Close(); err != nil {
t.Fatalf("error when closing handler for temporary log file '%v': %v", tempfile.Name(), err.Error())
}

l = GetMultiLogger(true, TestLogPrefix)

if err = l.AddStdLogger("StdLogger", false, true, logFlags); err != nil {
t.Fatalf("error when adding StdLogger to MultiLogger: %v", err.Error())
}
if err = l.AddFileLogger("FileLogger", logFlags, tempfilePath); err != nil {
t.Fatalf("error when adding FileLogger to MultiLogger: %v", err.Error())
}

if err = l.AddDefaultLogger("DefaultLogger", logFlags, tempfilePath); err != nil {
t.Fatalf("error when adding default logger to MultiLogger: %v", err.Error())
}

if err = l.AddSysdLogger("SystemDLogger"); err != nil {
t.Fatalf("error when adding SystemDLogger to MultiLogger: %v", err.Error())
}
if err = l.AddSyslogLogger("SyslogLogger"); err != nil {
t.Fatalf("error when adding SyslogLogger to MultiLogger: %v", err.Error())
}

t.Logf("Logger %v passed Setup. Logger: %#v", ltype, l)

if err = l.Alert(testAlert, ltype); err != nil {
t.Fatalf("error for Alert: %v", err.Error())
}

if err = l.Crit(testCrit, ltype); err != nil {
t.Fatalf("error for Crit: %v", err.Error())
}

if err = l.Debug(testDebug, ltype); err != nil {
t.Fatalf("error for Debug: %v", err.Error())
}

if err = l.Emerg(testEmerg, ltype); err != nil {
t.Fatalf("error for Emerg: %v", err.Error())
}

if err = l.Err(testErr, ltype); err != nil {
t.Fatalf("error for Err: %v", err.Error())
}

if err = l.Info(testInfo, ltype); err != nil {
t.Fatalf("error for Alert: %v", err.Error())
}

if err = l.Notice(testNotice, ltype); err != nil {
t.Fatalf("error for Notice: %v", err.Error())
}

if err = l.Warning(testWarning, ltype); err != nil {
t.Fatalf("error for Warning: %v", err.Error())
}

if prefix, err = l.GetPrefix(); err != nil {
t.Fatalf("error when fetching prefix: %v", err.Error())
}

if ltype == "StdLogger" || ltype == "FileLogger" { // StdLogger (and thus FileLogger) adds a space at the end.
testPrefix = TestLogPrefix + " "
} else {
testPrefix = TestLogPrefix
}

if prefix != testPrefix {
t.Fatalf("true prefix ('%v') does not match TestLogPrefix ('%v')", prefix, TestLogPrefix)
}
if err = l.SetPrefix(TestLogAltPrefix); err != nil {
t.Fatalf("error when setting prefix to %v: %v", TestLogAltPrefix, err.Error())
} else {
_ = l.SetPrefix(TestLogPrefix)
}

if err = l.DoDebug(false); err != nil {
t.Fatalf("error when changing debug to false: %v", err.Error())
} else {
_ = l.DoDebug(true)
}

if err = l.Shutdown(); err != nil {
t.Fatalf("Error when running Shutdown: %v", err.Error())
}

_, keepLog = os.LookupEnv(EnvVarKeepLog)

if !keepLog {
if err = os.Remove(tempfilePath); err != nil {
t.Fatalf("error when removing temporary log file '%v': %v", tempfilePath, err.Error())
}
}

t.Logf("Logger %v passed all logging targets.", ltype)
}

View File

@ -0,0 +1,118 @@
package logging

import (
`os`
`testing`
)

// TestMultiLogger tests GetMultiLogger and MultiLogger methods.
func TestMultiLogger(t *testing.T) {

var l *MultiLogger
var tempfile *os.File
var tempfilePath string
var keepLog bool
var ltype string = "MultiLogger"
var prefix string
var testPrefix string
var err error

if tempfile, err = os.CreateTemp("", ".LOGGINGTEST_*"); err != nil {
t.Fatalf("error when creating temporary log file '%v': %v", tempfile.Name(), err.Error())
}
tempfilePath = tempfile.Name()
// We can close the handler immediately; we don't need it since the FileLogger opens its own.
if err = tempfile.Close(); err != nil {
t.Fatalf("error when closing handler for temporary log file '%v': %v", tempfile.Name(), err.Error())
}

l = GetMultiLogger(true, TestLogPrefix)

if err = l.AddStdLogger("StdLogger", false, true, logFlags); err != nil {
t.Fatalf("error when adding StdLogger to MultiLogger: %v", err.Error())
}
if err = l.AddFileLogger("FileLogger", logFlags, tempfilePath); err != nil {
t.Fatalf("error when adding FileLogger to MultiLogger: %v", err.Error())
}

if err = l.AddDefaultLogger("DefaultLogger", DefaultEventID, logFlags, tempfilePath); err != nil {
t.Fatalf("error when adding default logger to MultiLogger: %v", err.Error())
}

if err = l.AddWinLogger("WinLogger", DefaultEventID); err != nil {
t.Fatalf("error when adding WinLogger to MultiLogger: %v", err.Error())
}

t.Logf("Logger %v passed Setup. Logger: %#v", ltype, l)

if err = l.Alert(testAlert, ltype); err != nil {
t.Fatalf("error for Alert: %v", err.Error())
}

if err = l.Crit(testCrit, ltype); err != nil {
t.Fatalf("error for Crit: %v", err.Error())
}

if err = l.Debug(testDebug, ltype); err != nil {
t.Fatalf("error for Debug: %v", err.Error())
}

if err = l.Emerg(testEmerg, ltype); err != nil {
t.Fatalf("error for Emerg: %v", err.Error())
}

if err = l.Err(testErr, ltype); err != nil {
t.Fatalf("error for Err: %v", err.Error())
}

if err = l.Info(testInfo, ltype); err != nil {
t.Fatalf("error for Alert: %v", err.Error())
}

if err = l.Notice(testNotice, ltype); err != nil {
t.Fatalf("error for Notice: %v", err.Error())
}

if err = l.Warning(testWarning, ltype); err != nil {
t.Fatalf("error for Warning: %v", err.Error())
}

if prefix, err = l.GetPrefix(); err != nil {
t.Fatalf("error when fetching prefix: %v", err.Error())
}

if ltype == "StdLogger" || ltype == "FileLogger" { // StdLogger (and thus FileLogger) adds a space at the end.
testPrefix = TestLogPrefix + " "
} else {
testPrefix = TestLogPrefix
}

if prefix != testPrefix {
t.Fatalf("true prefix ('%v') does not match TestLogPrefix ('%v')", prefix, TestLogPrefix)
}
if err = l.SetPrefix(TestLogAltPrefix); err != nil {
t.Fatalf("error when setting prefix to %v: %v", TestLogAltPrefix, err.Error())
} else {
_ = l.SetPrefix(TestLogPrefix)
}

if err = l.DoDebug(false); err != nil {
t.Fatalf("error when changing debug to false: %v", err.Error())
} else {
_ = l.DoDebug(true)
}

if err = l.Shutdown(); err != nil {
t.Fatalf("Error when running Shutdown: %v", err.Error())
}

_, keepLog = os.LookupEnv(EnvVarKeepLog)

if !keepLog {
if err = os.Remove(tempfilePath); err != nil {
t.Fatalf("error when removing temporary log file '%v': %v", tempfilePath, err.Error())
}
}

t.Logf("Logger %v passed all logging targets.", ltype)
}

View File

@ -48,6 +48,26 @@ type StdLogger struct {
You will need to run *StdLogger.Shutdown and then *StdLogger.Setup again if you wish to change this.
*/
LogFlags int
/*
EnableStdOut is true if the log will send to STDOUT.
If false (default), no output will be written to STDOUT.
You will need to run StdLogger.Shutdown and then StdLogger.Setup again if you wish to change this.

If EnableStdOut is false and EnableStdErr is false, no logging output will occur by default
and StdLogger.Logger will be largely useless.
It will be up to you to modify the underlying log.Logger to behave as you want.
*/
EnableStdOut bool
/*
EnableStdErr is true if the log will send to STDERR.
If false (default), no output will be written to STDERR.
You will need to run StdLogger.Shutdown and then StdLogger.Setup again if you wish to change this.

If EnableStdErr is false and EnableStdOut is false, no logging output will occur by default
and StdLogger.Logger will be largely useless.
It will be up to you to modify the underlying log.Logger to behave as you want.
*/
EnableStdErr bool
}

/*
@ -62,18 +82,6 @@ type FileLogger struct {
StdLogger
// Path is the path to the logfile.
Path string
/*
EnableStdOut is true if the log will send to STDOUT as well as the file (and STDERR if FileLogger.EnableStdErr == true).
If false (default), it will only (silently) write to the log file.
You will need to run FileLogger.Shutdown and then FileLogger.Setup again if you wish to change this.
*/
EnableStdOut bool
/*
EnableStdErr is true if the log will send to STDERR as well as the file (and STDOUT if FileLogger.EnableStdOut == true).
If false (default), it will only (silently) write to the log file.
You will need to run *FileLogger.Shutdown and then *FileLogger.Setup again if you wish to change this.
*/
EnableStdErr bool
// writer is used for the writing out of the log file.
writer *os.File
}

View File

@ -4,11 +4,15 @@ import (
`log/syslog`
)

/*
SystemDLogger (yes, I'm aware it's actually written as "systemd") writes to journald on systemd-enabled systems.
*/
type SystemDLogger struct {
EnableDebug bool
Prefix string
}

// SyslogLogger writes to syslog on syslog-enabled systems.