logfmt

package module
v0.0.0-...-5594cfe Latest Latest
Warning

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

Go to latest
Published: Feb 25, 2016 License: BSD-3-Clause Imports: 8 Imported by: 0

README

#logfmt Travis GoDoc

  • Package "logfmt" implements a logger for objects in logfmt format: details
  • Package "logfmt/logreader" implements a parser for logfmt streams: details
  • Package "logfmt/ql" implements an interpreter of a query language for logfmt records. details
  • Package "logfmt/cmd" is a collection of command line utilities for working with logfmt, it complements brandur's own collection. details

#logfmt

To use the package:

go get github.com/etnz/logfmt

logfmt is defined in Brandur's blog as a logging format optimal for easy development, consistency, and good legibility for humans and computers.

at=info method=GET path=/ host=mutelight.org status=200

The example above can be generated like:

logfmt.
  S("at", "info").
  S("method",r.Method).
  S("path", r.URL.Path).
  D("status", code ).
  Log()

Where 'S', 'Q', 'D' are method mapping the usual 'fmt' verbs.

Key/Value are stored in a map, so it's ok to call S("at", "info") several time, the last one is always right.

When writing the line in the output stream, keys are not printed in random order. Logs would be hard to read, and not reproducible. Instead key/value pairs are sorted in significance order: the shortest keys first, then alphabetically

at=info path=/ host=mutelight.org method=GET status=200

It enforce the tendency to keep generic keys short, and specific one longer, the first information you read is the most important.

Usually it is faster than the default "log" package

    r := Rec()
    r.D("timestamp", int(n))
    r.D("at", i)
    r.Q("username", "eric")
    r.K("debug")
    r.Log()

At 1389 ns/op : 720 logs per milliseconds

     log.Printf("at=%d", i)
     log.Printf("debug")
     log.Printf("username=%q\n", "eric")

At 2248 ns/op, that is 445 logs per milliseconds

Because using logfmt, you tend to group together information in less records, but richer, I compared a single logfmt record with 4 attributes with a 3 default logs.

'Record' object is idiomatic:

log:= logfmt.Rec()
defer log.Log()
//set an initial value
r.S("level", "debug")
...
if err != nil{
  r.S("level", "error") // escalate the record
  r.V("err", err)
}

See Examples or directly the godoc for more details.

Still on the workbench

  • rewriter logs (sort keys, filter out some matches), highlight lowlight some lines or keys
  • trim logs (before first match and after last match)

Documentation

Overview

Package logfmt implements a logfmt Record reader and writer.

Definition

logfmt is defined in https://brandur.org/logfmt as a logging format optimal for easy development, consistency, and good legibility for humans and computers.

at=info method=GET path=/ host=mutelight.org fwd="124.133.52.161"
dyno=web.2 connect=4ms service=8ms status=200 bytes=1653

A Record is a simple line in logfmt. It is a set of attribute that can have or have not a value.

The value is either a valid identifier, or a quoted string.

Reader

Package logfmt can be used to parse logfmt compliant logs.

Reader is a simple interface with two methods to read a stream as Records.

It parses any io.Reader and return a Record each time.

r := NewReader(os.Stdin)
for r.HasNext() {
    rec, _ := r.Next()
    fmt.Println(rec)
}

Logging API

Package logfmt can be used as a simple tool to write logfmt logs.

Record can be created using a fluent API based on the usual 'fmt' verbs

Q for %q : quoted string
S for %s : identifier
T for %t : boolean
D for %d : decimal base integer
G for %g : float
V for %v : interface{} uses go value
K        : just insert the key (no values)

There are basically only one new "words" to learn: 'K' stands for Key only.

Records are then created using a sequence of call to one of these functions.

Q("user", username).D("retry", retryCount).K("debug").Log()

See Examples for more details.

The Log method prints the Record in a single line, sorting attributes in 'significance' order. It means that general keys (short name) come first then specific attributes (long name).

This Log method is fitted for 'defer'.

Index

Examples

Constants

This section is empty.

Variables

View Source
var Default = New(os.Stderr)

Default is the default Logger implementation

Functions

This section is empty.

Types

type Logger

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

Logger is a basic object that logs records into an output io.Writer

func New

func New(out io.Writer) *Logger

New creates a new Logger. Out is the destination to write logs to.

func (*Logger) Log

func (l *Logger) Log(rec Record)

Log a Record to the Logger Output

type Record

type Record map[string]*string

Record contains a single logfmt line.

func D

func D(key string, val int) *Record

D creates a Record, call D method, and return the Record

Example
Default = New(os.Stdout)
D("key", 1).D("ends", 125).Log()
Output:

key=1 ends=125

func G

func G(key string, val float64) *Record

G creates a Record, call G method, and return the Record

Example
Default = New(os.Stdout)
G("load", 12.3).Log()
Output:

load=12.3

func K

func K(key string) *Record

K creates a Record, call K method, and return the Record

Example
Default = New(os.Stdout)
K("debug").K("verbose").Log()
Output:

debug verbose

func Q

func Q(key, val string) *Record

Q creates a new Record, call Q method, and return the Record

Example
Default = New(os.Stdout)
Q("key1", "value1").
	Q("key1.detail", "another value").
	Log()
Output:

key1="value1" key1.detail="another value"

func Rec

func Rec() *Record

Rec returns a newly created, empty Record

Example
Default = New(os.Stdout)
//create a record asap, and defer the actual log write.
r := Rec()
defer r.Log()

r.K("debug")
//somewhere else in the code
r.D("load", 125)
Output:

load=125 debug

func S

func S(key, val string) *Record

S creates a Record, call S method, and return the Record

Example
Default = New(os.Stdout)
S("key1", "ident1").S("key2", "ident2").Log()
Output:

key1=ident1 key2=ident2
Example (Autoquote)
Default = New(os.Stdout)
S("key1", "ident1 ident2").Log() //this would lead to an invalid value
S("key1", "\"ide nt1\"").Log()   //correctly quoted value is not super quoted
S("key1", "\"ide nt1").Log()     // invalid value is properly quoted
Output:

key1="ident1 ident2"
key1="ide nt1"
key1="\"ide nt1"

func T

func T(key string, val bool) *Record

T creates a Record, call T method, and return the Record

Example
Default = New(os.Stdout)
T("key", true).T("debug", false).Log()
Output:

key=true debug=false

func V

func V(key string, value interface{}) *Record

V creates a Record,call V method, and return the Record

func (*Record) D

func (rec *Record) D(key string, val int) *Record

D insert an integer attribute `key=12`

func (*Record) G

func (rec *Record) G(key string, val float64) *Record

G insert a float attribute `key=12.3`

func (*Record) K

func (rec *Record) K(key string) *Record

K insert a key only attribute `debug verbose`

func (Record) Log

func (rec Record) Log()

Log this Record now into the 'Default' Logger

func (*Record) Q

func (rec *Record) Q(key, val string) *Record

Q inserts a quoted string attribute like `key="val"`

func (*Record) S

func (rec *Record) S(key, val string) *Record

S insert an identifier attribute `key=val`.

'val' format is checked and quoted if needed.

func (Record) String

func (rec Record) String() string

String format the current record as a string

func (*Record) T

func (rec *Record) T(key string, val bool) *Record

T insert a boolean attribute `key=false`

func (*Record) V

func (rec *Record) V(key string, value interface{}) *Record

V insert value using fmt.Printf verb "%v".

The result is quoted if necessary

Directories

Path Synopsis
cmd
Package ql implements a query langage for logfmt records.
Package ql implements a query langage for logfmt records.

Jump to

Keyboard shortcuts

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