11 // A Decoder reads and decodes logfmt records from an input stream.
21 // NewDecoder returns a new decoder that reads from r.
23 // The decoder introduces its own buffering and may read data from r beyond
24 // the logfmt records requested.
25 func NewDecoder(r io.Reader) *Decoder {
27 s: bufio.NewScanner(r),
32 // ScanRecord advances the Decoder to the next record, which can then be
33 // parsed with the ScanKeyval method. It returns false when decoding stops,
34 // either by reaching the end of the input or an error. After ScanRecord
35 // returns false, the Err method will return any error that occurred during
36 // decoding, except that if it was io.EOF, Err will return nil.
37 func (dec *Decoder) ScanRecord() bool {
50 // ScanKeyval advances the Decoder to the next key/value pair of the current
51 // record, which can then be retrieved with the Key and Value methods. It
52 // returns false when decoding stops, either by reaching the end of the
53 // current record or an error.
54 func (dec *Decoder) ScanKeyval() bool {
55 dec.key, dec.value = nil, nil
63 for p, c := range line[dec.pos:] {
73 const invalidKeyError = "invalid key"
75 start, multibyte := dec.pos, false
76 for p, c := range line[dec.pos:] {
81 dec.key = line[start:dec.pos]
82 if multibyte && bytes.IndexRune(dec.key, utf8.RuneError) != -1 {
83 dec.syntaxError(invalidKeyError)
99 dec.key = line[start:dec.pos]
100 if multibyte && bytes.IndexRune(dec.key, utf8.RuneError) != -1 {
101 dec.syntaxError(invalidKeyError)
106 case c >= utf8.RuneSelf:
112 dec.key = line[start:dec.pos]
113 if multibyte && bytes.IndexRune(dec.key, utf8.RuneError) != -1 {
114 dec.syntaxError(invalidKeyError)
122 if dec.pos >= len(line) {
125 switch c := line[dec.pos]; {
134 for p, c := range line[dec.pos:] {
136 case c == '=' || c == '"':
138 dec.unexpectedByte(c)
143 dec.value = line[start:dec.pos]
150 dec.value = line[start:dec.pos]
156 untermQuote = "unterminated quoted value"
157 invalidQuote = "invalid quoted value"
160 hasEsc, esc := false, false
162 for p, c := range line[dec.pos+1:] {
167 hasEsc, esc = true, true
171 v, ok := unquoteBytes(line[start:dec.pos])
173 dec.syntaxError(invalidQuote)
181 dec.value = line[start:end]
188 dec.syntaxError(untermQuote)
192 // Key returns the most recent key found by a call to ScanKeyval. The returned
193 // slice may point to internal buffers and is only valid until the next call
194 // to ScanRecord. It does no allocation.
195 func (dec *Decoder) Key() []byte {
199 // Value returns the most recent value found by a call to ScanKeyval. The
200 // returned slice may point to internal buffers and is only valid until the
201 // next call to ScanRecord. It does no allocation when the value has no
203 func (dec *Decoder) Value() []byte {
207 // Err returns the first non-EOF error that was encountered by the Scanner.
208 func (dec *Decoder) Err() error {
212 func (dec *Decoder) syntaxError(msg string) {
213 dec.err = &SyntaxError{
220 func (dec *Decoder) unexpectedByte(c byte) {
221 dec.err = &SyntaxError{
222 Msg: fmt.Sprintf("unexpected %q", c),
228 // A SyntaxError represents a syntax error in the logfmt input stream.
229 type SyntaxError struct {
235 func (e *SyntaxError) Error() string {
236 return fmt.Sprintf("logfmt syntax error at pos %d on line %d: %s", e.Pos, e.Line, e.Msg)