aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/kr/logfmt/decode.go
diff options
context:
space:
mode:
authorRaúl Benencia <raul@thousandeyes.com>2018-04-13 16:30:31 -0700
committerRaúl Benencia <raul@thousandeyes.com>2018-05-11 15:02:34 -0700
commit77c172b823b64ebface655681ab0749b9d2f7081 (patch)
tree09c13e626eb95ae1d33e76ed683172eab1ab6c96 /vendor/github.com/kr/logfmt/decode.go
First public commit
Diffstat (limited to 'vendor/github.com/kr/logfmt/decode.go')
-rw-r--r--vendor/github.com/kr/logfmt/decode.go184
1 files changed, 184 insertions, 0 deletions
diff --git a/vendor/github.com/kr/logfmt/decode.go b/vendor/github.com/kr/logfmt/decode.go
new file mode 100644
index 0000000..1397fb7
--- /dev/null
+++ b/vendor/github.com/kr/logfmt/decode.go
@@ -0,0 +1,184 @@
+// 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
+package logfmt
+
+import (
+ "reflect"
+ "strconv"
+ "strings"
+ "time"
+)
+
+// 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.
+type Handler interface {
+ HandleLogfmt(key, val []byte) error
+}
+
+// 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.
+type HandlerFunc func(key, val []byte) error
+
+func (f HandlerFunc) HandleLogfmt(key, val []byte) error {
+ return f(key, val)
+}
+
+// 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.
+func Unmarshal(data []byte, v interface{}) (err error) {
+ h, ok := v.(Handler)
+ if !ok {
+ h, err = NewStructHandler(v)
+ if err != nil {
+ return err
+ }
+ }
+ return gotoScanner(data, h)
+}
+
+// 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.
+type StructHandler struct {
+ rv reflect.Value
+}
+
+func NewStructHandler(v interface{}) (Handler, error) {
+ rv := reflect.ValueOf(v)
+ if rv.Kind() != reflect.Ptr || rv.IsNil() {
+ return nil, &InvalidUnmarshalError{reflect.TypeOf(v)}
+ }
+ return &StructHandler{rv: rv}, nil
+}
+
+func (h *StructHandler) HandleLogfmt(key, val []byte) error {
+ el := h.rv.Elem()
+ skey := string(key)
+ for i := 0; i < el.NumField(); i++ {
+ fv := el.Field(i)
+ ft := el.Type().Field(i)
+ switch {
+ case ft.Name == skey:
+ case ft.Tag.Get("logfmt") == skey:
+ case strings.EqualFold(ft.Name, skey):
+ default:
+ continue
+ }
+ if fv.Kind() == reflect.Ptr {
+ if fv.IsNil() {
+ t := fv.Type().Elem()
+ v := reflect.New(t)
+ fv.Set(v)
+ fv = v
+ }
+ fv = fv.Elem()
+ }
+ switch fv.Interface().(type) {
+ case time.Duration:
+ d, err := time.ParseDuration(string(val))
+ if err != nil {
+ return &UnmarshalTypeError{string(val), fv.Type()}
+ }
+ fv.Set(reflect.ValueOf(d))
+ case string:
+ fv.SetString(string(val))
+ case []byte:
+ b := make([]byte, len(val))
+ copy(b, val)
+ fv.SetBytes(b)
+ case bool:
+ fv.SetBool(true)
+ default:
+ switch {
+ case reflect.Int <= fv.Kind() && fv.Kind() <= reflect.Int64:
+ v, err := strconv.ParseInt(string(val), 10, 64)
+ if err != nil {
+ return err
+ }
+ fv.SetInt(v)
+ case reflect.Uint32 <= fv.Kind() && fv.Kind() <= reflect.Uint64:
+ v, err := strconv.ParseUint(string(val), 10, 64)
+ if err != nil {
+ return err
+ }
+ fv.SetUint(v)
+ case reflect.Float32 <= fv.Kind() && fv.Kind() <= reflect.Float64:
+ v, err := strconv.ParseFloat(string(val), 10)
+ if err != nil {
+ return err
+ }
+ fv.SetFloat(v)
+ default:
+ return &UnmarshalTypeError{string(val), fv.Type()}
+ }
+ }
+
+ }
+ return nil
+}
+
+// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal.
+// (The argument to Unmarshal must be a non-nil pointer.)
+type InvalidUnmarshalError struct {
+ Type reflect.Type
+}
+
+func (e *InvalidUnmarshalError) Error() string {
+ if e.Type == nil {
+ return "logfmt: Unmarshal(nil)"
+ }
+
+ if e.Type.Kind() != reflect.Ptr {
+ return "logfmt: Unmarshal(non-pointer " + e.Type.String() + ")"
+ }
+ return "logfmt: Unmarshal(nil " + e.Type.String() + ")"
+}
+
+// An UnmarshalTypeError describes a logfmt value that was
+// not appropriate for a value of a specific Go type.
+type UnmarshalTypeError struct {
+ Value string // the logfmt value
+ Type reflect.Type // type of Go value it could not be assigned to
+}
+
+func (e *UnmarshalTypeError) Error() string {
+ return "logfmt: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String()
+}
nihil fit ex nihilo