diff --git a/lib/promscrape/scrapework.go b/lib/promscrape/scrapework.go index 81515c157..160c3b7f3 100644 --- a/lib/promscrape/scrapework.go +++ b/lib/promscrape/scrapework.go @@ -5,6 +5,7 @@ import ( "fmt" "math" "math/bits" + "strconv" "strings" "sync" "time" @@ -121,11 +122,24 @@ func (sw *ScrapeWork) LabelsString() string { } func promLabelsString(labels []prompbmarshal.Label) string { - a := make([]string, 0, len(labels)) + // Calculate the required memory for storing serialized labels. + n := 2 // for `{...}` for _, label := range labels { - a = append(a, fmt.Sprintf("%s=%q", label.Name, label.Value)) + n += len(label.Name) + len(label.Value) + n += 4 // for `="...",` } - return "{" + strings.Join(a, ", ") + "}" + b := make([]byte, 0, n) + b = append(b, '{') + for i, label := range labels { + b = append(b, label.Name...) + b = append(b, '=') + b = strconv.AppendQuote(b, label.Value) + if i+1 < len(labels) { + b = append(b, ',') + } + } + b = append(b, '}') + return bytesutil.ToUnsafeString(b) } type scrapeWork struct { diff --git a/lib/promscrape/scrapework_test.go b/lib/promscrape/scrapework_test.go index 856d3af62..9d1e54f92 100644 --- a/lib/promscrape/scrapework_test.go +++ b/lib/promscrape/scrapework_test.go @@ -11,6 +11,33 @@ import ( parser "github.com/VictoriaMetrics/VictoriaMetrics/lib/protoparser/prometheus" ) +func TestPromLabelsString(t *testing.T) { + f := func(labels []prompbmarshal.Label, resultExpected string) { + t.Helper() + result := promLabelsString(labels) + if result != resultExpected { + t.Fatalf("unexpected result; got\n%s\nwant\n%s", result, resultExpected) + } + } + f([]prompbmarshal.Label{}, "{}") + f([]prompbmarshal.Label{ + { + Name: "foo", + Value: "bar", + }, + }, `{foo="bar"}`) + f([]prompbmarshal.Label{ + { + Name: "foo", + Value: "bar", + }, + { + Name: "a", + Value: `"b"`, + }, + }, `{foo="bar",a="\"b\""}`) +} + func TestScrapeWorkScrapeInternalFailure(t *testing.T) { dataExpected := ` up 0 123