blob: 9590bc38f1e17c10badd914deee280c810235436 [file] [log] [blame]
Serge Bazanski5ade7322020-08-27 13:27:51 +02001// Copyright 2020 The Monogon Project Authors.
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17package logtree
18
Serge Bazanskib0272182020-11-02 18:39:44 +010019import (
20 "fmt"
21
Serge Bazanski31370b02021-01-07 16:31:14 +010022 apb "source.monogon.dev/metropolis/proto/api"
Serge Bazanskib0272182020-11-02 18:39:44 +010023)
24
Serge Bazanski216fe7b2021-05-21 18:36:16 +020025// LeveledLogger is a generic interface for glog-style logging. There are four
26// hardcoded log severities, in increasing order: INFO, WARNING, ERROR, FATAL.
27// Logging at a certain severity level logs not only to consumers expecting data at
28// that severity level, but also all lower severity levels. For example, an ERROR
29// log will also be passed to consumers looking at INFO or WARNING logs.
Serge Bazanski5ade7322020-08-27 13:27:51 +020030type LeveledLogger interface {
Serge Bazanski216fe7b2021-05-21 18:36:16 +020031 // Info logs at the INFO severity. Arguments are handled in the manner of
32 // fmt.Print, a terminating newline is added if missing.
Serge Bazanski5ade7322020-08-27 13:27:51 +020033 Info(args ...interface{})
Serge Bazanski216fe7b2021-05-21 18:36:16 +020034 // Infof logs at the INFO severity. Arguments are handled in the manner of
35 // fmt.Printf, a terminating newline is added if missing.
Serge Bazanski5ade7322020-08-27 13:27:51 +020036 Infof(format string, args ...interface{})
37
Serge Bazanski216fe7b2021-05-21 18:36:16 +020038 // Warning logs at the WARNING severity. Arguments are handled in the manner of
39 // fmt.Print, a terminating newline is added if missing.
Serge Bazanski5ade7322020-08-27 13:27:51 +020040 Warning(args ...interface{})
Serge Bazanski216fe7b2021-05-21 18:36:16 +020041 // Warningf logs at the WARNING severity. Arguments are handled in the manner of
42 // fmt.Printf, a terminating newline is added if missing.
Serge Bazanski5ade7322020-08-27 13:27:51 +020043 Warningf(format string, args ...interface{})
44
Serge Bazanski216fe7b2021-05-21 18:36:16 +020045 // Error logs at the ERROR severity. Arguments are handled in the manner of
46 // fmt.Print, a terminating newline is added if missing.
Serge Bazanski5ade7322020-08-27 13:27:51 +020047 Error(args ...interface{})
Serge Bazanski216fe7b2021-05-21 18:36:16 +020048 // Errorf logs at the ERROR severity. Arguments are handled in the manner of
49 // fmt.Printf, a terminating newline is added if missing.
Serge Bazanski5ade7322020-08-27 13:27:51 +020050 Errorf(format string, args ...interface{})
51
Serge Bazanski216fe7b2021-05-21 18:36:16 +020052 // Fatal logs at the FATAL severity and aborts the current program. Arguments are
53 // handled in the manner of fmt.Print, a terminating newline is added if missing.
Serge Bazanski5ade7322020-08-27 13:27:51 +020054 Fatal(args ...interface{})
Serge Bazanski216fe7b2021-05-21 18:36:16 +020055 // Fatalf logs at the FATAL severity and aborts the current program. Arguments are
56 // handled in the manner of fmt.Printf, a terminating newline is added if missing.
Serge Bazanski5ade7322020-08-27 13:27:51 +020057 Fatalf(format string, args ...interface{})
58
Serge Bazanski216fe7b2021-05-21 18:36:16 +020059 // V returns a VerboseLeveledLogger at a given verbosity level. These verbosity
60 // levels can be dynamically set and unset on a package-granular level by consumers
61 // of the LeveledLogger logs. The returned value represents whether logging at the
62 // given verbosity level was active at that time, and as such should not be a long-
63 // lived object in programs. This construct is further refered to as 'V-logs'.
Serge Bazanski5ade7322020-08-27 13:27:51 +020064 V(level VerbosityLevel) VerboseLeveledLogger
65}
66
Serge Bazanski216fe7b2021-05-21 18:36:16 +020067// VerbosityLevel is a verbosity level defined for V-logs. This can be changed
68// programmatically per Go package. When logging at a given VerbosityLevel V, the
69// current level must be equal or higher to V for the logs to be recorded.
70// Conversely, enabling a V-logging at a VerbosityLevel V also enables all logging
71// at lower levels [Int32Min .. (V-1)].
Serge Bazanski5ade7322020-08-27 13:27:51 +020072type VerbosityLevel int32
73
74type VerboseLeveledLogger interface {
Serge Bazanski216fe7b2021-05-21 18:36:16 +020075 // Enabled returns if this level was enabled. If not enabled, all logging into this
76 // logger will be discarded immediately. Thus, Enabled() can be used to check the
77 // verbosity level before performing any logging:
Serge Bazanski5ade7322020-08-27 13:27:51 +020078 // if l.V(3).Enabled() { l.Info("V3 is enabled") }
79 // or, in simple cases, the convenience function .Info can be used:
80 // l.V(3).Info("V3 is enabled")
Serge Bazanski216fe7b2021-05-21 18:36:16 +020081 // The second form is shorter and more convenient, but more expensive, as its
82 // arguments are always evaluated.
Serge Bazanski5ade7322020-08-27 13:27:51 +020083 Enabled() bool
Serge Bazanski216fe7b2021-05-21 18:36:16 +020084 // Info is the equivalent of a LeveledLogger's Info call, guarded by whether this
85 // VerboseLeveledLogger is enabled.
Serge Bazanski5ade7322020-08-27 13:27:51 +020086 Info(args ...interface{})
Serge Bazanski216fe7b2021-05-21 18:36:16 +020087 // Infof is the equivalent of a LeveledLogger's Infof call, guarded by whether this
88 // VerboseLeveledLogger is enabled.
Serge Bazanski5ade7322020-08-27 13:27:51 +020089 Infof(format string, args ...interface{})
90}
Serge Bazanski5faa2fc2020-09-07 14:09:30 +020091
92// Severity is one of the severities as described in LeveledLogger.
93type Severity string
94
95const (
96 INFO Severity = "I"
97 WARNING Severity = "W"
98 ERROR Severity = "E"
99 FATAL Severity = "F"
100)
101
102var (
Serge Bazanski216fe7b2021-05-21 18:36:16 +0200103 // SeverityAtLeast maps a given severity to a list of severities that at that
104 // severity or higher. In other words, SeverityAtLeast[X] returns a list of
105 // severities that might be seen in a log at severity X.
Serge Bazanski5faa2fc2020-09-07 14:09:30 +0200106 SeverityAtLeast = map[Severity][]Severity{
107 INFO: {INFO, WARNING, ERROR, FATAL},
108 WARNING: {WARNING, ERROR, FATAL},
109 ERROR: {ERROR, FATAL},
110 FATAL: {FATAL},
111 }
112)
113
114func (s Severity) AtLeast(other Severity) bool {
115 for _, el := range SeverityAtLeast[other] {
116 if el == s {
117 return true
118 }
119 }
120 return false
121}
Serge Bazanskib0272182020-11-02 18:39:44 +0100122
Serge Bazanski020b7c52021-07-07 14:22:28 +0200123// Valid returns whether true if this severity is one of the known levels
124// (INFO, WARNING, ERROR or FATAL), false otherwise.
125func (s Severity) Valid() bool {
126 switch s {
127 case INFO, WARNING, ERROR, FATAL:
128 return true
129 default:
130 return false
131 }
132}
133
Serge Bazanskib0272182020-11-02 18:39:44 +0100134func SeverityFromProto(s apb.LeveledLogSeverity) (Severity, error) {
135 switch s {
136 case apb.LeveledLogSeverity_INFO:
137 return INFO, nil
138 case apb.LeveledLogSeverity_WARNING:
139 return WARNING, nil
140 case apb.LeveledLogSeverity_ERROR:
141 return ERROR, nil
142 case apb.LeveledLogSeverity_FATAL:
143 return FATAL, nil
144 default:
145 return "", fmt.Errorf("unknown severity value %d", s)
146 }
147}
148
149func (s Severity) ToProto() apb.LeveledLogSeverity {
150 switch s {
151 case INFO:
152 return apb.LeveledLogSeverity_INFO
153 case WARNING:
154 return apb.LeveledLogSeverity_WARNING
155 case ERROR:
156 return apb.LeveledLogSeverity_ERROR
157 case FATAL:
158 return apb.LeveledLogSeverity_FATAL
159 default:
160 return apb.LeveledLogSeverity_INVALID
161 }
162}