Files
go_goutils/logging/funcs_windows.go
brent saner 01adbfc605 v1.12.0
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().
2025-11-22 15:53:38 -05:00

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
}