blob: 45dfc149f3f05c16aa1820542dc6186d1a8725fa [file] [log] [blame]
Tim Windelschmidt6d33a432025-02-04 14:34:25 +01001// Copyright The Monogon Project Authors.
2// SPDX-License-Identifier: Apache-2.0
3
Serge Bazanski3c5d0632024-09-12 10:49:12 +00004package logging
5
6// Leveled is a generic interface for glog-style logging. There are four
7// hardcoded log severities, in increasing order: INFO, WARNING, ERROR, FATAL.
8// Logging at a certain severity level logs not only to consumers expecting data
9// at that severity level, but also all lower severity levels. For example, an
10// ERROR log will also be passed to consumers looking at INFO or WARNING logs.
11type Leveled interface {
12 // Info logs at the INFO severity. Arguments are handled in the manner of
13 // fmt.Print, a terminating newline is added if missing.
14 Info(args ...any)
15 // Infof logs at the INFO severity. Arguments are handled in the manner of
16 // fmt.Printf, a terminating newline is added if missing.
17 Infof(format string, args ...any)
18
19 // Warning logs at the WARNING severity. Arguments are handled in the manner of
20 // fmt.Print, a terminating newline is added if missing.
21 Warning(args ...any)
22 // Warningf logs at the WARNING severity. Arguments are handled in the manner of
23 // fmt.Printf, a terminating newline is added if missing.
24 Warningf(format string, args ...any)
25
26 // Error logs at the ERROR severity. Arguments are handled in the manner of
27 // fmt.Print, a terminating newline is added if missing.
28 Error(args ...any)
29 // Errorf logs at the ERROR severity. Arguments are handled in the manner of
30 // fmt.Printf, a terminating newline is added if missing.
31 Errorf(format string, args ...any)
32
33 // Fatal logs at the FATAL severity and aborts the current program. Arguments are
34 // handled in the manner of fmt.Print, a terminating newline is added if missing.
35 Fatal(args ...any)
36 // Fatalf logs at the FATAL severity and aborts the current program. Arguments are
37 // handled in the manner of fmt.Printf, a terminating newline is added if missing.
38 Fatalf(format string, args ...any)
39
40 // V returns a VerboseLeveledLogger at a given verbosity level. These verbosity
41 // levels can be dynamically set and unset on a package-granular level by consumers
42 // of the LeveledLogger logs. The returned value represents whether logging at the
43 // given verbosity level was active at that time, and as such should not be a long-
44 // lived object in programs. This construct is further refered to as 'V-logs'.
45 V(level VerbosityLevel) VerboseLeveled
46
47 // WithAddedStackDepth returns the same LeveledLogger, but adjusted with an
48 // additional 'extra stack depth' which will be used to skip a given number of
49 // stack/call frames when determining the location where the error originated.
50 // For example, WithStackDepth(1) will return a logger that will skip one
51 // stack/call frame. Then, with function foo() calling function helper() which
52 // in turns call l.Infof(), the log line will be emitted with the call site of
53 // helper() within foo(), instead of the default behaviour of logging the
54 // call site of Infof() within helper().
55 //
56 // This is useful for functions which somehow wrap loggers in helper functions,
57 // for example to expose a slightly different API.
58 WithAddedStackDepth(depth int) Leveled
59}
60
61// VerbosityLevel is a verbosity level defined for V-logs. This can be changed
62// programmatically per Go package. When logging at a given VerbosityLevel V, the
63// current level must be equal or higher to V for the logs to be recorded.
64// Conversely, enabling a V-logging at a VerbosityLevel V also enables all logging
65// at lower levels [Int32Min .. (V-1)].
66type VerbosityLevel int32
67
68type VerboseLeveled interface {
69 // Enabled returns if this level was enabled. If not enabled, all logging into this
70 // logger will be discarded immediately. Thus, Enabled() can be used to check the
71 // verbosity level before performing any logging:
72 // if l.V(3).Enabled() { l.Info("V3 is enabled") }
73 // or, in simple cases, the convenience function .Info can be used:
74 // l.V(3).Info("V3 is enabled")
75 // The second form is shorter and more convenient, but more expensive, as its
76 // arguments are always evaluated.
77 Enabled() bool
78 // Info is the equivalent of a LeveledLogger's Info call, guarded by whether this
79 // VerboseLeveledLogger is enabled.
80 Info(args ...any)
81 // Infof is the equivalent of a LeveledLogger's Infof call, guarded by whether this
82 // VerboseLeveledLogger is enabled.
83 Infof(format string, args ...any)
84}
85
86// Severity is one of the severities as described in LeveledLogger.
87type Severity string
88
89const (
90 INFO Severity = "I"
91 WARNING Severity = "W"
92 ERROR Severity = "E"
93 FATAL Severity = "F"
94)
95
96var (
97 // SeverityAtLeast maps a given severity to a list of severities that at that
98 // severity or higher. In other words, SeverityAtLeast[X] returns a list of
99 // severities that might be seen in a log at severity X.
100 SeverityAtLeast = map[Severity][]Severity{
101 INFO: {INFO, WARNING, ERROR, FATAL},
102 WARNING: {WARNING, ERROR, FATAL},
103 ERROR: {ERROR, FATAL},
104 FATAL: {FATAL},
105 }
106)
107
108func (s Severity) AtLeast(other Severity) bool {
109 for _, el := range SeverityAtLeast[other] {
110 if el == s {
111 return true
112 }
113 }
114 return false
115}
116
117// Valid returns whether true if this severity is one of the known levels
118// (INFO, WARNING, ERROR or FATAL), false otherwise.
119func (s Severity) Valid() bool {
120 switch s {
121 case INFO, WARNING, ERROR, FATAL:
122 return true
123 default:
124 return false
125 }
126}