diff options
| author | Raúl Benencia <raul@thousandeyes.com> | 2018-04-13 16:30:31 -0700 | 
|---|---|---|
| committer | Raúl Benencia <raul@thousandeyes.com> | 2018-05-11 15:02:34 -0700 | 
| commit | 77c172b823b64ebface655681ab0749b9d2f7081 (patch) | |
| tree | 09c13e626eb95ae1d33e76ed683172eab1ab6c96 /vendor/github.com/go-logfmt | |
First public commit
Diffstat (limited to 'vendor/github.com/go-logfmt')
| -rw-r--r-- | vendor/github.com/go-logfmt/logfmt/.gitignore | 4 | ||||
| -rw-r--r-- | vendor/github.com/go-logfmt/logfmt/.travis.yml | 15 | ||||
| -rw-r--r-- | vendor/github.com/go-logfmt/logfmt/LICENSE | 22 | ||||
| -rw-r--r-- | vendor/github.com/go-logfmt/logfmt/README.md | 33 | ||||
| -rw-r--r-- | vendor/github.com/go-logfmt/logfmt/decode.go | 237 | ||||
| -rw-r--r-- | vendor/github.com/go-logfmt/logfmt/doc.go | 6 | ||||
| -rw-r--r-- | vendor/github.com/go-logfmt/logfmt/encode.go | 321 | ||||
| -rw-r--r-- | vendor/github.com/go-logfmt/logfmt/fuzz.go | 126 | ||||
| -rw-r--r-- | vendor/github.com/go-logfmt/logfmt/jsonstring.go | 277 | 
9 files changed, 1041 insertions, 0 deletions
| diff --git a/vendor/github.com/go-logfmt/logfmt/.gitignore b/vendor/github.com/go-logfmt/logfmt/.gitignore new file mode 100644 index 0000000..320e53e --- /dev/null +++ b/vendor/github.com/go-logfmt/logfmt/.gitignore @@ -0,0 +1,4 @@ +_testdata/ +_testdata2/ +logfmt-fuzz.zip +logfmt.test.exe diff --git a/vendor/github.com/go-logfmt/logfmt/.travis.yml b/vendor/github.com/go-logfmt/logfmt/.travis.yml new file mode 100644 index 0000000..b599f65 --- /dev/null +++ b/vendor/github.com/go-logfmt/logfmt/.travis.yml @@ -0,0 +1,15 @@ +language: go +sudo: false +go: +  - 1.3 +  - 1.4 +  - 1.5 +  - 1.6 +  - tip + +before_install: +  - go get github.com/mattn/goveralls +  - go get golang.org/x/tools/cmd/cover + +script: +  - goveralls -service=travis-ci diff --git a/vendor/github.com/go-logfmt/logfmt/LICENSE b/vendor/github.com/go-logfmt/logfmt/LICENSE new file mode 100644 index 0000000..c026508 --- /dev/null +++ b/vendor/github.com/go-logfmt/logfmt/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 go-logfmt + +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/go-logfmt/logfmt/README.md b/vendor/github.com/go-logfmt/logfmt/README.md new file mode 100644 index 0000000..3a8f10b --- /dev/null +++ b/vendor/github.com/go-logfmt/logfmt/README.md @@ -0,0 +1,33 @@ +[](https://godoc.org/github.com/go-logfmt/logfmt) +[](https://goreportcard.com/report/go-logfmt/logfmt) +[](https://travis-ci.org/go-logfmt/logfmt) +[](https://coveralls.io/github/go-logfmt/logfmt?branch=master) + +# logfmt + +Package logfmt implements utilities to marshal and unmarshal data in the [logfmt +format](https://brandur.org/logfmt). It provides an API similar to +[encoding/json](http://golang.org/pkg/encoding/json/) and +[encoding/xml](http://golang.org/pkg/encoding/xml/). + +The logfmt format was first documented by Brandur Leach in [this +article](https://brandur.org/logfmt). The format has not been formally +standardized. The most authoritative public specification to date has been the +documentation of a Go Language [package](http://godoc.org/github.com/kr/logfmt) +written by Blake Mizerany and Keith Rarick. + +## Goals + +This project attempts to conform as closely as possible to the prior art, while +also removing ambiguity where necessary to provide well behaved encoder and +decoder implementations. + +## Non-goals + +This project does not attempt to formally standardize the logfmt format. In the +event that logfmt is standardized this project would take conforming to the +standard as a goal. + +## Versioning + +Package logfmt publishes releases via [semver](http://semver.org/) compatible Git tags prefixed with a single 'v'. diff --git a/vendor/github.com/go-logfmt/logfmt/decode.go b/vendor/github.com/go-logfmt/logfmt/decode.go new file mode 100644 index 0000000..04e0eff --- /dev/null +++ b/vendor/github.com/go-logfmt/logfmt/decode.go @@ -0,0 +1,237 @@ +package logfmt + +import ( +	"bufio" +	"bytes" +	"fmt" +	"io" +	"unicode/utf8" +) + +// A Decoder reads and decodes logfmt records from an input stream. +type Decoder struct { +	pos     int +	key     []byte +	value   []byte +	lineNum int +	s       *bufio.Scanner +	err     error +} + +// NewDecoder returns a new decoder that reads from r. +// +// The decoder introduces its own buffering and may read data from r beyond +// the logfmt records requested. +func NewDecoder(r io.Reader) *Decoder { +	dec := &Decoder{ +		s: bufio.NewScanner(r), +	} +	return dec +} + +// ScanRecord advances the Decoder to the next record, which can then be +// parsed with the ScanKeyval method. It returns false when decoding stops, +// either by reaching the end of the input or an error. After ScanRecord +// returns false, the Err method will return any error that occurred during +// decoding, except that if it was io.EOF, Err will return nil. +func (dec *Decoder) ScanRecord() bool { +	if dec.err != nil { +		return false +	} +	if !dec.s.Scan() { +		dec.err = dec.s.Err() +		return false +	} +	dec.lineNum++ +	dec.pos = 0 +	return true +} + +// ScanKeyval advances the Decoder to the next key/value pair of the current +// record, which can then be retrieved with the Key and Value methods. It +// returns false when decoding stops, either by reaching the end of the +// current record or an error. +func (dec *Decoder) ScanKeyval() bool { +	dec.key, dec.value = nil, nil +	if dec.err != nil { +		return false +	} + +	line := dec.s.Bytes() + +	// garbage +	for p, c := range line[dec.pos:] { +		if c > ' ' { +			dec.pos += p +			goto key +		} +	} +	dec.pos = len(line) +	return false + +key: +	const invalidKeyError = "invalid key" + +	start, multibyte := dec.pos, false +	for p, c := range line[dec.pos:] { +		switch { +		case c == '=': +			dec.pos += p +			if dec.pos > start { +				dec.key = line[start:dec.pos] +				if multibyte && bytes.IndexRune(dec.key, utf8.RuneError) != -1 { +					dec.syntaxError(invalidKeyError) +					return false +				} +			} +			if dec.key == nil { +				dec.unexpectedByte(c) +				return false +			} +			goto equal +		case c == '"': +			dec.pos += p +			dec.unexpectedByte(c) +			return false +		case c <= ' ': +			dec.pos += p +			if dec.pos > start { +				dec.key = line[start:dec.pos] +				if multibyte && bytes.IndexRune(dec.key, utf8.RuneError) != -1 { +					dec.syntaxError(invalidKeyError) +					return false +				} +			} +			return true +		case c >= utf8.RuneSelf: +			multibyte = true +		} +	} +	dec.pos = len(line) +	if dec.pos > start { +		dec.key = line[start:dec.pos] +		if multibyte && bytes.IndexRune(dec.key, utf8.RuneError) != -1 { +			dec.syntaxError(invalidKeyError) +			return false +		} +	} +	return true + +equal: +	dec.pos++ +	if dec.pos >= len(line) { +		return true +	} +	switch c := line[dec.pos]; { +	case c <= ' ': +		return true +	case c == '"': +		goto qvalue +	} + +	// value +	start = dec.pos +	for p, c := range line[dec.pos:] { +		switch { +		case c == '=' || c == '"': +			dec.pos += p +			dec.unexpectedByte(c) +			return false +		case c <= ' ': +			dec.pos += p +			if dec.pos > start { +				dec.value = line[start:dec.pos] +			} +			return true +		} +	} +	dec.pos = len(line) +	if dec.pos > start { +		dec.value = line[start:dec.pos] +	} +	return true + +qvalue: +	const ( +		untermQuote  = "unterminated quoted value" +		invalidQuote = "invalid quoted value" +	) + +	hasEsc, esc := false, false +	start = dec.pos +	for p, c := range line[dec.pos+1:] { +		switch { +		case esc: +			esc = false +		case c == '\\': +			hasEsc, esc = true, true +		case c == '"': +			dec.pos += p + 2 +			if hasEsc { +				v, ok := unquoteBytes(line[start:dec.pos]) +				if !ok { +					dec.syntaxError(invalidQuote) +					return false +				} +				dec.value = v +			} else { +				start++ +				end := dec.pos - 1 +				if end > start { +					dec.value = line[start:end] +				} +			} +			return true +		} +	} +	dec.pos = len(line) +	dec.syntaxError(untermQuote) +	return false +} + +// Key returns the most recent key found by a call to ScanKeyval. The returned +// slice may point to internal buffers and is only valid until the next call +// to ScanRecord.  It does no allocation. +func (dec *Decoder) Key() []byte { +	return dec.key +} + +// Value returns the most recent value found by a call to ScanKeyval. The +// returned slice may point to internal buffers and is only valid until the +// next call to ScanRecord.  It does no allocation when the value has no +// escape sequences. +func (dec *Decoder) Value() []byte { +	return dec.value +} + +// Err returns the first non-EOF error that was encountered by the Scanner. +func (dec *Decoder) Err() error { +	return dec.err +} + +func (dec *Decoder) syntaxError(msg string) { +	dec.err = &SyntaxError{ +		Msg:  msg, +		Line: dec.lineNum, +		Pos:  dec.pos + 1, +	} +} + +func (dec *Decoder) unexpectedByte(c byte) { +	dec.err = &SyntaxError{ +		Msg:  fmt.Sprintf("unexpected %q", c), +		Line: dec.lineNum, +		Pos:  dec.pos + 1, +	} +} + +// A SyntaxError represents a syntax error in the logfmt input stream. +type SyntaxError struct { +	Msg  string +	Line int +	Pos  int +} + +func (e *SyntaxError) Error() string { +	return fmt.Sprintf("logfmt syntax error at pos %d on line %d: %s", e.Pos, e.Line, e.Msg) +} diff --git a/vendor/github.com/go-logfmt/logfmt/doc.go b/vendor/github.com/go-logfmt/logfmt/doc.go new file mode 100644 index 0000000..378e9ad --- /dev/null +++ b/vendor/github.com/go-logfmt/logfmt/doc.go @@ -0,0 +1,6 @@ +// Package logfmt implements utilities to marshal and unmarshal data in the +// logfmt format. The logfmt format records key/value pairs in a way that +// balances readability for humans and simplicity of computer parsing. It is +// most commonly used as a more human friendly alternative to JSON for +// structured logging. +package logfmt diff --git a/vendor/github.com/go-logfmt/logfmt/encode.go b/vendor/github.com/go-logfmt/logfmt/encode.go new file mode 100644 index 0000000..55f1603 --- /dev/null +++ b/vendor/github.com/go-logfmt/logfmt/encode.go @@ -0,0 +1,321 @@ +package logfmt + +import ( +	"bytes" +	"encoding" +	"errors" +	"fmt" +	"io" +	"reflect" +	"strings" +	"unicode/utf8" +) + +// MarshalKeyvals returns the logfmt encoding of keyvals, a variadic sequence +// of alternating keys and values. +func MarshalKeyvals(keyvals ...interface{}) ([]byte, error) { +	buf := &bytes.Buffer{} +	if err := NewEncoder(buf).EncodeKeyvals(keyvals...); err != nil { +		return nil, err +	} +	return buf.Bytes(), nil +} + +// An Encoder writes logfmt data to an output stream. +type Encoder struct { +	w       io.Writer +	scratch bytes.Buffer +	needSep bool +} + +// NewEncoder returns a new encoder that writes to w. +func NewEncoder(w io.Writer) *Encoder { +	return &Encoder{ +		w: w, +	} +} + +var ( +	space   = []byte(" ") +	equals  = []byte("=") +	newline = []byte("\n") +	null    = []byte("null") +) + +// EncodeKeyval writes the logfmt encoding of key and value to the stream. A +// single space is written before the second and subsequent keys in a record. +// Nothing is written if a non-nil error is returned. +func (enc *Encoder) EncodeKeyval(key, value interface{}) error { +	enc.scratch.Reset() +	if enc.needSep { +		if _, err := enc.scratch.Write(space); err != nil { +			return err +		} +	} +	if err := writeKey(&enc.scratch, key); err != nil { +		return err +	} +	if _, err := enc.scratch.Write(equals); err != nil { +		return err +	} +	if err := writeValue(&enc.scratch, value); err != nil { +		return err +	} +	_, err := enc.w.Write(enc.scratch.Bytes()) +	enc.needSep = true +	return err +} + +// EncodeKeyvals writes the logfmt encoding of keyvals to the stream. Keyvals +// is a variadic sequence of alternating keys and values. Keys of unsupported +// type are skipped along with their corresponding value. Values of +// unsupported type or that cause a MarshalerError are replaced by their error +// but do not cause EncodeKeyvals to return an error. If a non-nil error is +// returned some key/value pairs may not have be written. +func (enc *Encoder) EncodeKeyvals(keyvals ...interface{}) error { +	if len(keyvals) == 0 { +		return nil +	} +	if len(keyvals)%2 == 1 { +		keyvals = append(keyvals, nil) +	} +	for i := 0; i < len(keyvals); i += 2 { +		k, v := keyvals[i], keyvals[i+1] +		err := enc.EncodeKeyval(k, v) +		if err == ErrUnsupportedKeyType { +			continue +		} +		if _, ok := err.(*MarshalerError); ok || err == ErrUnsupportedValueType { +			v = err +			err = enc.EncodeKeyval(k, v) +		} +		if err != nil { +			return err +		} +	} +	return nil +} + +// MarshalerError represents an error encountered while marshaling a value. +type MarshalerError struct { +	Type reflect.Type +	Err  error +} + +func (e *MarshalerError) Error() string { +	return "error marshaling value of type " + e.Type.String() + ": " + e.Err.Error() +} + +// ErrNilKey is returned by Marshal functions and Encoder methods if a key is +// a nil interface or pointer value. +var ErrNilKey = errors.New("nil key") + +// ErrInvalidKey is returned by Marshal functions and Encoder methods if a key +// contains an invalid character. +var ErrInvalidKey = errors.New("invalid key") + +// ErrUnsupportedKeyType is returned by Encoder methods if a key has an +// unsupported type. +var ErrUnsupportedKeyType = errors.New("unsupported key type") + +// ErrUnsupportedValueType is returned by Encoder methods if a value has an +// unsupported type. +var ErrUnsupportedValueType = errors.New("unsupported value type") + +func writeKey(w io.Writer, key interface{}) error { +	if key == nil { +		return ErrNilKey +	} + +	switch k := key.(type) { +	case string: +		return writeStringKey(w, k) +	case []byte: +		if k == nil { +			return ErrNilKey +		} +		return writeBytesKey(w, k) +	case encoding.TextMarshaler: +		kb, err := safeMarshal(k) +		if err != nil { +			return err +		} +		if kb == nil { +			return ErrNilKey +		} +		return writeBytesKey(w, kb) +	case fmt.Stringer: +		ks, ok := safeString(k) +		if !ok { +			return ErrNilKey +		} +		return writeStringKey(w, ks) +	default: +		rkey := reflect.ValueOf(key) +		switch rkey.Kind() { +		case reflect.Array, reflect.Chan, reflect.Func, reflect.Map, reflect.Slice, reflect.Struct: +			return ErrUnsupportedKeyType +		case reflect.Ptr: +			if rkey.IsNil() { +				return ErrNilKey +			} +			return writeKey(w, rkey.Elem().Interface()) +		} +		return writeStringKey(w, fmt.Sprint(k)) +	} +} + +func invalidKeyRune(r rune) bool { +	return r <= ' ' || r == '=' || r == '"' || r == utf8.RuneError +} + +func invalidKeyString(key string) bool { +	return len(key) == 0 || strings.IndexFunc(key, invalidKeyRune) != -1 +} + +func invalidKey(key []byte) bool { +	return len(key) == 0 || bytes.IndexFunc(key, invalidKeyRune) != -1 +} + +func writeStringKey(w io.Writer, key string) error { +	if invalidKeyString(key) { +		return ErrInvalidKey +	} +	_, err := io.WriteString(w, key) +	return err +} + +func writeBytesKey(w io.Writer, key []byte) error { +	if invalidKey(key) { +		return ErrInvalidKey +	} +	_, err := w.Write(key) +	return err +} + +func writeValue(w io.Writer, value interface{}) error { +	switch v := value.(type) { +	case nil: +		return writeBytesValue(w, null) +	case string: +		return writeStringValue(w, v, true) +	case []byte: +		return writeBytesValue(w, v) +	case encoding.TextMarshaler: +		vb, err := safeMarshal(v) +		if err != nil { +			return err +		} +		if vb == nil { +			vb = null +		} +		return writeBytesValue(w, vb) +	case error: +		se, ok := safeError(v) +		return writeStringValue(w, se, ok) +	case fmt.Stringer: +		ss, ok := safeString(v) +		return writeStringValue(w, ss, ok) +	default: +		rvalue := reflect.ValueOf(value) +		switch rvalue.Kind() { +		case reflect.Array, reflect.Chan, reflect.Func, reflect.Map, reflect.Slice, reflect.Struct: +			return ErrUnsupportedValueType +		case reflect.Ptr: +			if rvalue.IsNil() { +				return writeBytesValue(w, null) +			} +			return writeValue(w, rvalue.Elem().Interface()) +		} +		return writeStringValue(w, fmt.Sprint(v), true) +	} +} + +func needsQuotedValueRune(r rune) bool { +	return r <= ' ' || r == '=' || r == '"' || r == utf8.RuneError +} + +func writeStringValue(w io.Writer, value string, ok bool) error { +	var err error +	if ok && value == "null" { +		_, err = io.WriteString(w, `"null"`) +	} else if strings.IndexFunc(value, needsQuotedValueRune) != -1 { +		_, err = writeQuotedString(w, value) +	} else { +		_, err = io.WriteString(w, value) +	} +	return err +} + +func writeBytesValue(w io.Writer, value []byte) error { +	var err error +	if bytes.IndexFunc(value, needsQuotedValueRune) != -1 { +		_, err = writeQuotedBytes(w, value) +	} else { +		_, err = w.Write(value) +	} +	return err +} + +// EndRecord writes a newline character to the stream and resets the encoder +// to the beginning of a new record. +func (enc *Encoder) EndRecord() error { +	_, err := enc.w.Write(newline) +	if err == nil { +		enc.needSep = false +	} +	return err +} + +// Reset resets the encoder to the beginning of a new record. +func (enc *Encoder) Reset() { +	enc.needSep = false +} + +func safeError(err error) (s string, ok bool) { +	defer func() { +		if panicVal := recover(); panicVal != nil { +			if v := reflect.ValueOf(err); v.Kind() == reflect.Ptr && v.IsNil() { +				s, ok = "null", false +			} else { +				panic(panicVal) +			} +		} +	}() +	s, ok = err.Error(), true +	return +} + +func safeString(str fmt.Stringer) (s string, ok bool) { +	defer func() { +		if panicVal := recover(); panicVal != nil { +			if v := reflect.ValueOf(str); v.Kind() == reflect.Ptr && v.IsNil() { +				s, ok = "null", false +			} else { +				panic(panicVal) +			} +		} +	}() +	s, ok = str.String(), true +	return +} + +func safeMarshal(tm encoding.TextMarshaler) (b []byte, err error) { +	defer func() { +		if panicVal := recover(); panicVal != nil { +			if v := reflect.ValueOf(tm); v.Kind() == reflect.Ptr && v.IsNil() { +				b, err = nil, nil +			} else { +				panic(panicVal) +			} +		} +	}() +	b, err = tm.MarshalText() +	if err != nil { +		return nil, &MarshalerError{ +			Type: reflect.TypeOf(tm), +			Err:  err, +		} +	} +	return +} diff --git a/vendor/github.com/go-logfmt/logfmt/fuzz.go b/vendor/github.com/go-logfmt/logfmt/fuzz.go new file mode 100644 index 0000000..6553b35 --- /dev/null +++ b/vendor/github.com/go-logfmt/logfmt/fuzz.go @@ -0,0 +1,126 @@ +// +build gofuzz + +package logfmt + +import ( +	"bufio" +	"bytes" +	"fmt" +	"io" +	"reflect" + +	kr "github.com/kr/logfmt" +) + +// Fuzz checks reserialized data matches +func Fuzz(data []byte) int { +	parsed, err := parse(data) +	if err != nil { +		return 0 +	} +	var w1 bytes.Buffer +	if err = write(parsed, &w1); err != nil { +		panic(err) +	} +	parsed, err = parse(w1.Bytes()) +	if err != nil { +		panic(err) +	} +	var w2 bytes.Buffer +	if err = write(parsed, &w2); err != nil { +		panic(err) +	} +	if !bytes.Equal(w1.Bytes(), w2.Bytes()) { +		panic(fmt.Sprintf("reserialized data does not match:\n%q\n%q\n", w1.Bytes(), w2.Bytes())) +	} +	return 1 +} + +// FuzzVsKR checks go-logfmt/logfmt against kr/logfmt +func FuzzVsKR(data []byte) int { +	parsed, err := parse(data) +	parsedKR, errKR := parseKR(data) + +	// github.com/go-logfmt/logfmt is a stricter parser. It returns errors for +	// more inputs than github.com/kr/logfmt. Ignore any inputs that have a +	// stict error. +	if err != nil { +		return 0 +	} + +	// Fail if the more forgiving parser finds an error not found by the +	// stricter parser. +	if errKR != nil { +		panic(fmt.Sprintf("unmatched error: %v", errKR)) +	} + +	if !reflect.DeepEqual(parsed, parsedKR) { +		panic(fmt.Sprintf("parsers disagree:\n%+v\n%+v\n", parsed, parsedKR)) +	} +	return 1 +} + +type kv struct { +	k, v []byte +} + +func parse(data []byte) ([][]kv, error) { +	var got [][]kv +	dec := NewDecoder(bytes.NewReader(data)) +	for dec.ScanRecord() { +		var kvs []kv +		for dec.ScanKeyval() { +			kvs = append(kvs, kv{dec.Key(), dec.Value()}) +		} +		got = append(got, kvs) +	} +	return got, dec.Err() +} + +func parseKR(data []byte) ([][]kv, error) { +	var ( +		s   = bufio.NewScanner(bytes.NewReader(data)) +		err error +		h   saveHandler +		got [][]kv +	) +	for err == nil && s.Scan() { +		h.kvs = nil +		err = kr.Unmarshal(s.Bytes(), &h) +		got = append(got, h.kvs) +	} +	if err == nil { +		err = s.Err() +	} +	return got, err +} + +type saveHandler struct { +	kvs []kv +} + +func (h *saveHandler) HandleLogfmt(key, val []byte) error { +	if len(key) == 0 { +		key = nil +	} +	if len(val) == 0 { +		val = nil +	} +	h.kvs = append(h.kvs, kv{key, val}) +	return nil +} + +func write(recs [][]kv, w io.Writer) error { +	enc := NewEncoder(w) +	for _, rec := range recs { +		for _, f := range rec { +			if err := enc.EncodeKeyval(f.k, f.v); err != nil { +				return err +			} +		} +		if err := enc.EndRecord(); err != nil { +			return err +		} +	} +	return nil +} diff --git a/vendor/github.com/go-logfmt/logfmt/jsonstring.go b/vendor/github.com/go-logfmt/logfmt/jsonstring.go new file mode 100644 index 0000000..030ac85 --- /dev/null +++ b/vendor/github.com/go-logfmt/logfmt/jsonstring.go @@ -0,0 +1,277 @@ +package logfmt + +import ( +	"bytes" +	"io" +	"strconv" +	"sync" +	"unicode" +	"unicode/utf16" +	"unicode/utf8" +) + +// Taken from Go's encoding/json and modified for use here. + +// 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. + +var hex = "0123456789abcdef" + +var bufferPool = sync.Pool{ +	New: func() interface{} { +		return &bytes.Buffer{} +	}, +} + +func getBuffer() *bytes.Buffer { +	return bufferPool.Get().(*bytes.Buffer) +} + +func poolBuffer(buf *bytes.Buffer) { +	buf.Reset() +	bufferPool.Put(buf) +} + +// NOTE: keep in sync with writeQuotedBytes below. +func writeQuotedString(w io.Writer, s string) (int, error) { +	buf := getBuffer() +	buf.WriteByte('"') +	start := 0 +	for i := 0; i < len(s); { +		if b := s[i]; b < utf8.RuneSelf { +			if 0x20 <= b && b != '\\' && b != '"' { +				i++ +				continue +			} +			if start < i { +				buf.WriteString(s[start:i]) +			} +			switch b { +			case '\\', '"': +				buf.WriteByte('\\') +				buf.WriteByte(b) +			case '\n': +				buf.WriteByte('\\') +				buf.WriteByte('n') +			case '\r': +				buf.WriteByte('\\') +				buf.WriteByte('r') +			case '\t': +				buf.WriteByte('\\') +				buf.WriteByte('t') +			default: +				// This encodes bytes < 0x20 except for \n, \r, and \t. +				buf.WriteString(`\u00`) +				buf.WriteByte(hex[b>>4]) +				buf.WriteByte(hex[b&0xF]) +			} +			i++ +			start = i +			continue +		} +		c, size := utf8.DecodeRuneInString(s[i:]) +		if c == utf8.RuneError { +			if start < i { +				buf.WriteString(s[start:i]) +			} +			buf.WriteString(`\ufffd`) +			i += size +			start = i +			continue +		} +		i += size +	} +	if start < len(s) { +		buf.WriteString(s[start:]) +	} +	buf.WriteByte('"') +	n, err := w.Write(buf.Bytes()) +	poolBuffer(buf) +	return n, err +} + +// NOTE: keep in sync with writeQuoteString above. +func writeQuotedBytes(w io.Writer, s []byte) (int, error) { +	buf := getBuffer() +	buf.WriteByte('"') +	start := 0 +	for i := 0; i < len(s); { +		if b := s[i]; b < utf8.RuneSelf { +			if 0x20 <= b && b != '\\' && b != '"' { +				i++ +				continue +			} +			if start < i { +				buf.Write(s[start:i]) +			} +			switch b { +			case '\\', '"': +				buf.WriteByte('\\') +				buf.WriteByte(b) +			case '\n': +				buf.WriteByte('\\') +				buf.WriteByte('n') +			case '\r': +				buf.WriteByte('\\') +				buf.WriteByte('r') +			case '\t': +				buf.WriteByte('\\') +				buf.WriteByte('t') +			default: +				// This encodes bytes < 0x20 except for \n, \r, and \t. +				buf.WriteString(`\u00`) +				buf.WriteByte(hex[b>>4]) +				buf.WriteByte(hex[b&0xF]) +			} +			i++ +			start = i +			continue +		} +		c, size := utf8.DecodeRune(s[i:]) +		if c == utf8.RuneError { +			if start < i { +				buf.Write(s[start:i]) +			} +			buf.WriteString(`\ufffd`) +			i += size +			start = i +			continue +		} +		i += size +	} +	if start < len(s) { +		buf.Write(s[start:]) +	} +	buf.WriteByte('"') +	n, err := w.Write(buf.Bytes()) +	poolBuffer(buf) +	return n, err +} + +// 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) +} + +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 { +			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 +} | 
