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 }