logger

package module
v1.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 1, 2021 License: MIT Imports: 7 Imported by: 1

README

logger

godoc Licence Latest version

Build Status Code quality Code coverage

One logger to rule them all.

Motivation

I was using logrus for some times when I discovered zap. I wanted to try out zap in a project where I already used logrus. I was first thinking it should only be a matter of replacing all logrus occurence with zap's one modulo some renaming. But it was not that easy: interfaces were different, exposed API contained special types (for instance logrus.Field) or tooks differents parameters, logrus was handling standard output redirection differently than zap, etc. The cost of trying zap over logrus was high and the outcome was not that much a blast. All loggers are differents and no-one can expect one to work like another. Well, why the last sentence should be true ?

From that question is born this project which:

  • expose a unique abstract way of logging through a unique interface
  • expose a unique configuration
  • expose a unique way of redirect standard output
  • expose a unique way of writing to an io.Writer
  • is modulable (can use already built zap or logrus instances, or any other logger)
  • is easily mockable
  • help to test logs

Example

// var log = <some way of building one>

// same interface we are used to see
log.WithField(key, value).Info(args...)

// easy way to get a io.Writer to inject in every components that require a logger
logger.WriterLevel(log, logger.LevelError)

// easy way of redirecting golang log standard library
logger.RedirectStdLog(log, logger.LevelWarn)

Changing the underlying logger takes literraly one line.

package main

import (
    "github.com/krostar/logger"
    "github.com/krostar/logger/logrus"
    "github.com/krostar/logger/zap"
)

func main() {
    var config = logger.Config{
        Formatter: "json",
    }

    // create a logrus-based logger with configuration
    log := logrus.New(logrus.WithConfig(config))
    log.Info("i'm a logrus-based logger")

    // as any logger keep the same interface
    // switching to a zap-based logger with configuration is easy
    log = zap.New(zap.WithConfig(config))
    log.Info("i'm a zap-based logger")
}

You have a lot of code that:

  • is using io.Writer or
  • is logging directly with standard library log
  • takes a *log.Logger parameter

There is actually few methods to help with that:

func setupHTTP(addr string, logger *log.Logger) *http.Server {
    return &http.Server{
		Addr:     addr,
		ErrorLog: logger,
	}
}

func doSomethingElse(doIt func() error, errWriter io.Writer) {
    if err := doIt(); err != nil {
        io.WriteString(errWriter, err.String())
    }
}

func main() {
    var (
        log         logger.Logger // init it the way you want (zap, logrus, ...)
        stdlog    = logger.StdLog(log, logger.LevelError)
        writerlog = logger.WriterLevel(log, logger.LevelError)
    )

    setupHTTP(":80", stdlog)

    doSomethingElse(func()error{
        return errors.New("bim bam boum")
    }, stdlog)
}

License

This project is under the MIT licence, please see the LICENCE file.

Documentation

Overview

Package logger exposes a unique interface that hides the underlying implementation and exposes useful function to switch back to a writer, or to a standard logger.

Index

Constants

View Source
const FieldErrorKey = "error"

FieldErrorKey is the name of the field set by WithError.

Variables

This section is empty.

Functions

func CaptureOutput

func CaptureOutput(writeFunc func()) (string, error)

CaptureOutput catpures and merge stdout and stderr. This function is voluntary not thread-safe as it belongs to the caller to make sure there should not be two logs that are written from two different goroutines. Moreover os.Std{out,err} can't be modified from two different goroutines, because behavior in this case is undefined.

func LogAtLevelFunc

func LogAtLevelFunc(log Logger, l Level) func(...interface{})

LogAtLevelFunc returns a function that can log to the provided level.

func LogFAtLevelFunc

func LogFAtLevelFunc(log Logger, l Level) func(string, ...interface{})

LogFAtLevelFunc is the same as LogAtLevelFunc but with log formatting.

func RedirectStdLog

func RedirectStdLog(l Logger, at Level) func()

RedirectStdLog redirects standard logger calls to the underlying logger. This is heavily inspired by zap's way of doing the same thing.

func StdLog

func StdLog(logger Logger, at Level) *stdlog.Logger

StdLog returns a standard logger which will use the provided logger internally.

func WriteCloserLevel added in v1.2.0

func WriteCloserLevel(l Logger, close func() error, at Level) io.WriteCloser

WriteCloserLevel returns a writer that writes as if LogAtLevelFunc(l) were called, with a closer.

func WriterLevel

func WriterLevel(l Logger, at Level) io.Writer

WriterLevel returns a writer that writes as if LogAtLevelFunc(l) were called.

Types

type Config

type Config struct {
	Verbosity string `json:"verbosity"  yaml:"verbosity"`
	Formatter string `json:"formatter"  yaml:"formatter"`
	WithColor bool   `json:"with-color" yaml:"with-color"`
	Output    string `json:"output"     yaml:"output"`
}

Config defines all the configurable options for the logger.

func (*Config) SetDefault

func (c *Config) SetDefault()

SetDefault set sane default for logger's config.

func (*Config) Validate

func (c *Config) Validate() error

Validate makes sure the configuration is valid.

type InMemory

type InMemory struct {
	Entries []InMemoryEntry
	// contains filtered or unexported fields
}

InMemory defines a memory logger. It is designed for tests purposes only.

func NewInMemory

func NewInMemory(lvl Level) *InMemory

NewInMemory returns a logger that stores log in memory.

func (*InMemory) Debug

func (n *InMemory) Debug(args ...interface{})

Debug implements Logger for Memory.

func (*InMemory) Debugf

func (n *InMemory) Debugf(format string, args ...interface{})

Debugf implements Logger for Memory.

func (*InMemory) Error

func (n *InMemory) Error(args ...interface{})

Error implements Logger for Memory.

func (*InMemory) Errorf

func (n *InMemory) Errorf(format string, args ...interface{})

Errorf implements Logger for Memory.

func (*InMemory) Info

func (n *InMemory) Info(args ...interface{})

Info implements Logger for Memory.

func (*InMemory) Infof

func (n *InMemory) Infof(format string, args ...interface{})

Infof implements Logger for Memory.

func (*InMemory) Reset

func (n *InMemory) Reset()

Reset clears all fields and entries.

func (*InMemory) SetLevel

func (n *InMemory) SetLevel(lvl Level) error

SetLevel implements Logger for Memory.

func (*InMemory) Warn

func (n *InMemory) Warn(args ...interface{})

Warn implements Logger for Memory.

func (*InMemory) Warnf

func (n *InMemory) Warnf(format string, args ...interface{})

Warnf implements Logger for Memory.

func (*InMemory) WithError

func (n *InMemory) WithError(err error) Logger

WithError implements Logger for Memory.

func (*InMemory) WithField

func (n *InMemory) WithField(key string, value interface{}) Logger

WithField implements Logger for Memory.

func (*InMemory) WithFields

func (n *InMemory) WithFields(fields map[string]interface{}) Logger

WithFields implements Logger for Memory.

type InMemoryEntry

type InMemoryEntry struct {
	Level  Level
	Format string
	Args   []interface{}
	Fields map[string]interface{}
}

InMemoryEntry stores a log entry for the Memory logger.

type Level

type Level int8

A Level is a logging priority. Higher levels are more important.

const (
	// LevelDebug logs are typically voluminous, and are usually disabled in production.
	LevelDebug Level = iota
	// LevelInfo is the default logging priority.
	LevelInfo
	// LevelWarn logs are more important than Info, and may need individual human review.
	LevelWarn
	// LevelError logs are high-priority and should require a human review.
	LevelError
	// LevelQuiet hide everything.
	LevelQuiet
)

func ParseLevel

func ParseLevel(levelStr string) (Level, error)

ParseLevel converts a string representation of a level to a level type.

func (Level) String

func (l Level) String() string

String returns a lower-case ASCII representation of the log level.

type Logger

type Logger interface {
	// Update apply the configuration on the logger.
	SetLevel(Level) error

	// Debug logs a message at the 'debug' level.
	Debug(args ...interface{})
	Debugf(format string, args ...interface{})

	// Info logs a message at the 'info' level.
	Info(args ...interface{})
	Infof(format string, args ...interface{})

	// Info logs a message at the 'warn' level.
	Warn(args ...interface{})
	Warnf(format string, args ...interface{})

	// Error logs a message at the 'error' level.
	Error(args ...interface{})
	Errorf(format string, args ...interface{})

	// WithField adds a field to the logging context.
	WithField(key string, value interface{}) Logger
	// WithFields adds multiple fields to the logging context.
	WithFields(fields map[string]interface{}) Logger
	// WithError adds an error field to the logging context.
	WithError(err error) Logger
}

Logger defines the way logs can be handled.

type Noop

type Noop struct{}

Noop defines a no-operation logger.

func (Noop) Debug

func (Noop) Debug(...interface{})

Debug implements Logger for Noop.

func (Noop) Debugf

func (Noop) Debugf(string, ...interface{})

Debugf implements Logger for Noop.

func (Noop) Error

func (Noop) Error(...interface{})

Error implements Logger for Noop.

func (Noop) Errorf

func (Noop) Errorf(string, ...interface{})

Errorf implements Logger for Noop.

func (Noop) Info

func (Noop) Info(...interface{})

Info implements Logger for Noop.

func (Noop) Infof

func (Noop) Infof(string, ...interface{})

Infof implements Logger for Noop.

func (Noop) SetLevel

func (Noop) SetLevel(Level) error

SetLevel implements Logger for Noop.

func (Noop) Warn

func (Noop) Warn(...interface{})

Warn implements Logger for Noop.

func (Noop) Warnf

func (Noop) Warnf(string, ...interface{})

Warnf implements Logger for Noop.

func (Noop) WithError

func (Noop) WithError(error) Logger

WithError implements Logger for Noop.

func (Noop) WithField

func (Noop) WithField(string, interface{}) Logger

WithField implements Logger for Noop.

func (Noop) WithFields

func (Noop) WithFields(map[string]interface{}) Logger

WithFields implements Logger for Noop.

Directories

Path Synopsis
Package logmid is a net/http middleware that uses httpinfo and logger.Logger to log HTTP requests.
Package logmid is a net/http middleware that uses httpinfo and logger.Logger to log HTTP requests.
Package logrus implements the logger.Logger interface using sirupsen/logrus implementation.
Package logrus implements the logger.Logger interface using sirupsen/logrus implementation.
Package zap implements the logger.Logger interface using uber/zap implementation.
Package zap implements the logger.Logger interface using uber/zap implementation.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL