FIXED: * logging package on Windows had a non-conformant GetLogger(). While this fix technically breaks API, this was a horribly broken thing so I'm including it as a minor bump instead of major and thus breaking SemVer. Too bad, so sad, deal with it; Go modules have versioning for a reason. The previous logging.GetLogger() behavior on Windows has been moved to logging.GetLoggerWindows().
163 lines
5.2 KiB
Go
163 lines
5.2 KiB
Go
package logging
|
|
|
|
import (
|
|
`errors`
|
|
`path`
|
|
`strings`
|
|
|
|
`r00t2.io/goutils/bitmask`
|
|
`r00t2.io/sysutils/paths`
|
|
)
|
|
|
|
/*
|
|
GetLogger returns an instance of Logger that best suits your system's capabilities.
|
|
Note that this is a VERY generalized interface to the Windows Event Log to conform with multiplatform compat.
|
|
You'd have a little more flexibility with [GetLoggerWindows] (this function wraps that one).
|
|
If you need more custom behavior than that, I recommend using [golang.org/x/sys/windows/svc/eventlog] directly
|
|
(or using another logging module).
|
|
|
|
If `enableDebug` is true, debug messages (which according to your program may or may not contain sensitive data) are rendered and written (otherwise they are ignored).
|
|
|
|
The `prefix` correlates to the `source` parameter in [GetLoggerWindows], and this function inherently uses [DefaultEventID],
|
|
but otherwise it remains the same as [GetLoggerWindows] - refer to it for documentation on the other parameters.
|
|
|
|
If you call [GetLogger], you will only get a single ("best") logger your system supports.
|
|
If you want to log to multiple [Logger] destinations at once (or want to log to an explicit [Logger] type),
|
|
use [GetMultiLogger].
|
|
*/
|
|
func GetLogger(enableDebug bool, prefix string, logConfigFlags int, logPaths ...string) (logger Logger, err error) {
|
|
|
|
if logger, err = GetLoggerWindows(enableDebug, prefix, DefaultEventID, logConfigFlags, logPaths...); err != nil {
|
|
return
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
/*
|
|
GetLoggerWindows returns an instance of Logger that best suits your system's capabilities.
|
|
This is a slightly less (but still quite) generalized interface to the Windows Event Log than [GetLogger].
|
|
|
|
If you require more robust logging capabilities (e.g. custom event IDs per uniquely identifiable event),
|
|
you will want to set up your own logger via [golang.org/x/sys/windows/svc/eventlog].
|
|
|
|
If `enableDebug` is true, debug messages (which according to your program may or may not contain sensitive data)
|
|
are rendered and written (otherwise they are ignored).
|
|
|
|
A blank `source` will return an error as it's used as the source name.
|
|
Throughout the rest of this documentation you will see this referred to as the `prefix` to remain platform-agnostic.
|
|
|
|
A pointer to a [WinEventID] struct may be specified for `eventIDs` to map extended logging levels
|
|
(as Windows only supports three levels natively).
|
|
If it is nil, a default one (DefaultEventID) will be used.
|
|
|
|
`logConfigFlags` is the corresponding flag(s) OR'd for [StdLogger.LogFlags] (and/or the [StdLogger.LogFlags] for [FileLogger])
|
|
if either is selected. See [StdLogger.LogFlags] and [stdlib log's constants] for details.
|
|
|
|
`logPaths` is an (optional) list of strings to use as paths to test for writing.
|
|
If the file can be created/written to, it will be used (assuming you have no higher-level loggers available).
|
|
|
|
Only the first `logPaths` entry that "works" will be used, later entries will be ignored.
|
|
Currently this will almost always return a [WinLogger].
|
|
|
|
If you call [GetLoggerWindows], you will only get a single ("best") logger your system supports.
|
|
If you want to log to multiple [Logger] destinations at once (or want to log to an explicit [Logger] type),
|
|
use [GetMultiLogger].
|
|
|
|
[stdlib log's constants]: https://pkg.go.dev/log#pkg-constants
|
|
*/
|
|
func GetLoggerWindows(enableDebug bool, source string, eventIDs *WinEventID, logConfigFlags int, logPaths ...string) (logger Logger, err error) {
|
|
|
|
var logPath string
|
|
var logFlags bitmask.MaskBit
|
|
var exists bool
|
|
var success bool
|
|
var ckLogPaths []string
|
|
var prefix string
|
|
|
|
if strings.TrimSpace(source) == "" {
|
|
err = errors.New("invalid source for Windows logging")
|
|
return
|
|
}
|
|
|
|
// Configure system-supported logger(s). The Windows Event Logger (should) ALWAYS be available.
|
|
logFlags.AddFlag(LogWinLogger)
|
|
if eventIDs == nil {
|
|
eventIDs = DefaultEventID
|
|
}
|
|
|
|
if logPaths != nil {
|
|
ckLogPaths = logPaths
|
|
ckLogPaths = append(ckLogPaths, defLogPaths...)
|
|
|
|
for _, p := range ckLogPaths {
|
|
if exists, _ = paths.RealPathExists(&p); exists {
|
|
if success, err = testOpen(p); err != nil {
|
|
continue
|
|
} else if !success {
|
|
continue
|
|
}
|
|
logFlags.AddFlag(LogFile)
|
|
logPath = p
|
|
break
|
|
} else {
|
|
dirPath := path.Dir(p)
|
|
if err = paths.MakeDirIfNotExist(dirPath); err != nil {
|
|
continue
|
|
}
|
|
if success, err = testOpen(p); err != nil {
|
|
continue
|
|
} else if !success {
|
|
continue
|
|
}
|
|
logFlags.AddFlag(LogFile)
|
|
logPath = p
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
if logFlags.HasFlag(LogWinLogger) {
|
|
logger = &WinLogger{
|
|
Prefix: source,
|
|
EnableDebug: enableDebug,
|
|
EIDs: eventIDs,
|
|
}
|
|
} else {
|
|
if logFlags.HasFlag(LogFile) {
|
|
logger = &FileLogger{
|
|
StdLogger: StdLogger{
|
|
Prefix: source,
|
|
EnableDebug: enableDebug,
|
|
LogFlags: logConfigFlags,
|
|
},
|
|
Path: logPath,
|
|
}
|
|
} else {
|
|
logger = &StdLogger{
|
|
Prefix: source,
|
|
EnableDebug: enableDebug,
|
|
LogFlags: logConfigFlags,
|
|
}
|
|
}
|
|
}
|
|
|
|
if err = logger.Setup(); err != nil {
|
|
return
|
|
}
|
|
if source != "\x00" {
|
|
if err = logger.SetPrefix(source); err != nil {
|
|
return
|
|
}
|
|
}
|
|
|
|
if prefix, err = logger.GetPrefix(); err != nil {
|
|
return
|
|
}
|
|
|
|
logger.Debug("logger initialized of type %T with source %v", logger, prefix)
|
|
|
|
return
|
|
|
|
}
|