diff options
Diffstat (limited to 'vendor/github.com/kr/logfmt')
-rw-r--r-- | vendor/github.com/kr/logfmt/.gitignore | 3 | ||||
-rw-r--r-- | vendor/github.com/kr/logfmt/Readme | 12 | ||||
-rw-r--r-- | vendor/github.com/kr/logfmt/decode.go | 184 | ||||
-rw-r--r-- | vendor/github.com/kr/logfmt/scanner.go | 149 | ||||
-rw-r--r-- | vendor/github.com/kr/logfmt/unquote.go | 149 |
5 files changed, 497 insertions, 0 deletions
diff --git a/vendor/github.com/kr/logfmt/.gitignore b/vendor/github.com/kr/logfmt/.gitignore new file mode 100644 index 0000000..8e524f6 --- /dev/null +++ b/vendor/github.com/kr/logfmt/.gitignore @@ -0,0 +1,3 @@ +*.test +*.swp +*.prof diff --git a/vendor/github.com/kr/logfmt/Readme b/vendor/github.com/kr/logfmt/Readme new file mode 100644 index 0000000..1865a11 --- /dev/null +++ b/vendor/github.com/kr/logfmt/Readme @@ -0,0 +1,12 @@ +Go package for parsing (and, eventually, generating) +log lines in the logfmt style. + +See http://godoc.org/github.com/kr/logfmt for format, and other documentation and examples. + +Copyright (C) 2013 Keith Rarick, Blake Mizerany + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 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() +} diff --git a/vendor/github.com/kr/logfmt/scanner.go b/vendor/github.com/kr/logfmt/scanner.go new file mode 100644 index 0000000..095221f --- /dev/null +++ b/vendor/github.com/kr/logfmt/scanner.go @@ -0,0 +1,149 @@ +package logfmt + +import ( + "errors" + "fmt" +) + +var ErrUnterminatedString = errors.New("logfmt: unterminated string") + +func gotoScanner(data []byte, h Handler) (err error) { + saveError := func(e error) { + if err == nil { + err = e + } + } + + var c byte + var i int + var m int + var key []byte + var val []byte + var ok bool + var esc bool + +garbage: + if i == len(data) { + return + } + + c = data[i] + switch { + case c > ' ' && c != '"' && c != '=': + key, val = nil, nil + m = i + i++ + goto key + default: + i++ + goto garbage + } + +key: + if i >= len(data) { + if m >= 0 { + key = data[m:i] + saveError(h.HandleLogfmt(key, nil)) + } + return + } + + c = data[i] + switch { + case c > ' ' && c != '"' && c != '=': + i++ + goto key + case c == '=': + key = data[m:i] + i++ + goto equal + default: + key = data[m:i] + i++ + saveError(h.HandleLogfmt(key, nil)) + goto garbage + } + +equal: + if i >= len(data) { + if m >= 0 { + i-- + key = data[m:i] + saveError(h.HandleLogfmt(key, nil)) + } + return + } + + c = data[i] + switch { + case c > ' ' && c != '"' && c != '=': + m = i + i++ + goto ivalue + case c == '"': + m = i + i++ + esc = false + goto qvalue + default: + if key != nil { + saveError(h.HandleLogfmt(key, val)) + } + i++ + goto garbage + } + +ivalue: + if i >= len(data) { + if m >= 0 { + val = data[m:i] + saveError(h.HandleLogfmt(key, val)) + } + return + } + + c = data[i] + switch { + case c > ' ' && c != '"' && c != '=': + i++ + goto ivalue + default: + val = data[m:i] + saveError(h.HandleLogfmt(key, val)) + i++ + goto garbage + } + +qvalue: + if i >= len(data) { + if m >= 0 { + saveError(ErrUnterminatedString) + } + return + } + + c = data[i] + switch c { + case '\\': + i += 2 + esc = true + goto qvalue + case '"': + i++ + val = data[m:i] + if esc { + val, ok = unquoteBytes(val) + if !ok { + saveError(fmt.Errorf("logfmt: error unquoting bytes %q", string(val))) + goto garbage + } + } else { + val = val[1 : len(val)-1] + } + saveError(h.HandleLogfmt(key, val)) + goto garbage + default: + i++ + goto qvalue + } +} diff --git a/vendor/github.com/kr/logfmt/unquote.go b/vendor/github.com/kr/logfmt/unquote.go new file mode 100644 index 0000000..fb088a4 --- /dev/null +++ b/vendor/github.com/kr/logfmt/unquote.go @@ -0,0 +1,149 @@ +package logfmt + +import ( + "strconv" + "unicode" + "unicode/utf16" + "unicode/utf8" +) + +// Taken from Go's encoding/json + +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// getu4 decodes \uXXXX from the beginning of s, returning the hex value, +// or it returns -1. +func getu4(s []byte) rune { + if len(s) < 6 || s[0] != '\\' || s[1] != 'u' { + return -1 + } + r, err := strconv.ParseUint(string(s[2:6]), 16, 64) + if err != nil { + return -1 + } + return rune(r) +} + +// unquote converts a quoted JSON string literal s into an actual string t. +// The rules are different than for Go, so cannot use strconv.Unquote. +func unquote(s []byte) (t string, ok bool) { + s, ok = unquoteBytes(s) + t = string(s) + return +} + +func unquoteBytes(s []byte) (t []byte, ok bool) { + if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' { + return + } + s = s[1 : len(s)-1] + + // Check for unusual characters. If there are none, + // then no unquoting is needed, so return a slice of the + // original bytes. + r := 0 + for r < len(s) { + c := s[r] + if c == '\\' || c == '"' || c < ' ' { + break + } + if c < utf8.RuneSelf { + r++ + continue + } + rr, size := utf8.DecodeRune(s[r:]) + if rr == utf8.RuneError && size == 1 { + break + } + r += size + } + if r == len(s) { + return s, true + } + + b := make([]byte, len(s)+2*utf8.UTFMax) + w := copy(b, s[0:r]) + for r < len(s) { + // Out of room? Can only happen if s is full of + // malformed UTF-8 and we're replacing each + // byte with RuneError. + if w >= len(b)-2*utf8.UTFMax { + nb := make([]byte, (len(b)+utf8.UTFMax)*2) + copy(nb, b[0:w]) + b = nb + } + switch c := s[r]; { + case c == '\\': + r++ + if r >= len(s) { + return + } + switch s[r] { + default: + return + case '"', '\\', '/', '\'': + b[w] = s[r] + r++ + w++ + case 'b': + b[w] = '\b' + r++ + w++ + case 'f': + b[w] = '\f' + r++ + w++ + case 'n': + b[w] = '\n' + r++ + w++ + case 'r': + b[w] = '\r' + r++ + w++ + case 't': + b[w] = '\t' + r++ + w++ + case 'u': + r-- + rr := getu4(s[r:]) + if rr < 0 { + return + } + r += 6 + if utf16.IsSurrogate(rr) { + rr1 := getu4(s[r:]) + if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar { + // A valid pair; consume. + r += 6 + w += utf8.EncodeRune(b[w:], dec) + break + } + // Invalid surrogate; fall back to replacement rune. + rr = unicode.ReplacementChar + } + w += utf8.EncodeRune(b[w:], rr) + } + + // Quote, control characters are invalid. + case c == '"', c < ' ': + return + + // ASCII + case c < utf8.RuneSelf: + b[w] = c + r++ + w++ + + // Coerce to well-formed UTF-8. + default: + rr, size := utf8.DecodeRune(s[r:]) + r += size + w += utf8.EncodeRune(b[w:], rr) + } + } + return b[0:w], true +} |