parser.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. package parser
  2. import (
  3. "fmt"
  4. "io"
  5. "strconv"
  6. "strings"
  7. "time"
  8. )
  9. // MetricRecord is the definition of a single metric instance in time.
  10. type MetricRecord struct {
  11. Name string
  12. Labels map[string]string
  13. Value float64
  14. Timestamp *time.Time
  15. }
  16. // Parses Metrics from raw metric format.
  17. //
  18. // metric_name ["{" label_name "=" `"` label_value `"` { "," label_name"=" `"` label_value `"` } [ "," ] "}"] value [ timestamp ]
  19. //
  20. // In the sample syntax:
  21. // - metric_name and label_name carry the usual Prometheus expression language
  22. // restrictions.
  23. // - label_value can be any sequence of UTF-8 characters, but the backslash
  24. // (\), double-quote ("), and line feed (\n) characters have to be escaped as
  25. // \\, \", and \n, respectively.
  26. // - value is a float represented as required by Go's ParseFloat() function. In
  27. // addition to standard numerical values, NaN, +Inf, and -Inf are valid
  28. // values representing not a number, positive infinity, and negative
  29. // infinity, respectively.
  30. // - The timestamp is an int64 (milliseconds since epoch, i.e. 1970-01-01
  31. // 00:00:00 UTC, excluding leap seconds), represented as required by Go's
  32. // ParseInt() function.
  33. type parser struct {
  34. lex *lexer
  35. current token
  36. }
  37. // creates a new parser, which is meant to be used once and discarded
  38. func newParser(r io.Reader) *parser {
  39. return &parser{
  40. lex: newLexer(r),
  41. }
  42. }
  43. func (p *parser) advance() token {
  44. p.current = p.lex.next()
  45. return p.current
  46. }
  47. func (p *parser) parse() ([]*MetricRecord, error) {
  48. var metrics []*MetricRecord
  49. p.advance()
  50. for {
  51. if p.current.Type == Eof {
  52. break
  53. }
  54. if p.current.Type == Comment {
  55. p.advance()
  56. continue
  57. }
  58. metric, err := p.parseMetric()
  59. if err != nil {
  60. return nil, err
  61. }
  62. metrics = append(metrics, metric)
  63. }
  64. if len(p.lex.errors) > 0 {
  65. var sb strings.Builder
  66. for _, err := range p.lex.errors {
  67. sb.WriteString(" * ")
  68. sb.WriteString(err.Error())
  69. sb.WriteRune('\n')
  70. }
  71. return nil, fmt.Errorf("lexical errors: \n%s", sb.String())
  72. }
  73. return metrics, nil
  74. }
  75. func (p *parser) parseMetric() (*MetricRecord, error) {
  76. // expected to be advanced to current token
  77. if p.current.Type != Literal {
  78. return nil, fmt.Errorf("[metric parse error] expected literal, got unexpected token %v", p.current)
  79. }
  80. metric := &MetricRecord{
  81. Name: p.current.Value,
  82. }
  83. p.advance()
  84. // No Bracket: Parse Value/Timestamp
  85. if p.current.Type != OpenBracket {
  86. v, ts, err := p.parseValueAndTimestamp()
  87. if err != nil {
  88. return nil, err
  89. }
  90. metric.Value = v
  91. metric.Timestamp = ts
  92. return metric, nil
  93. }
  94. // Parse Label Pairs
  95. p.advance()
  96. for {
  97. if p.current.Type == Comma {
  98. p.advance()
  99. continue
  100. }
  101. if p.current.Type == CloseBracket {
  102. break
  103. }
  104. labelName, labelValue, err := p.parseLabelValuePair()
  105. if err != nil {
  106. return nil, err
  107. }
  108. if metric.Labels == nil {
  109. metric.Labels = make(map[string]string)
  110. }
  111. metric.Labels[labelName] = labelValue
  112. }
  113. p.advance()
  114. // Value and Timestamp
  115. v, ts, err := p.parseValueAndTimestamp()
  116. if err != nil {
  117. return nil, err
  118. }
  119. metric.Value = v
  120. metric.Timestamp = ts
  121. return metric, nil
  122. }
  123. func (p *parser) parseValueAndTimestamp() (float64, *time.Time, error) {
  124. var ts *time.Time
  125. if p.current.Type != Value {
  126. return 0.0, nil, fmt.Errorf("[value and time parse error] expected value, got unexpected token %v", p.current)
  127. }
  128. v, err := strconv.ParseFloat(p.current.Value, 64)
  129. if err != nil {
  130. return 0.0, nil, fmt.Errorf("failed to parse value %v: %v", p.current.Value, err)
  131. }
  132. p.advance()
  133. if p.current.Type == Value {
  134. t, err := strconv.ParseInt(p.current.Value, 10, 64)
  135. if err != nil {
  136. return 0.0, nil, fmt.Errorf("failed to parse timestamp %v: %v", p.current.Value, err)
  137. }
  138. epoch := time.Unix(0, t*int64(time.Millisecond))
  139. ts = &epoch
  140. p.advance()
  141. }
  142. return v, ts, nil
  143. }
  144. func (p *parser) parseLabelValuePair() (string, string, error) {
  145. if p.current.Type != Literal {
  146. return "", "", fmt.Errorf("[label parse error] expected literal, got unexpected token %v", p.current)
  147. }
  148. // start with label name literal
  149. labelName := p.current.Value
  150. p.advance()
  151. // must be '='
  152. if p.current.Type != Equal {
  153. return "", "", fmt.Errorf("[label parse error] expected '=', got unexpected token %v", p.current)
  154. }
  155. p.advance()
  156. // must be string type
  157. if p.current.Type != String {
  158. return "", "", fmt.Errorf("[label parse error] expected string, got unexpected token %v", p.current)
  159. }
  160. // label value string
  161. labelValue := p.current.Value
  162. p.advance()
  163. return labelName, labelValue, nil
  164. }