log

package module
v0.0.0-...-f3b7e90 Latest Latest
Warning

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

Go to latest
Published: Oct 15, 2017 License: MIT Imports: 12 Imported by: 1

README

ozzo-log

GoDoc Build Status Coverage Status Go Report

Other languages

简体中文 Русский

Description

ozzo-log is a Go package providing enhanced logging support for Go programs. It has the following features:

  • High performance through asynchronous logging;
  • Recording message severity levels;
  • Recording message categories;
  • Recording message call stacks;
  • Filtering via severity levels and categories;
  • Customizable message format;
  • Configurable and pluggable message handling through log targets;
  • Included console, file, network, and email log targets.

Requirements

Go 1.2 or above.

Installation

Run the following command to install the package:

go get github.com/go-ozzo/ozzo-log

Getting Started

The following code snippet shows how you can use this package.

package main

import (
	"github.com/go-ozzo/ozzo-log"
)

func main() {
    // creates the root logger
	logger := log.NewLogger()

	// adds a console target and a file target
	t1 := log.NewConsoleTarget()
	t2 := log.NewFileTarget()
	t2.FileName = "app.log"
	t2.MaxLevel = log.LevelError
	logger.Targets = append(logger.Targets, t1, t2)

	logger.Open()
	defer logger.Close()

	// calls log methods to log various log messages
	logger.Error("plain text error")
	logger.Error("error with format: %v", true)
	logger.Debug("some debug info")

	// customizes log category
	l := logger.GetLogger("app.services")
	l.Info("some info")
	l.Warning("some warning")

	...
}

Loggers and Targets

A logger provides various log methods that can be called by application code to record messages of various severity levels.

A target filters log messages by their severity levels and message categories and processes the filtered messages in various ways, such as saving them in files, sending them in emails, etc.

A logger can be equipped with multiple targets each with different filtering conditions.

The following targets are included in the ozzo-log package.

  • ConsoleTarget: displays filtered messages to console window
  • FileTarget: saves filtered messages in a file (supporting file rotating)
  • NetworkTarget: sends filtered messages to an address on a network
  • MailTarget: sends filtered messages in emails

You can create a logger, configure its targets, and start to use logger with the following code:

// creates the root logger
logger := log.NewLogger()
logger.Targets = append(logger.Targets, target1, target2, ...)
logger.Open()
...calling log methods...
logger.Close()

Severity Levels

You can log a message of a particular severity level (following the RFC5424 standard) by calling one of the following methods of the Logger struct:

  • Emergency(): the system is unusable.
  • Alert(): action must be taken immediately.
  • Critical(): critical conditions.
  • Error(): error conditions.
  • Warning(): warning conditions.
  • Notice(): normal but significant conditions.
  • Info(): informational purpose.
  • Debug(): debugging purpose.

Message Categories

Each log message is associated with a category which can be used to group messages. For example, you may use the same category for messages logged by the same Go package. This will allow you to selectively send messages to different targets.

When you call log.NewLogger(), a root logger is returned which logs messages using the category named as app. To log messages with a different category, call the GetLogger() method of the root logger or a parent logger to get a child logger and then call its log methods:

logger := log.NewLogger()
// the message is of category "app"
logger.Error("...")

l1 := logger.GetLogger("system")
// the message is of category "system"
l1.Error("...")

l2 := l1.GetLogger("app.models")
// the message is of category "app.models"
l2.Error("...")

Message Formatting

By default, each log message takes this format when being sent to different targets:

2015-10-22T08:39:28-04:00 [Error][app.models] something is wrong
...call stack (if enabled)...

You may customize the message format by specifying your own message formatter when calling Logger.GetLogger(). For example,

logger := log.NewLogger()
logger = logger.GetLogger("app", func (l *Logger, e *Entry) string {
    return fmt.Sprintf("%v [%v][%v] %v%v", e.Time.Format(time.RFC822Z), e.Level, e.Category, e.Message, e.CallStack)
})

Logging Call Stacks

By setting Logger.CallStackDepth as a positive number, it is possible to record call stack information for each log method call. You may further configure Logger.CallStackFilter so that only call stack frames containing the specified substring will be recorded. For example,

logger := log.NewLogger()
// record call stacks containing "myapp/src" up to 5 frames per log message
logger.CallStackDepth = 5
logger.CallStackFilter = "myapp/src"

Message Filtering

By default, messages of all severity levels will be recorded. You may customize Logger.MaxLevel to change this behavior. For example,

logger := log.NewLogger()
// only record messages between Emergency and Warning levels
logger.MaxLevel = log.LevelWarning

Besides filtering messages at the logger level, a finer grained message filtering can be done at target level. For each target, you can specify its MaxLevel similar to that with the logger; you can also specify which categories of the messages the target should handle. For example,

target := log.NewConsoleTarget()
// handle messages between Emergency and Info levels
target.MaxLevel = log.LevelInfo
// handle messages of categories which start with "system.db." or "app."
target.Categories = []string{"system.db.*", "app.*"}

Configuring Logger

When an application is deployed for production, a common need is to allow changing the logging configuration of the application without recompiling its source code. ozzo-log is designed with this in mind.

For example, you can use a JSON file to specify how the application and its logger should be configured:

{
    "Logger": {
        "Targets": [
            {
                "type": "ConsoleTarget",
            },
            {
                "type": "FileTarget",
                "FileName": "app.log",
                "MaxLevel": 4   // Warning or above
            }
        ]
    }
}

Assuming the JSON file is app.json, in your application code you can use the ozzo-config package to load the JSON file and configure the logger used by the application:

package main

import (
	"github.com/go-ozzo/ozzo-config"
    "github.com/go-ozzo/ozzo-log"
)

func main() {
    c := config.New()
    c.Load("app.json")
    // register the target types to allow configuring Logger.Targets.
    c.Register("ConsoleTarget", log.NewConsoleTarget)
    c.Register("FileTarget", log.NewFileTarget)

    logger := log.NewLogger()
    if err := c.Configure(logger, "Logger"); err != nil {
        panic(err)
    }
}

To change the logger configuration, simply modify the JSON file without recompiling the Go source files.

Documentation

Overview

Package log implements logging with severity levels and message categories.

Index

Examples

Constants

This section is empty.

Variables

View Source
var LevelNames = map[Level]string{
	LevelDebug:     "Debug",
	LevelInfo:      "Info",
	LevelNotice:    "Notice",
	LevelWarning:   "Warning",
	LevelError:     "Error",
	LevelCritical:  "Critical",
	LevelAlert:     "Alert",
	LevelEmergency: "Emergency",
}

LevelNames maps log levels to names

Functions

func DefaultFormatter

func DefaultFormatter(l *Logger, e *Entry) string

DefaultFormatter is the default formatter used to format every log message.

func GetCallStack

func GetCallStack(skip int, frames int, filter string) string

GetCallStack returns the current call stack information as a string. The skip parameter specifies how many top frames should be skipped, while the frames parameter specifies at most how many frames should be returned.

Types

type ConsoleTarget

type ConsoleTarget struct {
	*Filter
	ColorMode  bool      // whether to use colors to differentiate log levels
	Writer     io.Writer // the writer to write log messages
	WriterName string    // the writer name of writer (stdout, stderr, discard)
	// contains filtered or unexported fields
}

ConsoleTarget writes filtered log messages to console window.

func NewConsoleTarget

func NewConsoleTarget() *ConsoleTarget

NewConsoleTarget creates a ConsoleTarget. The new ConsoleTarget takes these default options: MaxLevel: LevelDebug, ColorMode: true, Writer: os.Stdout

Example
logger := log.NewLogger()

// creates a ConsoleTarget with color mode being disabled
target := log.NewConsoleTarget()
target.ColorMode = false

logger.Targets = append(logger.Targets, target)

logger.Open()

// ... logger is ready to use ...
Output:

func (*ConsoleTarget) Close

func (t *ConsoleTarget) Close()

Close closes the console target.

func (*ConsoleTarget) Open

func (t *ConsoleTarget) Open(io.Writer) error

Open prepares ConsoleTarget for processing log messages.

func (*ConsoleTarget) Process

func (t *ConsoleTarget) Process(e *Entry)

Process writes a log message using Writer.

type Entry

type Entry struct {
	Level     Level
	Category  string
	Message   string
	Time      time.Time
	CallStack string

	FormattedMessage string
}

Entry represents a log entry.

func (*Entry) String

func (e *Entry) String() string

String returns the string representation of the log entry

type FileTarget

type FileTarget struct {
	*Filter
	// the log file name. When Rotate is true, log file name will be suffixed
	// to differentiate different backup copies (e.g. app.log.1)
	FileName string
	// whether to enable file rotating at specific time interval or when maximum file size is reached.
	Rotate bool
	// how many log files should be kept when Rotate is true (the current log file is not included).
	// This field is ignored when Rotate is false.
	BackupCount int
	// maximum number of bytes allowed for a log file. Zero means no limit.
	// This field is ignored when Rotate is false.
	MaxBytes int64
	// contains filtered or unexported fields
}

FileTarget writes filtered log messages to a file. FileTarget supports file rotation by keeping certain number of backup log files.

func NewFileTarget

func NewFileTarget() *FileTarget

NewFileTarget creates a FileTarget. The new FileTarget takes these default options: MaxLevel: LevelDebug, Rotate: true, BackupCount: 10, MaxBytes: 1 << 20 You must specify the FileName field.

Example
logger := log.NewLogger()

// creates a FileTarget which keeps log messages in the app.log file
target := log.NewFileTarget()
target.FileName = "app.log"

logger.Targets = append(logger.Targets, target)

logger.Open()

// ... logger is ready to use ...
Output:

func (*FileTarget) Close

func (t *FileTarget) Close()

Close closes the file target.

func (*FileTarget) Open

func (t *FileTarget) Open(errWriter io.Writer) error

Open prepares FileTarget for processing log messages.

func (*FileTarget) Process

func (t *FileTarget) Process(e *Entry)

Process saves an allowed log message into the log file.

type Filter

type Filter struct {
	MaxLevel   Level    // the maximum severity level that is allowed
	Categories []string // the allowed message categories. Categories can use "*" as a suffix for wildcard matching.
	// contains filtered or unexported fields
}

Filter checks if a log message meets the level and category requirements.

func (*Filter) Allow

func (t *Filter) Allow(e *Entry) bool

Allow checks if a message meets the severity level and category requirements.

func (*Filter) Init

func (t *Filter) Init()

Init initializes the filter. Init must be called before Allow is called.

type Formatter

type Formatter func(*Logger, *Entry) string

Formatter formats a log message into an appropriate string.

type Level

type Level int

Level describes the level of a log message.

const (
	LevelEmergency Level = iota
	LevelAlert
	LevelCritical
	LevelError
	LevelWarning
	LevelNotice
	LevelInfo
	LevelDebug
)

RFC5424 log message levels.

func (Level) String

func (l Level) String() string

String returns the string representation of the log level

type Logger

type Logger struct {
	Category  string    // the category associated with this logger
	Formatter Formatter // message formatter
	// contains filtered or unexported fields
}

Logger records log messages and dispatches them to various targets for further processing.

func NewLogger

func NewLogger() *Logger

NewLogger creates a root logger. The new logger takes these default options: ErrorWriter: os.Stderr, BufferSize: 1024, MaxLevel: LevelDebug, Category: app, Formatter: DefaultFormatter

func (*Logger) Alert

func (l *Logger) Alert(format string, a ...interface{})

Alert logs a message indicating action must be taken immediately. Please refer to Error() for how to use this method.

func (Logger) Close

func (l Logger) Close()

Close closes the logger and the targets. Existing messages will be processed before the targets are closed. New incoming messages will be discarded after calling this method.

func (*Logger) Critical

func (l *Logger) Critical(format string, a ...interface{})

Critical logs a message indicating critical conditions. Please refer to Error() for how to use this method.

func (*Logger) Debug

func (l *Logger) Debug(format string, a ...interface{})

Debug logs a message for debugging purpose. Please refer to Error() for how to use this method.

func (*Logger) Emergency

func (l *Logger) Emergency(format string, a ...interface{})

Emergency logs a message indicating the system is unusable. Please refer to Error() for how to use this method.

func (*Logger) Error

func (l *Logger) Error(format string, a ...interface{})

Error logs a message indicating an error condition. This method takes one or multiple parameters. If a single parameter is provided, it will be treated as the log message. If multiple parameters are provided, they will be passed to fmt.Sprintf() to generate the log message.

Example
logger := log.NewLogger()

logger.Targets = append(logger.Targets, log.NewConsoleTarget())

logger.Open()

// log without formatting
logger.Error("a plain message")
// log with formatting
logger.Error("the value is: %v", 100)
Output:

func (*Logger) GetLogger

func (l *Logger) GetLogger(category string, formatter ...Formatter) *Logger

GetLogger creates a logger with the specified category and log formatter. Messages logged through this logger will carry the same category name. The formatter, if not specified, will inherit from the calling logger. It will be used to format all messages logged through this logger.

func (*Logger) Info

func (l *Logger) Info(format string, a ...interface{})

Info logs a message for informational purpose. Please refer to Error() for how to use this method.

func (*Logger) Log

func (l *Logger) Log(level Level, format string, a ...interface{})

Log logs a message of a specified severity level.

func (*Logger) Notice

func (l *Logger) Notice(format string, a ...interface{})

Notice logs a message meaning normal but significant condition. Please refer to Error() for how to use this method.

func (Logger) Open

func (l Logger) Open() error

Open prepares the logger and the targets for logging purpose. Open must be called before any message can be logged.

func (*Logger) Warning

func (l *Logger) Warning(format string, a ...interface{})

Warning logs a message indicating a warning condition. Please refer to Error() for how to use this method.

type MailTarget

type MailTarget struct {
	*Filter
	Host       string   // SMTP server address
	Username   string   // SMTP server login username
	Password   string   // SMTP server login password
	Subject    string   // the mail subject
	Sender     string   // the mail sender
	Recipients []string // the mail recipients
	BufferSize int      // the size of the message channel.
	// contains filtered or unexported fields
}

MailTarget sends log messages in emails via an SMTP server.

func NewMailTarget

func NewMailTarget() *MailTarget

NewMailTarget creates a MailTarget. The new MailTarget takes these default options: MaxLevel: LevelDebug, BufferSize: 1024. You must specify these fields: Host, Username, Subject, Sender, and Recipients.

Example
logger := log.NewLogger()

// creates a MailTarget which sends emails to admin@example.com
target := log.NewMailTarget()
target.Host = "smtp.example.com"
target.Username = "foo"
target.Password = "bar"
target.Subject = "log messages for foobar"
target.Sender = "admin@example.com"
target.Recipients = []string{"admin@example.com"}

logger.Targets = append(logger.Targets, target)

logger.Open()

// ... logger is ready to use ...
Output:

func (*MailTarget) Close

func (t *MailTarget) Close()

Close closes the mail target.

func (*MailTarget) Open

func (t *MailTarget) Open(errWriter io.Writer) error

Open prepares MailTarget for processing log messages.

func (*MailTarget) Process

func (t *MailTarget) Process(e *Entry)

Process puts filtered log messages into a channel for sending in emails.

type NetworkTarget

type NetworkTarget struct {
	*Filter
	// the network to connect to. Valid networks include
	// tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only),
	// "udp", "udp4" (IPv4-only), "udp6" (IPv6-only), "ip", "ip4"
	// (IPv4-only), "ip6" (IPv6-only), "unix", "unixgram" and
	// "unixpacket".
	Network string
	// the address on the network to connect to.
	// For TCP and UDP networks, addresses have the form host:port.
	// If host is a literal IPv6 address it must be enclosed
	// in square brackets as in "[::1]:80" or "[ipv6-host%zone]:80".
	Address string
	// whether to use a persistent network connection.
	// If this is false, for every message to be sent, a network
	// connection will be open and closed.
	Persistent bool
	// the size of the message channel.
	BufferSize int
	// contains filtered or unexported fields
}

NetworkTarget sends log messages over a network connection.

func NewNetworkTarget

func NewNetworkTarget() *NetworkTarget

NewNetworkTarget creates a NetworkTarget. The new NetworkTarget takes these default options: MaxLevel: LevelDebug, Persistent: true, BufferSize: 1024. You must specify the Network and Address fields.

Example
logger := log.NewLogger()

// creates a NetworkTarget which uses tcp network and address :10234
target := log.NewNetworkTarget()
target.Network = "tcp"
target.Address = ":10234"

logger.Targets = append(logger.Targets, target)

logger.Open()

// ... logger is ready to use ...
Output:

func (*NetworkTarget) Close

func (t *NetworkTarget) Close()

Close closes the network target.

func (*NetworkTarget) Open

func (t *NetworkTarget) Open(errWriter io.Writer) error

Open prepares NetworkTarget for processing log messages.

func (*NetworkTarget) Process

func (t *NetworkTarget) Process(e *Entry)

Process puts filtered log messages into a channel for sending over network.

type Target

type Target interface {
	// Open prepares the target for processing log messages.
	// Open will be invoked when Logger.Open() is called.
	// If an error is returned, the target will be removed from the logger.
	// errWriter should be used to write errors found while processing log messages.
	Open(errWriter io.Writer) error
	// Process processes an incoming log message.
	Process(*Entry)
	// Close closes a target.
	// Close is called when Logger.Close() is called, which gives each target
	// a chance to flush the logged messages to their destination storage.
	Close()
}

Target represents a target where the logger can send log messages to for further processing.

Jump to

Keyboard shortcuts

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