import "github.com/kr/logfmt"
Package implements the decoding of logfmt key-value pairs.
Example logfmt message:
foo=bar a=14 baz="hello kitty" cool%story=bro f %^asdf
Example result in JSON:
{ "foo": "bar", "a": 14, "baz": "hello kitty", "cool%story": "bro", "f": true, "%^asdf": true }
EBNFish:
ident_byte = any byte greater than ' ', excluding '=' and '"' string_byte = any byte excluding '"' and '\' garbage = !ident_byte ident = ident_byte, { ident byte } key = ident value = ident | '"', { string_byte | '\', '"' }, '"' pair = key, '=', value | key, '=' | key message = { garbage, pair }, garbage
Code:
package main import ( "bytes" "fmt" "github.com/kr/logfmt" "log" "strconv" ) type Measurement struct { Key string Val float64 Unit string // (e.g. ms, MB, etc) } type Measurements []*Measurement var measurePrefix = []byte("measure.") func (mm *Measurements) HandleLogfmt(key, val []byte) error { if !bytes.HasPrefix(key, measurePrefix) { return nil } i := bytes.LastIndexFunc(val, isDigit) v, err := strconv.ParseFloat(string(val[:i+1]), 10) if err != nil { return err } m := &Measurement{ Key: string(key[len(measurePrefix):]), Val: v, Unit: string(val[i+1:]), } *mm = append(*mm, m) return nil } // return true if r is an ASCII digit only, as opposed to unicode.IsDigit. func isDigit(r rune) bool { return '0' <= r && r <= '9' } func main() { var data = []byte("measure.a=1ms measure.b=10 measure.c=100MB measure.d=1s garbage") mm := make(Measurements, 0) if err := logfmt.Unmarshal(data, &mm); err != nil { log.Fatalf("err=%q", err) } for _, m := range mm { fmt.Printf("%v\n", *m) } }
decode.go scanner.go unquote.go
Unmarshal parses the logfmt encoding data and stores the result in the value pointed to by v. If v is an Handler, HandleLogfmt will be called for each key-value pair.
If v is not a Handler, it will pass v to NewStructHandler and use the returned StructHandler for decoding.
Handler is the interface implemented by objects that accept logfmt key-value pairs. HandleLogfmt must copy the logfmt data if it wishes to retain the data after returning.
The HandlerFunc type is an adapter to allow the use of ordinary functions as logfmt handlers. If f is a function with the appropriate signature, HandlerFunc(f) is a Handler object that calls f.
func (f HandlerFunc) HandleLogfmt(key, val []byte) error
An InvalidUnmarshalError describes an invalid argument passed to Unmarshal. (The argument to Unmarshal must be a non-nil pointer.)
func (e *InvalidUnmarshalError) Error() string
type StructHandler struct {
// contains filtered or unexported fields
}
StructHandler unmarshals logfmt into a struct. It matches incoming keys to the the struct's fields (either the struct field name or its tag, preferring an exact match but also accepting a case-insensitive match.
Field types supported by StructHandler are:
all numeric types (e.g. float32, int, etc.) []byte string bool - true if key is present, false otherwise (the value is ignored). time.Duration - uses time.ParseDuration
If a field is a pointer to an above type, and a matching key is not present in the logfmt data, the pointer will be untouched.
If v is not a pointer to an Handler or struct, Unmarshal will return an error.
func (h *StructHandler) HandleLogfmt(key, val []byte) error
type UnmarshalTypeError struct { Value string // the logfmt value Type reflect.Type // type of Go value it could not be assigned to }
An UnmarshalTypeError describes a logfmt value that was not appropriate for a value of a specific Go type.
func (e *UnmarshalTypeError) Error() string
Package logfmt imports 9 packages (graph) and is imported by 38 packages. Updated 2021-01-22. Refresh now. Tools for package owners.