miss

package module
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Dec 20, 2018 License: Apache-2.0 Imports: 14 Imported by: 0

README

miss

Package miss provides an flexible, extensible and powerful logging management tool based on the level, which has done the better balance between the flexibility and the performance.

miss is meaning:

  1. love: Because of loving it, I miss it.
  2. flexible and extensible: Something can be customized according to demand, so they are missing.
  3. no any third-party dependencies: for the core package, you don't care any other packages, including the third-party.

It is inspired by log15, logrus, go-kit.

See the GoDoc.

Basic Principle

  • The better performance
  • Flexible, extensible, and powerful
  • No any third-party dependencies

Features

  • A simple, easy-to-understand API
  • No any third-party dependencies for the core package.
  • A flexible and powerful interface supporting many encoders, such as the Key-Value or Format style encoder
  • Child loggers which inherit and add their own private context
  • Lazy evaluation of expensive operations
  • Support the native io.Writer as the output, and provied some advanced io.Writer implementations, such as MultiWriter and LevelWriter.
  • Built-in support for logging to files, syslog, and the network

Logger

type Logger interface {
	// Depth returns a new Logger with the stack depth.
	//
	// stackDepth is the calling depth of the logger, which will be passed to
	// the encoder. The default depth is the global variable DefaultLoggerDepth
	// for the new Logger.
	//
	// It should be used typically when you wrap the logger. For example,
	//
	//   logger := miss.New(miss.KvTextEncoder(os.Stdout))
	//   logger = logger.Depth(logger.GetDepth() + 1)
	//
	//   func Debug(m string, args ...interface{}) { logger.Debug(m, args...) }
	//   func Info(m string, args ...interface{}) { logger.Debug(m, args...) }
	//   func Warn(m string, args ...interface{}) { logger.Debug(m, args...) }
	//   ...
	//
	Depth(stackDepth int) Logger

	// Level returns a new Logger with the new level.
	Level(level Level) Logger

	// Encoder returns a new logger with the new encoder.
	Encoder(encoder Encoder) Logger

	// Ctx returns a new logger with the new contexts.
	Cxt(ctxs ...interface{}) Logger

	GetDepth() int
	GetLevel() Level
	GetEncoder() Encoder

	Trace(msg string, args ...interface{}) error
	Debug(msg string, args ...interface{}) error
	Info(msg string, args ...interface{}) error
	Warn(msg string, args ...interface{}) error
	Error(msg string, args ...interface{}) error
	Panic(msg string, args ...interface{}) error
	Fatal(msg string, args ...interface{}) error
}

Example

  1. Prepare a writer having implemented io.Writer, such as os.Stdout.
  2. Create an encoder.
  3. Create a logger with the encoder.
  4. Output the log.
package main

import (
	"os"

	"github.com/xgfone/miss"
)

func main() {
	conf := miss.EncoderConfig{IsLevel: true, IsTime: true}
	encoder := miss.KvTextEncoder(os.Stdout, conf)
	logger := miss.New(encoder).Level(miss.WARN)

	logger.Info("don't output")
	logger.Error("will output", "key", "value")
	// Output:
	// t=2018-10-25T10:46:22.0035694+08:00 lvl=ERROR key=value msg=will output
}

Notice:

miss is based on the level, and the log output interfaces is func(string, ...interface{}) error, the meaning of the arguments of which is decided by the encoder. See below.

Furthermore, miss has built in a global logger, which is equal to miss.New(miss.KvTextEncoder(os.Stdout, miss.EncoderConfig{IsLevel: true, IsTime: true})), and you can use the functions as follow:

SetGlobalLogger(newLogger Logger)
GetGlobalLogger() Logger

WithLevel(level Level) Logger
WithEncoder(encoder Encoder) Logger
WithCtx(ctxs ...interface{}) Logger
WithDepth(depth int) Logger

GetDepth() int
GetLevel() Level
GetEncoder() Encoder

Trace(msg string, args ...interface{}) error
Debug(msg string, args ...interface{}) error
Info(msg string, args ...interface{}) error
Warn(msg string, args ...interface{}) error
Error(msg string, args ...interface{}) error
Panic(msg string, args ...interface{}) error
Fatal(msg string, args ...interface{}) error

If you prefer the logger without the error, you maybe use LoggerWithoutError converted by ToLoggerWithoutError(Logger) from Logger as follow:

type LoggerWithoutError interface {
	Depth(stackDepth int) LoggerWithoutError
	Level(level Level) LoggerWithoutError
	Encoder(encoder Encoder) LoggerWithoutError
	Cxt(ctxs ...interface{}) LoggerWithoutError

	GetDepth() int
	GetLevel() Level
	GetEncoder() Encoder

	Trace(msg string, args ...interface{})
	Debug(msg string, args ...interface{})
	Info(msg string, args ...interface{})
	Warn(msg string, args ...interface{})
	Error(msg string, args ...interface{})
	Panic(msg string, args ...interface{})
	Fatal(msg string, args ...interface{})
}
Inherit the context of the parent logger
encoder := FmtTextEncoder(os.Stdout)
parent := logger.New(encoder).Ctx("parent")
child := parent.Ctx("child")
child.Info("hello %s", "world")
// Output:
// [parent][child] :=>: hello world

OR

parent := logger.New("key1", "value1")
child := parent.New("key2", "value2").Encoder(KvTextEncoder(os.Stdout))
child.Info("hello world", "key3", "value3")
// Output:
// key1=value1 key2=value2 key3=value3 msg=hello world
Encoder

The core package provides three kinds of encoders: the text encoder based on Key-Value KvTextEncoder, the text encoder based on Format FmtTextEncoder and the json encoder based on Key-Value KvStdJSONEncoder and KvSimpleJSONEncoder.

For the encoders based on Format, the arguments of the log output function, such as Info(), are the same as those of fmt.Sprintf(). For the encoders based on Key-Value, but, the first argument is the log description, and the rests are the key-value pairs, the number of which are even, for example, logger.Info("log description", "key1", "value1", "key2", "value2").

kvlog := miss.New(miss.KvTextEncoder(os.Stdout))
kvlog.Info("creating connection", "host", "127.0.0.1", "port", 80)

fmtlog := miss.New(miss.FmtTextEncoder(os.Stdout))
kvlog.Info("creating connection to %s:%d", "127.0.0.1", 80)
LevelFilterEncoder and MultiEncoder

You can use LevelFilterEncoder to filter some logs by the level, for example,

encoders := ["kvtext", "kvjson"]
textenc := miss.KvTextEncoder(os.Stdout)
jsonenc := miss.KvSimpleJSONEncoder(os.Stderr)

textenc = miss.LevelFilterEncoder(miss.INFO, textenc)
jsonenc = miss.LevelFilterEncoder(miss.ERROR, jsonenc)

logger := miss.New(miss.MultiEncoder(textenc, jsonenc))

if err := logger.Info("only output to stdout"); err != nil {
    for i, e := range err.(miss.MultiError) {
        fmt.Printf("%s: %s\n", encoders[i], e.Error())
    }
}

if err := logger.Error("output to stdout & stderr); err != nil {
    for i, e := range err.(miss.MultiError) {
        fmt.Printf("%s: %s\n", encoders[i], e.Error())
    }
}
Writer

All implementing the interface io.Writer are a Writer.

There are some the built-in writers in the core package, such as DiscardWriter, NetWriter, FileWriter, MultiWriter, FailoverWriter, SafeWriter, ChannelWriter, BufferedWriter, LevelFilterWriter, SyslogWriter, SyslogNetWriter, SizedRotatingFileWriter and Must.

MultiWriter

For an encoder, you can output the result to more than one destination by using MultiWriter. For example, output the log to STDOUT and the file:

writer := miss.MultiWriter(os.Stdout, miss.FileWriter("/path/to/file"))
encoder := miss.KvTextEncoder(writer)
logger := miss.New(encoder)

logger.Info("output to stdout and file")
Lazy evaluation

If the type of a certain value is Valuer, the default encoder engine will call it and encode the returned result. For example,

logger := miss.New("hello", func(d int, l Level) (interface{}, error) { return "world", nil })

or

logger.Info("hello %v", func(d int, l Level) (interface{}, error) { return "world", nil })

Performance

The log framework itself has no any performance costs.

There may be some performance costs below:

  1. Use format arguments or Key-Value pairs when firing a log. For example, logger.Info("hello %s", "world") will allocate the 16-byte memory once for the encoder FmtTextEncoder , logger.Info("hello world", "key", "value") will allocate the 32-byte memory once for the encoder KvTextEncoder.
  2. Encode the arguments to io.Writer. For string or []byte, there is no any performance cost, but for other types, such as int, it maybe have once memory allocation.
Performance Test

The test program is from go-loggers-bench.

MacBook Pro(Retina, 13-inch, Mid 2014)
2.6 GHz Intel Core i5
8 GB 1600 MHz DDR3
macOS Mojave
TextNegative
test ops ns/op bytes/op allocs/op
BenchmarkMissTextNegative-4 1000000000 7.25 ns/op 0 B/op 0 allocs/op
BenchmarkGokitTextNegative-4 300000000 26.8 ns/op 32 B/op 1 allocs/op
BenchmarkLog15TextNegative-4 10000000 723 ns/op 368 B/op 3 allocs/op
BenchmarkLogrusTextNegative-4 10000000000 1.93 ns/op 0 B/op 0 allocs/op
BenchmarkSeelogTextNegative-4 200000000 47.4 ns/op 48 B/op 2 allocs/op
BenchmarkZerologTextNegative-4 2000000000 4.39 ns/op 0 B/op 0 allocs/op
BenchmarkGologgingTextNegative-4 100000000 92.1 ns/op 144 B/op 2 allocs/op
TextPositive
test ops ns/op bytes/op allocs/op
BenchmarkMissTextPositive-4 20000000 372 ns/op 48 B/op 1 allocs/op
BenchmarkLog15TextPositive-4 1000000 5125 ns/op 856 B/op 14 allocs/op
BenchmarkGokitTextPositive-4 10000000 846 ns/op 256 B/op 4 allocs/op
BenchmarkSeelogTextPositive-4 2000000 3313 ns/op 440 B/op 11 allocs/op
BenchmarkLogrusTextPositive-4 2000000 4433 ns/op 448 B/op 12 allocs/op
BenchmarkZerologTextPositive-4 30000000 288 ns/op 0 B/op 0 allocs/op
BenchmarkGologgingTextPositive-4 10000000 1093 ns/op 920 B/op 15 allocs/op
JSONNegative
test ops ns/op bytes/op allocs/op
BenchmarkMissJSONNegative-4 200000000 41.9 ns/op 96 B/op 1 allocs/op
BenchmarkLog15JSONNegative-4 10000000 813 ns/op 560 B/op 5 allocs/op
BenchmarkGokitJSONNegative-4 200000000 45.0 ns/op 128 B/op 1 allocs/op
BenchmarkLogrusJSONNegative-4 20000000 367 ns/op 480 B/op 4 allocs/op
BenchmarkZerologJSONNegative-4 1000000000 8.80 ns/op 0 B/op 0 allocs/op
JSONPositive
test ops ns/op bytes/op allocs/op
BenchmarkMissJSONPositive-4 10000000 1181 ns/op 640 B/op 10 allocs/op
BenchmarkLog15JSONPositive-4 500000 11108 ns/op 2256 B/op 32 allocs/op
BenchmarkGokitJSONPositive-4 3000000 2726 ns/op 1552 B/op 24 allocs/op
BenchmarkLogrusJSONPositive-4 1000000 9273 ns/op 1843 B/op 30 allocs/op
BenchmarkZerologJSONPositive-4 20000000 397 ns/op 0 B/op 0 allocs/op

NOTICE: For pursuing the extreme performance, you maybe see zerolog.

Documentation

Overview

Package miss provides an flexible, extensible and powerful logging management tool based on the level, which has done the better balance between the flexibility and the performance.

Meaning

  • love: Because of loving it, I miss it.
  • flexible and extensible: Something can be customized according to demand, so they are missing.
  • no any third-party dependencies: for the core package, you don't care any other packages, including the third-party.

Basic Principle

  • The better performance
  • Flexible, extensible, and powerful
  • No any third-party dependencies

Features

  • A simple, easy-to-understand API
  • No any third-party dependencies for the core package.
  • A flexible and powerful interface supporting many encoders
  • Child loggers which inherit and add their own private context
  • Lazy evaluation of expensive operations
  • Support any `io.Writer` and provied some advanced `io.Writer` implementations
  • Built-in support for logging to files, syslog, and the network

Encoder

The core package provides three kinds of encoders:

  • the text encoder based on Key-Value `KvTextEncoder`
  • the text encoder based on Format `FmtTextEncoder`
  • the json encoder based on Key-Value `KvStdJSONEncoder` and `KvSimpleJSONEncoder`

For the encoders based on Format, the arguments of the log output function, such as `Info()`, are the same as those of `fmt.Sprintf()`. For the encoders based on Key-Value, howerer, the first argument is the log description, and the rests are the key-value pairs, the number of which are even, for example,

logger.Info("log description", "key1", "value1", "key2", "value2")

You can use `LevelFilterEncoder` to filter some logs by the level, for example,

Writer

All implementing the interface `io.Writer` are a Writer.

There are some the built-in writers in the core package, For example,

NetWriter    SyslogWriter    SizedRotatingFileWriter
FileWriter   ChannelWriter   LevelFilterWriter
SafeWriter   DiscardWriter   SyslogNetWriter
MultiWriter  BufferedWriter  FailoverWriter

Performance

The log framework itself has no any performance costs.

There may be some performance costs below:

  1. Use format arguments or Key-Value pairs when firing a log. For example, `logger.Info("hello %s", "world")` will allocate the 16-byte memory once for the encoder `FmtTextEncoder`, `logger.Info("hello world", "key", "value")` will allocate the 32-byte memory once for the encoder `KvTextEncoder`.
  2. Encode the arguments to `io.Writer`. For `string` or `[]byte`, there is no any performance cost, but for other types, such as `int`, it maybe have once memory allocation.

Index

Examples

Constants

View Source
const (
	TextKVSep     = "="
	TextKVPairSep = " "
)

The separators of the KV and the KV pair.

View Source
const (
	LevelKey = "lvl"
	TimeKey  = "t"
	MsgKey   = "msg"
)

Some key names. You can modify them to redefine them.

View Source
const DefaultLoggerDepth = 2

DefaultLoggerDepth is the depth for the default implementing logger.

Variables

View Source
var (
	NullBytes  = []byte("null")
	TrueBytes  = []byte("true")
	FalseBytes = []byte("false")

	CommaBytes        = []byte{','}
	ColonBytes        = []byte{':'}
	LeftBracketBytes  = []byte{'['}
	RightBracketBytes = []byte{']'}
	LeftBraceBytes    = []byte{'{'}
	RightBraceBytes   = []byte{'}'}
)

Predefine some json mark

View Source
var (
	DefaultBytesPools  = NewBytesPool()
	DefaultBufferPools = NewBufferPool()
)

Some default global pools.

View Source
var EncoderToWriterCaches = make(map[Encoder]io.Writer, 4)

EncoderToWriterCaches is used to cache the writer for the built-in encoder.

When you use the built-in encoder, it will add the encoder and the writer into this map. So later you can get the corresponding writer by the encoder.

For the third-part encoders, they may be added into it automatically.

View Source
var ErrKeyValueNum = fmt.Errorf("the number of key-values must be even")

ErrKeyValueNum will be used when the number of key-values is not even.

View Source
var ErrPanic = fmt.Errorf("the panic level log")

ErrPanic will be used when firing a PANIC level log.

View Source
var (
	ErrType = fmt.Errorf("not support the type")
)

Predefine some errors.

View Source
var Must muster

Must object provides the following writer creation functions which instead of returning an error parameter only return a writer and panic on failure: FileWriter, NetWriter, SyslogWriter, SyslogNetWriter.

Functions

func BufferedWriter

func BufferedWriter(bufSize int, w io.Writer) io.Writer

BufferedWriter writes all records to a buffered channel of the given size which flushes into the wrapped handler whenever it is available for writing.

Since these writes happen asynchronously, all writes to a BufferedWriter never return an error and any errors from the wrapped writer are ignored.

func ChannelWriter

func ChannelWriter(ch chan<- []byte) io.Writer

ChannelWriter writes all logs to the given channel.

It blocks if the channel is full. Useful for async processing of log messages, it's used by BufferedWriter.

func Debug

func Debug(msg string, args ...interface{}) error

Debug fires a DEBUG log.

The meaning of arguments is in accordance with the encoder.

func DiscardWriter

func DiscardWriter() io.Writer

DiscardWriter returns a writer which will discard all input.

func Error

func Error(msg string, args ...interface{}) error

Error fires a ERROR log.

The meaning of arguments is in accordance with the encoder.

func FailoverWriter

func FailoverWriter(outs ...io.Writer) io.Writer

FailoverWriter writes all log records to the first handler specified, but will failover and write to the second handler if the first handler has failed, and so on for all handlers specified.

For example, you might want to log to a network socket, but failover to writing to a file if the network fails, and then to standard out if the file write fails.

func Fatal

func Fatal(msg string, args ...interface{}) error

Fatal fires a FATAL log then terminates the program.

The meaning of arguments is in accordance with the encoder.

func FileWriter

func FileWriter(path string, mode ...os.FileMode) (io.Writer, io.Closer, error)

FileWriter returns a writer which writes log records to the give file.

If the path already exists, FileHook will append to the given file. If it does not, FileHook will create the file with mode 0644, but you can pass the second argument, mode, to modify it.

func GetDepth

func GetDepth() int

GetDepth returns the caller depth of the global logger.

func Info

func Info(msg string, args ...interface{}) error

Info fires a INFO log.

The meaning of arguments is in accordance with the encoder.

func MarshalJSON

func MarshalJSON(w io.Writer, v interface{}) (n int, err error)

MarshalJSON marshals a value v as JSON into w.

Support the types:

nil
bool
string
float32
float64
int
int8
int16
int32
int64
uint
uint8
uint16
uint32
uint64
time.Time
map[string]interface{} for json object
json.Marshaler
Array or Slice of the type above
Example
buf := bytes.NewBuffer(nil)

MarshalJSON(buf, 123)
buf.WriteByte('\n')
MarshalJSON(buf, 1.23)
buf.WriteByte('\n')
MarshalJSON(buf, "123")
buf.WriteByte('\n')
MarshalJSON(buf, time.Time{})
buf.WriteByte('\n')
MarshalJSON(buf, []int{1, 2, 3})
buf.WriteByte('\n')
MarshalJSON(buf, []string{"a", "b", "c"})
buf.WriteByte('\n')
MarshalJSON(buf, []float64{1.2, 1.4, 1.6})
buf.WriteByte('\n')
MarshalJSON(buf, map[string]interface{}{"number": 123, "name": "abc"})
buf.WriteByte('\n')

fmt.Printf("%s", buf.String())
Output:

123
1.23
"123"
"0001-01-01T00:00:00Z"
[1,2,3]
["a","b","c"]
[1.2,1.4,1.6]
{"number":123,"name":"abc"}

func MayBeValuer

func MayBeValuer(depth int, lvl Level, v interface{}) (interface{}, error)

MayBeValuer calls it and returns the result if v is Valuer. Or returns v without change.

func MayWriteLevel

func MayWriteLevel(w io.Writer, level Level, bs []byte) (int, error)

MayWriteLevel firstly tries to call the method WriteLevel to write the data. Or use io.Writer to write it.

func MultiWriter

func MultiWriter(outs ...io.Writer) io.Writer

MultiWriter writes one data to more than one destination.

func NetWriter

func NetWriter(network, addr string) (io.Writer, io.Closer, error)

NetWriter opens a socket to the given address and writes the log over the connection.

func Panic

func Panic(msg string, args ...interface{}) error

Panic fires a PANIC log then panic.

The meaning of arguments is in accordance with the encoder.

func Range

func Range(start, stop, step int) (r []int)

Range returns a integer range between start and stop, which progressively increase or descrease by step.

If step is positive, r[i] = start + step*i when i>0 and r[i]<stop.

If step is negative, r[i] = start + step*i but when i>0 and r[i]>stop.

If step is 0, it will panic.

func ReopenWriter

func ReopenWriter(factory func() (w io.WriteCloser, reopen <-chan bool, err error)) (io.Writer, error)

ReopenWriter returns a writer that can be closed then re-opened, which is used for logrotate typically.

Notice: it used SafeWriter to wrap the writer, so it's thread-safe.

func SafeWriter

func SafeWriter(w io.Writer) io.Writer

SafeWriter is guaranteed that only a single writing operation can proceed at a time.

It's necessary for thread-safe concurrent writes.

func SetGlobalLogger

func SetGlobalLogger(log Logger)

SetGlobalLogger sets the global logger to log.

If log is nil, it will do nothing.

Notice: for the global logger, it must be the builtin implementation.

func SizedRotatingFileWriter

func SizedRotatingFileWriter(filename string, size, count int,
	mode ...os.FileMode) (io.WriteCloser, error)

SizedRotatingFileWriter returns a new file writer with rotating based on the size of the file.

It is thread-safe for concurrent writes.

The default permission of the log file is 0644.

func SyslogNetWriter

func SyslogNetWriter(net, addr string, priority syslog.Priority,
	tag string) (io.Writer, io.Closer, error)

SyslogNetWriter opens a connection to a log daemon over the network and writes all logs to it.

func SyslogWriter

func SyslogWriter(priority syslog.Priority, tag string) (io.Writer,
	io.Closer, error)

SyslogWriter opens a connection to the system syslog daemon by calling syslog.New and writes all logs to it.

Example
conf := EncoderConfig{IsLevel: true}
out, c := Must.SyslogWriter(syslog.LOG_DEBUG, "testsyslog")
defer c.Close()
log := New(FmtTextEncoder(out, conf))
if err := log.Info("test %s %s", "syslog", "writer"); err != nil {
	fmt.Printf("Error: %s\n", err)
}
Output:

func ToBytes

func ToBytes(i interface{}, fmtSprintf ...bool) []byte

ToBytes is the same as ToBytesErr, but ignoring the error.

func ToBytesErr

func ToBytesErr(i interface{}, fmtSprintf ...bool) ([]byte, error)

ToBytesErr encodes a value to []byte.

For the time.Time, it uses time.RFC3339Nano to format it.

Support the types:

nil
bool
[]byte
string
float32
float64
int
int8
int16
int32
int64
uint
uint8
uint16
uint32
uint64
time.Time
interface error
interface fmt.Stringer
interface Byter
interface MarshalText

For other types, use fmt.Sprintf("%v") to format it if fmtSprintf is true, or return the error ErrType.

func ToString

func ToString(i interface{}, fmtSprintf ...bool) string

ToString is the same as ToBytesErr, but returns string and ignores the error.

func ToStringErr

func ToStringErr(i interface{}, fmtSprintf ...bool) (string, error)

ToStringErr is the same as ToBytesErr, but returns string.

func Trace

func Trace(msg string, args ...interface{}) error

Trace fires a TRACE log.

The meaning of arguments is in accordance with the encoder.

func Warn

func Warn(msg string, args ...interface{}) error

Warn fires a WARN log.

The meaning of arguments is in accordance with the encoder.

func WriteIntoBuffer

func WriteIntoBuffer(w *bytes.Buffer, i interface{}, fmtSprintf ...bool) error

WriteIntoBuffer is the same as ToBytesErr, but writes the result into w.

func WriteString

func WriteString(w io.Writer, s string, quote ...bool) (n int, err error)

WriteString writes s into w.

func WriterFunc

func WriterFunc(f func([]byte) (int, error)) io.Writer

WriterFunc converts a function to io.Writer.

Types

type BufferPool

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

BufferPool is the bytes.Buffer wrapper of sync.Pool

func NewBufferPool

func NewBufferPool(bufSize ...int) BufferPool

NewBufferPool returns a new bytes.Buffer pool.

bufSize is the initializing size of the buffer. If the size is equal to or less than 0, it will be ignored, and use the default size, 1024.

func (BufferPool) Get

func (p BufferPool) Get() *bytes.Buffer

Get returns a bytes.Buffer.

func (BufferPool) Put

func (p BufferPool) Put(b *bytes.Buffer)

Put places a bytes.Buffer to the pool.

type Byter

type Byter interface {
	Bytes() []byte
}

Byter returns a []byte.

type BytesPool

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

BytesPool is the []byte wrapper of sync.Pool

func NewBytesPool

func NewBytesPool(sliceCap ...int) BytesPool

NewBytesPool returns a new []byte pool.

sliceCap is the capacity of []byte. If the size is equal to or less than 0, it will be ignored, and use the default size, 1024.

func (BytesPool) Get

func (p BytesPool) Get() []byte

Get returns a bytes.Buffer.

func (BytesPool) Put

func (p BytesPool) Put(s []byte)

Put places []byte to the pool.

type Encoder

type Encoder interface {
	// Return the underlying writer.
	//
	// Notice: only the most underlying encoder requires it. For the inner
	// encoder, such as FilterEncoder and MultiEncoder, it may be nil.
	// So, at the moment, the log information should be passed to the next encoder.
	Writer() io.Writer

	// Encode the log and write it into the underlying writer.
	Encode(depth int, level Level, msg string, args []interface{}, ctx []interface{}) error
}

Encoder is a log encoder.

Notice: if the encoder implementation supports the level when writing data, it should firstly decide whether the writer is LevelWriter and use WriteLevel to write the log, not Write.

func EncoderFunc

func EncoderFunc(w io.Writer, f FuncEncoder) Encoder

EncoderFunc converts a function to an hashable Encoder.

func FilterEncoder

func FilterEncoder(f func(lvl Level, msg string, args []interface{}, ctx []interface{}) bool,
	encoder Encoder) Encoder

FilterEncoder returns an encoder that only forwards logs to the wrapped encoder if the given function evaluates true.

For example, filter those logs that the level is less than ERROR.

FilterEncoder(func(lvl Level, msg string, args []interface{},
                   ctxs []interface{}) bool {
    return level >= ERROR
})

func FmtTextEncoder

func FmtTextEncoder(out io.Writer, conf ...EncoderConfig) Encoder

FmtTextEncoder returns a text encoder based on the % formatter, which will output the result into out.

Notice: This encoder supports LevelWriter.

Example
conf := EncoderConfig{IsLevel: true}
encoder := FmtTextEncoder(os.Stdout, conf)
log := New(encoder).Cxt("kv", "text", "example")
log.Info("test %s %s", "value1", "value2")
Output:

INFO [kv][text][example] :=>: test value1 value2

func GetEncoder

func GetEncoder() Encoder

GetEncoder returns the encoder of the global logger.

func KvSimpleJSONEncoder

func KvSimpleJSONEncoder(w io.Writer, conf ...EncoderConfig) Encoder

KvSimpleJSONEncoder returns a new JSON encoder using the funcion MarshalJSON to encode the log record.

Except for the type of Array and Slice, it does not use the reflection. So it's faster than the standard library json.

func KvStdJSONEncoder

func KvStdJSONEncoder(w io.Writer, conf ...EncoderConfig) Encoder

KvStdJSONEncoder returns a new JSON encoder using the standard library, json, to encode the log record.

Example
conf := EncoderConfig{IsLevel: true}
encoder := KvStdJSONEncoder(os.Stdout, conf)
log := New(encoder).Cxt("name", "example", "id", 123)
log.Info("test", "key1", "value1", "key2", "value2")
Output:

{"id":123,"key1":"value1","key2":"value2","lvl":"INFO","msg":"test","name":"example"}

func KvTextEncoder

func KvTextEncoder(out io.Writer, conf ...EncoderConfig) Encoder

KvTextEncoder returns a text encoder based on the key-value pair, which will output the result into out.

Notice: This encoder supports LevelWriter.

Example
conf := EncoderConfig{IsLevel: true}
encoder := KvTextEncoder(os.Stdout, conf)
log := New(encoder).Cxt("name", "example", "id", 123)
log.Info("test", "key1", "value1", "key2", "value2")
Output:

lvl=INFO name=example id=123 key1=value1 key2=value2 msg=test

func LevelFilterEncoder

func LevelFilterEncoder(level Level, encoder Encoder) Encoder

LevelFilterEncoder returns an encoder that only writes records which are greater than the given verbosity level to the wrapped Handler.

For example, to only output Error/PANIC/FATAL logs:

miss.LevelFilterEncoder(miss.ERROR, miss.KvTextEncoder(os.Stdout))

func MultiEncoder

func MultiEncoder(encoders ...Encoder) Encoder

MultiEncoder uses many encoders to encode the log record.

It will return a MultiError if there is a error returned by an encoder in the corresponding order. For example,

encoders = ["kvtext", "kvjson"]
enc1 := KvTextEncoder(os.Stdout)
enc2 := KvJsonEncoder(os.Stderr)
logger := New(MultiEncoder(enc1, enc2))
err := logger.Info("msg", "key", "value")
if err != nil {
    errs := err.(MultiError)
    for i, e := range errs {
        if e != nil {
            fmt.Printf("%s: %s\n", encoders[i], e.Error())
        }
    }
}

func NothingEncoder

func NothingEncoder() Encoder

NothingEncoder returns an encoder that does nothing.

type EncoderConfig

type EncoderConfig struct {
	Slice []interface{}
	Map   map[string]interface{}

	// If true, the encoder disable appending a newline.
	NotNewLine bool

	// TimeLayout is used to format time.Time.
	//
	// The default is time.RFC3339Nano.
	TimeLayout string

	// If true, the time uses UTC.
	IsTimeUTC bool

	// If ture, the encoder will encode the current time.
	IsTime bool

	// If ture, the encoder will encode the level.
	IsLevel bool

	// For the Key-Value encoder, it represents the key name of the time.
	// The global constant, TimeKey, will be used by default.
	TimeKey string

	// For the Key-Value encoder, it represents the key name of the level.
	// The global constant, LvlKey, will be used by default.
	LevelKey string

	// For the Key-Value encoder, it represents the key name of the message.
	// The global constant, MsgKey, will be used by default.
	MsgKey string

	// The separator between key and value, such as "=".
	// The global constant, TextKVSep, will be used by default.
	TextKVSep string

	// The separator between the key-value pairs, such as " ".
	// The global constant, TextKVPairSep, will be used by default.
	TextKVPairSep string
}

EncoderConfig configures the encoder.

type FuncEncoder added in v0.3.0

type FuncEncoder func(w io.Writer, depth int, lvl Level, msg string, args []interface{}, ctx []interface{}) error

FuncEncoder stands for a function encoder, which is used to simplify the funcion signature.

type Level

type Level int

Level represents a level.

const (
	TRACE Level = iota // It will output the log unconditionally.
	DEBUG
	INFO
	WARN
	ERROR
	PANIC
	FATAL
)

Predefine some levels

func GetLevel

func GetLevel() Level

GetLevel returns the level of the global logger.

func NameToLevel

func NameToLevel(name string) Level

NameToLevel returns the Level by the name, which is case Insensitive.

If the name is unknown, it will panic.

Notice: WARNING is the alias of WARN.

func (Level) Bytes

func (l Level) Bytes() []byte

Bytes returns the []byte representation.

func (Level) String

func (l Level) String() string

String returns the string representation.

type LevelWriter

type LevelWriter interface {
	io.Writer

	WriteLevel(level Level, bs []byte) (n int, err error)
}

LevelWriter supports not only io.Writer but also WriteLevel.

func LevelFilterWriter

func LevelFilterWriter(lvl Level, w io.Writer) LevelWriter

LevelFilterWriter filters the logs whose level is less than lvl.

Example
logger1 := New(FmtTextEncoder(os.Stdout))
logger1.Info("will output")

writer := LevelFilterWriter(ERROR, os.Stdout)
logger2 := New(FmtTextEncoder(writer))
logger2.Info("won't output")
Output:

will output

func LevelWriterFunc

func LevelWriterFunc(f func(Level, []byte) (int, error)) LevelWriter

LevelWriterFunc converts a function to LevelWriter.

type Logger

type Logger interface {
	// Depth returns a new Logger with the stack depth.
	//
	// stackDepth is the calling depth of the logger, which will be passed to
	// the encoder. The default depth is the global variable DefaultLoggerDepth
	// for the new Logger.
	//
	// It should be used typically when you wrap the logger. For example,
	//
	//   logger := miss.New(miss.KvTextEncoder(os.Stdout))
	//   logger = logger.Depth(logger.GetDepth() + 1)
	//
	//   func Debug(m string, args ...interface{}) { logger.Debug(m, args...) }
	//   func Info(m string, args ...interface{}) { logger.Debug(m, args...) }
	//   func Warn(m string, args ...interface{}) { logger.Debug(m, args...) }
	//   ...
	//
	Depth(stackDepth int) Logger

	// Level returns a new Logger with the new level.
	Level(level Level) Logger

	// Encoder returns a new logger with the new encoder.
	Encoder(encoder Encoder) Logger

	// Ctx returns a new logger with the new contexts.
	Cxt(ctxs ...interface{}) Logger

	GetDepth() int
	GetLevel() Level
	GetEncoder() Encoder

	Trace(msg string, args ...interface{}) error
	Debug(msg string, args ...interface{}) error
	Info(msg string, args ...interface{}) error
	Warn(msg string, args ...interface{}) error
	Error(msg string, args ...interface{}) error
	Panic(msg string, args ...interface{}) error
	Fatal(msg string, args ...interface{}) error
}

Logger is a logger interface.

func GetGlobalLogger

func GetGlobalLogger() Logger

GetGlobalLogger returns the global logger.

func New

func New(encoder Encoder) Logger

New returns a new Logger.

func ToLogger added in v0.3.0

func ToLogger(logger LoggerWithoutError) Logger

ToLogger converts the LoggerWithoutError to Logger.

Notice: LoggerWithoutError must be the built-in implementation returned by ToLoggerWithoutError.

func WithCtx

func WithCtx(ctxs ...interface{}) Logger

WithCtx returns a new logger with the contexts.

In order to keep consistent with WithLevel and WithEncoder, we use WithCtx, not Ctx.

func WithDepth

func WithDepth(depth int) Logger

WithDepth returns a new logger with the caller depth.

func WithEncoder

func WithEncoder(encoder Encoder) Logger

WithEncoder returns a new logger with the encoder.

Since Encoder is the encoder type, we use WithEncoder as the function name.

func WithLevel

func WithLevel(level Level) Logger

WithLevel returns a new logger with the level.

Since Level is the level type, we use WithLevel as the function name.

type LoggerWithoutError added in v0.3.0

type LoggerWithoutError interface {
	Depth(stackDepth int) LoggerWithoutError
	Level(level Level) LoggerWithoutError
	Encoder(encoder Encoder) LoggerWithoutError
	Cxt(ctxs ...interface{}) LoggerWithoutError

	GetDepth() int
	GetLevel() Level
	GetEncoder() Encoder

	Trace(msg string, args ...interface{})
	Debug(msg string, args ...interface{})
	Info(msg string, args ...interface{})
	Warn(msg string, args ...interface{})
	Error(msg string, args ...interface{})
	Panic(msg string, args ...interface{})
	Fatal(msg string, args ...interface{})
}

LoggerWithoutError is equal to Logger, but not returning the error.

func ToLoggerWithoutError added in v0.3.0

func ToLoggerWithoutError(logger Logger) LoggerWithoutError

ToLoggerWithoutError converts the Logger to LoggerWithoutError.

type MarshalText

type MarshalText interface {
	MarshalText() ([]byte, error)
}

MarshalText is an interface to marshal a value to text.

type MultiError

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

MultiError represents more than one error.

func (MultiError) Error

func (m MultiError) Error() string

func (MultiError) Errors

func (m MultiError) Errors() []error

Errors returns a list of errors.

type StringWriter

type StringWriter interface {
	WriteString(string) (int, error)
}

StringWriter is a WriteString interface.

type Valuer

type Valuer func(depth int, level Level) (interface{}, error)

A Valuer generates a log value, which represents a dynamic value that is re-evaluated with each log event before firing it.

func Caller

func Caller(fullPath ...bool) Valuer

Caller returns a Valuer that returns a file and line from a specified depth in the callstack.

If fullPath is true, it will return the full path of the file.

Example
logger := New(KvTextEncoder(os.Stdout)).Cxt("caller1", Caller())
logger.Info("msg", "caller2", Caller())
Output:

caller1=value_test.go:23 caller2=value_test.go:23 msg=msg

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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