From 01adbfc605bd6b385c82170dfd3556f47be2c076 Mon Sep 17 00:00:00 2001 From: brent saner Date: Sat, 22 Nov 2025 15:46:23 -0500 Subject: [PATCH] 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(). --- logging/TODO | 2 + logging/funcs_multilogger_mgr_windows.go | 4 +- logging/funcs_windows.go | 61 ++++++++++++++++++------ logging/funcs_windows_test.go | 2 +- 4 files changed, 51 insertions(+), 18 deletions(-) diff --git a/logging/TODO b/logging/TODO index 1af075a..1b026a0 100644 --- a/logging/TODO +++ b/logging/TODO @@ -1,3 +1,5 @@ +- logging probably needs mutexes + - macOS support beyond the legacy NIX stuff. it apparently uses something called "ULS", "Unified Logging System". -- https://developer.apple.com/documentation/os/logging -- https://developer.apple.com/documentation/os/generating-log-messages-from-your-code diff --git a/logging/funcs_multilogger_mgr_windows.go b/logging/funcs_multilogger_mgr_windows.go index 1354499..c154f7c 100644 --- a/logging/funcs_multilogger_mgr_windows.go +++ b/logging/funcs_multilogger_mgr_windows.go @@ -36,9 +36,9 @@ func (m *MultiLogger) AddDefaultLogger(identifier string, eventIDs *WinEventID, } if logPaths != nil { - l, err = GetLogger(m.EnableDebug, m.Prefix, eventIDs, logFlags, logPaths...) + l, err = GetLoggerWindows(m.EnableDebug, m.Prefix, eventIDs, logFlags, logPaths...) } else { - l, err = GetLogger(m.EnableDebug, m.Prefix, eventIDs, logFlags) + l, err = GetLoggerWindows(m.EnableDebug, m.Prefix, eventIDs, logFlags) } if err != nil { return diff --git a/logging/funcs_windows.go b/logging/funcs_windows.go index 07436ed..f49300e 100644 --- a/logging/funcs_windows.go +++ b/logging/funcs_windows.go @@ -10,32 +10,63 @@ import ( ) /* - 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. + 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 (golang.org/x/sys/windows/svc/eventlog). + 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). + 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. Other functions, struct fields, etc. will refer to this as the "prefix". + 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). + 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 / FileLogger.StdLogger.LogFlags if either is selected. See StdLogger.LogFlags and - https://pkg.go.dev/log#pkg-constants for details. + `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). + `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. + 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 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. + 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 GetLogger(enableDebug bool, source string, eventIDs *WinEventID, logConfigFlags int, logPaths ...string) (logger Logger, err error) { +func GetLoggerWindows(enableDebug bool, source string, eventIDs *WinEventID, logConfigFlags int, logPaths ...string) (logger Logger, err error) { var logPath string var logFlags bitmask.MaskBit diff --git a/logging/funcs_windows_test.go b/logging/funcs_windows_test.go index 4635467..b0c58b2 100644 --- a/logging/funcs_windows_test.go +++ b/logging/funcs_windows_test.go @@ -124,7 +124,7 @@ func TestDefaultLogger(t *testing.T) { 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 { + if l, err = GetLoggerWindows(true, TestLogPrefix, DefaultEventID, logFlags, tempfilePath); err != nil { t.Fatalf("error when spawning default Windows logger via GetLogger: %v", err.Error()) }