| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- 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)
- }
|