diff --git a/cmd/promtool/main.go b/cmd/promtool/main.go
index 3b5ba78e4c..c76790e13b 100644
--- a/cmd/promtool/main.go
+++ b/cmd/promtool/main.go
@@ -187,7 +187,7 @@ func main() {
"metric-files",
"The metric files to push, default is read from standard input (STDIN).",
).ExistingFiles()
- metricJobLabel := pushMetricsCmd.Flag("job-label", "Job label to attach to metrics.").Default("promtool").String()
+ pushMetricsLabels := pushMetricsCmd.Flag("label", "Label to attach to metrics. Can be specified multiple times.").Default("job=promtool").StringMap()
pushMetricsTimeout := pushMetricsCmd.Flag("timeout", "The time to wait for pushing metrics.").Default("30s").Duration()
pushMetricsHeaders := pushMetricsCmd.Flag("header", "Prometheus remote write header.").StringMap()
@@ -315,7 +315,7 @@ func main() {
os.Exit(CheckMetrics(*checkMetricsExtended))
case pushMetricsCmd.FullCommand():
- os.Exit(PushMetrics(remoteWriteURL, httpRoundTripper, *pushMetricsHeaders, *pushMetricsTimeout, *metricJobLabel, *metricFiles...))
+ os.Exit(PushMetrics(remoteWriteURL, httpRoundTripper, *pushMetricsHeaders, *pushMetricsTimeout, *pushMetricsLabels, *metricFiles...))
case queryInstantCmd.FullCommand():
os.Exit(QueryInstant(serverURL, httpRoundTripper, *queryInstantExpr, *queryInstantTime, p))
diff --git a/cmd/promtool/metrics.go b/cmd/promtool/metrics.go
index c845b5a587..8abe32cf41 100644
--- a/cmd/promtool/metrics.go
+++ b/cmd/promtool/metrics.go
@@ -32,7 +32,7 @@ import (
)
// Push metrics to a prometheus remote write (for testing purpose only).
-func PushMetrics(url *url.URL, roundTripper http.RoundTripper, headers map[string]string, timeout time.Duration, jobLabel string, files ...string) int {
+func PushMetrics(url *url.URL, roundTripper http.RoundTripper, headers map[string]string, timeout time.Duration, labels map[string]string, files ...string) int {
failed := false
addressURL, err := url.Parse(url.String())
@@ -76,32 +76,32 @@ func PushMetrics(url *url.URL, roundTripper http.RoundTripper, headers map[strin
if file == "" {
data, err = io.ReadAll(os.Stdin)
if err != nil {
- fmt.Fprintln(os.Stderr, err)
+ fmt.Fprintln(os.Stderr, " FAILED:", err)
failed = true
break
}
- fmt.Printf("Parsing stdin\n")
+ fmt.Printf("Parsing input from stdin\n")
} else {
data, err = os.ReadFile(file)
if err != nil {
- fmt.Fprintln(os.Stderr, err)
+ fmt.Fprintln(os.Stderr, " FAILED:", err)
failed = true
continue
}
- fmt.Printf("Parsing metric file %s\n", file)
+ fmt.Printf("Parsing input from metric file %s\n", file)
}
- metricsData, err := fmtutil.ParseMetricsTextAndFormat(bytes.NewReader(data), jobLabel)
+ metricsData, err := fmtutil.ParseMetricsTextAndFormat(bytes.NewReader(data), labels)
if err != nil {
- fmt.Fprintln(os.Stderr, err)
+ fmt.Fprintln(os.Stderr, " FAILED:", err)
failed = true
continue
}
raw, err := metricsData.Marshal()
if err != nil {
- fmt.Fprintln(os.Stderr, err)
+ fmt.Fprintln(os.Stderr, " FAILED:", err)
failed = true
continue
}
@@ -110,11 +110,16 @@ func PushMetrics(url *url.URL, roundTripper http.RoundTripper, headers map[strin
compressed := snappy.Encode(nil, raw)
err = client.Store(context.Background(), compressed)
if err != nil {
- fmt.Fprintln(os.Stderr, err)
+ fmt.Fprintln(os.Stderr, " FAILED:", err)
failed = true
continue
}
- fmt.Printf("Successfully pushed metric file %s\n", file)
+
+ if file == "" {
+ fmt.Printf(" SUCCESS: metric pushed to remote write.\n")
+ } else {
+ fmt.Printf(" SUCCESS: metric file %s pushed to remote write.\n", file)
+ }
}
if failed {
diff --git a/docs/command-line/promtool.md b/docs/command-line/promtool.md
index 024c71e51a..c78900b991 100644
--- a/docs/command-line/promtool.md
+++ b/docs/command-line/promtool.md
@@ -398,7 +398,7 @@ Push metrics to a prometheus remote write (for testing purpose only).
| Flag | Description | Default |
| --- | --- | --- |
-| --job-label
| Job label to attach to metrics. | `promtool` |
+| --label
| Label to attach to metrics. Can be specified multiple times. | `job=promtool` |
| --timeout
| The time to wait for pushing metrics. | `30s` |
| --header
| Prometheus remote write header. | |
diff --git a/util/fmtutil/format.go b/util/fmtutil/format.go
index 9a06d6bb15..b5bb9469ce 100644
--- a/util/fmtutil/format.go
+++ b/util/fmtutil/format.go
@@ -38,7 +38,7 @@ var MetricMetadataTypeValue = map[string]int32{
}
// FormatMetrics convert metric family to a writerequest.
-func FormatMetrics(mf map[string]*dto.MetricFamily, jobLabel string) (*prompb.WriteRequest, error) {
+func FormatMetrics(mf map[string]*dto.MetricFamily, extraLabels map[string]string) (*prompb.WriteRequest, error) {
wr := &prompb.WriteRequest{}
// build metric list
@@ -63,10 +63,15 @@ func FormatMetrics(mf map[string]*dto.MetricFamily, jobLabel string) (*prompb.Wr
var timeserie prompb.TimeSeries
// build labels map
- labels := make(map[string]string, len(metric.Label)+2)
+ labels := make(map[string]string, len(metric.Label)+len(extraLabels))
labels[model.MetricNameLabel] = metricName
- labels[model.JobLabel] = jobLabel
+ // add extra labels
+ for key, value := range extraLabels {
+ labels[key] = value
+ }
+
+ // add metric labels
for _, label := range metric.Label {
labelname := label.GetName()
if labelname == model.JobLabel {
@@ -133,10 +138,10 @@ func ParseMetricsTextReader(input io.Reader) (map[string]*dto.MetricFamily, erro
}
// ParseMetricsTextAndFormat return the data in the expected prometheus metrics write request format.
-func ParseMetricsTextAndFormat(input io.Reader, jobLabel string) (*prompb.WriteRequest, error) {
+func ParseMetricsTextAndFormat(input io.Reader, labels map[string]string) (*prompb.WriteRequest, error) {
mf, err := ParseMetricsTextReader(input)
if err != nil {
return nil, err
}
- return FormatMetrics(mf, jobLabel)
+ return FormatMetrics(mf, labels)
}
diff --git a/util/fmtutil/format_test.go b/util/fmtutil/format_test.go
index ef3b7fcd40..9deed2de90 100644
--- a/util/fmtutil/format_test.go
+++ b/util/fmtutil/format_test.go
@@ -63,8 +63,9 @@ func TestParseMetricsTextAndFormat(t *testing.T) {
test_metric1{b="c",baz="qux",d="e",foo="bar"} 1 1
test_metric1{b="c",baz="qux",d="e",foo="bar"} 2 1
`))
+ labels := map[string]string{"job": "promtool"}
- expected, err := ParseMetricsTextAndFormat(input, "promtool")
+ expected, err := ParseMetricsTextAndFormat(input, labels)
require.NoError(t, err)
require.Equal(t, writeRequestFixture, expected)