14 // MarshalKeyvals returns the logfmt encoding of keyvals, a variadic sequence
15 // of alternating keys and values.
16 func MarshalKeyvals(keyvals ...interface{}) ([]byte, error) {
17 buf := &bytes.Buffer{}
18 if err := NewEncoder(buf).EncodeKeyvals(keyvals...); err != nil {
21 return buf.Bytes(), nil
24 // An Encoder writes logfmt data to an output stream.
31 // NewEncoder returns a new encoder that writes to w.
32 func NewEncoder(w io.Writer) *Encoder {
41 newline = []byte("\n")
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.
48 func (enc *Encoder) EncodeKeyval(key, value interface{}) error {
51 if _, err := enc.scratch.Write(space); err != nil {
55 if err := writeKey(&enc.scratch, key); err != nil {
58 if _, err := enc.scratch.Write(equals); err != nil {
61 if err := writeValue(&enc.scratch, value); err != nil {
64 _, err := enc.w.Write(enc.scratch.Bytes())
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.
75 func (enc *Encoder) EncodeKeyvals(keyvals ...interface{}) error {
76 if len(keyvals) == 0 {
79 if len(keyvals)%2 == 1 {
80 keyvals = append(keyvals, nil)
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 {
88 if _, ok := err.(*MarshalerError); ok || err == ErrUnsupportedValueType {
90 err = enc.EncodeKeyval(k, v)
99 // MarshalerError represents an error encountered while marshaling a value.
100 type MarshalerError struct {
105 func (e *MarshalerError) Error() string {
106 return "error marshaling value of type " + e.Type.String() + ": " + e.Err.Error()
109 // ErrNilKey is returned by Marshal functions and Encoder methods if a key is
110 // a nil interface or pointer value.
111 var ErrNilKey = errors.New("nil key")
113 // ErrInvalidKey is returned by Marshal functions and Encoder methods if a key
114 // contains an invalid character.
115 var ErrInvalidKey = errors.New("invalid key")
117 // ErrUnsupportedKeyType is returned by Encoder methods if a key has an
119 var ErrUnsupportedKeyType = errors.New("unsupported key type")
121 // ErrUnsupportedValueType is returned by Encoder methods if a value has an
123 var ErrUnsupportedValueType = errors.New("unsupported value type")
125 func writeKey(w io.Writer, key interface{}) error {
130 switch k := key.(type) {
132 return writeStringKey(w, k)
137 return writeBytesKey(w, k)
138 case encoding.TextMarshaler:
139 kb, err := safeMarshal(k)
146 return writeBytesKey(w, kb)
148 ks, ok := safeString(k)
152 return writeStringKey(w, ks)
154 rkey := reflect.ValueOf(key)
156 case reflect.Array, reflect.Chan, reflect.Func, reflect.Map, reflect.Slice, reflect.Struct:
157 return ErrUnsupportedKeyType
162 return writeKey(w, rkey.Elem().Interface())
164 return writeStringKey(w, fmt.Sprint(k))
168 func invalidKeyRune(r rune) bool {
169 return r <= ' ' || r == '=' || r == '"' || r == utf8.RuneError
172 func invalidKeyString(key string) bool {
173 return len(key) == 0 || strings.IndexFunc(key, invalidKeyRune) != -1
176 func invalidKey(key []byte) bool {
177 return len(key) == 0 || bytes.IndexFunc(key, invalidKeyRune) != -1
180 func writeStringKey(w io.Writer, key string) error {
181 if invalidKeyString(key) {
184 _, err := io.WriteString(w, key)
188 func writeBytesKey(w io.Writer, key []byte) error {
192 _, err := w.Write(key)
196 func writeValue(w io.Writer, value interface{}) error {
197 switch v := value.(type) {
199 return writeBytesValue(w, null)
201 return writeStringValue(w, v, true)
203 return writeBytesValue(w, v)
204 case encoding.TextMarshaler:
205 vb, err := safeMarshal(v)
212 return writeBytesValue(w, vb)
214 se, ok := safeError(v)
215 return writeStringValue(w, se, ok)
217 ss, ok := safeString(v)
218 return writeStringValue(w, ss, ok)
220 rvalue := reflect.ValueOf(value)
221 switch rvalue.Kind() {
222 case reflect.Array, reflect.Chan, reflect.Func, reflect.Map, reflect.Slice, reflect.Struct:
223 return ErrUnsupportedValueType
226 return writeBytesValue(w, null)
228 return writeValue(w, rvalue.Elem().Interface())
230 return writeStringValue(w, fmt.Sprint(v), true)
234 func needsQuotedValueRune(r rune) bool {
235 return r <= ' ' || r == '=' || r == '"' || r == utf8.RuneError
238 func writeStringValue(w io.Writer, value string, ok bool) error {
240 if ok && value == "null" {
241 _, err = io.WriteString(w, `"null"`)
242 } else if strings.IndexFunc(value, needsQuotedValueRune) != -1 {
243 _, err = writeQuotedString(w, value)
245 _, err = io.WriteString(w, value)
250 func writeBytesValue(w io.Writer, value []byte) error {
252 if bytes.IndexFunc(value, needsQuotedValueRune) != -1 {
253 _, err = writeQuotedBytes(w, value)
255 _, err = w.Write(value)
260 // EndRecord writes a newline character to the stream and resets the encoder
261 // to the beginning of a new record.
262 func (enc *Encoder) EndRecord() error {
263 _, err := enc.w.Write(newline)
270 // Reset resets the encoder to the beginning of a new record.
271 func (enc *Encoder) Reset() {
275 func safeError(err error) (s string, ok bool) {
277 if panicVal := recover(); panicVal != nil {
278 if v := reflect.ValueOf(err); v.Kind() == reflect.Ptr && v.IsNil() {
279 s, ok = "null", false
285 s, ok = err.Error(), true
289 func safeString(str fmt.Stringer) (s string, ok bool) {
291 if panicVal := recover(); panicVal != nil {
292 if v := reflect.ValueOf(str); v.Kind() == reflect.Ptr && v.IsNil() {
293 s, ok = "null", false
299 s, ok = str.String(), true
303 func safeMarshal(tm encoding.TextMarshaler) (b []byte, err error) {
305 if panicVal := recover(); panicVal != nil {
306 if v := reflect.ValueOf(tm); v.Kind() == reflect.Ptr && v.IsNil() {
313 b, err = tm.MarshalText()
315 return nil, &MarshalerError{
316 Type: reflect.TypeOf(tm),