Skip to content

oVirt/go-ovirt-client-log

Repository files navigation

Unified logging interface for Go client libraries

This repository contains a simple unified logging interface for all oVirt Go client libraries. This is not a logger itself, just an interface definition coupled with default loggers.

This library is used as a dependency, so you will most likely not need to rely on it. However, if you need to fetch it you can do so using go get:

go get github.com/ovirt/go-ovirt-client-log/v2

You can then reference this library using the ovirtclientlog package name.

Default loggers

This library providers 3 default loggers:

  • Go logging
  • Go test logging
  • "NOOP" logging

Go logging

A Go logger can be created using the NewGoLogger() function.

logger := ovirtclientlog.NewGoLogger()

Optionally, a *log.Logger instance can be passed. If it is not passed, the log is written to the globally configured log destination.

buf := &bytes.Buffer{}
backingLogger := log.New(buf, "", 0)
logger := ovirtclientlog.NewGoLogger(backingLogger)

Test logging

This library also contains the ability to log via Logf in *testing.T. You can create a logger like this:

func TestYourFeature(t *testing.T) {
	logger := ovirtclientlog.NewTestLogger(t)
}

Using the test logger will have the benefit that the log messages will be properly attributed to the test that wrote them even if multiple tests are executed in parallel.

NOOP logging

If you need a logger that doesn't do anything simply use ovirtclientlog.NewNOOPLogger().

klog logging

We provide klog-based logging in a separate library. You can use it as follows:

go get github.com/oVirt/go-ovirt-client-log-klog
package main

import (
	kloglogger "github.com/ovirt/go-ovirt-client-log-klog"
)

func main() {
	logger := kloglogger.New()
	
	// Pass logger to other library as needed.
}

You can also specify separate verbosity levels:

package main

import (
	kloglogger "github.com/ovirt/go-ovirt-client-log-klog"
	"k8s.io/klog/v2"
)

func main() {
	logger := kloglogger.NewVerbose(
		klog.V(4),
		klog.V(3),
		klog.V(2),
		klog.V(1),
    )

	// Pass logger to other library as needed.
}

Adding your own logger

You can easily integrate your own logger too. Loggers must satisfy the following interface:

type Logger interface {
	Debugf(format string, args ...interface{})
	Infof(format string, args ...interface{})
	Warningf(format string, args ...interface{})
	Errorf(format string, args ...interface{})

    WithContext(ctx context.Context) Logger
}

For example, you can adapt logging to klog like this:

type klogLogger struct {
}

func (k klogLogger) Debugf(format string, args ...interface{}) {
	// klog doesn't have a debug level
	klog.Infof(format, args...)
}

func (k klogLogger) Infof(format string, args ...interface{}) {
	klog.Infof(format, args...)
}

func (k klogLogger) Warningf(format string, args ...interface{}) {
	klog.Warningf(format, args...)
}

func (k klogLogger) Errorf(format string, args ...interface{}) {
	klog.Errorf(format, args...)
}

func (k klogLogger) WithContext(_ context.Context) Logger {
    return k
}

You can then create a new logger copy like this:

logger := &klogLogger{}