2 Commits

Author SHA1 Message Date
brent saner
79f10b7611 v1.12.1
FIXED:
* Aaaannnddd need to make the Windows multilogger AddDefaultLogger
  use the right/matching parameters as well.
2025-11-22 17:19:41 -05:00
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
5 changed files with 53 additions and 20 deletions

View File

@@ -1,3 +1,5 @@
- logging probably needs mutexes
- macOS support beyond the legacy NIX stuff. it apparently uses something called "ULS", "Unified Logging System". - 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/logging
-- https://developer.apple.com/documentation/os/generating-log-messages-from-your-code -- https://developer.apple.com/documentation/os/generating-log-messages-from-your-code

View File

@@ -21,7 +21,7 @@ import (
Only the first logPaths entry that "works" will be used, later entries will be ignored. Only the first logPaths entry that "works" will be used, later entries will be ignored.
Currently this will almost always return a WinLogger. Currently this will almost always return a WinLogger.
*/ */
func (m *MultiLogger) AddDefaultLogger(identifier string, eventIDs *WinEventID, logFlags int, logPaths ...string) (err error) { func (m *MultiLogger) AddDefaultLogger(identifier string, logFlags int, logPaths ...string) (err error) {
var l Logger var l Logger
var exists bool var exists bool
@@ -36,9 +36,9 @@ func (m *MultiLogger) AddDefaultLogger(identifier string, eventIDs *WinEventID,
} }
if logPaths != nil { if logPaths != nil {
l, err = GetLogger(m.EnableDebug, m.Prefix, eventIDs, logFlags, logPaths...) l, err = GetLogger(m.EnableDebug, m.Prefix, logFlags, logPaths...)
} else { } else {
l, err = GetLogger(m.EnableDebug, m.Prefix, eventIDs, logFlags) l, err = GetLogger(m.EnableDebug, m.Prefix, logFlags)
} }
if err != nil { if err != nil {
return return

View File

@@ -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), 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. 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 `logConfigFlags` is the corresponding flag(s) OR'd for [StdLogger.LogFlags] (and/or the [StdLogger.LogFlags] for [FileLogger])
https://pkg.go.dev/log#pkg-constants for details. 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, `logPaths` is an (optional) list of strings to use as paths to test for writing.
it will be used (assuming you have no higher-level loggers available). 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. Only the first `logPaths` entry that "works" will be used, later entries will be ignored.
Currently this will almost always return a WinLogger. 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 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), If you want to log to multiple [Logger] destinations at once (or want to log to an explicit [Logger] type),
use GetMultiLogger. 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 logPath string
var logFlags bitmask.MaskBit var logFlags bitmask.MaskBit

View File

@@ -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()) 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()) t.Fatalf("error when spawning default Windows logger via GetLogger: %v", err.Error())
} }

View File

@@ -35,7 +35,7 @@ func TestMultiLogger(t *testing.T) {
t.Fatalf("error when adding FileLogger to MultiLogger: %v", err.Error()) t.Fatalf("error when adding FileLogger to MultiLogger: %v", err.Error())
} }
if err = l.AddDefaultLogger("DefaultLogger", DefaultEventID, logFlags, tempfilePath); err != nil { if err = l.AddDefaultLogger("DefaultLogger", logFlags, tempfilePath); err != nil {
t.Fatalf("error when adding default logger to MultiLogger: %v", err.Error()) t.Fatalf("error when adding default logger to MultiLogger: %v", err.Error())
} }