clog

package module
v2.2.0 Latest Latest
Warning

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

Go to latest
Published: Nov 22, 2020 License: MIT Imports: 16 Imported by: 72

README

Clog

GitHub Workflow Status codecov GoDoc Sourcegraph

Package clog is a channel-based logging package for Go.

This package supports multiple loggers across different levels of logging. It uses Go's native channel feature to provide goroutine-safe mechanism on large concurrency.

Installation

The minimum requirement of Go is 1.11.

go get unknwon.dev/clog/v2

Please apply -u flag to update in the future.

Getting Started

It is extremely easy to create one with all default settings. Generally, you would want to create new logger inside init or main function.

Let's create a logger that prints logs to the console:

import (
	log "unknwon.dev/clog/v2"
)

func init() {
	err := log.NewConsole()
	if err != nil {
		panic("unable to create new logger: " + err.Error())
	}
}

func main() {
	log.Trace("Hello %s!", "World") // YYYY/MM/DD 12:34:56 [TRACE] Hello World!
	log.Info("Hello %s!", "World")  // YYYY/MM/DD 12:34:56 [ INFO] Hello World!
	log.Warn("Hello %s!", "World")  // YYYY/MM/DD 12:34:56 [ WARN] Hello World!

	// Graceful stopping all loggers before exiting the program.
	log.Stop()
}

The code inside init function is equivalent to the following:

func init() {
	err := log.NewConsole(0, 
        log.ConsoleConfig{
		    Level: log.LevelTrace,
	    },
    )
	if err != nil {
		panic("unable to create new logger: " + err.Error())
	}
}

Or expand further:

func init() {
	err := log.NewConsoleWithName(log.DefaultConsoleName, 0, 
        log.ConsoleConfig{
		    Level: log.LevelTrace,
	    },
    )
	if err != nil {
		panic("unable to create new logger: " + err.Error())
	}
}
  • The 0 is an integer type so it is used as underlying buffer size. In this case, 0 creates synchronized logger (call hangs until write is finished).
  • Any non-integer type is used as the config object, in this case ConsoleConfig is the respective config object for the console logger.
  • The LevelTrace used here is the lowest logging level, meaning prints every log to the console. All levels from lowest to highest are: LevelTrace, LevelInfo, LevelWarn, LevelError, LevelFatal, each of them has at least one respective function, e.g. log.Trace, log.Info, log.Warn, log.Error and log.Fatal.

In production, you may want to make log less verbose and be asynchronous:

func init() {
	// The buffer size mainly depends on number of logs could be produced at the same time, 
	// 100 is a good default.
	err := log.NewConsole(100,
        log.ConsoleConfig{
		    Level:      log.LevelInfo,
	    },
    )
	if err != nil {
		panic("unable to create new logger: " + err.Error())
	}
}
  • When you set level to be LevelInfo, calls to the log.Trace will be simply noop.
  • The console logger comes with color output, but for non-colorable destination, the color output will be disabled automatically.

Other builtin loggers are file (log.NewFile), Slack (log.NewSlack) and Discord (log.NewDiscord), see later sections in the documentation for usage details.

Multiple Loggers

You can have multiple loggers in different modes across levels.

func init() {
	err := log.NewConsole()
	if err != nil {
		panic("unable to create new logger: " + err.Error())
	}
	err := log.NewFile(
        log.FileConfig{
		    Level:    log.LevelInfo,
		    Filename: "clog.log",
	    },
    )
	if err != nil {
		panic("unable to create new logger: " + err.Error())
	}
}

In this example, all logs will be printed to console, and only logs with level Info or higher (i.e. Warn, Error and Fatal) will be written into file.

Write to a specific logger

When multiple loggers are registered, it is also possible to write logs to a special logger by giving its name.

func main() {
	log.TraceTo(log.DefaultConsoleName, "Hello %s!", "World")
	log.InfoTo(log.DefaultConsoleName, "Hello %s!", "World")
	log.WarnTo(log.DefaultConsoleName, "Hello %s!", "World")
	log.ErrorTo(log.DefaultConsoleName, "So bad... %v", err)
	log.FatalTo(log.DefaultConsoleName, "Boom! %v", err)

	// ...
}
Caller Location

When using log.Error and log.Fatal functions, the caller location is written along with logs.

func main() {
	log.Error("So bad... %v", err) // YYYY/MM/DD 12:34:56 [ERROR] [...er/main.go:64 main()] ...
	log.Fatal("Boom! %v", err)     // YYYY/MM/DD 12:34:56 [FATAL] [...er/main.go:64 main()] ...

	// ...
}
  • Calling log.Fatal will exit the program.
  • If you want to have different skip depth than the default, use log.ErrorDepth or log.FatalDepth.
Clean Exit

You should always call log.Stop() to wait until all logs are processed before program exits.

Builtin Loggers

File Logger

File logger is the single most powerful builtin logger, it has the ability to rotate based on file size, line, and date:

func init() {
	err := log.NewFile(100, 
        log.FileConfig{
            Level:              log.LevelInfo,
            Filename:           "clog.log",  
            FileRotationConfig: log.FileRotationConfig {
                Rotate: true,
                Daily:  true,
            },
        },
    )
	if err != nil {
		panic("unable to create new logger: " + err.Error())
	}
}

In case you have some other packages that write to a file, and you want to take advatange of this file rotation feature. You can do so by using the log.NewFileWriter function. It acts like a standard io.Writer.

func init() {
	w, err := log.NewFileWriter("filename",
        log.FileRotationConfig{
            Rotate: true,
            Daily:  true,
        },
    )
	if err != nil {
		panic("unable to create new logger: " + err.Error())
	}
}
Slack Logger

Slack logger is also supported in a simple way:

func init() {
	err := log.NewSlack(100,
        log.SlackConfig{
            Level: log.LevelInfo,
            URL:   "https://url-to-slack-webhook",
        },
    )
	if err != nil {
		panic("unable to create new logger: " + err.Error())
	}
}

This logger also works for Discord Slack endpoint.

Discord Logger

Discord logger is supported in rich format via Embed Object:

func init() {
	err := log.NewDiscord(100,
        log.DiscordConfig{
            Level: log.LevelInfo,
            URL:   "https://url-to-discord-webhook",
        },
    )
	if err != nil {
		panic("unable to create new logger: " + err.Error())
	}
}

This logger automatically retries up to 3 times if hits rate limit with respect to retry_after.

Build Your Own Logger

You can implement your own logger and all the concurrency stuff are handled automatically!

Here is an example which sends all logs to a channel, we call it chanLogger here:

import log "unknwon.dev/clog/v2"

type chanConfig struct {
	c chan string
}

var _ log.Logger = (*chanLogger)(nil)

type chanLogger struct {
	name  string
	level log.Level
	c     chan string
}

func (l *chanLogger) Name() string     { return l.name }
func (l *chanLogger) Level() log.Level { return l.level }

func (l *chanLogger) Write(m log.Messager) error {
	l.c <- m.String()
	return nil
}

func main() {
	log.New("channel", func(name string, vs ...interface{}) (log.Logger, error) {
		var cfg *chanConfig
		for i := range vs {
			switch v := vs[i].(type) {
			case chanConfig:
				cfg = &v
			}
		}

		if cfg == nil {
			return nil, fmt.Errorf("config object with the type '%T' not found", chanConfig{})
		} else if cfg.c == nil {
			return nil, errors.New("channel is nil")
		}

		return &chanLogger{
			name: name,
			c:    cfg.c,
		}, nil
	})
}

Have fun!

Credits

License

This project is under MIT License. See the LICENSE file for the full license text.

Documentation

Overview

Package clog is a channel-based logging package for Go.

Index

Constants

View Source
const DefaultConsoleName = "console"

DefaultConsoleName is the default name for the console logger.

View Source
const DefaultDiscordName = "discord"

DefaultDiscordName is the default name for the Discord logger.

View Source
const DefaultFileName = "file"

DefaultFileName is the default name for the file logger.

View Source
const DefaultSlackName = "slack"

DefaultSlackName is the default name for the Slack logger.

Variables

This section is empty.

Functions

func Error

func Error(format string, v ...interface{})

Error writes formatted log in Error level.

func ErrorDepth

func ErrorDepth(skip int, format string, v ...interface{})

ErrorDepth writes formatted log with given skip depth in Error level.

func ErrorDepthTo added in v2.2.0

func ErrorDepthTo(name string, skip int, format string, v ...interface{})

ErrorDepthTo writes formatted log with given skip depth in Error level to the logger with given name.

func ErrorTo added in v2.2.0

func ErrorTo(name, format string, v ...interface{})

ErrorTo writes formatted log in Error level to the logger with given name.

func Fatal

func Fatal(format string, v ...interface{})

Fatal writes formatted log in Fatal level then exits.

func FatalDepth

func FatalDepth(skip int, format string, v ...interface{})

FatalDepth writes formatted log with given skip depth in Fatal level then exits.

func FatalDepthTo added in v2.2.0

func FatalDepthTo(name string, skip int, format string, v ...interface{})

FatalDepthTo writes formatted log with given skip depth in Fatal level to the logger with given name then exits.

func FatalTo added in v2.2.0

func FatalTo(name, format string, v ...interface{})

FatalTo writes formatted log in Fatal level to the logger with given name then exits.

func Info

func Info(format string, v ...interface{})

Info writes formatted log in Info level.

func InfoTo added in v2.2.0

func InfoTo(name, format string, v ...interface{})

InfoTo writes formatted log in Info level to the logger with given name.

func New

func New(name string, initer Initer, opts ...interface{}) error

New initializes and appends a new logger to the managed list. Calling this function multiple times will overwrite previous initialized logger with the same name.

Any integer type (i.e. int, int32, int64) will be used as buffer size. Otherwise, the value will be passed to the initer.

NOTE: This function is not concurrent safe.

func NewConsole

func NewConsole(vs ...interface{}) error

NewConsole initializes and appends a new console logger with default name to the managed list.

func NewConsoleWithName

func NewConsoleWithName(name string, vs ...interface{}) error

NewConsoleWithName initializes and appends a new console logger with given name to the managed list.

func NewDiscord

func NewDiscord(vs ...interface{}) error

NewDiscord initializes and appends a new Discord logger with default name to the managed list.

func NewDiscordWithName

func NewDiscordWithName(name string, vs ...interface{}) error

NewDiscordWithName initializes and appends a new Discord logger with given name to the managed list.

func NewFile

func NewFile(vs ...interface{}) error

NewFile initializes and appends a new file logger with default name to the managed list.

func NewFileWithName

func NewFileWithName(name string, vs ...interface{}) error

NewFileWithName initializes and appends a new file logger with given name to the managed list.

func NewFileWriter

func NewFileWriter(filename string, cfg FileRotationConfig) (io.Writer, error)

NewFileWriter returns an io.Writer for synchronized file logger.

func NewSlack

func NewSlack(vs ...interface{}) error

NewSlack initializes and appends a new Slack logger with default name to the managed list.

func NewSlackWithName

func NewSlackWithName(name string, vs ...interface{}) error

NewSlackWithName initializes and appends a new Slack logger with given name to the managed list.

func Remove

func Remove(name string)

Remove removes a logger with given name from the managed list.

NOTE: This function is not concurrent safe.

func Stop

func Stop()

Stop propagates cancellation to all loggers and waits for completion. This function should always be called before exiting the program.

func Trace

func Trace(format string, v ...interface{})

Trace writes formatted log in Trace level.

func TraceTo added in v2.2.0

func TraceTo(name, format string, v ...interface{})

TraceTo writes formatted log in Trace level to the logger with given name.

func Warn

func Warn(format string, v ...interface{})

Warn writes formatted log in Warn level.

func WarnTo added in v2.2.0

func WarnTo(name, format string, v ...interface{})

WarnTo writes formatted log in Warn level to the logger with given name.

Types

type ConsoleConfig

type ConsoleConfig struct {
	// Minimum logging level of messages to be processed.
	Level Level
}

ConsoleConfig is the config object for the console logger.

type DiscordConfig

type DiscordConfig struct {
	// Minimum logging level of messages to be processed.
	Level Level
	// Discord webhook URL.
	URL string
	// Username to be shown in the message.
	// Leave empty to use default as set in the Discord.
	Username string
	// Title for different levels, must have exact 5 elements in the order of
	// Trace, Info, Warn, Error, and Fatal.
	Titles []string
	// Colors for different levels, must have exact 5 elements in the order of
	// Trace, Info, Warn, Error, and Fatal.
	Colors []int
}

DiscordConfig is the config object for the Discord logger.

type FileConfig

type FileConfig struct {
	// Minimum level of messages to be processed.
	Level Level
	// File name to output messages.
	Filename string
	// Rotation related configurations.
	FileRotationConfig
}

FileConfig is the config object for the file logger.

type FileRotationConfig

type FileRotationConfig struct {
	// Do rotation for output files.
	Rotate bool
	// Rotate on daily basis.
	Daily bool
	// Maximum size in bytes of file for a rotation.
	MaxSize int64
	// Maximum number of lines for a rotation.
	MaxLines int64
	// Maximum lifetime of a output file in days.
	MaxDays int64
}

FileRotationConfig represents rotation related configurations for file mode logger. All the settings can take effect at the same time, remain zero values to disable them.

type Initer

type Initer func(string, ...interface{}) (Logger, error)

Initer takes a name and arbitrary number of parameters needed for initalization and returns an initalized logger.

func ConsoleIniter

func ConsoleIniter() Initer

ConsoleIniter returns the initer for the console logger.

func DiscordIniter

func DiscordIniter() Initer

DiscordIniter returns the initer for the Discord logger.

func FileIniter

func FileIniter() Initer

FileIniter returns the initer for the file logger.

func SlackIniter

func SlackIniter() Initer

SlackIniter returns the initer for the Slack logger.

type Level

type Level int

Level is the logging level.

const (
	LevelTrace Level = iota
	LevelInfo
	LevelWarn
	LevelError
	LevelFatal
)

Available logging levels.

func (Level) String

func (l Level) String() string

type Logger

type Logger interface {
	// Name returns the name can used to identify the logger.
	Name() string
	// Level returns the minimum logging level of the logger.
	Level() Level
	// Write processes a Messager entry.
	Write(Messager) error
}

Logger is an interface for a logger with a specific name and level.

type Messager

type Messager interface {
	// Level returns the level of the message.
	Level() Level
	fmt.Stringer
}

Messager is a message entry to be processed by logger.

type SlackConfig

type SlackConfig struct {
	// Minimum logging level of messages to be processed.
	Level Level
	// Slack webhook URL.
	URL string
	// Colors for different levels, must have exact 5 elements in the order of
	// Trace, Info, Warn, Error, and Fatal.
	Colors []string
}

SlackConfig is the config object for the Slack logger.

Jump to

Keyboard shortcuts

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