genelog

package module
v1.0.19 Latest Latest
Warning

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

Go to latest
Published: Jul 18, 2022 License: MIT Imports: 6 Imported by: 0

README

genelog

godoc license

Small (200 loc) and composable logger with context, hooks and formatter.

Features

  • Composable
  • Support any context
  • Support any formatter
  • Support hook functions to update context and message on writes
  • Extensions:
    • Fields:
      • Level
      • Time
    • Formatter:
      • JSON

Usage

Basic
logger := New(os.Stdout).
  WithFormatter(func(context interface{}, msg string) (string, error) {
    return msg, nil
  })

logger.Println("mylog1")
logger.Println("mylog2")

// Output:
// mylog1
// mylog2
With context
type Context struct {
  S string
  N int
}

// updateContext is an helper function to update
// this specific context
func updateContext(update func(Context) Context) Update {
  return func(v interface{}) (interface{}, error) {
    context, ok := v.(Context)
    if !ok {
      return nil, errors.New("not Context type")
    }
    return update(context), nil
  }
}

func main() {
  // our context
  context := Context{}

  // create logger
  logger := New(os.Stdout).
    WithContext(context).
    WithFormatter(func(v interface{}, msg string) (string, error) {
      context, ok := v.(Context)
      if !ok {
        return "", errors.New("not Context type")
      }
      return fmt.Sprintf("%s %d %s", context.S, context.N, msg), nil
    })

  // update context
  logger.UpdateContext(updateContext(
    func(context Context) Context {
      context.S = "A"
      context.N = 1
      return context
    }))

  // write log items
  logger.Print("mylog")

  // Output:
  // A 1 mylog
With level
package main

import (
  "os"

  "github.com/6prod/genelog"
  "github.com/6prod/genelog/format/json"
  "github.com/6prod/genelog/field/level"
)

type Context struct {
  *level.WithLevel
}

func main() {
  context := Context{
    NewWithLevel(INFO),
  }

  logger := NewLevelLogger(genelog.New(os.Stdout).
    WithContext(context).
    WithFormatter(json.JSON))

  logger.Print("mylog")
  logger.Info("mylog")
  logger.Error("mylog")
  logger.Debug("mylog")
  logger.Warning("mylog")
  logger.Fatalf("%s", "mylog")

  // Output:
  // {"context":{"level":"UNSET"},"message":"mylog"}
  // {"context":{"level":"INFO"},"message":"mylog"}
  // {"context":{"level":"ERR"},"message":"mylog"}
  // {"context":{"level":"WARNING"},"message":"mylog"}
  // {"context":{"level":"FATAL"},"message":"mylog"}
}

See documentation for more examples.

Benchmark

$ ci/bench
goos: openbsd
goarch: amd64
pkg: github.com/6prod/genelog
cpu: Intel(R) Core(TM) i7-5600U CPU @ 2.60GHz
BenchmarkLogger-2         350896              3142 ns/op
BenchmarkGoLogger-2       276690              4432 ns/op
BenchmarkZerolog-2        591278              2223 ns/op
PASS
ok      github.com/6prod/genelog        3.845s

Documentation

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrLogger is the general logger error
	ErrLogger = errors.New("logger error")
	// ErrSkip tells the logger to skip a log entry
	ErrSkip = errors.New("skip")
)

Functions

This section is empty.

Types

type Format

type Format func(context interface{}, msg string) (out string, err error)

Format assembles context and msg into a single string

type Hook

type Hook func(context interface{}, msg string) (newcontext interface{}, newmsg string, err error)

Hook is called before each write to update the context or message

If err is ErrSkip, just return without writing anything

Example (Context)
buf := bytes.Buffer{}

context := Context{}

logger := New(&buf).
	WithContext(context).
	WithFormatter(func(v interface{}, msg string) (string, error) {
		context, ok := v.(Context)
		if !ok {
			return "", errors.New("not Context type")
		}
		return fmt.Sprintf("%s %d %s", context.S, context.N, msg), nil
	})

_ = logger.UpdateContext(updateContext(
	func(context Context) Context {
		context.S = "A"
		context.N = 1
		return context
	}))

logger.Print("mylog")

fmt.Print(buf.String())
Output:

A 1 mylog
Example (ContextUpdateTime)
var context time.Time = time.Date(2021, 2, 1, 12, 30, 0, 0, time.UTC)

hookUpdateTime := func(v interface{}, msg string) (interface{}, string, error) {
	context := time.Date(2022, 2, 1, 12, 30, 0, 0, time.UTC)
	return context, msg, nil
}

formatter := func(v interface{}, msg string) (string, error) {
	context, ok := v.(time.Time)
	if !ok {
		return "", fmt.Errorf("%T: not time type", v)
	}

	return fmt.Sprintf("%s: %s", context, msg), nil
}

buf := bytes.Buffer{}
logger := New(&buf).
	WithContext(context).
	WithFormatter(formatter).
	AddHook(hookUpdateTime)

logger.Println("message")
fmt.Println(buf.String())
Output:

2022-02-01 12:30:00 +0000 UTC: message
Example (MultiFormatter)

Write to the io.Writer of the logger with no format and to console using a hook

var context string

// To replace with os.Stdout
var console bytes.Buffer

hookWriteConsole := func(v interface{}, msg string) (interface{}, string, error) {
	context, ok := v.(string)
	if !ok {
		return nil, "", fmt.Errorf("%T: not string type", v)
	}

	fmt.Fprintf(&console, "%s: %s", context, msg)
	return v, msg, nil
}

logger := New(io.Discard).
	WithContext(context).
	AddHook(hookWriteConsole)

_ = logger.UpdateContext(func(v interface{}) (interface{}, error) {
	context = "mycontext"
	return context, nil
})

logger.Println("message")
fmt.Println(console.String())
Output:

mycontext: message

type Logger

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

func New

func New(w io.Writer) *Logger

func (*Logger) AddHook

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

AddHook adds a hook function to the list of hooks of the logger.

Hooks are called in the added order

func (*Logger) Context

func (l *Logger) Context() interface{}

Context returns the context

func (*Logger) Print

func (l *Logger) Print(v ...interface{})

Print uses fmt.Print to write to the logger

func (*Logger) Printf

func (l *Logger) Printf(format string, v ...interface{})

Printf uses fmt.Printf to write to the logger

func (*Logger) Println

func (l *Logger) Println(v ...interface{})

Println uses fmt.Println to write to the logger

Example
buf := bytes.Buffer{}

logger := New(&buf).
	WithFormatter(func(v interface{}, msg string) (string, error) {
		return msg, nil
	})

logger.Println("mylog1")
logger.Println("mylog2")
logger.Println("mylog3")
logger.Println("mylog4")

fmt.Print(&buf)
Output:

mylog1
mylog2
mylog3
mylog4

func (*Logger) SetOutput added in v1.0.13

func (l *Logger) SetOutput(w io.Writer)

SetOutput changes the output writer of the logger

Example
logger := New(io.Discard).
	WithFormatter(func(v interface{}, msg string) (string, error) {
		return msg, nil
	})

logger.Println("mylog1")

buf := bytes.Buffer{}
logger.SetOutput(&buf)
logger.Println("mylog2")

fmt.Print(&buf)
Output:

mylog2

func (*Logger) UpdateContext

func (l *Logger) UpdateContext(update Update) error

UpdateContext updates the logger context with the update function

func (*Logger) WithContext

func (l *Logger) WithContext(v interface{}) *Logger

WithContext adds a context to the logger

func (*Logger) WithFormatter

func (l *Logger) WithFormatter(f Format) *Logger

WithFormatter adds a formatter function to the logger

func (*Logger) Write added in v1.0.1

func (l *Logger) Write(p []byte) (n int, err error)

Write writes into the logger

type Update

type Update func(context interface{}) (newcontext interface{}, err error)

Update returns a new updated context

Directories

Path Synopsis
field
format
json
Package JSON formats log outputs into JSON using the structure { "context": {}, "message": "message" }
Package JSON formats log outputs into JSON using the structure { "context": {}, "message": "message" }

Jump to

Keyboard shortcuts

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