Newer
Older
AnthosCertManager / pkg / logs / logs.go
package logs

import (
	"context"
	"flag"
	"fmt"
	"log"
	"time"

	api "gitbucket.jerxie.com/yangyangxie/AnthosCertManager/pkg/api"
	"github.com/go-logr/logr"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"k8s.io/apimachinery/pkg/util/wait"
	"k8s.io/klog/v2"
	"k8s.io/klog/v2/klogr"
)

var (
	Log = klogr.New().WithName("anthos-cert-manager")
)

const (
	// Following analog to https://github.com/kubernetes/community/blob/master/contributors/devel/sig-instrumentation/logging.md

	ErrorLevel        = 0
	WarnLevel         = 1
	InfoLevel         = 2
	ExtendedInfoLevel = 3
	DebugLevel        = 4
	TraceLevel        = 5
)

var logFlushFreq = flag.Duration("log-flush-frequency", 5*time.Second, "Maximum number of seconds between log flushes")

// GlogWriter serves as a bridge between the standard log package and the glog package.
type GlogWriter struct{}

// Write implements the io.Writer interface.
func (writer GlogWriter) Write(data []byte) (n int, err error) {
	klog.Info(string(data))
	return len(data), nil
}

// InitLogs initializes logs the way we want for kubernetes.
func InitLogs(fs *flag.FlagSet) {
	if fs == nil {
		fs = flag.CommandLine
	}
	klog.InitFlags(fs)
	_ = fs.Set("logtostderr", "true")

	log.SetOutput(GlogWriter{})
	log.SetFlags(0)

	// The default glog flush interval is 30 seconds, which is frighteningly long.
	go wait.Until(klog.Flush, *logFlushFreq, wait.NeverStop)
}

// FlushLogs flushes logs immediately.
func FlushLogs() {
	klog.Flush()
}

const (
	ResourceNameKey      = "resource_name"
	ResourceNamespaceKey = "resource_namespace"
	ResourceKindKey      = "resource_kind"
	ResourceVersionKey   = "resource_version"

	RelatedResourceNameKey      = "related_resource_name"
	RelatedResourceNamespaceKey = "related_resource_namespace"
	RelatedResourceKindKey      = "related_resource_kind"
	RelatedResourceVersionKey   = "related_resource_version"
)

func WithResource(l logr.Logger, obj metav1.Object) logr.Logger {
	var gvk schema.GroupVersionKind

	if runtimeObj, ok := obj.(runtime.Object); ok {
		gvks, _, _ := api.Scheme.ObjectKinds(runtimeObj)
		if len(gvks) > 0 {
			gvk = gvks[0]
		}
	}

	return l.WithValues(
		ResourceNameKey, obj.GetName(),
		ResourceNamespaceKey, obj.GetNamespace(),
		ResourceKindKey, gvk.Kind,
		ResourceVersionKey, gvk.Version,
	)
}

func WithRelatedResource(l logr.Logger, obj metav1.Object) logr.Logger {
	var gvk schema.GroupVersionKind

	if runtimeObj, ok := obj.(runtime.Object); ok {
		gvks, _, _ := api.Scheme.ObjectKinds(runtimeObj)
		if len(gvks) > 0 {
			gvk = gvks[0]
		}
	}

	return l.WithValues(
		RelatedResourceNameKey, obj.GetName(),
		RelatedResourceNamespaceKey, obj.GetNamespace(),
		RelatedResourceKindKey, gvk.Kind,
		RelatedResourceVersionKey, gvk.Version,
	)
}

func WithRelatedResourceName(l logr.Logger, name, namespace, kind string) logr.Logger {
	return l.WithValues(
		RelatedResourceNameKey, name,
		RelatedResourceNamespaceKey, namespace,
		RelatedResourceKindKey, kind,
	)
}

func FromContext(ctx context.Context, names ...string) logr.Logger {
	l, err := logr.FromContext(ctx)
	if err != nil {
		l = Log
	}
	for _, n := range names {
		l = l.WithName(n)
	}
	return l
}

func NewContext(ctx context.Context, l logr.Logger, names ...string) context.Context {
	for _, n := range names {
		l = l.WithName(n)
	}
	return logr.NewContext(ctx, l)
}

func V(level int) klog.Verbose {
	return klog.V(klog.Level(level))
}

// LogWithFormat is a wrapper for logger that adds Infof method to log messages
// with the given format and arguments.
//
// Used as a patch to the controller eventBroadcaster for sending non-string objects.
type LogWithFormat struct {
	logr.Logger
}

func WithInfof(l logr.Logger) *LogWithFormat {
	return &LogWithFormat{l}
}

// Infof logs message with the given format and arguments.
func (l *LogWithFormat) Infof(format string, a ...interface{}) {
	l.Info(fmt.Sprintf(format, a...))
}