encode.go

  1package logfmt
  2
  3import (
  4	"bytes"
  5	"encoding"
  6	"errors"
  7	"fmt"
  8	"io"
  9	"reflect"
 10	"strings"
 11	"unicode/utf8"
 12)
 13
 14// MarshalKeyvals returns the logfmt encoding of keyvals, a variadic sequence
 15// of alternating keys and values.
 16func MarshalKeyvals(keyvals ...interface{}) ([]byte, error) {
 17	buf := &bytes.Buffer{}
 18	if err := NewEncoder(buf).EncodeKeyvals(keyvals...); err != nil {
 19		return nil, err
 20	}
 21	return buf.Bytes(), nil
 22}
 23
 24// An Encoder writes logfmt data to an output stream.
 25type Encoder struct {
 26	w       io.Writer
 27	scratch bytes.Buffer
 28	needSep bool
 29}
 30
 31// NewEncoder returns a new encoder that writes to w.
 32func NewEncoder(w io.Writer) *Encoder {
 33	return &Encoder{
 34		w: w,
 35	}
 36}
 37
 38var (
 39	space   = []byte(" ")
 40	equals  = []byte("=")
 41	newline = []byte("\n")
 42	null    = []byte("null")
 43)
 44
 45// EncodeKeyval writes the logfmt encoding of key and value to the stream. A
 46// single space is written before the second and subsequent keys in a record.
 47// Nothing is written if a non-nil error is returned.
 48func (enc *Encoder) EncodeKeyval(key, value interface{}) error {
 49	enc.scratch.Reset()
 50	if enc.needSep {
 51		if _, err := enc.scratch.Write(space); err != nil {
 52			return err
 53		}
 54	}
 55	if err := writeKey(&enc.scratch, key); err != nil {
 56		return err
 57	}
 58	if _, err := enc.scratch.Write(equals); err != nil {
 59		return err
 60	}
 61	if err := writeValue(&enc.scratch, value); err != nil {
 62		return err
 63	}
 64	_, err := enc.w.Write(enc.scratch.Bytes())
 65	enc.needSep = true
 66	return err
 67}
 68
 69// EncodeKeyvals writes the logfmt encoding of keyvals to the stream. Keyvals
 70// is a variadic sequence of alternating keys and values. Keys of unsupported
 71// type are skipped along with their corresponding value. Values of
 72// unsupported type or that cause a MarshalerError are replaced by their error
 73// but do not cause EncodeKeyvals to return an error. If a non-nil error is
 74// returned some key/value pairs may not have be written.
 75func (enc *Encoder) EncodeKeyvals(keyvals ...interface{}) error {
 76	if len(keyvals) == 0 {
 77		return nil
 78	}
 79	if len(keyvals)%2 == 1 {
 80		keyvals = append(keyvals, nil)
 81	}
 82	for i := 0; i < len(keyvals); i += 2 {
 83		k, v := keyvals[i], keyvals[i+1]
 84		err := enc.EncodeKeyval(k, v)
 85		if err == ErrUnsupportedKeyType {
 86			continue
 87		}
 88		if _, ok := err.(*MarshalerError); ok || err == ErrUnsupportedValueType {
 89			v = err
 90			err = enc.EncodeKeyval(k, v)
 91		}
 92		if err != nil {
 93			return err
 94		}
 95	}
 96	return nil
 97}
 98
 99// MarshalerError represents an error encountered while marshaling a value.
100type MarshalerError struct {
101	Type reflect.Type
102	Err  error
103}
104
105func (e *MarshalerError) Error() string {
106	return "error marshaling value of type " + e.Type.String() + ": " + e.Err.Error()
107}
108
109// ErrNilKey is returned by Marshal functions and Encoder methods if a key is
110// a nil interface or pointer value.
111var ErrNilKey = errors.New("nil key")
112
113// ErrInvalidKey is returned by Marshal functions and Encoder methods if, after
114// dropping invalid runes, a key is empty.
115var ErrInvalidKey = errors.New("invalid key")
116
117// ErrUnsupportedKeyType is returned by Encoder methods if a key has an
118// unsupported type.
119var ErrUnsupportedKeyType = errors.New("unsupported key type")
120
121// ErrUnsupportedValueType is returned by Encoder methods if a value has an
122// unsupported type.
123var ErrUnsupportedValueType = errors.New("unsupported value type")
124
125func writeKey(w io.Writer, key interface{}) error {
126	if key == nil {
127		return ErrNilKey
128	}
129
130	switch k := key.(type) {
131	case string:
132		return writeStringKey(w, k)
133	case []byte:
134		if k == nil {
135			return ErrNilKey
136		}
137		return writeBytesKey(w, k)
138	case encoding.TextMarshaler:
139		kb, err := safeMarshal(k)
140		if err != nil {
141			return err
142		}
143		if kb == nil {
144			return ErrNilKey
145		}
146		return writeBytesKey(w, kb)
147	case fmt.Stringer:
148		ks, ok := safeString(k)
149		if !ok {
150			return ErrNilKey
151		}
152		return writeStringKey(w, ks)
153	default:
154		rkey := reflect.ValueOf(key)
155		switch rkey.Kind() {
156		case reflect.Array, reflect.Chan, reflect.Func, reflect.Map, reflect.Slice, reflect.Struct:
157			return ErrUnsupportedKeyType
158		case reflect.Ptr:
159			if rkey.IsNil() {
160				return ErrNilKey
161			}
162			return writeKey(w, rkey.Elem().Interface())
163		}
164		return writeStringKey(w, fmt.Sprint(k))
165	}
166}
167
168// keyRuneFilter returns r for all valid key runes, and -1 for all invalid key
169// runes. When used as the mapping function for strings.Map and bytes.Map
170// functions it causes them to remove invalid key runes from strings or byte
171// slices respectively.
172func keyRuneFilter(r rune) rune {
173	if r <= ' ' || r == '=' || r == '"' || r == utf8.RuneError {
174		return -1
175	}
176	return r
177}
178
179func writeStringKey(w io.Writer, key string) error {
180	k := strings.Map(keyRuneFilter, key)
181	if k == "" {
182		return ErrInvalidKey
183	}
184	_, err := io.WriteString(w, k)
185	return err
186}
187
188func writeBytesKey(w io.Writer, key []byte) error {
189	k := bytes.Map(keyRuneFilter, key)
190	if len(k) == 0 {
191		return ErrInvalidKey
192	}
193	_, err := w.Write(k)
194	return err
195}
196
197func writeValue(w io.Writer, value interface{}) error {
198	switch v := value.(type) {
199	case nil:
200		return writeBytesValue(w, null)
201	case string:
202		return writeStringValue(w, v, true)
203	case []byte:
204		return writeBytesValue(w, v)
205	case encoding.TextMarshaler:
206		vb, err := safeMarshal(v)
207		if err != nil {
208			return err
209		}
210		if vb == nil {
211			vb = null
212		}
213		return writeBytesValue(w, vb)
214	case error:
215		se, ok := safeError(v)
216		return writeStringValue(w, se, ok)
217	case fmt.Stringer:
218		ss, ok := safeString(v)
219		return writeStringValue(w, ss, ok)
220	default:
221		rvalue := reflect.ValueOf(value)
222		switch rvalue.Kind() {
223		case reflect.Array, reflect.Chan, reflect.Func, reflect.Map, reflect.Slice, reflect.Struct:
224			return ErrUnsupportedValueType
225		case reflect.Ptr:
226			if rvalue.IsNil() {
227				return writeBytesValue(w, null)
228			}
229			return writeValue(w, rvalue.Elem().Interface())
230		}
231		return writeStringValue(w, fmt.Sprint(v), true)
232	}
233}
234
235func needsQuotedValueRune(r rune) bool {
236	return r <= ' ' || r == '=' || r == '"' || r == utf8.RuneError
237}
238
239func writeStringValue(w io.Writer, value string, ok bool) error {
240	var err error
241	if ok && value == "null" {
242		_, err = io.WriteString(w, `"null"`)
243	} else if strings.IndexFunc(value, needsQuotedValueRune) != -1 {
244		_, err = writeQuotedString(w, value)
245	} else {
246		_, err = io.WriteString(w, value)
247	}
248	return err
249}
250
251func writeBytesValue(w io.Writer, value []byte) error {
252	var err error
253	if bytes.IndexFunc(value, needsQuotedValueRune) != -1 {
254		_, err = writeQuotedBytes(w, value)
255	} else {
256		_, err = w.Write(value)
257	}
258	return err
259}
260
261// EndRecord writes a newline character to the stream and resets the encoder
262// to the beginning of a new record.
263func (enc *Encoder) EndRecord() error {
264	_, err := enc.w.Write(newline)
265	if err == nil {
266		enc.needSep = false
267	}
268	return err
269}
270
271// Reset resets the encoder to the beginning of a new record.
272func (enc *Encoder) Reset() {
273	enc.needSep = false
274}
275
276func safeError(err error) (s string, ok bool) {
277	defer func() {
278		if panicVal := recover(); panicVal != nil {
279			if v := reflect.ValueOf(err); v.Kind() == reflect.Ptr && v.IsNil() {
280				s, ok = "null", false
281			} else {
282				s, ok = fmt.Sprintf("PANIC:%v", panicVal), false
283			}
284		}
285	}()
286	s, ok = err.Error(), true
287	return
288}
289
290func safeString(str fmt.Stringer) (s string, ok bool) {
291	defer func() {
292		if panicVal := recover(); panicVal != nil {
293			if v := reflect.ValueOf(str); v.Kind() == reflect.Ptr && v.IsNil() {
294				s, ok = "null", false
295			} else {
296				s, ok = fmt.Sprintf("PANIC:%v", panicVal), true
297			}
298		}
299	}()
300	s, ok = str.String(), true
301	return
302}
303
304func safeMarshal(tm encoding.TextMarshaler) (b []byte, err error) {
305	defer func() {
306		if panicVal := recover(); panicVal != nil {
307			if v := reflect.ValueOf(tm); v.Kind() == reflect.Ptr && v.IsNil() {
308				b, err = nil, nil
309			} else {
310				b, err = nil, fmt.Errorf("panic when marshalling: %s", panicVal)
311			}
312		}
313	}()
314	b, err = tm.MarshalText()
315	if err != nil {
316		return nil, &MarshalerError{
317			Type: reflect.TypeOf(tm),
318			Err:  err,
319		}
320	}
321	return
322}