blob: a4220f9f463824907738623a93a972f817f02710 [file] [log] [blame]
// Copyright 2020 The Monogon Project Authors.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package logtree
import (
"fmt"
apb "source.monogon.dev/metropolis/proto/api"
)
// LeveledLogger 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 LeveledLogger 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 ...interface{})
// 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 ...interface{})
// Warning logs at the WARNING severity. Arguments are handled in the manner of
// fmt.Print, a terminating newline is added if missing.
Warning(args ...interface{})
// 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 ...interface{})
// Error logs at the ERROR severity. Arguments are handled in the manner of
// fmt.Print, a terminating newline is added if missing.
Error(args ...interface{})
// 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 ...interface{})
// 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 ...interface{})
// 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 ...interface{})
// 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) VerboseLeveledLogger
}
// 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 VerboseLeveledLogger 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 ...interface{})
// Infof is the equivalent of a LeveledLogger's Infof call, guarded by whether this
// VerboseLeveledLogger is enabled.
Infof(format string, args ...interface{})
}
// 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
}
func SeverityFromProto(s apb.LeveledLogSeverity) (Severity, error) {
switch s {
case apb.LeveledLogSeverity_INFO:
return INFO, nil
case apb.LeveledLogSeverity_WARNING:
return WARNING, nil
case apb.LeveledLogSeverity_ERROR:
return ERROR, nil
case apb.LeveledLogSeverity_FATAL:
return FATAL, nil
default:
return "", fmt.Errorf("unknown severity value %d", s)
}
}
func (s Severity) ToProto() apb.LeveledLogSeverity {
switch s {
case INFO:
return apb.LeveledLogSeverity_INFO
case WARNING:
return apb.LeveledLogSeverity_WARNING
case ERROR:
return apb.LeveledLogSeverity_ERROR
case FATAL:
return apb.LeveledLogSeverity_FATAL
default:
return apb.LeveledLogSeverity_INVALID
}
}