osbase/logtree.LeveledLogger -> go/logging.Leveled
This factors out the common leveled logger interface out of the logtree.
We want to use the same interface outside of logtree/supervisor usage
within the resolver code, which will be exposed to clients.
Change-Id: I299e76d91e8cefddf8f36f1e58432418c4694df2
Reviewed-on: https://review.monogon.dev/c/monogon/+/3411
Reviewed-by: Tim Windelschmidt <tim@monogon.tech>
Tested-by: Jenkins CI
diff --git a/go/logging/BUILD.bazel b/go/logging/BUILD.bazel
new file mode 100644
index 0000000..4a5feae
--- /dev/null
+++ b/go/logging/BUILD.bazel
@@ -0,0 +1,8 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+ name = "logging",
+ srcs = ["leveled.go"],
+ importpath = "source.monogon.dev/go/logging",
+ visibility = ["//visibility:public"],
+)
diff --git a/go/logging/leveled.go b/go/logging/leveled.go
new file mode 100644
index 0000000..a32b62d
--- /dev/null
+++ b/go/logging/leveled.go
@@ -0,0 +1,123 @@
+package logging
+
+// Leveled is a generic interface for glog-style logging. There are four
+// hardcoded log severities, in increasing order: INFO, WARNING, ERROR, FATAL.
+// Logging at a certain severity level logs not only to consumers expecting data
+// at that severity level, but also all lower severity levels. For example, an
+// ERROR log will also be passed to consumers looking at INFO or WARNING logs.
+type Leveled interface {
+ // Info logs at the INFO severity. Arguments are handled in the manner of
+ // fmt.Print, a terminating newline is added if missing.
+ Info(args ...any)
+ // Infof logs at the INFO severity. Arguments are handled in the manner of
+ // fmt.Printf, a terminating newline is added if missing.
+ Infof(format string, args ...any)
+
+ // Warning logs at the WARNING severity. Arguments are handled in the manner of
+ // fmt.Print, a terminating newline is added if missing.
+ Warning(args ...any)
+ // Warningf logs at the WARNING severity. Arguments are handled in the manner of
+ // fmt.Printf, a terminating newline is added if missing.
+ Warningf(format string, args ...any)
+
+ // Error logs at the ERROR severity. Arguments are handled in the manner of
+ // fmt.Print, a terminating newline is added if missing.
+ Error(args ...any)
+ // Errorf logs at the ERROR severity. Arguments are handled in the manner of
+ // fmt.Printf, a terminating newline is added if missing.
+ Errorf(format string, args ...any)
+
+ // Fatal logs at the FATAL severity and aborts the current program. Arguments are
+ // handled in the manner of fmt.Print, a terminating newline is added if missing.
+ Fatal(args ...any)
+ // Fatalf logs at the FATAL severity and aborts the current program. Arguments are
+ // handled in the manner of fmt.Printf, a terminating newline is added if missing.
+ Fatalf(format string, args ...any)
+
+ // V returns a VerboseLeveledLogger at a given verbosity level. These verbosity
+ // levels can be dynamically set and unset on a package-granular level by consumers
+ // of the LeveledLogger logs. The returned value represents whether logging at the
+ // given verbosity level was active at that time, and as such should not be a long-
+ // lived object in programs. This construct is further refered to as 'V-logs'.
+ V(level VerbosityLevel) VerboseLeveled
+
+ // WithAddedStackDepth returns the same LeveledLogger, but adjusted with an
+ // additional 'extra stack depth' which will be used to skip a given number of
+ // stack/call frames when determining the location where the error originated.
+ // For example, WithStackDepth(1) will return a logger that will skip one
+ // stack/call frame. Then, with function foo() calling function helper() which
+ // in turns call l.Infof(), the log line will be emitted with the call site of
+ // helper() within foo(), instead of the default behaviour of logging the
+ // call site of Infof() within helper().
+ //
+ // This is useful for functions which somehow wrap loggers in helper functions,
+ // for example to expose a slightly different API.
+ WithAddedStackDepth(depth int) Leveled
+}
+
+// VerbosityLevel is a verbosity level defined for V-logs. This can be changed
+// programmatically per Go package. When logging at a given VerbosityLevel V, the
+// current level must be equal or higher to V for the logs to be recorded.
+// Conversely, enabling a V-logging at a VerbosityLevel V also enables all logging
+// at lower levels [Int32Min .. (V-1)].
+type VerbosityLevel int32
+
+type VerboseLeveled interface {
+ // Enabled returns if this level was enabled. If not enabled, all logging into this
+ // logger will be discarded immediately. Thus, Enabled() can be used to check the
+ // verbosity level before performing any logging:
+ // if l.V(3).Enabled() { l.Info("V3 is enabled") }
+ // or, in simple cases, the convenience function .Info can be used:
+ // l.V(3).Info("V3 is enabled")
+ // The second form is shorter and more convenient, but more expensive, as its
+ // arguments are always evaluated.
+ Enabled() bool
+ // Info is the equivalent of a LeveledLogger's Info call, guarded by whether this
+ // VerboseLeveledLogger is enabled.
+ Info(args ...any)
+ // Infof is the equivalent of a LeveledLogger's Infof call, guarded by whether this
+ // VerboseLeveledLogger is enabled.
+ Infof(format string, args ...any)
+}
+
+// Severity is one of the severities as described in LeveledLogger.
+type Severity string
+
+const (
+ INFO Severity = "I"
+ WARNING Severity = "W"
+ ERROR Severity = "E"
+ FATAL Severity = "F"
+)
+
+var (
+ // SeverityAtLeast maps a given severity to a list of severities that at that
+ // severity or higher. In other words, SeverityAtLeast[X] returns a list of
+ // severities that might be seen in a log at severity X.
+ SeverityAtLeast = map[Severity][]Severity{
+ INFO: {INFO, WARNING, ERROR, FATAL},
+ WARNING: {WARNING, ERROR, FATAL},
+ ERROR: {ERROR, FATAL},
+ FATAL: {FATAL},
+ }
+)
+
+func (s Severity) AtLeast(other Severity) bool {
+ for _, el := range SeverityAtLeast[other] {
+ if el == s {
+ return true
+ }
+ }
+ return false
+}
+
+// Valid returns whether true if this severity is one of the known levels
+// (INFO, WARNING, ERROR or FATAL), false otherwise.
+func (s Severity) Valid() bool {
+ switch s {
+ case INFO, WARNING, ERROR, FATAL:
+ return true
+ default:
+ return false
+ }
+}