treewide: introduce osbase package and move things around

All except localregistry moved from metropolis/pkg to osbase,
localregistry moved to metropolis/test as its only used there anyway.

Change-Id: If1a4bf377364bef0ac23169e1b90379c71b06d72
Reviewed-on: https://review.monogon.dev/c/monogon/+/3079
Tested-by: Jenkins CI
Reviewed-by: Serge Bazanski <serge@monogon.tech>
diff --git a/osbase/logtree/leveled.go b/osbase/logtree/leveled.go
new file mode 100644
index 0000000..98699b8
--- /dev/null
+++ b/osbase/logtree/leveled.go
@@ -0,0 +1,175 @@
+// 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"
+
+	lpb "source.monogon.dev/osbase/logtree/proto"
+)
+
+// 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
+
+	// 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) LeveledLogger
+}
+
+// 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
+}
+
+// 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
+	}
+}
+
+func SeverityFromProto(s lpb.LeveledLogSeverity) (Severity, error) {
+	switch s {
+	case lpb.LeveledLogSeverity_INFO:
+		return INFO, nil
+	case lpb.LeveledLogSeverity_WARNING:
+		return WARNING, nil
+	case lpb.LeveledLogSeverity_ERROR:
+		return ERROR, nil
+	case lpb.LeveledLogSeverity_FATAL:
+		return FATAL, nil
+	default:
+		return "", fmt.Errorf("unknown severity value %d", s)
+	}
+}
+
+func (s Severity) ToProto() lpb.LeveledLogSeverity {
+	switch s {
+	case INFO:
+		return lpb.LeveledLogSeverity_INFO
+	case WARNING:
+		return lpb.LeveledLogSeverity_WARNING
+	case ERROR:
+		return lpb.LeveledLogSeverity_ERROR
+	case FATAL:
+		return lpb.LeveledLogSeverity_FATAL
+	default:
+		return lpb.LeveledLogSeverity_INVALID
+	}
+}