zlog

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

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

Go to latest
Published: Nov 1, 2017 License: Apache-2.0 Imports: 3 Imported by: 0

README

🔍 ZLOG - Structured Logging Interface

GoDoc Build Status Coverage Status Go Report Card

zlog aims to provide a consistent, easy to use structured logging interface.

The interface is inspired by zerolog and uses it for the default implementation that provides JSON.

zlog's API mimics the chaining API style from zerolog and logrus to provide a simple intuitive interface to the developers while allowing high performance implementations avoiding reflection and allocations.

Refer complete documentation : https://godoc.org/github.com/anuvu/zlog

Features

  • Context based logging
  • Log level support
  • Near-zero allocations

Usage

import "github.com/anuvu/zlog"
log.Info().Msg("hello world")

// Output: {"level":"info","time":1494567715,"message":"hello world"}
Fields can be added to log messages
log.Info().Str("foo", "bar").Int("n", 123).Msg("hello world")

// Output: {"level":"info",foo":"bar","n":123,"message":"hello world"}
Create logger instance to manage different outputs
logger := zlog.New("test_logger").With().Timestamp().Logger()

logger.Info().Str("foo", "bar").Msg("hello world")

// Output: {"level":"info","time":1494567715,"message":"hello world","foo":"bar"}
Sub-loggers let you chain loggers with additional context
sublogger := log.With().Str("component": "foo").Logger()
sublogger.Info().Msg("hello world")

// Output: {"level":"info","time":1494567715,"message":"hello world","component":"foo"}
Set as standard logger output
log := zlog.New("test_logger").With().Str("foo", "bar").Logger()

stdlog.SetFlags(0)
stdlog.SetOutput(log)

stdlog.Print("hello world")

// Output: {"foo":"bar","message":"hello world"}

Field Types

Standard Types
  • Str
  • Bool
  • Int
  • Uint
  • Float32
Advanced Fields
  • Error: Takes an error and render it as a string using the error field name.
  • Timestamp: Insert a timestamp field with time field name and formatted using RFC 3339 format.

Performance

$ go test -bench=. -benchmem
.........
9 total assertions

goos: darwin
goarch: amd64
pkg: github.com/anuvu/zlog
BenchmarkLogEmpty-8             50000000                31.2 ns/op             0 B/op          0 allocs/op
BenchmarkDisabled-8             200000000                6.37 ns/op            0 B/op          0 allocs/op
BenchmarkInfo-8                 30000000                50.7 ns/op             0 B/op          0 allocs/op
BenchmarkContextFields-8        10000000               143 ns/op               0 B/op          0 allocs/op
BenchmarkContextAppend-8        10000000               150 ns/op             832 B/op          3 allocs/op
BenchmarkLogFields-8            10000000               229 ns/op               0 B/op          0 allocs/op
BenchmarkLogFieldType/Int-8     30000000                49.1 ns/op             0 B/op          0 allocs/op
BenchmarkLogFieldType/Str-8     30000000                43.7 ns/op             0 B/op          0 allocs/op
BenchmarkLogFieldType/Err-8     30000000                49.5 ns/op             0 B/op          0 allocs/op
BenchmarkLogFieldType/Object-8  10000000               109 ns/op              64 B/op          2 allocs/op
BenchmarkLogFieldType/Bool-8    30000000                43.2 ns/op             0 B/op          0 allocs/op
PASS
ok      github.com/anuvu/zlog       17.846s

Documentation

Overview

Package zlog provides a consistent, easy to use structure logging interface.

The interface is inspired by zerolog (https://github.com/rs/zerolog) and uses it for the default implementation that provides json formatted logs.

Every logger is named so that it can be registered with a logging service. To create a new logger:

log := zlog.New("test")
log.Info().Msg("test")
// Output: {level":"info","message":"test"}

Fields can be added to log messages:

log.Info().Str("foo", "bar").Msg("hello world")
// Output: {level":"info","message":"hello world","foo":"bar"}

Create logger instance to manage different outputs:

logger := zlog.New(os.Stderr).With().Timestamp().Logger()
logger.Info().
       Str("foo", "bar").
       Msg("hello world")
// Output: {"time":1494567715,"level":"info","message":"hello world","foo":"bar"}

Sub-loggers let you chain loggers with additional context:

sublogger := log.With().Str("component": "foo").Logger()
sublogger.Info().Msg("hello world")
// Output: {"time":1494567715,"level":"info","message":"hello world","component":"foo"}

Level logging

log.Level(zlog.Info)

log.Debug().Msg("filtered out message")
log.Info().Msg("routed message")

if e := log.Debug(); e.Enabled() {
    // Compute log output only if enabled.
    value := compute()
    e.Str("foo": value).Msg("some debug message")
}
// Output: {"level":"info","time":1494567715,"routed message"}

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Context

type Context interface {
	// Logger returns the logger with the context previously set.
	Logger() Logger

	// Str adds the field key with val as a string to the logger context.
	Str(key string, val string) Context

	// Int adds the field key with i as a int to the logger context.
	Int(key string, val int) Context

	// Uint adds the field key with i as a uint to the event.
	Uint(key string, i uint) Context

	// Float32 adds the field key with f as a float32 to the event.
	Float32(key string, f float32) Context

	// Bool adds the field key with val as a bool to event.
	Bool(key string, val bool) Context

	// Err adds the field "error" with err as a string to the event.
	// If err is nil, no field is added.
	Error(e error) Context

	// Timestamp adds the current local time as UNIX timestamp to the event.
	Timestamp() Context

	// Object marshals a custom type that implements ObjectMarshaler interface.
	Object(key string, obj ObjectMarshaler) Context
}

Context configures a new sub-logger with contextual fields.

Example (With)
package main

import (
	"fmt"

	"github.com/anuvu/zlog"
)

func main() {
	log := zlog.New("tst_logger")
	ctx := log.With()
	// Add Int, Bool and Str context to every log
	l := ctx.Int("n", 100).Bool("b", false).Str("t", "test").Uint("u", 1).Float32("f", 1.1).Logger()
	// Add Error context in addition to  above contexts.
	l = l.With().Error(nil).Logger()
	// Add one more Error Event in addition to above contexts.
	l = l.With().Error(fmt.Errorf("test error")).Logger()
	l.Info().Msg("context test")

}
Output:
{"level":"info","name":"tst_logger","n":100,"b":false,"t":"test","u":1,"f":1.1,"error":"test error","message":"context test"}
Example (With_object)
package main

import (
	"github.com/anuvu/zlog"
)

type User struct {
	Name string
	ID   string
}

func (u *User) Marshal(e zlog.Event) {
	e.Str("name", u.Name).Str("id", u.ID)
}

func main() {
	log := zlog.New("tst_logger")
	l := log.With().Object("user", &User{"Jalaja", "Ganapathy"}).Logger()
	l.Info().Msg("object test")

}
Output:
{"level":"info","name":"tst_logger","user":{"name":"Jalaja","id":"Ganapathy"},"message":"object test"}

type Event

type Event interface {

	// Enabled return false if the *Event is going to be filtered out by
	// log level or sampling.
	Enabled() bool

	// Msg sends the Event with msg added as the message field if not empty.
	//
	// NOTICE: once this method is called, the Event should be disposed.
	// Calling Msg twice can have unexpected result.
	Msg(msg string)

	// Str adds the field key with val as a string to the event.
	Str(key string, val string) Event

	// Int adds the field key with i as a int to the event.
	Int(key string, val int) Event

	// Uint adds the field key with i as a uint to the event.
	Uint(key string, i uint) Event

	// Float32 adds the field key with f as a float32 to the event.
	Float32(key string, f float32) Event

	// Bool adds the field key with val as a bool to event.
	Bool(key string, val bool) Event

	// Err adds the field "error" with err as a string to the event.
	// If err is nil, no field is added.
	Error(e error) Event

	// Timestamp adds the current local time as UNIX timestamp to the event.
	Timestamp() Event

	// Object marshals a custom type that implements ObjectMarshaler interface.
	Object(key string, obj ObjectMarshaler) Event
}

Event provides a log event interface.

Example (Float32)
package main

import (
	"github.com/anuvu/zlog"
)

func main() {
	log := zlog.New("tst_logger")
	log.Info().Float32("float32", 5.5555).Msg("hello world")
}
Output:
{"level":"info","name":"tst_logger","float32":5.5555,"message":"hello world"}
Example (Object)
package main

import (
	"github.com/anuvu/zlog"
)

type User struct {
	Name string
	ID   string
}

func (u *User) Marshal(e zlog.Event) {
	e.Str("name", u.Name).Str("id", u.ID)
}

func main() {
	log := zlog.New("tst_logger")
	log.Info().Object("user", &User{"Jalaja", "Ganapathy"}).Msg("object test")

}
Output:
{"level":"info","name":"tst_logger","user":{"name":"Jalaja","id":"Ganapathy"},"message":"object test"}
Example (Timestamp)
package main

import (
	"github.com/anuvu/zlog"
)

func main() {
	log := zlog.New("tst_logger")
	log = log.Level(zlog.Warn)
	// We cant test timestamp as its a moving target, lets filter it out
	// and figure it out later
	log.Info().Timestamp().Msg("hello world")
	log.Warn().Msg("hello world")

}
Output:
{"level":"warn","name":"tst_logger","message":"hello world"}
Example (Uint)
package main

import (
	"github.com/anuvu/zlog"
)

func main() {
	log := zlog.New("tst_logger")
	log.Info().Uint("uint", 1000).Msg("hello world")
}
Output:
{"level":"info","name":"tst_logger","uint":1000,"message":"hello world"}

type Level

type Level uint8

Level defines supported log levels.

const (
	// Debug log level.
	Debug Level = iota

	// Info log level.
	Info

	// Warn log level.
	Warn

	// Error log level.
	Error

	// Fatal log level.
	Fatal

	// Panic log level.
	Panic

	// Disabled log level.
	Disabled
)

type Logger

type Logger interface {
	// Name returns the name of the logger.
	Name() string

	// LogLevel returns the current level of the logger.
	LogLevel() Level

	// Test returns True if the logger will emit a log event at the given level.
	Test(lvl Level) bool

	// Write provides the io.Writer interface for this logger to be chained the standard
	// logging library.
	Write([]byte) (int, error)

	// Stream duplicates the current logger and sets the output to the given writer.
	Stream(w io.Writer) Logger

	// Level sets logger to the minimum accepted log level.
	Level(lvl Level) Logger

	// With creates a child logger with the field added to its context.
	With() Context

	// Debug starts a new message with debug level.
	// You must call Msg on the returned event in order to send the event.
	Debug() Event

	// Info starts a new message with info level.
	// You must call Msg on the returned event in order to send the event.
	Info() Event

	// Warn starts a new message with warn level.
	// You must call Msg on the returned event in order to send the event.
	Warn() Event

	// Error starts a new message with error level.
	// You must call Msg on the returned event in order to send the event.
	Error() Event

	// Fatal starts a new message with fatal level. The os.Exit(1) function
	// is called by the Msg method.
	//
	// You must call Msg on the returned event in order to send the event.
	Fatal() Event

	// Panic starts a new message with panic level. The message is also sent
	// to the panic function.
	//
	// You must call Msg on the returned event in order to send the event.
	Panic() Event
}

Logger provides a leveled logging interface.

Example (Error)
package main

import (
	"errors"

	"github.com/anuvu/zlog"
)

func main() {
	log := zlog.New("tst_logger")

	log.Error().Error(errors.New("some error")).Msg("error doing something")

}
Output:
{"level":"error","name":"tst_logger","error":"some error","message":"error doing something"}
Example (Info)
package main

import (
	"github.com/anuvu/zlog"
)

func main() {
	log := zlog.New("tst_logger")

	log.Info().Str("foo", "bar").Int("n", 123).Bool("b", true).Msg("hello world")

}
Output:
{"level":"info","name":"tst_logger","foo":"bar","n":123,"b":true,"message":"hello world"}
Example (Level)
package main

import (
	"github.com/anuvu/zlog"
)

func main() {
	log := zlog.New("tst_logger").Level(zlog.Warn)

	log.Info().Msg("filtered out message")
	log.Error().Msg("kept message")

}
Output:
{"level":"error","name":"tst_logger","message":"kept message"}
Example (Msg)
package main

import (
	"github.com/anuvu/zlog"
)

func main() {
	log := zlog.New("tst_logger")

	log.Debug().Str("foo", "bar").Str("bar", "baz").Msg("")

}
Output:
{"level":"debug","name":"tst_logger","foo":"bar","bar":"baz"}
Example (Warn)
package main

import (
	"github.com/anuvu/zlog"
)

func main() {
	log := zlog.New("tst_logger")

	log.Warn().Str("foo", "bar").Msg("a warning message")

}
Output:
{"level":"warn","name":"tst_logger","foo":"bar","message":"a warning message"}
Example (With)
package main

import (
	"github.com/anuvu/zlog"
)

func main() {
	log := zlog.New("tst_logger").With().Str("foo", "bar").Logger()

	log.Info().Msg("hello world")

}
Output:
{"level":"info","name":"tst_logger","foo":"bar","message":"hello world"}
Example (Write)
package main

import (
	stdlog "log"

	"github.com/anuvu/zlog"
)

func main() {
	log := zlog.New("tst_logger").With().Str("foo", "bar").Logger()

	stdlog.SetFlags(0)
	stdlog.SetOutput(log)

	stdlog.Print("hello world")

}
Output:
{"name":"tst_logger","foo":"bar","message":"hello world"}

func New

func New(name string) Logger

New creates a new named logger at Debug level with output written to stdout.

Example
package main

import (
	"github.com/anuvu/zlog"
)

func main() {
	log := zlog.New("tst_logger")

	log.Info().Msg("hello world")

}
Output:
{"level":"info","name":"tst_logger","message":"hello world"}

func NewWithStream

func NewWithStream(name string, w io.Writer, lvl Level) Logger

NewWithStream creates a new named logger with the given output writer and log level.

Each logging operation must issue only a single call to the Writer's write method. The writer object is assumed to be thread-safe.

type ObjectMarshaler

type ObjectMarshaler interface {
	Marshal(e Event)
}

ObjectMarshaler provides a strongly-typed encoding agnostic interface to be implemented by custom types for efficient encoding

Jump to

Keyboard shortcuts

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