mirror of
https://github.com/prometheus/prometheus.git
synced 2024-12-24 21:24:05 -08:00
feat: enhance stdin check and add tests parsing error
Signed-off-by: François Gouteroux <francois.gouteroux@gmail.com>
This commit is contained in:
parent
ca6580828a
commit
6ae4a46845
|
@ -185,7 +185,7 @@ func main() {
|
|||
pushMetricsCmd.Arg("remote-write-url", "Prometheus remote write url to push metrics.").Required().URLVar(&remoteWriteURL)
|
||||
metricFiles := pushMetricsCmd.Arg(
|
||||
"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.",
|
||||
).ExistingFiles()
|
||||
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()
|
||||
|
|
|
@ -33,8 +33,6 @@ 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, labels map[string]string, files ...string) int {
|
||||
failed := false
|
||||
|
||||
addressURL, err := url.Parse(url.String())
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
|
@ -63,63 +61,37 @@ func PushMetrics(url *url.URL, roundTripper http.RoundTripper, headers map[strin
|
|||
headers: headers,
|
||||
}
|
||||
|
||||
// add empty string to avoid matching filename
|
||||
var data []byte
|
||||
var failed bool
|
||||
|
||||
if len(files) == 0 {
|
||||
files = append(files, "")
|
||||
data, err = io.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, " FAILED:", err)
|
||||
return failureExitCode
|
||||
}
|
||||
fmt.Printf("Parsing standard input\n")
|
||||
if parseAndPushMetrics(client, data, labels) {
|
||||
fmt.Printf(" SUCCESS: metrics pushed to remote write.\n")
|
||||
return successExitCode
|
||||
}
|
||||
return failureExitCode
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
var data []byte
|
||||
var err error
|
||||
|
||||
// if file is an empty string it is a stdin
|
||||
if file == "" {
|
||||
data, err = io.ReadAll(os.Stdin)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, " FAILED:", err)
|
||||
failed = true
|
||||
break
|
||||
}
|
||||
|
||||
fmt.Printf("Parsing input from stdin\n")
|
||||
} else {
|
||||
data, err = os.ReadFile(file)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, " FAILED:", err)
|
||||
failed = true
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Printf("Parsing input from metric file %s\n", file)
|
||||
}
|
||||
metricsData, err := fmtutil.ParseMetricsTextAndFormat(bytes.NewReader(data), labels)
|
||||
data, err = os.ReadFile(file)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, " FAILED:", err)
|
||||
failed = true
|
||||
continue
|
||||
}
|
||||
|
||||
raw, err := metricsData.Marshal()
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, " FAILED:", err)
|
||||
failed = true
|
||||
fmt.Printf("Parsing metrics file %s\n", file)
|
||||
if parseAndPushMetrics(client, data, labels) {
|
||||
fmt.Printf(" SUCCESS: metrics file %s pushed to remote write.\n", file)
|
||||
continue
|
||||
}
|
||||
|
||||
// Encode the request body into snappy encoding.
|
||||
compressed := snappy.Encode(nil, raw)
|
||||
err = client.Store(context.Background(), compressed)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, " FAILED:", err)
|
||||
failed = true
|
||||
continue
|
||||
}
|
||||
|
||||
if file == "" {
|
||||
fmt.Printf(" SUCCESS: metric pushed to remote write.\n")
|
||||
} else {
|
||||
fmt.Printf(" SUCCESS: metric file %s pushed to remote write.\n", file)
|
||||
}
|
||||
failed = true
|
||||
}
|
||||
|
||||
if failed {
|
||||
|
@ -129,6 +101,30 @@ func PushMetrics(url *url.URL, roundTripper http.RoundTripper, headers map[strin
|
|||
return successExitCode
|
||||
}
|
||||
|
||||
func parseAndPushMetrics(client *remote.Client, data []byte, labels map[string]string) bool {
|
||||
metricsData, err := fmtutil.ParseMetricsTextAndFormat(bytes.NewReader(data), labels)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, " FAILED:", err)
|
||||
return false
|
||||
}
|
||||
|
||||
raw, err := metricsData.Marshal()
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, " FAILED:", err)
|
||||
return false
|
||||
}
|
||||
|
||||
// Encode the request body into snappy encoding.
|
||||
compressed := snappy.Encode(nil, raw)
|
||||
err = client.Store(context.Background(), compressed)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, " FAILED:", err)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
type setHeadersTransport struct {
|
||||
http.RoundTripper
|
||||
headers map[string]string
|
||||
|
|
|
@ -410,7 +410,7 @@ Push metrics to a prometheus remote write (for testing purpose only).
|
|||
| Argument | Description | Required |
|
||||
| --- | --- | --- |
|
||||
| remote-write-url | Prometheus remote write url to push metrics. | Yes |
|
||||
| metric-files | The metric files to push, default is read from standard input (STDIN). | |
|
||||
| metric-files | The metric files to push, default is read from standard input. | |
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -173,7 +173,7 @@ var writeRequestFixture = &prompb.WriteRequest{
|
|||
},
|
||||
}
|
||||
|
||||
func TestParseMetricsTextAndFormat(t *testing.T) {
|
||||
func TestParseAndPushMetricsTextAndFormat(t *testing.T) {
|
||||
input := bytes.NewReader([]byte(`
|
||||
# HELP http_request_duration_seconds A histogram of the request duration.
|
||||
# TYPE http_request_duration_seconds histogram
|
||||
|
@ -206,3 +206,28 @@ func TestParseMetricsTextAndFormat(t *testing.T) {
|
|||
|
||||
require.Equal(t, writeRequestFixture, expected)
|
||||
}
|
||||
|
||||
func TestParseMetricsTextAndFormatErrorParsingFloatValue(t *testing.T) {
|
||||
input := bytes.NewReader([]byte(`
|
||||
# HELP http_requests_total The total number of HTTP requests.
|
||||
# TYPE http_requests_total counter
|
||||
http_requests_total{method="post",code="200"} 1027Error 1395066363000
|
||||
http_requests_total{method="post",code="400"} 3 1395066363000
|
||||
`))
|
||||
labels := map[string]string{"job": "promtool"}
|
||||
|
||||
_, err := ParseMetricsTextAndFormat(input, labels)
|
||||
require.Equal(t, err.Error(), "text format parsing error in line 4: expected float as value, got \"1027Error\"")
|
||||
}
|
||||
|
||||
func TestParseMetricsTextAndFormatErrorParsingMetricType(t *testing.T) {
|
||||
input := bytes.NewReader([]byte(`
|
||||
# HELP node_info node info summary.
|
||||
# TYPE node_info info
|
||||
node_info{test="summary"} 1 1395066363000
|
||||
`))
|
||||
labels := map[string]string{"job": "promtool"}
|
||||
|
||||
_, err := ParseMetricsTextAndFormat(input, labels)
|
||||
require.Equal(t, err.Error(), "text format parsing error in line 3: unknown metric type \"info\"")
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue