From ffe7efb4113f445519b6c50c9bb14088c6b79397 Mon Sep 17 00:00:00 2001 From: Brian Brazil Date: Thu, 4 Oct 2018 14:52:03 +0100 Subject: [PATCH] Prepare for multiple text formats Pass content type down to text parser. Add layer of indirection in front of text parser, and rename to avoid future clashes. Signed-off-by: Brian Brazil --- Makefile | 3 +- pkg/textparse/interface.go | 76 +++++++++++++++++++ pkg/textparse/{lex.l => promlex.l} | 4 +- pkg/textparse/{lex.l.go => promlex.l.go} | 6 +- pkg/textparse/{parse.go => promparse.go} | 67 ++++++---------- .../{parse_test.go => promparse_test.go} | 44 +++++------ ...ata.nometa.txt => promtestdata.nometa.txt} | 0 .../{testdata.txt => promtestdata.txt} | 0 scrape/scrape.go | 33 ++++---- scrape/scrape_test.go | 34 ++++----- 10 files changed, 161 insertions(+), 106 deletions(-) create mode 100644 pkg/textparse/interface.go rename pkg/textparse/{lex.l => promlex.l} (97%) rename pkg/textparse/{lex.l.go => promlex.l.go} (98%) rename pkg/textparse/{parse.go => promparse.go} (85%) rename pkg/textparse/{parse_test.go => promparse_test.go} (91%) rename pkg/textparse/{testdata.nometa.txt => promtestdata.nometa.txt} (100%) rename pkg/textparse/{testdata.txt => promtestdata.txt} (100%) diff --git a/Makefile b/Makefile index 6742a44f9d..64423ccf07 100644 --- a/Makefile +++ b/Makefile @@ -17,8 +17,7 @@ STATICCHECK_IGNORE = \ github.com/prometheus/prometheus/discovery/kubernetes/kubernetes.go:SA1019 \ github.com/prometheus/prometheus/discovery/kubernetes/node.go:SA1019 \ github.com/prometheus/prometheus/documentation/examples/remote_storage/remote_storage_adapter/main.go:SA1019 \ - github.com/prometheus/prometheus/pkg/textparse/lex.l.go:SA4006 \ - github.com/prometheus/prometheus/pkg/textparse/lex.l.go:SA4006 \ + github.com/prometheus/prometheus/pkg/textparse/promlex.l.go:SA4006 \ github.com/prometheus/prometheus/pkg/pool/pool.go:SA6002 \ github.com/prometheus/prometheus/promql/engine.go:SA6002 \ github.com/prometheus/prometheus/prompb/rpc.pb.gw.go:SA1019 diff --git a/pkg/textparse/interface.go b/pkg/textparse/interface.go new file mode 100644 index 0000000000..75549a287a --- /dev/null +++ b/pkg/textparse/interface.go @@ -0,0 +1,76 @@ +// Copyright 2017 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package textparse + +import ( + "github.com/prometheus/prometheus/pkg/labels" +) + +// Parser parses samples from a byte slice of samples in the official +// Prometheus text exposition format. +type Parser interface { + // Series returns the bytes of the series, the timestamp if set, and the value + // of the current sample. + Series() ([]byte, *int64, float64) + + // Help returns the metric name and help text in the current entry. + // Must only be called after Next returned a help entry. + // The returned byte slices become invalid after the next call to Next. + Help() ([]byte, []byte) + + // Type returns the metric name and type in the current entry. + // Must only be called after Next returned a type entry. + // The returned byte slices become invalid after the next call to Next. + Type() ([]byte, MetricType) + + // Comment returns the text of the current comment. + // Must only be called after Next returned a comment entry. + // The returned byte slice becomes invalid after the next call to Next. + Comment() []byte + + // Metric writes the labels of the current sample into the passed labels. + // It returns the string from which the metric was parsed. + Metric(l *labels.Labels) string + + // Next advances the parser to the next sample. It returns false if no + // more samples were read or an error occurred. + Next() (Entry, error) +} + +// New returns a new parser of the byte slice. +func New(b []byte, contentType string) Parser { + return NewPromParser(b) +} + +// Entry represents the type of a parsed entry. +type Entry int + +const ( + EntryInvalid Entry = -1 + EntryType Entry = 0 + EntryHelp Entry = 1 + EntrySeries Entry = 2 + EntryComment Entry = 3 +) + +// MetricType represents metric type values. +type MetricType string + +const ( + MetricTypeCounter = "counter" + MetricTypeGauge = "gauge" + MetricTypeHistogram = "histogram" + MetricTypeSummary = "summary" + MetricTypeUntyped = "untyped" +) diff --git a/pkg/textparse/lex.l b/pkg/textparse/promlex.l similarity index 97% rename from pkg/textparse/lex.l rename to pkg/textparse/promlex.l index 590c7774d4..c3c5c3bb00 100644 --- a/pkg/textparse/lex.l +++ b/pkg/textparse/promlex.l @@ -32,7 +32,7 @@ const ( // Lex is called by the parser generated by "go tool yacc" to obtain each // token. The method is opened before the matching rules block and closed at // the end of the file. -func (l *lexer) Lex() token { +func (l *promlexer) Lex() token { if l.i >= len(l.b) { return tEOF } @@ -87,7 +87,7 @@ C [^\n] return tInvalid } -func (l *lexer) consumeComment() token { +func (l *promlexer) consumeComment() token { for c := l.cur(); ; c = l.next() { switch c { case 0: diff --git a/pkg/textparse/lex.l.go b/pkg/textparse/promlex.l.go similarity index 98% rename from pkg/textparse/lex.l.go rename to pkg/textparse/promlex.l.go index 5ddfb562ef..ff01536251 100644 --- a/pkg/textparse/lex.l.go +++ b/pkg/textparse/promlex.l.go @@ -1,4 +1,4 @@ -// CAUTION: Generated file - DO NOT EDIT. +// Code generated by golex. DO NOT EDIT. // Copyright 2017 The Prometheus Authors // Licensed under the Apache License, Version 2.0 (the "License"); @@ -33,7 +33,7 @@ const ( // Lex is called by the parser generated by "go tool yacc" to obtain each // token. The method is opened before the matching rules block and closed at // the end of the file. -func (l *lexer) Lex() token { +func (l *promlexer) Lex() token { if l.i >= len(l.b) { return tEOF } @@ -537,7 +537,7 @@ yyabort: // no lexem recognized return tInvalid } -func (l *lexer) consumeComment() token { +func (l *promlexer) consumeComment() token { for c := l.cur(); ; c = l.next() { switch c { case 0: diff --git a/pkg/textparse/parse.go b/pkg/textparse/promparse.go similarity index 85% rename from pkg/textparse/parse.go rename to pkg/textparse/promparse.go index f7db282fc3..b1fa90a1dc 100644 --- a/pkg/textparse/parse.go +++ b/pkg/textparse/promparse.go @@ -12,9 +12,8 @@ // limitations under the License. //go:generate go get github.com/cznic/golex -//go:generate golex -o=lex.l.go lex.l +//go:generate golex -o=promlex.l.go promlex.l -// Package textparse contains an efficient parser for the Prometheus text format. package textparse import ( @@ -32,7 +31,7 @@ import ( "github.com/prometheus/prometheus/pkg/value" ) -type lexer struct { +type promlexer struct { b []byte i int start int @@ -106,16 +105,16 @@ func (t token) String() string { } // buf returns the buffer of the current token. -func (l *lexer) buf() []byte { +func (l *promlexer) buf() []byte { return l.b[l.start:l.i] } -func (l *lexer) cur() byte { +func (l *promlexer) cur() byte { return l.b[l.i] } -// next advances the lexer to the next character. -func (l *lexer) next() byte { +// next advances the promlexer to the next character. +func (l *promlexer) next() byte { l.i++ if l.i >= len(l.b) { l.err = io.EOF @@ -129,14 +128,14 @@ func (l *lexer) next() byte { return l.b[l.i] } -func (l *lexer) Error(es string) { +func (l *promlexer) Error(es string) { l.err = errors.New(es) } -// Parser parses samples from a byte slice of samples in the official +// PromParser parses samples from a byte slice of samples in the official // Prometheus text exposition format. -type Parser struct { - l *lexer +type PromParser struct { + l *promlexer series []byte text []byte mtype MetricType @@ -148,13 +147,13 @@ type Parser struct { } // New returns a new parser of the byte slice. -func New(b []byte) *Parser { - return &Parser{l: &lexer{b: append(b, '\n')}} +func NewPromParser(b []byte) Parser { + return &PromParser{l: &promlexer{b: append(b, '\n')}} } // Series returns the bytes of the series, the timestamp if set, and the value // of the current sample. -func (p *Parser) Series() ([]byte, *int64, float64) { +func (p *PromParser) Series() ([]byte, *int64, float64) { if p.hasTS { return p.series, &p.ts, p.val } @@ -164,7 +163,7 @@ func (p *Parser) Series() ([]byte, *int64, float64) { // Help returns the metric name and help text in the current entry. // Must only be called after Next returned a help entry. // The returned byte slices become invalid after the next call to Next. -func (p *Parser) Help() ([]byte, []byte) { +func (p *PromParser) Help() ([]byte, []byte) { m := p.l.b[p.offsets[0]:p.offsets[1]] // Replacer causes allocations. Replace only when necessary. @@ -177,20 +176,20 @@ func (p *Parser) Help() ([]byte, []byte) { // Type returns the metric name and type in the current entry. // Must only be called after Next returned a type entry. // The returned byte slices become invalid after the next call to Next. -func (p *Parser) Type() ([]byte, MetricType) { +func (p *PromParser) Type() ([]byte, MetricType) { return p.l.b[p.offsets[0]:p.offsets[1]], p.mtype } // Comment returns the text of the current comment. // Must only be called after Next returned a comment entry. // The returned byte slice becomes invalid after the next call to Next. -func (p *Parser) Comment() []byte { +func (p *PromParser) Comment() []byte { return p.text } // Metric writes the labels of the current sample into the passed labels. // It returns the string from which the metric was parsed. -func (p *Parser) Metric(l *labels.Labels) string { +func (p *PromParser) Metric(l *labels.Labels) string { // Allocate the full immutable string immediately, so we just // have to create references on it below. s := string(p.series) @@ -221,9 +220,9 @@ func (p *Parser) Metric(l *labels.Labels) string { return s } -// nextToken returns the next token from the lexer. It skips over tabs +// nextToken returns the next token from the promlexer. It skips over tabs // and spaces. -func (p *Parser) nextToken() token { +func (p *PromParser) nextToken() token { for { if tok := p.l.Lex(); tok != tWhitespace { return tok @@ -231,35 +230,13 @@ func (p *Parser) nextToken() token { } } -// Entry represents the type of a parsed entry. -type Entry int - -const ( - EntryInvalid Entry = -1 - EntryType Entry = 0 - EntryHelp Entry = 1 - EntrySeries Entry = 2 - EntryComment Entry = 3 -) - -// MetricType represents metric type values. -type MetricType string - -const ( - MetricTypeCounter = "counter" - MetricTypeGauge = "gauge" - MetricTypeHistogram = "histogram" - MetricTypeSummary = "summary" - MetricTypeUntyped = "untyped" -) - func parseError(exp string, got token) error { return fmt.Errorf("%s, got %q", exp, got) } // Next advances the parser to the next sample. It returns false if no // more samples were read or an error occurred. -func (p *Parser) Next() (Entry, error) { +func (p *PromParser) Next() (Entry, error) { var err error p.start = p.l.i @@ -371,7 +348,7 @@ func (p *Parser) Next() (Entry, error) { return EntryInvalid, err } -func (p *Parser) parseLVals() error { +func (p *PromParser) parseLVals() error { t := p.nextToken() for { switch t { @@ -393,7 +370,7 @@ func (p *Parser) parseLVals() error { return fmt.Errorf("invalid UTF-8 label value") } - // The lexer ensures the value string is quoted. Strip first + // The promlexer ensures the value string is quoted. Strip first // and last character. p.offsets = append(p.offsets, p.l.start+1, p.l.i-1) diff --git a/pkg/textparse/parse_test.go b/pkg/textparse/promparse_test.go similarity index 91% rename from pkg/textparse/parse_test.go rename to pkg/textparse/promparse_test.go index 07d4b0c891..3e493f3ab4 100644 --- a/pkg/textparse/parse_test.go +++ b/pkg/textparse/promparse_test.go @@ -27,7 +27,7 @@ import ( "github.com/stretchr/testify/require" ) -func TestParse(t *testing.T) { +func TestPromParse(t *testing.T) { input := `# HELP go_gc_duration_seconds A summary of the GC invocation durations. # TYPE go_gc_duration_seconds summary go_gc_duration_seconds{quantile="0"} 4.9351e-05 @@ -164,7 +164,7 @@ testmetric{label="\"bar\""} 1` }, } - p := New([]byte(input)) + p := NewPromParser([]byte(input)) i := 0 var res labels.Labels @@ -207,7 +207,7 @@ testmetric{label="\"bar\""} 1` require.Equal(t, len(exp), i) } -func TestParseErrors(t *testing.T) { +func TestPromParseErrors(t *testing.T) { cases := []struct { input string err string @@ -247,7 +247,7 @@ func TestParseErrors(t *testing.T) { } for i, c := range cases { - p := New([]byte(c.input)) + p := NewPromParser([]byte(c.input)) var err error for err == nil { _, err = p.Next() @@ -257,7 +257,7 @@ func TestParseErrors(t *testing.T) { } } -func TestNullByteHandling(t *testing.T) { +func TestPromNullByteHandling(t *testing.T) { cases := []struct { input string err string @@ -297,7 +297,7 @@ func TestNullByteHandling(t *testing.T) { } for i, c := range cases { - p := New([]byte(c.input)) + p := NewPromParser([]byte(c.input)) var err error for err == nil { _, err = p.Next() @@ -314,11 +314,11 @@ func TestNullByteHandling(t *testing.T) { } const ( - testdataSampleCount = 410 + promtestdataSampleCount = 410 ) -func BenchmarkParse(b *testing.B) { - for _, fn := range []string{"testdata.txt", "testdata.nometa.txt"} { +func BenchmarkPromParse(b *testing.B) { + for _, fn := range []string{"promtestdata.txt", "promtestdata.nometa.txt"} { f, err := os.Open(fn) require.NoError(b, err) defer f.Close() @@ -329,12 +329,12 @@ func BenchmarkParse(b *testing.B) { b.Run("no-decode-metric/"+fn, func(b *testing.B) { total := 0 - b.SetBytes(int64(len(buf) * (b.N / testdataSampleCount))) + b.SetBytes(int64(len(buf) * (b.N / promtestdataSampleCount))) b.ReportAllocs() b.ResetTimer() - for i := 0; i < b.N; i += testdataSampleCount { - p := New(buf) + for i := 0; i < b.N; i += promtestdataSampleCount { + p := NewPromParser(buf) Outer: for i < b.N { @@ -357,12 +357,12 @@ func BenchmarkParse(b *testing.B) { b.Run("decode-metric/"+fn, func(b *testing.B) { total := 0 - b.SetBytes(int64(len(buf) * (b.N / testdataSampleCount))) + b.SetBytes(int64(len(buf) * (b.N / promtestdataSampleCount))) b.ReportAllocs() b.ResetTimer() - for i := 0; i < b.N; i += testdataSampleCount { - p := New(buf) + for i := 0; i < b.N; i += promtestdataSampleCount { + p := NewPromParser(buf) Outer: for i < b.N { @@ -390,12 +390,12 @@ func BenchmarkParse(b *testing.B) { total := 0 res := make(labels.Labels, 0, 5) - b.SetBytes(int64(len(buf) * (b.N / testdataSampleCount))) + b.SetBytes(int64(len(buf) * (b.N / promtestdataSampleCount))) b.ReportAllocs() b.ResetTimer() - for i := 0; i < b.N; i += testdataSampleCount { - p := New(buf) + for i := 0; i < b.N; i += promtestdataSampleCount { + p := NewPromParser(buf) Outer: for i < b.N { @@ -420,13 +420,13 @@ func BenchmarkParse(b *testing.B) { _ = total }) b.Run("expfmt-text/"+fn, func(b *testing.B) { - b.SetBytes(int64(len(buf) * (b.N / testdataSampleCount))) + b.SetBytes(int64(len(buf) * (b.N / promtestdataSampleCount))) b.ReportAllocs() b.ResetTimer() total := 0 - for i := 0; i < b.N; i += testdataSampleCount { + for i := 0; i < b.N; i += promtestdataSampleCount { var ( decSamples = make(model.Vector, 0, 50) ) @@ -450,7 +450,7 @@ func BenchmarkParse(b *testing.B) { } } func BenchmarkGzip(b *testing.B) { - for _, fn := range []string{"testdata.txt", "testdata.nometa.txt"} { + for _, fn := range []string{"promtestdata.txt", "promtestdata.nometa.txt"} { b.Run(fn, func(b *testing.B) { f, err := os.Open(fn) require.NoError(b, err) @@ -466,7 +466,7 @@ func BenchmarkGzip(b *testing.B) { gbuf, err := ioutil.ReadAll(&buf) require.NoError(b, err) - k := b.N / testdataSampleCount + k := b.N / promtestdataSampleCount b.ReportAllocs() b.SetBytes(int64(k) * int64(n)) diff --git a/pkg/textparse/testdata.nometa.txt b/pkg/textparse/promtestdata.nometa.txt similarity index 100% rename from pkg/textparse/testdata.nometa.txt rename to pkg/textparse/promtestdata.nometa.txt diff --git a/pkg/textparse/testdata.txt b/pkg/textparse/promtestdata.txt similarity index 100% rename from pkg/textparse/testdata.txt rename to pkg/textparse/promtestdata.txt diff --git a/scrape/scrape.go b/scrape/scrape.go index f1814b6edc..da447be279 100644 --- a/scrape/scrape.go +++ b/scrape/scrape.go @@ -434,7 +434,7 @@ func appender(app storage.Appender, limit int) storage.Appender { // A scraper retrieves samples and accepts a status report at the end. type scraper interface { - scrape(ctx context.Context, w io.Writer) error + scrape(ctx context.Context, w io.Writer) (string, error) report(start time.Time, dur time.Duration, err error) offset(interval time.Duration) time.Duration } @@ -455,11 +455,11 @@ const acceptHeader = `text/plain;version=0.0.4;q=1,*/*;q=0.1` var userAgentHeader = fmt.Sprintf("Prometheus/%s", version.Version) -func (s *targetScraper) scrape(ctx context.Context, w io.Writer) error { +func (s *targetScraper) scrape(ctx context.Context, w io.Writer) (string, error) { if s.req == nil { req, err := http.NewRequest("GET", s.URL().String(), nil) if err != nil { - return err + return "", err } req.Header.Add("Accept", acceptHeader) req.Header.Add("Accept-Encoding", "gzip") @@ -471,35 +471,38 @@ func (s *targetScraper) scrape(ctx context.Context, w io.Writer) error { resp, err := ctxhttp.Do(ctx, s.client, s.req) if err != nil { - return err + return "", err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return fmt.Errorf("server returned HTTP status %s", resp.Status) + return "", fmt.Errorf("server returned HTTP status %s", resp.Status) } if resp.Header.Get("Content-Encoding") != "gzip" { _, err = io.Copy(w, resp.Body) - return err + return "", err } if s.gzipr == nil { s.buf = bufio.NewReader(resp.Body) s.gzipr, err = gzip.NewReader(s.buf) if err != nil { - return err + return "", err } } else { s.buf.Reset(resp.Body) if err = s.gzipr.Reset(s.buf); err != nil { - return err + return "", err } } _, err = io.Copy(w, s.gzipr) s.gzipr.Close() - return err + if err != nil { + return "", err + } + return resp.Header.Get("Content-Type"), nil } // A loop can run and be stopped again. It must not be reused after it was stopped. @@ -789,7 +792,7 @@ mainLoop: b := sl.buffers.Get(sl.lastScrapeSize).([]byte) buf := bytes.NewBuffer(b) - scrapeErr := sl.scraper.scrape(scrapeCtx, buf) + contentType, scrapeErr := sl.scraper.scrape(scrapeCtx, buf) cancel() if scrapeErr == nil { @@ -809,12 +812,12 @@ mainLoop: // A failed scrape is the same as an empty scrape, // we still call sl.append to trigger stale markers. - total, added, appErr := sl.append(b, start) + total, added, appErr := sl.append(b, contentType, start) if appErr != nil { level.Warn(sl.l).Log("msg", "append failed", "err", appErr) // The append failed, probably due to a parse error or sample limit. // Call sl.append again with an empty scrape to trigger stale markers. - if _, _, err := sl.append([]byte{}, start); err != nil { + if _, _, err := sl.append([]byte{}, "", start); err != nil { level.Warn(sl.l).Log("msg", "append failed", "err", err) } } @@ -885,7 +888,7 @@ func (sl *scrapeLoop) endOfRunStaleness(last time.Time, ticker *time.Ticker, int // Call sl.append again with an empty scrape to trigger stale markers. // If the target has since been recreated and scraped, the // stale markers will be out of order and ignored. - if _, _, err := sl.append([]byte{}, staleTime); err != nil { + if _, _, err := sl.append([]byte{}, "", staleTime); err != nil { level.Error(sl.l).Log("msg", "stale append failed", "err", err) } if err := sl.reportStale(staleTime); err != nil { @@ -921,10 +924,10 @@ func (s samples) Less(i, j int) bool { return s[i].t < s[j].t } -func (sl *scrapeLoop) append(b []byte, ts time.Time) (total, added int, err error) { +func (sl *scrapeLoop) append(b []byte, contentType string, ts time.Time) (total, added int, err error) { var ( app = sl.appender() - p = textparse.New(b) + p = textparse.New(b, contentType) defTime = timestamp.FromTime(ts) numOutOfOrder = 0 numDuplicates = 0 diff --git a/scrape/scrape_test.go b/scrape/scrape_test.go index 380f45489f..f4eda1f7da 100644 --- a/scrape/scrape_test.go +++ b/scrape/scrape_test.go @@ -621,7 +621,7 @@ func TestScrapeLoopMetadata(t *testing.T) { # other comment test_metric 1 # TYPE test_metric_no_help gauge -# HELP test_metric_no_type other help text`), time.Now()) +# HELP test_metric_no_type other help text`), "", time.Now()) testutil.Ok(t, err) testutil.Equals(t, 1, total) @@ -824,7 +824,7 @@ func TestScrapeLoopAppend(t *testing.T) { now := time.Now() - _, _, err := sl.append([]byte(test.scrapeLabels), now) + _, _, err := sl.append([]byte(test.scrapeLabels), "", now) if err != nil { t.Fatalf("Unexpected append error: %s", err) } @@ -870,7 +870,7 @@ func TestScrapeLoopAppendSampleLimit(t *testing.T) { beforeMetricValue := beforeMetric.GetCounter().GetValue() now := time.Now() - _, _, err = sl.append([]byte("metric_a 1\nmetric_b 1\nmetric_c 1\n"), now) + _, _, err = sl.append([]byte("metric_a 1\nmetric_b 1\nmetric_c 1\n"), "", now) if err != errSampleLimit { t.Fatalf("Did not see expected sample limit error: %s", err) } @@ -922,11 +922,11 @@ func TestScrapeLoop_ChangingMetricString(t *testing.T) { ) now := time.Now() - _, _, err = sl.append([]byte(`metric_a{a="1",b="1"} 1`), now) + _, _, err = sl.append([]byte(`metric_a{a="1",b="1"} 1`), "", now) if err != nil { t.Fatalf("Unexpected append error: %s", err) } - _, _, err = sl.append([]byte(`metric_a{b="1",a="1"} 2`), now.Add(time.Minute)) + _, _, err = sl.append([]byte(`metric_a{b="1",a="1"} 2`), "", now.Add(time.Minute)) if err != nil { t.Fatalf("Unexpected append error: %s", err) } @@ -961,11 +961,11 @@ func TestScrapeLoopAppendStaleness(t *testing.T) { ) now := time.Now() - _, _, err := sl.append([]byte("metric_a 1\n"), now) + _, _, err := sl.append([]byte("metric_a 1\n"), "", now) if err != nil { t.Fatalf("Unexpected append error: %s", err) } - _, _, err = sl.append([]byte(""), now.Add(time.Second)) + _, _, err = sl.append([]byte(""), "", now.Add(time.Second)) if err != nil { t.Fatalf("Unexpected append error: %s", err) } @@ -1006,11 +1006,11 @@ func TestScrapeLoopAppendNoStalenessIfTimestamp(t *testing.T) { ) now := time.Now() - _, _, err := sl.append([]byte("metric_a 1 1000\n"), now) + _, _, err := sl.append([]byte("metric_a 1 1000\n"), "", now) if err != nil { t.Fatalf("Unexpected append error: %s", err) } - _, _, err = sl.append([]byte(""), now.Add(time.Second)) + _, _, err = sl.append([]byte(""), "", now.Add(time.Second)) if err != nil { t.Fatalf("Unexpected append error: %s", err) } @@ -1120,7 +1120,7 @@ func TestScrapeLoopAppendGracefullyIfAmendOrOutOfOrderOrOutOfBounds(t *testing.T ) now := time.Unix(1, 0) - _, _, err := sl.append([]byte("out_of_order 1\namend 1\nnormal 1\nout_of_bounds 1\n"), now) + _, _, err := sl.append([]byte("out_of_order 1\namend 1\nnormal 1\nout_of_bounds 1\n"), "", now) if err != nil { t.Fatalf("Unexpected append error: %s", err) } @@ -1153,7 +1153,7 @@ func TestScrapeLoopOutOfBoundsTimeError(t *testing.T) { ) now := time.Now().Add(20 * time.Minute) - total, added, err := sl.append([]byte("normal 1\n"), now) + total, added, err := sl.append([]byte("normal 1\n"), "", now) if total != 1 { t.Error("expected 1 metric") return @@ -1209,7 +1209,7 @@ func TestTargetScraperScrapeOK(t *testing.T) { } var buf bytes.Buffer - if err := ts.scrape(context.Background(), &buf); err != nil { + if _, err := ts.scrape(context.Background(), &buf); err != nil { t.Fatalf("Unexpected scrape error: %s", err) } require.Equal(t, "metric_a 1\nmetric_b 2\n", buf.String()) @@ -1249,7 +1249,7 @@ func TestTargetScrapeScrapeCancel(t *testing.T) { }() go func() { - if err := ts.scrape(ctx, ioutil.Discard); err != context.Canceled { + if _, err := ts.scrape(ctx, ioutil.Discard); err != context.Canceled { errc <- fmt.Errorf("Expected context cancelation error but got: %s", err) } close(errc) @@ -1291,7 +1291,7 @@ func TestTargetScrapeScrapeNotFound(t *testing.T) { client: http.DefaultClient, } - if err := ts.scrape(context.Background(), ioutil.Discard); !strings.Contains(err.Error(), "404") { + if _, err := ts.scrape(context.Background(), ioutil.Discard); !strings.Contains(err.Error(), "404") { t.Fatalf("Expected \"404 NotFound\" error but got: %s", err) } } @@ -1319,9 +1319,9 @@ func (ts *testScraper) report(start time.Time, duration time.Duration, err error ts.lastError = err } -func (ts *testScraper) scrape(ctx context.Context, w io.Writer) error { +func (ts *testScraper) scrape(ctx context.Context, w io.Writer) (string, error) { if ts.scrapeFunc != nil { - return ts.scrapeFunc(ctx, w) + return "", ts.scrapeFunc(ctx, w) } - return ts.scrapeErr + return "", ts.scrapeErr }