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