onelogplus

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

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

Go to latest
Published: Jan 9, 2020 License: MIT Imports: 6 Imported by: 0

README

Build Status codecov Go Report Card Go doc MIT License

OnelogPlus

Based on github.com/francoispqt/onelog

Adds more log levels to include

const (
	_ = iota

	FINEST uint32 = 1 << iota
	FINE
	FINER
	DEBUG
	CONFIG
	INFO
	WARN
	ERROR
	SEVERE
	FATAL
)

Most common use cases a subset is used as a conventions.

  • The log4j set [TRACE, DEBUG, INFO, WARN, ERROR]
  • The JUL set [FINEST, FINER, FINE, CONFIG, WARN, SEVERE]

It uses the same implementation as onelog, the only difference is the level setting is based on range. If you set the level on DEBUG then all levels are enabled above DEBUG => CONFIG, INFO, WARN, ERROR, SEVERE, FATAL FINEST is the lowest to FATAL the highest.

You loose the bitwise comparison of onelog, but the speeds are comparable

FROM francois
It is a dead simple but very efficient JSON logger. 
It is one of the fastest JSON logger out there. Also, it is one of the logger with the lowest allocation.

It gives more control over log levels enabled by using bitwise operation for setting levels on a logger.

It is also modular as you can add a custom hook, define level text values, level and message keys.

Go 1.9 is required as it uses a type alias over gojay.Encoder.

It is named onelog as a reference to zerolog and because it sounds like `One Love` song from Bob Marley :)

Get Started

go get github.com/gerhardvanwyk/onelogplus

Basic usage:

import "github.com/gerhardvanyk/onelogplus"

func main() {
    // create a new Logger
    // first argument is an io.Writer
    // second argument is the level, which is an integer
    logger := onelog.New(
        os.Stdout, 
        onelog.DEBUG, // All levels above DEBUG (FINEST lowest, FATAL highest),
    )
    logger.Info("hello world !") // {"level":"info","message":"hello world"}
}

Levels

Levels are ints mapped to a string. The logger will check if level is enabled with an efficient bitwise &(AND), if disabled, it returns right away which makes onelog the fastest when running disabled logging with 0 allocs and less than 1ns/op. See benchmarks

When creating a logger you must use the | operator with different levels to toggle bytes.

Example if you want levels INFO, WARN, SEVERE, ERROR and FATAL:

logger := onelog.New(
    os.Stdout, 
    onelog.INFO,
)

You can change their textual values by doing, do this only once at runtime as it is not thread safe:

onelog.LevelText(onelog.INFO, "INFORMATION")

Hook

You can define a hook which will be run for every log message.

Example:

logger := onelog.New(
    os.Stdout, 
    onelog.DEBUG,
)
logger.Hook(func(e onelog.Entry) {
    e.String("time", time.Now().Format(time.RFC3339))
})
logger.Info("hello world !") // {"level":"debug","message":"hello world","time":"2018-05-06T02:21:01+08:00"}

Context

Context allows enforcing a grouping format where all logs fields key-values pairs from all logging methods (With, Info, Debug, InfoWith, InfoWithEntry, ...etc) except for values from using logger.Hook, will be enclosed in giving context name provided as it's key. For example using a context key "params" as below

logger := onelog.NewContext(
    os.Stdout, 
    onelog.INFO,
    "params"
)

logger.InfoWithFields("breaking news !", func(e onelog.Entry) {
    e.String("userID", "123455")
}) 

// {"level":"info","message":"breaking news !", "params":{"userID":"123456"}}

This principle also applies when inheriting from a previous created logger as below

parentLogger := onelog.New(
    os.Stdout, 
    onelog.INFO,
)


logger := parentLogger.WithContext("params")
logger.InfoWithFields("breaking news !", func(e onelog.Entry) {
    e.String("userID", "123455")
}) 

// {"level":"info","message":"breaking news !", "params":{"userID":"123456"}}

You can always reset the context by calling WithContext("") to create a no-context logger from a context logger parent.

Logging

Without extra fields

Logging without extra fields is easy as:

logger := onelog.New(
    os.Stdout, 
    onelog.ALL,
)
logger.Debug("i'm not sure what's going on") // {"level":"debug","message":"i'm not sure what's going on"}
logger.Info("breaking news !") // {"level":"info","message":"breaking news !"}
logger.Warn("beware !") // {"level":"warn","message":"beware !"}
logger.Error("my printer is on fire") // {"level":"error","message":"my printer is on fire"}
logger.Fatal("oh my...") // {"level":"fatal","message":"oh my..."}
With extra fields

Logging with extra fields is quite simple, specially if you have used gojay:

logger := onelog.New(
    os.Stdout, 
    onelog.ALL,
)

logger.DebugWithFields("i'm not sure what's going on", func(e onelog.Entry) {
    e.String("string", "foobar")
    e.Int("int", 12345)
    e.Int64("int64", 12345)
    e.Float("float64", 0.15)
    e.Bool("bool", true)
    e.Err("err", errors.New("someError"))
    e.ObjectFunc("user", func(e Entry) {
        e.String("name", "somename")
    })
}) 
// {"level":"debug","message":"i'm not sure what's going on","string":"foobar","int":12345,"int64":12345,"float64":0.15,"bool":true,"err":"someError","user":{"name":"somename"}}

logger.InfoWithFields("breaking news !", func(e onelog.Entry) {
    e.String("userID", "123455")
}) 
// {"level":"info","message":"breaking news !","userID":"123456"}

logger.WarnWithFields("beware !", func(e onelog.Entry) {
    e.String("userID", "123455")
}) 
// {"level":"warn","message":"beware !","userID":"123456"}

logger.ErrorWithFields("my printer is on fire", func(e onelog.Entry) {
    e.String("userID", "123455")
}) 
// {"level":"error","message":"my printer is on fire","userID":"123456"}

logger.FatalWithFields("oh my...", func(e onelog.Entry) {
    e.String("userID", "123455")
}) 
// {"level":"fatal","message":"oh my...","userID":"123456"}

Alternatively, you can use the chain syntax:

logger.InfoWith("foo bar").
    Int("testInt", 1).
    Int64("testInt64", 2).
    Float("testFloat", 1.15234).
    String("testString", "string").
    Bool("testBool", true).
    ObjectFunc("testObj", func(e Entry) {
        e.Int("testInt", 100)
    }).
    Object("testObj2", testObj). // implementation of gojay.MarshalerJSONObject
    Array("testArr", testArr). // implementation of gojay.MarshalerJSONArray
    Err("testErr", errors.New("my printer is on fire !")).
    Write() // don't forget to call this method! 

Accumulate context

You can create get a logger with some accumulated context that will be included on all logs created by this logger.

To do that, you must call the With method on a logger. Internally it creates a copy of the current logger and returns it.

Example:

logger := onelog.New(
    os.Stdout, 
    onelog.ALL,
).With(func(e onelog.Entry) {
    e.String("userID", "123456")
})

logger.Info("user logged in") // {"level":"info","message":"user logged in","userID":"123456"}

logger.Debug("wtf?") // {"level":"debug","message":"wtf?","userID":"123456"}

logger.ErrorWithFields("Oops", func(e onelog.Entry) {
    e.String("error_code", "ROFL")
}) // {"level":"error","message":"oops","userID":"123456","error_code":"ROFL"}

Change levels txt values, message and/or level keys

You can change globally the levels values by calling the function:

onelog.LevelText(onelog.INFO, "INFO")

You can change the key of the message by calling the function:

onelog.MsgKey("msg")

You can change the key of the level by calling the function:

onelog.LevelKey("lvl")

Beware, these changes are global (affects all instances of the logger). Also, these function should be called only once at runtime to avoid any data race issue.

Benchmarks TODO...

For thorough benchmarks please see the results in the bench suite created by the author of zerolog here: https://github.com/rs/logbench

The benchmarks data presented below is the one from Uber's benchmark suite where we added onelog.

Benchmarks are here: https://github.com/francoispqt/zap/tree/onelog-bench/benchmarks

Disabled Logging

ns/op bytes/op allocs/op
Zap 8.73 0 0
zerolog 2.45 0 0
logrus 12.1 16 1
onelog 0.74 0 0

Disabled with fields

ns/op bytes/op allocs/op
Zap 208 768 5
zerolog 68.7 128 4
logrus 721 1493 12
onelog 1.31 0 0
onelog-chain 68.2 0 0

Logging basic message

ns/op bytes/op allocs/op
Zap 205 0 0
zerolog 135 0 0
logrus 1256 1554 24
onelog 84.8 0 0

Logging basic message and accumulated context

ns/op bytes/op allocs/op
Zap 276 0 0
zerolog 141 0 0
logrus 1256 1554 24
onelog 82.4 0 0

Logging message with extra fields

ns/op bytes/op allocs/op
Zap 1764 770 5
zerolog 1210 128 4
logrus 13211 13584 129
onelog 971 128 4
onelog-chain 1030 128 4

Documentation

Overview

Package onelogplus is a fast, low allocation and modular JSON logger.

It uses github.com/francoispqt/gojay as JSON encoder.

Basic usage:

import "github.com/gerhardvanwyk/onelogplus/log"

log.Info("hello world !") // {"level":"info","message":"hello world !", "time":1494567715}

You can create your own logger:

import "github.com/gerhardvanwyk/onelogplus

var logger = onelog.New(os.Stdout, onelog.ALL)

func main() {
	logger.Info("hello world !") // {"level":"info","message":"hello world !"}
}

Index

Constants

View Source
const (
	FINEST uint32 = 1 << iota
	FINE
	FINER
	DEBUG
	CONFIG
	INFO
	WARN
	ERROR
	SEVERE
	FATAL
)

Variables

View Source
var Levels = make([]string, 2048)

Levels is the mapping between int log levels and their string value

Functions

func LevelKey

func LevelKey(s string)

LevelKey sets the key for the level field.

func LevelText

func LevelText(level uint32, txt string)

LevelText personalises the text for a specific level.

func MsgKey

func MsgKey(s string)

MsgKey sets the key for the message field.

Types

type ChainEntry

type ChainEntry struct {
	Entry
	// contains filtered or unexported fields
}

ChainEntry is for chaining calls to the entry.

func (ChainEntry) Any

func (e ChainEntry) Any(k string, obj interface{}) ChainEntry

Any adds anything stuff to the log entry based on it's type

func (ChainEntry) Array

Array adds an object to the log entry by passing an implementation of gojay.MarshalerJSONObject.

func (ChainEntry) Bool

func (e ChainEntry) Bool(k string, v bool) ChainEntry

Bool adds a bool to the log entry.

func (ChainEntry) Err

func (e ChainEntry) Err(k string, v error) ChainEntry

Err adds an error to the log entry.

func (ChainEntry) Float

func (e ChainEntry) Float(k string, v float64) ChainEntry

Float adds a float64 to the log entry.

func (ChainEntry) Int

func (e ChainEntry) Int(k string, v int) ChainEntry

Int adds an int to the log entry.

func (ChainEntry) Int64

func (e ChainEntry) Int64(k string, v int64) ChainEntry

Int64 adds an int64 to the log entry.

func (ChainEntry) Object

Object adds an object to the log entry by passing an implementation of gojay.MarshalerJSONObject.

func (ChainEntry) ObjectFunc

func (e ChainEntry) ObjectFunc(k string, v func(Entry)) ChainEntry

ObjectFunc adds an object to the log entry by calling a function.

func (ChainEntry) String

func (e ChainEntry) String(k, v string) ChainEntry

String adds a string to the log entry.

func (ChainEntry) Write

func (e ChainEntry) Write()

Info logs an entry with INFO level.

type Encoder

type Encoder = gojay.Encoder

Encoder is an alias to gojay.Encoder.

type Entry

type Entry struct {
	Level   uint32
	Message string
	// contains filtered or unexported fields
}

Entry is the structure wrapping a pointer to the current encoder. It provides easy API to work with GoJay's encoder.

func (Entry) Array

func (e Entry) Array(k string, obj gojay.MarshalerJSONArray) Entry

Array adds an object to the log entry by passing an implementation of gojay.MarshalerJSONObject.

func (Entry) Bool

func (e Entry) Bool(k string, v bool) Entry

Bool adds a bool to the log entry.

func (Entry) Err

func (e Entry) Err(k string, v error) Entry

Err adds an error to the log entry.

func (Entry) Float

func (e Entry) Float(k string, v float64) Entry

Float adds a float64 to the log entry.

func (Entry) Int

func (e Entry) Int(k string, v int) Entry

Int adds an int to the log entry.

func (Entry) Int64

func (e Entry) Int64(k string, v int64) Entry

Int64 adds an int64 to the log entry.

func (Entry) Object

func (e Entry) Object(k string, obj gojay.MarshalerJSONObject) Entry

Object adds an object to the log entry by passing an implementation of gojay.MarshalerJSONObject.

func (Entry) ObjectFunc

func (e Entry) ObjectFunc(k string, v func(Entry)) Entry

ObjectFunc adds an object to the log entry by calling a function.

func (Entry) String

func (e Entry) String(k, v string) Entry

String adds a string to the log entry.

type ExitFunc

type ExitFunc func(int)

ExitFunc is used to exit the app, `os.Exit()` is set as default on `New()`

type Logger

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

Logger is the type representing a logger.

func New

func New(w io.Writer, levels uint32) *Logger

New returns a fresh onelog Logger with default values.

func NewContext

func NewContext(w io.Writer, levels uint32, contextName string) *Logger

NewContext returns a fresh onelog Logger with default values and context name set to provided contextName value.

func (*Logger) Caller

func (l *Logger) Caller(n int) string

Caller returns the caller in the stack trace, skipped n times.

func (*Logger) Config

func (l *Logger) Config(msg string)

Config logs an entry with CONFIG level.

func (*Logger) ConfigWith

func (l *Logger) ConfigWith(msg string) ChainEntry

FineWith return an ChainEntry with CONFIG level.

func (*Logger) ConfigWithFields

func (l *Logger) ConfigWithFields(msg string, fields func(Entry))

ConfigWithFields logs an entry with CONFIG level and custom fields.

func (*Logger) Debug

func (l *Logger) Debug(msg string)

Debug logs an entry with DEBUG level.

func (*Logger) DebugWith

func (l *Logger) DebugWith(msg string) ChainEntry

DebugWith return ChainEntry with DEBUG level.

func (*Logger) DebugWithFields

func (l *Logger) DebugWithFields(msg string, fields func(Entry))

DebugWithFields logs an entry with DEBUG level and custom fields.

func (*Logger) Error

func (l *Logger) Error(msg string)

Error logs an entry with ERROR level

func (*Logger) ErrorWith

func (l *Logger) ErrorWith(msg string) ChainEntry

ErrorWith returns a ChainEntry with ERROR level.

func (*Logger) ErrorWithFields

func (l *Logger) ErrorWithFields(msg string, fields func(Entry))

ErrorWithFields logs an entry with ERROR level and custom fields.

func (*Logger) Fatal

func (l *Logger) Fatal(msg string)

Fatal logs an entry with FATAL level.

func (*Logger) FatalWith

func (l *Logger) FatalWith(msg string) ChainEntry

FatalWith returns a ChainEntry with FATAL level.

func (*Logger) FatalWithFields

func (l *Logger) FatalWithFields(msg string, fields func(Entry))

FatalWithFields logs an entry with FATAL level and custom fields.

func (*Logger) Fine

func (l *Logger) Fine(msg string)

Fine logs an entry with FINE level.

func (*Logger) FineWith

func (l *Logger) FineWith(msg string) ChainEntry

FineWith return an ChainEntry with FINE level.

func (*Logger) FineWithFields

func (l *Logger) FineWithFields(msg string, fields func(Entry))

FineWithFields logs an entry with FINE level and custom fields.

func (*Logger) Finer

func (l *Logger) Finer(msg string)

Finer logs an entry with FINER level.

func (*Logger) FinerWith

func (l *Logger) FinerWith(msg string) ChainEntry

FinerWith return an ChainEntry with FINER level.

func (*Logger) FinerWithFields

func (l *Logger) FinerWithFields(msg string, fields func(Entry))

FinerWithFields logs an entry with FINER level and custom fields.

func (*Logger) Finest

func (l *Logger) Finest(msg string)

Finest logs an entry with FINEST level.

func (*Logger) FinestWith

func (l *Logger) FinestWith(msg string) ChainEntry

FinestWith return an ChainEntry with INFO level.

func (*Logger) FinestWithFields

func (l *Logger) FinestWithFields(msg string, fields func(Entry))

FinestWithFields logs an entry with INFO level and custom fields.

func (*Logger) Hook

func (l *Logger) Hook(h func(Entry)) *Logger

Hook sets a hook to run for all log entries to add generic fields

func (*Logger) Info

func (l *Logger) Info(msg string)

Info logs an entry with INFO level.

func (*Logger) InfoWith

func (l *Logger) InfoWith(msg string) ChainEntry

InfoWith return an ChainEntry with INFO level.

func (*Logger) InfoWithFields

func (l *Logger) InfoWithFields(msg string, fields func(Entry))

InfoWithFields logs an entry with INFO level and custom fields.

func (*Logger) Log

func (l *Logger) Log(level uint32, msg string)

func (*Logger) LogWith

func (l *Logger) LogWith(level uint32, msg string) ChainEntry

func (*Logger) LogWithFields

func (l *Logger) LogWithFields(level uint32, msg string, fields func(Entry))

func (*Logger) Severe

func (l *Logger) Severe(msg string)

Severe logs an entry with SEVERE level.

func (*Logger) SevereWith

func (l *Logger) SevereWith(msg string) ChainEntry

SevereWith returns a ChainEntry with SEVERE level.

func (*Logger) SevereWithFields

func (l *Logger) SevereWithFields(msg string, fields func(Entry))

SevereWithFields logs an entry with SEVERE level and custom fields.

func (*Logger) Warn

func (l *Logger) Warn(msg string)

Warn logs an entry with WARN level.

func (*Logger) WarnWith

func (l *Logger) WarnWith(msg string) ChainEntry

WarnWith returns a ChainEntry with WARN level

func (*Logger) WarnWithFields

func (l *Logger) WarnWithFields(msg string, fields func(Entry))

WarnWithFields logs an entry with WARN level and custom fields.

func (*Logger) With

func (l *Logger) With(f func(Entry)) *Logger

With copies the current Logger and adds it a given context by running func f.

func (*Logger) WithContext

func (l *Logger) WithContext(contextName string) *Logger

WithContext copies current logger enforcing all entry fields to be set into a map with the contextName set as the key name for giving map. This allows allocating all future uses of the logging methods to follow such formatting. The only exception are values provided by added hooks which will remain within the root level of generated json.

type Object

type Object = gojay.EncodeObjectFunc

Object is an alias to gojay.EncodeObjectFunc.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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