2022-04-16 02:43:53 +00:00
|
|
|
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
|
|
|
|
package plog
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"encoding/json"
|
|
|
|
"strconv"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"go.uber.org/zap/zapcore"
|
|
|
|
"k8s.io/apimachinery/pkg/util/wait"
|
|
|
|
"k8s.io/component-base/logs"
|
|
|
|
|
|
|
|
"go.pinniped.dev/internal/constable"
|
|
|
|
)
|
|
|
|
|
|
|
|
type LogFormat string
|
|
|
|
|
|
|
|
func (l *LogFormat) UnmarshalJSON(b []byte) error {
|
|
|
|
switch string(b) {
|
|
|
|
case `""`, `"json"`:
|
|
|
|
*l = FormatJSON
|
|
|
|
case `"text"`:
|
|
|
|
*l = FormatText
|
|
|
|
// there is no "cli" case because it is not a supported option via our config
|
|
|
|
default:
|
|
|
|
return errInvalidLogFormat
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
|
|
|
FormatJSON LogFormat = "json"
|
|
|
|
FormatText LogFormat = "text"
|
|
|
|
FormatCLI LogFormat = "cli" // only used by the pinniped CLI and not the server components
|
|
|
|
|
|
|
|
errInvalidLogLevel = constable.Error("invalid log level, valid choices are the empty string, info, debug, trace and all")
|
|
|
|
errInvalidLogFormat = constable.Error("invalid log format, valid choices are the empty string, json and text")
|
|
|
|
)
|
|
|
|
|
|
|
|
var _ json.Unmarshaler = func() *LogFormat {
|
|
|
|
var f LogFormat
|
|
|
|
return &f
|
|
|
|
}()
|
|
|
|
|
|
|
|
type LogSpec struct {
|
|
|
|
Level LogLevel `json:"level,omitempty"`
|
|
|
|
Format LogFormat `json:"format,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func MaybeSetDeprecatedLogLevel(level *LogLevel, log *LogSpec) {
|
|
|
|
if level != nil {
|
|
|
|
Warning("logLevel is deprecated, set log.level instead")
|
|
|
|
log.Level = *level
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func ValidateAndSetLogLevelAndFormatGlobally(ctx context.Context, spec LogSpec) error {
|
|
|
|
klogLevel := klogLevelForPlogLevel(spec.Level)
|
|
|
|
if klogLevel < 0 {
|
|
|
|
return errInvalidLogLevel
|
|
|
|
}
|
|
|
|
|
|
|
|
// set the global log levels used by our code and the kube code underneath us
|
|
|
|
if _, err := logs.GlogSetter(strconv.Itoa(int(klogLevel))); err != nil {
|
|
|
|
panic(err) // programmer error
|
|
|
|
}
|
|
|
|
globalLevel.SetLevel(zapcore.Level(-klogLevel)) // klog levels are inverted when zap handles them
|
|
|
|
|
|
|
|
var encoding string
|
|
|
|
switch spec.Format {
|
|
|
|
case "", FormatJSON:
|
|
|
|
encoding = "json"
|
|
|
|
case FormatCLI:
|
|
|
|
encoding = "console"
|
|
|
|
case FormatText:
|
|
|
|
encoding = "text"
|
|
|
|
default:
|
|
|
|
return errInvalidLogFormat
|
|
|
|
}
|
|
|
|
|
|
|
|
log, flush, err := newLogr(ctx, encoding, klogLevel)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
setGlobalLoggers(log, flush)
|
|
|
|
|
2022-08-24 21:45:55 +00:00
|
|
|
//nolint:exhaustive // the switch above is exhaustive for format already
|
2022-04-16 02:43:53 +00:00
|
|
|
switch spec.Format {
|
|
|
|
case FormatCLI:
|
|
|
|
return nil // do not spawn go routines on the CLI to allow the CLI to call this more than once
|
|
|
|
case FormatText:
|
|
|
|
Warning("setting log.format to 'text' is deprecated - this option will be removed in a future release")
|
|
|
|
}
|
|
|
|
|
|
|
|
// do spawn go routines on the server
|
|
|
|
go wait.UntilWithContext(ctx, func(_ context.Context) { flush() }, time.Minute)
|
|
|
|
go func() {
|
|
|
|
<-ctx.Done()
|
|
|
|
flush() // best effort flush before shutdown as this is not coordinated with a wait group
|
|
|
|
}()
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|