mirror of
https://github.com/prometheus/prometheus.git
synced 2025-01-12 06:17:27 -08:00
feat: make push metrics labels generic and repeatable
Signed-off-by: François Gouteroux <francois.gouteroux@gmail.com>
This commit is contained in:
parent
3524a16aa0
commit
934c5ddb8d
|
@ -187,7 +187,7 @@ func main() {
|
||||||
"metric-files",
|
"metric-files",
|
||||||
"The metric files to push, default is read from standard input (STDIN).",
|
"The metric files to push, default is read from standard input (STDIN).",
|
||||||
).ExistingFiles()
|
).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()
|
pushMetricsTimeout := pushMetricsCmd.Flag("timeout", "The time to wait for pushing metrics.").Default("30s").Duration()
|
||||||
pushMetricsHeaders := pushMetricsCmd.Flag("header", "Prometheus remote write header.").StringMap()
|
pushMetricsHeaders := pushMetricsCmd.Flag("header", "Prometheus remote write header.").StringMap()
|
||||||
|
|
||||||
|
@ -315,7 +315,7 @@ func main() {
|
||||||
os.Exit(CheckMetrics(*checkMetricsExtended))
|
os.Exit(CheckMetrics(*checkMetricsExtended))
|
||||||
|
|
||||||
case pushMetricsCmd.FullCommand():
|
case pushMetricsCmd.FullCommand():
|
||||||
os.Exit(PushMetrics(remoteWriteURL, httpRoundTripper, *pushMetricsHeaders, *pushMetricsTimeout, *metricJobLabel, *metricFiles...))
|
os.Exit(PushMetrics(remoteWriteURL, httpRoundTripper, *pushMetricsHeaders, *pushMetricsTimeout, *pushMetricsLabels, *metricFiles...))
|
||||||
|
|
||||||
case queryInstantCmd.FullCommand():
|
case queryInstantCmd.FullCommand():
|
||||||
os.Exit(QueryInstant(serverURL, httpRoundTripper, *queryInstantExpr, *queryInstantTime, p))
|
os.Exit(QueryInstant(serverURL, httpRoundTripper, *queryInstantExpr, *queryInstantTime, p))
|
||||||
|
|
|
@ -32,7 +32,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Push metrics to a prometheus remote write (for testing purpose only).
|
// 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
|
failed := false
|
||||||
|
|
||||||
addressURL, err := url.Parse(url.String())
|
addressURL, err := url.Parse(url.String())
|
||||||
|
@ -76,32 +76,32 @@ func PushMetrics(url *url.URL, roundTripper http.RoundTripper, headers map[strin
|
||||||
if file == "" {
|
if file == "" {
|
||||||
data, err = io.ReadAll(os.Stdin)
|
data, err = io.ReadAll(os.Stdin)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(os.Stderr, err)
|
fmt.Fprintln(os.Stderr, " FAILED:", err)
|
||||||
failed = true
|
failed = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Parsing stdin\n")
|
fmt.Printf("Parsing input from stdin\n")
|
||||||
} else {
|
} else {
|
||||||
data, err = os.ReadFile(file)
|
data, err = os.ReadFile(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(os.Stderr, err)
|
fmt.Fprintln(os.Stderr, " FAILED:", err)
|
||||||
failed = true
|
failed = true
|
||||||
continue
|
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 {
|
if err != nil {
|
||||||
fmt.Fprintln(os.Stderr, err)
|
fmt.Fprintln(os.Stderr, " FAILED:", err)
|
||||||
failed = true
|
failed = true
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
raw, err := metricsData.Marshal()
|
raw, err := metricsData.Marshal()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(os.Stderr, err)
|
fmt.Fprintln(os.Stderr, " FAILED:", err)
|
||||||
failed = true
|
failed = true
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -110,11 +110,16 @@ func PushMetrics(url *url.URL, roundTripper http.RoundTripper, headers map[strin
|
||||||
compressed := snappy.Encode(nil, raw)
|
compressed := snappy.Encode(nil, raw)
|
||||||
err = client.Store(context.Background(), compressed)
|
err = client.Store(context.Background(), compressed)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(os.Stderr, err)
|
fmt.Fprintln(os.Stderr, " FAILED:", err)
|
||||||
failed = true
|
failed = true
|
||||||
continue
|
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 {
|
if failed {
|
||||||
|
|
|
@ -398,7 +398,7 @@ Push metrics to a prometheus remote write (for testing purpose only).
|
||||||
|
|
||||||
| Flag | Description | Default |
|
| Flag | Description | Default |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| <code class="text-nowrap">--job-label</code> | Job label to attach to metrics. | `promtool` |
|
| <code class="text-nowrap">--label</code> | Label to attach to metrics. Can be specified multiple times. | `job=promtool` |
|
||||||
| <code class="text-nowrap">--timeout</code> | The time to wait for pushing metrics. | `30s` |
|
| <code class="text-nowrap">--timeout</code> | The time to wait for pushing metrics. | `30s` |
|
||||||
| <code class="text-nowrap">--header</code> | Prometheus remote write header. | |
|
| <code class="text-nowrap">--header</code> | Prometheus remote write header. | |
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ var MetricMetadataTypeValue = map[string]int32{
|
||||||
}
|
}
|
||||||
|
|
||||||
// FormatMetrics convert metric family to a writerequest.
|
// 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{}
|
wr := &prompb.WriteRequest{}
|
||||||
|
|
||||||
// build metric list
|
// build metric list
|
||||||
|
@ -63,10 +63,15 @@ func FormatMetrics(mf map[string]*dto.MetricFamily, jobLabel string) (*prompb.Wr
|
||||||
var timeserie prompb.TimeSeries
|
var timeserie prompb.TimeSeries
|
||||||
|
|
||||||
// build labels map
|
// 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.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 {
|
for _, label := range metric.Label {
|
||||||
labelname := label.GetName()
|
labelname := label.GetName()
|
||||||
if labelname == model.JobLabel {
|
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.
|
// 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)
|
mf, err := ParseMetricsTextReader(input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return FormatMetrics(mf, jobLabel)
|
return FormatMetrics(mf, labels)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"} 1 1
|
||||||
test_metric1{b="c",baz="qux",d="e",foo="bar"} 2 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.NoError(t, err)
|
||||||
|
|
||||||
require.Equal(t, writeRequestFixture, expected)
|
require.Equal(t, writeRequestFixture, expected)
|
||||||
|
|
Loading…
Reference in a new issue