ltsvlog

package module
v3.2.0 Latest Latest
Warning

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

Go to latest
Published: Jun 14, 2023 License: MIT Imports: 8 Imported by: 3

README

ltsvlog PkgGoDev

ltsvlog is a minimalist LTSV; Labeled Tab-separated Values logging library in Go. See https://godoc.org/github.com/hnakamur/ltsvlog for the API document.

Warning

  • This project is open source, but closed development, no support, no pull request welcome. If you are unsatisfied, feel free to fork it, pick another library, or roll your own.
  • I understand this may be a "Don't do that" style in the Go logging and error handling best practices.
  • I don't promise the future compatibility. Also this library may not work in the future versions of Go, and a migration path may not be provided, leading to the dead end, users of this library will have to rewrite all of your code. You are on your own with no help.

An example code and output

An example code:

package main

import (
	"github.com/hnakamur/errstack"
	ltsvlog "github.com/hnakamur/ltsvlog/v3"
)

func main() {
	if ltsvlog.Logger.DebugEnabled() {
		ltsvlog.Logger.Debug().String("msg", "This is a debug message").
			String("str", "foo").Int("int", 234).Log()
	}

	ltsvlog.Logger.Info().Fmt("float1", "%3.2f", 3.14).Log()

	if err := outer(); err != nil {
		ltsvlog.Logger.Err(err)
	}
}

func outer() error {
	if err := inner(); err != nil {
		return errstack.WithLV(errstack.Errorf("add some message here: %s", err)).Int64("userID", 1)
	}
	return nil
}

func inner() error {
	return errstack.WithLV(errstack.New("some error")).String("reqID", "req1")
}

An example output:

time:2019-10-21T21:46:53.777197Z	level:Debug	msg:This is a debug message	str:foo	int:234
time:2019-10-21T21:46:53.777232Z	level:Info	float1:3.14
time:2019-10-21T21:46:53.777272Z	level:Error	err:add some message here: some error	userID:1	stack:main.inner@/home/hnakamur/go/src/github.com/hnakamur/ltsvlog/example/main.go:31 main.outer@/home/hnakamur/go/src/github.com/hnakamur/ltsvlog/example/main.go:22 main.main@/home/hnakamur/go/src/github.com/hnakamur/ltsvlog/example/main.go:16 runtime.main@/usr/local/go/src/runtime/proc.go:203

Since these log lines are long, please scroll horizontally to the right to see all the output.

Goals and non-goals

Goals
  • structured logging in LTSV format.
  • fast operation and minimum count of memory allocations for Debug and Info.
  • log call stack frames with optional labeled values as long as the error message.
Non-Goals
  • compatiblity with the Go logging best practices.
  • fast operation and minimum count of memory allocations for Err.
  • flexibility and features.

Benchmark result

hnakamur/go-log-benchmarks

License

MIT

Documentation

Overview

Package ltsvlog is a minimalist logging library for writing logs in LTSV (Labeled Tab-separated Value) format. See http://ltsv.org/ for LTSV.

This logging library has three log levels: Debug, Info and Error. The Info and Error levels are always enabled. You can disable the Debug level but only when you create a logger.

Each log record is printed as one line. A line has multiple fields separated by a tab character. Each field has a label and a value which are separated by a colon ':' character.

So you must not contain a colon character in labels. This is not checked in this library for performance reason, so it is your responsibility not to contain a colon character in labels.

Newline, tab, and backslach characters in values are escaped with "\\n", "\\t", and "\\\\" respectively. Show the example for Event.String.

Index

Examples

Constants

This section is empty.

Variables

Logger is the global logger. You can change this logger like ltsvlog.Logger = ltsvlog.NewLTSVLogger(os.Stdout, false) You can change the global logger safely only before writing to the logger. Changing the logger while writing may cause the unexpected behavior.

Functions

This section is empty.

Types

type Discard

type Discard struct{}

Discard discards any logging outputs.

func (*Discard) Debug

func (*Discard) Debug() *Event

Debug prints nothing. Note there still exists the cost of evaluating argument values, even though they are not used. Guarding with if and DebugEnabled is recommended.

func (*Discard) DebugEnabled

func (*Discard) DebugEnabled() bool

DebugEnabled always return false

func (*Discard) Err

func (*Discard) Err(err error)

Err prints nothing.

func (*Discard) Info

func (*Discard) Info() *Event

Info prints nothing. Note there still exists the cost of evaluating argument values, even though they are not used.

type Event

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

Event is a temporary object for building a log record of Debug or Info level.

func (*Event) Bool

func (e *Event) Bool(label string, value bool) *Event

Bool appends a labeled bool value to Event.

func (*Event) Byte

func (e *Event) Byte(label string, value byte) *Event

Byte appends a labeled byte value to Event. Deprecated. Use HexByte instead.

func (*Event) Bytes

func (e *Event) Bytes(label string, value []byte) *Event

Bytes appends a labeled bytes value in hex format to Event. Deprecated. Use HexBytes instead.

func (*Event) Float32

func (e *Event) Float32(label string, value float32) *Event

Float32 appends a labeled float32 value to Event.

func (*Event) Float64

func (e *Event) Float64(label string, value float64) *Event

Float64 appends a labeled float64 value to Event.

func (*Event) Fmt

func (e *Event) Fmt(label, format string, a ...interface{}) *Event

Fmt appends a labeled formatted string value to Event.

func (*Event) Format

func (e *Event) Format(s fmt.State, c rune)

Format formats the error. With "%v" and "%s", labeled values are appended to the message in LTSV format. With "%q", quoted LTSV format string is returned.

func (*Event) HexByte added in v3.0.2

func (e *Event) HexByte(label string, value byte) *Event

HexByte appends a labeled byte value to Event.

func (*Event) HexBytes added in v3.0.2

func (e *Event) HexBytes(label string, value []byte) *Event

HexBytes appends a labeled bytes value in hex format to Event.

func (*Event) Int

func (e *Event) Int(label string, value int) *Event

Int appends a labeled int value to Event.

func (*Event) Int16

func (e *Event) Int16(label string, value int16) *Event

Int16 appends a labeled int16 value to Event.

func (*Event) Int32

func (e *Event) Int32(label string, value int32) *Event

Int32 appends a labeled int32 value to Event.

func (*Event) Int64

func (e *Event) Int64(label string, value int64) *Event

Int64 appends a labeled int64 value to Event.

func (*Event) Int8

func (e *Event) Int8(label string, value int8) *Event

Int8 appends a labeled int8 value to Event.

func (*Event) Log

func (e *Event) Log()

Log writes this event if the logger which created this event is enabled, and puts the event back to the event pool.

func (*Event) String

func (e *Event) String(label string, value string) *Event

String appends a labeled string value to Event.

Example
package main

import (
	ltsvlog "github.com/hnakamur/ltsvlog/v3"
)

func main() {
	jsonStr := "{\n\t\"foo\": \"bar\\nbaz\"\n}\n"
	ltsvlog.Logger.Info().String("json", jsonStr).Log()

	// Output example:
	// time:2017-06-10T10:22:48.083226Z	level:Info	json:{\n\t"foo": "bar\\nbaz"\n}\n
	
Output:

func (*Event) Stringer

func (e *Event) Stringer(label string, value fmt.Stringer) *Event

Stringer appends a labeled string value to Event. The value will be converted to a string with String() method.

func (*Event) Time

func (e *Event) Time(label string, value time.Time, format string) *Event

Time appends a labeled formatted time value to Event. The format is the same as that in the Go standard time package. If the format is empty, time.RFC3339 is used.

func (*Event) UTCTime

func (e *Event) UTCTime(label string, value time.Time) *Event

UTCTime appends a labeled UTC time value to Event. The time value is converted to UTC and then printed in the same format as the log time field, that is the ISO8601 format with microsecond precision and the timezone "Z".

func (*Event) Uint

func (e *Event) Uint(label string, value uint) *Event

Uint appends a labeled uint value to Event.

func (*Event) Uint16

func (e *Event) Uint16(label string, value uint16) *Event

Uint16 appends a labeled uint16 value to Event.

func (*Event) Uint32

func (e *Event) Uint32(label string, value uint32) *Event

Uint32 appends a labeled uint32 value to Event.

func (*Event) Uint64

func (e *Event) Uint64(label string, value uint64) *Event

Uint64 appends a labeled uint64 value to Event.

func (*Event) Uint8

func (e *Event) Uint8(label string, value uint8) *Event

Uint8 appends a labeled uint8 value to Event.

type FileReopener added in v3.2.0

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

func NewFileReopener added in v3.2.0

func NewFileReopener(name string, flag int, perm os.FileMode) (*FileReopener, error)

func (*FileReopener) Reopen added in v3.2.0

func (h *FileReopener) Reopen() error

func (*FileReopener) SyncAndClose added in v3.2.0

func (h *FileReopener) SyncAndClose() error

func (*FileReopener) Write added in v3.2.0

func (h *FileReopener) Write(p []byte) (n int, err error)

type LTSVLogger

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

LTSVLogger is a LTSV logger.

func NewLTSVLogger

func NewLTSVLogger(w io.Writer, debugEnabled bool, options ...Option) *LTSVLogger

NewLTSVLogger creates a LTSV logger with the default time and value format.

The folloing two values are prepended to each log line.

The first value is the current time, and has the default label "time". The time format is RFC3339 with microseconds in UTC timezone. This format is the same as "2006-01-02T15:04:05.000000Z" in the go time format https://golang.org/pkg/time/#Time.Format

The second value is the log level with the default label "level".

Example
package main

import (
	"os"

	ltsvlog "github.com/hnakamur/ltsvlog/v3"
)

func main() {
	// Change the global logger to a logger which does not print level values.
	ltsvlog.Logger = ltsvlog.NewLTSVLogger(os.Stdout, true, ltsvlog.SetLevelLabel(""))
	
Output:

func (*LTSVLogger) Debug

func (l *LTSVLogger) Debug() *Event

Debug returns a new Event for writing a Debug level log. This Event is returned from the internal event pool, so be sure to call Log() to put this event back to the event pool.

Note there still exists the cost of evaluating argument values if the debug level is disabled, even though those arguments are not used. So guarding with if and DebugEnabled is recommended.

Example
package main

import (
	ltsvlog "github.com/hnakamur/ltsvlog/v3"
)

func main() {
	if ltsvlog.Logger.DebugEnabled() {
		// In real usage, you might do a time consuming operation to
		// build values for logging, but it will be skipped when the debug
		// log is disabled.
		n := 234
		ltsvlog.Logger.Debug().String("msg", "This is a debug message").
			String("key", "key1").Int("intValue", n).Log()
	}

	// Output example:
	// time:2017-05-20T19:12:10.883958Z	level:Debug	msg:This is a debug message	key:key1	intValue:234
	
Output:

func (*LTSVLogger) DebugEnabled

func (l *LTSVLogger) DebugEnabled() bool

DebugEnabled returns whether or not the debug level is enabled. You can avoid the cost of evaluation of arguments passed to Debug like:

if ltsvlog.Logger.DebugEnabled() {
    ltsvlog.Logger.Debug().String("label1", someSlowFunction()).Log()
}

func (*LTSVLogger) Err

func (l *LTSVLogger) Err(err error)

Err writes a log for an error with the error level. It writes the err.Error() value with the label "err".

If the result of github.com/hnakamur/errstack.LV(err) is not empty, then the pairs of labels and values are appended.

Also, if the result of github.com/hnakamur/errstack.Stack(err) is not empty, then the call stack value with the "stack" label is appended.

Example
package main

import (
	"github.com/hnakamur/errstack"
	ltsvlog "github.com/hnakamur/ltsvlog/v3"
)

func main() {
	if err := exampleErrOuter(); err != nil {
		ltsvlog.Logger.Err(err)
	}

	// Output example:
	// time:2019-10-21T22:05:06.784512Z	level:Error	err:add some message here: some error	reqID:req1	userID:1	stack:github.com/hnakamur/ltsvlog/v3_test.exampleErrInner@/home/hnakamur/go/src/github.com/hnakamur/ltsvlog/example_err_test.go:24 github.com/hnakamur/ltsvlog/v3_test.exampleErrOuter@/home/hnakamur/go/src/github.com/hnakamur/ltsvlog/example_err_test.go:17 github.com/hnakamur/ltsvlog/v3_test.ExampleLTSVLogger_Err@/home/hnakamur/go/src/github.com/hnakamur/ltsvlog/example_err_test.go:9 testing.runExample@/usr/local/go/src/testing/run_example.go:62 testing.runExamples@/usr/local/go/src/testing/example.go:44 testing.(*M).Run@/usr/local/go/src/testing/testing.go:1118 main.main@_testmain.go:52 runtime.main@/usr/local/go/src/runtime/proc.go:203
	
Output:

func (*LTSVLogger) Info

func (l *LTSVLogger) Info() *Event

Info returns a new Event for writing a Info level log. This Event is returned from the internal event pool, so be sure to call Log() to put this event back to the event pool.

Example
package main

import (
	ltsvlog "github.com/hnakamur/ltsvlog/v3"
)

func main() {
	ltsvlog.Logger.Info().String("msg", "goodbye, world").String("foo", "bar").
		Fmt("nilValue", "%v", nil).HexBytes("bytes", []byte("a/b")).Log()

	// Output example:
	// time:2017-05-20T19:16:11.798840Z	level:Info	msg:goodbye, world	foo:bar	nilValue:<nil>	bytes:0x612f62
	
Output:

type LogWriter

type LogWriter interface {
	DebugEnabled() bool
	Debug() *Event
	Info() *Event
	Err(err error)
}

LogWriter is a LTSV logger interface

type Option

type Option func(l *LTSVLogger)

Option is the function type to set an option of LTSVLogger

func SetLevelLabel

func SetLevelLabel(label string) Option

SetLevelLabel returns the option function to set the level label. If the label is empty, loggers do not print level values.

func SetTimeLabel

func SetTimeLabel(label string) Option

SetTimeLabel returns the option function to set the time label. If the label is empty, loggers do not print time values.

type SwitchableWriter added in v3.1.0

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

func NewSwitchableWriter added in v3.1.0

func NewSwitchableWriter(w io.Writer) *SwitchableWriter

func (*SwitchableWriter) Switch added in v3.1.0

func (sw *SwitchableWriter) Switch(w io.Writer)

func (*SwitchableWriter) Write added in v3.1.0

func (sw *SwitchableWriter) Write(p []byte) (n int, err error)

Jump to

Keyboard shortcuts

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