aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/kr/logfmt/decode.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/kr/logfmt/decode.go')
-rw-r--r--vendor/github.com/kr/logfmt/decode.go184
1 files changed, 0 insertions, 184 deletions
diff --git a/vendor/github.com/kr/logfmt/decode.go b/vendor/github.com/kr/logfmt/decode.go
deleted file mode 100644
index 1397fb7..0000000
--- a/vendor/github.com/kr/logfmt/decode.go
+++ /dev/null
@@ -1,184 +0,0 @@
1// Package implements the decoding of logfmt key-value pairs.
2//
3// Example logfmt message:
4//
5// foo=bar a=14 baz="hello kitty" cool%story=bro f %^asdf
6//
7// Example result in JSON:
8//
9// { "foo": "bar", "a": 14, "baz": "hello kitty", "cool%story": "bro", "f": true, "%^asdf": true }
10//
11// EBNFish:
12//
13// ident_byte = any byte greater than ' ', excluding '=' and '"'
14// string_byte = any byte excluding '"' and '\'
15// garbage = !ident_byte
16// ident = ident_byte, { ident byte }
17// key = ident
18// value = ident | '"', { string_byte | '\', '"' }, '"'
19// pair = key, '=', value | key, '=' | key
20// message = { garbage, pair }, garbage
21package logfmt
22
23import (
24 "reflect"
25 "strconv"
26 "strings"
27 "time"
28)
29
30// Handler is the interface implemented by objects that accept logfmt
31// key-value pairs. HandleLogfmt must copy the logfmt data if it
32// wishes to retain the data after returning.
33type Handler interface {
34 HandleLogfmt(key, val []byte) error
35}
36
37// The HandlerFunc type is an adapter to allow the use of ordinary functions as
38// logfmt handlers. If f is a function with the appropriate signature,
39// HandlerFunc(f) is a Handler object that calls f.
40type HandlerFunc func(key, val []byte) error
41
42func (f HandlerFunc) HandleLogfmt(key, val []byte) error {
43 return f(key, val)
44}
45
46// Unmarshal parses the logfmt encoding data and stores the result in the value
47// pointed to by v. If v is an Handler, HandleLogfmt will be called for each
48// key-value pair.
49//
50// If v is not a Handler, it will pass v to NewStructHandler and use the
51// returned StructHandler for decoding.
52func Unmarshal(data []byte, v interface{}) (err error) {
53 h, ok := v.(Handler)
54 if !ok {
55 h, err = NewStructHandler(v)
56 if err != nil {
57 return err
58 }
59 }
60 return gotoScanner(data, h)
61}
62
63// StructHandler unmarshals logfmt into a struct. It matches incoming keys to
64// the the struct's fields (either the struct field name or its tag, preferring
65// an exact match but also accepting a case-insensitive match.
66//
67// Field types supported by StructHandler are:
68//
69// all numeric types (e.g. float32, int, etc.)
70// []byte
71// string
72// bool - true if key is present, false otherwise (the value is ignored).
73// time.Duration - uses time.ParseDuration
74//
75// If a field is a pointer to an above type, and a matching key is not present
76// in the logfmt data, the pointer will be untouched.
77//
78// If v is not a pointer to an Handler or struct, Unmarshal will return an
79// error.
80type StructHandler struct {
81 rv reflect.Value
82}
83
84func NewStructHandler(v interface{}) (Handler, error) {
85 rv := reflect.ValueOf(v)
86 if rv.Kind() != reflect.Ptr || rv.IsNil() {
87 return nil, &InvalidUnmarshalError{reflect.TypeOf(v)}
88 }
89 return &StructHandler{rv: rv}, nil
90}
91
92func (h *StructHandler) HandleLogfmt(key, val []byte) error {
93 el := h.rv.Elem()
94 skey := string(key)
95 for i := 0; i < el.NumField(); i++ {
96 fv := el.Field(i)
97 ft := el.Type().Field(i)
98 switch {
99 case ft.Name == skey:
100 case ft.Tag.Get("logfmt") == skey:
101 case strings.EqualFold(ft.Name, skey):
102 default:
103 continue
104 }
105 if fv.Kind() == reflect.Ptr {
106 if fv.IsNil() {
107 t := fv.Type().Elem()
108 v := reflect.New(t)
109 fv.Set(v)
110 fv = v
111 }
112 fv = fv.Elem()
113 }
114 switch fv.Interface().(type) {
115 case time.Duration:
116 d, err := time.ParseDuration(string(val))
117 if err != nil {
118 return &UnmarshalTypeError{string(val), fv.Type()}
119 }
120 fv.Set(reflect.ValueOf(d))
121 case string:
122 fv.SetString(string(val))
123 case []byte:
124 b := make([]byte, len(val))
125 copy(b, val)
126 fv.SetBytes(b)
127 case bool:
128 fv.SetBool(true)
129 default:
130 switch {
131 case reflect.Int <= fv.Kind() && fv.Kind() <= reflect.Int64:
132 v, err := strconv.ParseInt(string(val), 10, 64)
133 if err != nil {
134 return err
135 }
136 fv.SetInt(v)
137 case reflect.Uint32 <= fv.Kind() && fv.Kind() <= reflect.Uint64:
138 v, err := strconv.ParseUint(string(val), 10, 64)
139 if err != nil {
140 return err
141 }
142 fv.SetUint(v)
143 case reflect.Float32 <= fv.Kind() && fv.Kind() <= reflect.Float64:
144 v, err := strconv.ParseFloat(string(val), 10)
145 if err != nil {
146 return err
147 }
148 fv.SetFloat(v)
149 default:
150 return &UnmarshalTypeError{string(val), fv.Type()}
151 }
152 }
153
154 }
155 return nil
156}
157
158// An InvalidUnmarshalError describes an invalid argument passed to Unmarshal.
159// (The argument to Unmarshal must be a non-nil pointer.)
160type InvalidUnmarshalError struct {
161 Type reflect.Type
162}
163
164func (e *InvalidUnmarshalError) Error() string {
165 if e.Type == nil {
166 return "logfmt: Unmarshal(nil)"
167 }
168
169 if e.Type.Kind() != reflect.Ptr {
170 return "logfmt: Unmarshal(non-pointer " + e.Type.String() + ")"
171 }
172 return "logfmt: Unmarshal(nil " + e.Type.String() + ")"
173}
174
175// An UnmarshalTypeError describes a logfmt value that was
176// not appropriate for a value of a specific Go type.
177type UnmarshalTypeError struct {
178 Value string // the logfmt value
179 Type reflect.Type // type of Go value it could not be assigned to
180}
181
182func (e *UnmarshalTypeError) Error() string {
183 return "logfmt: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String()
184}