golog

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

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

Go to latest
Published: Mar 30, 2023 License: MIT Imports: 13 Imported by: 1

README

golog

GoDoc Build Status Go Report Card codecov

Features

  1. Unstructured
  2. Leveled
  3. With caller (file path / name and line number)
  4. Customizable output format
  5. Rotating by size, date or hour
  6. Cross platform, tested on Linux, macOS and Windows
  7. No 3rd party dependance
  8. Fast
  9. Thread safe

Installation

go get -u github.com/keakon/golog

Examples

Logging to console
package main

import (
    "github.com/keakon/golog"
    "github.com/keakon/golog/log"
)

func main() {
    l := golog.NewStdoutLogger()
    defer l.Close()

    l.Infof("hello %d", 1)

    log.SetDefaultLogger(l)
    test()
}

func test() {
    log.Infof("hello %d", 2)
}
Logging to file
func main() {
    w, _ := golog.NewBufferedFileWriter("test.log")
    l := golog.NewLoggerWithWriter(w)
    defer l.Close()

    l.Infof("hello world")
}
Rotating
func main() {
    w, _ := golog.NewTimedRotatingFileWriter("test", golog.RotateByDate, 30)
    l := golog.NewLoggerWithWriter(w)
    defer l.Close()

    l.Infof("hello world")
}
Formatting
func main() {
    w := golog.NewStdoutWriter()

    f := golog.ParseFormat("[%l %D %T %S] %m")
    h := golog.NewHandler(golog.InfoLevel, f)
    h.AddWriter(w)

    l := golog.NewLogger(golog.InfoLevel)
    l.AddHandler(h)
    defer l.Close()

    l.Infof("hello world")
}

Check document for more format directives.

Fast timer
func main() {
    golog.StartFastTimer()
    defer golog.StopFastTimer()

    l := golog.NewStdoutLogger()
    defer l.Close()

    l.Infof("hello world")
}

The fast timer is about 30% faster than calling time.Time() for each logging record. But it's not thread-safe which may cause some problems (I think those are negligible in most cases):

  1. The timer updates every 1 second, so the logging time can be at most 1 second behind the real time.
  2. Each thread will notice the changes of timer in a few milliseconds, so the concurrent logging messages may get different logging time (less than 2% probability). eg:
[I 2021-09-13 14:31:25 log_test:206] test
[I 2021-09-13 14:31:24 log_test:206] test
[I 2021-09-13 14:31:25 log_test:206] test
  1. When the day changing, the logging date and time might belong to different day. eg:
[I 2021-09-12 23:59:59 log_test:206] test
[I 2021-09-13 23:59:59 log_test:206] test
[I 2021-09-12 00:00:00 log_test:206] test
ConcurrentFileWriter (experimental)
func main() {
    w, _ := golog.NewConcurrentFileWriter("test.log")
    l := golog.NewLoggerWithWriter(w)
    defer l.Close()

    l.Infof("hello world")
}

The ConcurrentFileWriter is designed for high concurrency applications. It is about 140% faster than BufferedFileWriter at 6C12H by reducing the lock overhead, but a little slower at single thread.
Note: The order of logging records from different cpu cores within each 0.1 second is random.

Benchmarks

Platform

go1.19.2 darwin/amd64 cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz

Result
Name Time/op Time (x) Alloc/op allocs/op
DiscardLogger 483ns ± 1% 1.00 0B 0
DiscardLoggerParallel 89.0ns ± 6% 1.00 0B 0
DiscardLoggerWithoutTimer 691ns ± 7% 1.43 0B 0
DiscardLoggerWithoutTimerParallel 129ns ± 5% 1.45 0B 0
NopLog 1.5ns ± 1% 0.003 0B 0
NopLogParallel 0.22ns ± 3% 0.002 0B 0
MultiLevels 2.77µs ± 7% 5.73 0B 0
MultiLevelsParallel 532ns ± 15% 5.98 0B 0
BufferedFileLogger 588ns ± 2% 1.22 0B 0
BufferedFileLoggerParallel 241ns ± 1% 2.71 0B 0
ConcurrentFileLogger 593ns ± 1% 1.23 0B 0
ConcurrentFileLoggerParallel 101ns ± 2% 1.13 0B 0
DiscardZerolog 2.24µs ± 1% 4.64 280B 3
DiscardZerologParallel 408ns ± 10% 4.58 280B 3
DiscardZap 2.13µs ± 0% 4.41 272B 5
DiscardZapParallel 465ns ± 5% 5.22 274B 5
  • DiscardLogger: writes logs to ioutil.Discard
  • DiscardLoggerWithoutTimer: the same as above but without fast timer
  • NopLog: skips logs with lower level than the logger or handler
  • MultiLevels: writes 5 levels of logs to 5 levels handlers of a warning level logger
  • BufferedFileLogger: writes logs to a disk file
  • ConcurrentFileLogger: writes logs to a disk file with ConcurrentFileWriter
  • DiscardZerolog: writes logs to ioutil.Discard with zerolog
  • DiscardZap: writes logs to ioutil.Discard with zap using zap.NewProductionEncoderConfig()

All the logs include 4 parts: level, time, caller and message. This is an example output of the benchmarks:

[I 2018-11-20 17:05:37 log_test:118] test

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// DefaultFormatter is the default formatter
	DefaultFormatter = ParseFormat("[%l %D %T %s] %m")
	// TimedRotatingFormatter is a formatter for TimedRotatingFileWriter
	TimedRotatingFormatter = ParseFormat("[%l %T %s] %m")
)

Functions

func Caller

func Caller(skip int) (file string, line int)

Caller caches the result for runtime.Caller(). Inspired by https://zhuanlan.zhihu.com/p/403417640

func NewFileWriter

func NewFileWriter(path string) (*os.File, error)

NewFileWriter creates a FileWriter by its path.

func SetInternalLogger

func SetInternalLogger(l *Logger)

SetInternalLogger sets a logger as the internalLogger which is used to log internal errors. The logger and its handlers will be marked as internal, so do not reuse them. The internalLogger may discard its own errors to prevent recursive log.

func StartFastTimer

func StartFastTimer()

StartFastTimer starts the fastTimer.

func StopFastTimer

func StopFastTimer()

StopFastTimer stops the fastTimer.

Types

type BufferedFileWriter

type BufferedFileWriter struct {
	// contains filtered or unexported fields
}

A BufferedFileWriter is a buffered file writer. The written bytes will be flushed to the log file every 0.1 second, or when reaching the buffer capacity (4 MB).

func NewBufferedFileWriter

func NewBufferedFileWriter(path string, options ...BufferedFileWriterOption) (*BufferedFileWriter, error)

NewBufferedFileWriter creates a new BufferedFileWriter.

func (*BufferedFileWriter) Close

func (w *BufferedFileWriter) Close() error

Close flushes the buffer, then closes the file writer.

func (*BufferedFileWriter) Write

func (w *BufferedFileWriter) Write(p []byte) (n int, err error)

Write writes a byte slice to the buffer.

type BufferedFileWriterOption

type BufferedFileWriterOption func(*bufferedFileWriter)

func BufferSize

func BufferSize(size uint32) BufferedFileWriterOption

BufferSize sets the buffer size.

type ByteFormatPart

type ByteFormatPart struct {
	// contains filtered or unexported fields
}

ByteFormatPart is a FormatPart containing a byte.

func (*ByteFormatPart) Format

func (p *ByteFormatPart) Format(r *Record, buf *bytes.Buffer)

Format writes its byte to the buf.

type BytesFormatPart

type BytesFormatPart struct {
	// contains filtered or unexported fields
}

BytesFormatPart is a FormatPart containing a byte slice.

func (*BytesFormatPart) Format

func (p *BytesFormatPart) Format(r *Record, buf *bytes.Buffer)

Format writes its bytes to the buf.

type ConcurrentFileWriter

type ConcurrentFileWriter struct {
	// contains filtered or unexported fields
}

func NewConcurrentFileWriter

func NewConcurrentFileWriter(path string, options ...BufferedFileWriterOption) (*ConcurrentFileWriter, error)

NewBufferedFileWriter creates a new BufferedFileWriter.

func (*ConcurrentFileWriter) Close

func (w *ConcurrentFileWriter) Close() (err error)

Close flushes the buffer, then closes the file writer.

func (*ConcurrentFileWriter) Write

func (w *ConcurrentFileWriter) Write(p []byte) (n int, err error)

Write writes a byte slice to the buffer.

type ConsoleWriter

type ConsoleWriter struct {
	*os.File // faster than io.Writer
}

A ConsoleWriter is a writer which should not be actually closed.

func NewConsoleWriter

func NewConsoleWriter(f *os.File) *ConsoleWriter

NewConsoleWriter creates a new ConsoleWriter.

func NewStderrWriter

func NewStderrWriter() *ConsoleWriter

NewStderrWriter creates a new stderr writer.

func NewStdoutWriter

func NewStdoutWriter() *ConsoleWriter

NewStdoutWriter creates a new stdout writer.

func (*ConsoleWriter) Close

func (w *ConsoleWriter) Close() error

Close sets its File to nil.

type DateFormatPart

type DateFormatPart struct{}

DateFormatPart is a FormatPart of the date placeholder.

func (*DateFormatPart) Format

func (p *DateFormatPart) Format(r *Record, buf *bytes.Buffer)

Format writes the date string of the record to the buf.

type DiscardWriter

type DiscardWriter struct {
	io.Writer
}

DiscardWriter is a WriteCloser which write everything to devNull

func NewDiscardWriter

func NewDiscardWriter() *DiscardWriter

NewDiscardWriter creates a new ConsoleWriter.

func (*DiscardWriter) Close

func (w *DiscardWriter) Close() error

Close sets its Writer to nil.

type FastTimer

type FastTimer struct {
	// contains filtered or unexported fields
}

FastTimer is not thread-safe for performance reason, but all the threads will notice its changes in a few milliseconds.

type FormatPart

type FormatPart interface {
	Format(r *Record, buf *bytes.Buffer)
}

FormatPart is an interface containing the Format() method.

type Formatter

type Formatter struct {
	// contains filtered or unexported fields
}

A Formatter containing a sequence of FormatParts.

func ParseFormat

func ParseFormat(format string) (formatter *Formatter)

ParseFormat parses a format string into a formatter.

func (*Formatter) Format

func (f *Formatter) Format(r *Record, buf *bytes.Buffer)

Format formats a record to a bytes.Buffer. Supported format directives:

%%: %
%l: short name of the level
%T: time string (HH:MM:SS)
%D: date string (YYYY-mm-DD)
%s: source code string (filename:line)
%S: full source code string (/path/filename.go:line)

type FullSourceFormatPart

type FullSourceFormatPart struct{}

FullSourceFormatPart is a FormatPart of the full source code placeholder.

func (*FullSourceFormatPart) Format

func (p *FullSourceFormatPart) Format(r *Record, buf *bytes.Buffer)

Format writes the source file path and line number of the record to the buf.

type Handler

type Handler struct {
	// contains filtered or unexported fields
}

A Handler is a leveled log handler with a formatter and several writers.

func NewHandler

func NewHandler(level Level, formatter *Formatter) *Handler

NewHandler creates a new Handler of the given level with the formatter. Records with the lower level than the handler will be ignored.

func (*Handler) AddWriter

func (h *Handler) AddWriter(w io.WriteCloser)

AddWriter adds a writer to the Handler. The Write() method of the writer should be thread-safe.

func (*Handler) Close

func (h *Handler) Close()

Close closes all its writers. It's safe to call this method more than once, but it's unsafe to call its writers' Close() more than once.

func (*Handler) Handle

func (h *Handler) Handle(r *Record) bool

Handle formats a record using its formatter, then writes the formatted result to all of its writers. Returns true if it can handle the record. The errors during writing will be logged by the internalLogger. It's not thread-safe, concurrent record may be written in a random order through different writers. But two records won't be mixed in a single line.

type Level

type Level uint8

Level specifies the log level.

const (
	DebugLevel Level = iota
	InfoLevel
	WarnLevel
	ErrorLevel
	CritLevel
)

All the log levels.

type LevelFormatPart

type LevelFormatPart struct{}

LevelFormatPart is a FormatPart of the level placeholder.

func (*LevelFormatPart) Format

func (p *LevelFormatPart) Format(r *Record, buf *bytes.Buffer)

Format writes the short level name of the record to the buf.

type Logger

type Logger struct {
	// contains filtered or unexported fields
}

A Logger is a leveled logger with several handlers.

func NewLogger

func NewLogger(lv Level) *Logger

NewLogger creates a new Logger of the given level. Messages with lower level than the logger will be ignored.

func NewLoggerWithWriter

func NewLoggerWithWriter(w io.WriteCloser) *Logger

NewLoggerWithWriter creates an info level logger with a writer.

func NewStderrLogger

func NewStderrLogger() *Logger

NewStderrLogger creates a logger with a stderr writer.

func NewStdoutLogger

func NewStdoutLogger() *Logger

NewStdoutLogger creates a logger with a stdout writer.

func (*Logger) AddHandler

func (l *Logger) AddHandler(h *Handler)

AddHandler adds a Handler to the Logger.

func (*Logger) Close

func (l *Logger) Close()

Close closes its handlers. It's safe to call this method more than once.

func (*Logger) Crit

func (l *Logger) Crit(args ...interface{})

Crit logs a critical level message. It uses fmt.Fprint() to format args.

func (*Logger) Critf

func (l *Logger) Critf(msg string, args ...interface{})

Critf logs a critical level message. It uses fmt.Fprintf() to format msg and args.

func (*Logger) Debug

func (l *Logger) Debug(args ...interface{})

Debug logs a debug level message. It uses fmt.Fprint() to format args.

func (*Logger) Debugf

func (l *Logger) Debugf(msg string, args ...interface{})

Debugf logs a debug level message. It uses fmt.Fprintf() to format msg and args.

func (*Logger) Error

func (l *Logger) Error(args ...interface{})

Error logs an error level message. It uses fmt.Fprint() to format args.

func (*Logger) Errorf

func (l *Logger) Errorf(msg string, args ...interface{})

Errorf logs a error level message. It uses fmt.Fprintf() to format msg and args.

func (*Logger) GetMinLevel

func (l *Logger) GetMinLevel() Level

GetMinLevel returns its minLevel. Records lower than its minLevel will be ignored.

func (*Logger) Info

func (l *Logger) Info(args ...interface{})

Info logs a info level message. It uses fmt.Fprint() to format args.

func (*Logger) Infof

func (l *Logger) Infof(msg string, args ...interface{})

Infof logs a info level message. It uses fmt.Fprintf() to format msg and args.

func (*Logger) IsEnabledFor

func (l *Logger) IsEnabledFor(level Level) bool

IsEnabledFor returns whether it's enabled for the level.

func (*Logger) Log

func (l *Logger) Log(lv Level, file string, line int, msg string, args ...interface{})

Log logs a message with context. A logger should check the message level before call its Log(). The line param should be uint32. It's not thread-safe, concurrent messages may be written in a random order through different handlers or writers. But two messages won't be mixed in a single line.

func (*Logger) Warn

func (l *Logger) Warn(args ...interface{})

Warn logs a warning level message. It uses fmt.Fprint() to format args.

func (*Logger) Warnf

func (l *Logger) Warnf(msg string, args ...interface{})

Warnf logs a warning level message. It uses fmt.Fprintf() to format msg and args.

type MessageFormatPart

type MessageFormatPart struct{}

MessageFormatPart is a FormatPart of the message placeholder.

func (*MessageFormatPart) Format

func (p *MessageFormatPart) Format(r *Record, buf *bytes.Buffer)

Format writes the formatted message with args to the buf.

type Record

type Record struct {
	// contains filtered or unexported fields
}

A Record is an item which contains required context for the logger.

type RotateDuration

type RotateDuration uint8

RotateDuration specifies rotate duration type, should be either RotateByDate or RotateByHour.

const (
	// RotateByDate set the log file to be rotated each day.
	RotateByDate RotateDuration = iota
	// RotateByHour set the log file to be rotated each hour.
	RotateByHour
)

type RotatingFileWriter

type RotatingFileWriter struct {
	BufferedFileWriter
	// contains filtered or unexported fields
}

A RotatingFileWriter is a buffered file writer which will rotate before reaching its maxSize. An exception is when a record is larger than maxSize, it won't be separated into 2 files. It keeps at most backupCount backups.

func NewRotatingFileWriter

func NewRotatingFileWriter(path string, maxSize uint64, backupCount uint8, options ...BufferedFileWriterOption) (*RotatingFileWriter, error)

NewRotatingFileWriter creates a new RotatingFileWriter.

func (*RotatingFileWriter) Write

func (w *RotatingFileWriter) Write(p []byte) (n int, err error)

Write writes a byte slice to the buffer and rotates if reaching its maxSize.

type SourceFormatPart

type SourceFormatPart struct{}

SourceFormatPart is a FormatPart of the source code placeholder.

func (*SourceFormatPart) Format

func (p *SourceFormatPart) Format(r *Record, buf *bytes.Buffer)

Format writes the source file name and line number of the record to the buf.

type TimeFormatPart

type TimeFormatPart struct{}

TimeFormatPart is a FormatPart of the time placeholder.

func (*TimeFormatPart) Format

func (p *TimeFormatPart) Format(r *Record, buf *bytes.Buffer)

Format writes the time string of the record to the buf.

type TimedRotatingFileWriter

type TimedRotatingFileWriter struct {
	BufferedFileWriter
	// contains filtered or unexported fields
}

A TimedRotatingFileWriter is a buffered file writer which will rotate by time. Its rotateDuration can be either RotateByDate or RotateByHour. It keeps at most backupCount backups.

func NewTimedRotatingFileWriter

func NewTimedRotatingFileWriter(pathPrefix string, rotateDuration RotateDuration, backupCount uint8, options ...BufferedFileWriterOption) (*TimedRotatingFileWriter, error)

NewTimedRotatingFileWriter creates a new TimedRotatingFileWriter.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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