brent saner d9bd928edb
v1.9.0
ADD:
* `iox` subpackage

FIX:
* `logging` now has a way to return logWritier directly
* added significant `io.*` interface compat to logWriter -- allowing a `logging.Logger` to essentially be used for a large amount of io interaction in other libraries.
2025-07-31 03:45:32 -04:00

65 lines
3.2 KiB
Go

/*
Package logging implements and presents various loggers under a unified interface, making them completely swappable.
These particular loggers (logging.Logger) available are:
NullLogger
StdLogger
FileLogger
SystemDLogger (Linux only)
SyslogLogger (Linux/macOS/other *NIX-like only)
WinLogger (Windows only)
There is a seventh type of logging.Logger, MultiLogger, that allows for multiple loggers to be written to with a single call.
(This is similar to stdlib's io.MultiWriter()'s return value, but with priority awareness and fmt string support).
As you may have guessed, NullLogger doesn't actually log anything but is fully "functional" as a logging.Logger (similar to io.discard/io.Discard()'s return).
Note that for some Loggers, the prefix may be modified after the Logger has already initialized.
"Literal" loggers (StdLogger and FileLogger) will append a space to the end of the prefix by default.
If this is undesired (unlikely), you will need to modify (Logger).Prefix and run (Logger).Logger.SetPrefix(yourPrefixHere) for the respective logger.
Every logging.Logger type has the following methods that correspond to certain "levels".
Alert(s string, v ...interface{}) (err error)
Crit(s string, v ...interface{}) (err error)
Debug(s string, v ...interface{}) (err error)
Emerg(s string, v ...interface{}) (err error)
Err(s string, v ...interface{}) (err error)
Info(s string, v ...interface{}) (err error)
Notice(s string, v ...interface{}) (err error)
Warning(s string, v ...interface{}) (err error)
Not all loggers implement the concept of levels, so approximations are made when/where possible.
In each of the above methods, s is the message that is optionally in a fmt.Sprintf-compatible format.
If it is, the values to fmt.Sprintf can be passed as v.
Note that in the case of a MultiLogger, err (if not nil) will be a (r00t2.io/goutils/)multierr.MultiError.
logging.Logger types also have the following methods:
DoDebug(d bool) (err error)
GetDebug() (d bool)
SetPrefix(p string) (err error)
GetPrefix() (p string, err error)
Setup() (err error)
Shutdown() (err error)
In some cases, Logger.Setup and Logger.Shutdown are no-ops. In other cases, they perform necessary initialization/cleanup and closing of the logger.
It is recommended to *always* run Setup and Shutdown before and after using, respectively, regardless of the actual logging.Logger type.
Lastly, all logging.Loggers have a ToLogger() method. This returns a *log.Logger (from stdlib log), which also conforms to io.Writer inherently.
In addition. all have a ToRaw() method, which extends a Logger even further and returns an unexported type (*logging.logWriter) compatible with:
- io.ByteWriter
- io.Writer
- io.WriteCloser (Shutdown() on the Logger backend is called during Close(), rendering the underlying Logger unsafe to use afterwards)
- io.StringWriter
and, if stdlib io ever defines an e.g. RuneWriter (WriteRune(r rune) (n int, err error)), it will conform to that too (see (r00t2.io/goutils/iox).RuneWriter).
Obviously this and io.ByteWriter are fairly silly, as they're intended to be high-speed throughput-optimized methods, but if you wanted to e.g.
log every single byte on a wire as a separate log message, go ahead; I'm not your dad.
*/
package logging