fix/msp: flatten custom alert promQL query for GCP (#63084)

The GCP monitoring alert configuration expects, for some reason, a
single-line PromQL query only, otherwise the threshold doesn't work. In
configuration, however, we may want to write a multi-line query, for
ease of readability. This change automatically flattens the PromQL query
into a single line and strips extra spaces.

Part of CORE-161

## Test plan

Unit tests
This commit is contained in:
Robert Lin 2024-06-04 14:37:51 -07:00 committed by GitHub
parent 7d35662a59
commit a3fe573b59
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 67 additions and 3 deletions

View File

@ -29,6 +29,7 @@ go_test(
name = "alertpolicy_test",
srcs = [
"conditionbuilder_test.go",
"customalert_test.go",
"responsecode_test.go",
],
embed = [":alertpolicy"],

View File

@ -1,6 +1,9 @@
package alertpolicy
import (
"fmt"
"strings"
"github.com/sourcegraph/managed-services-platform-cdktf/gen/google/monitoringalertpolicy"
"github.com/sourcegraph/sourcegraph/dev/managedservicesplatform/spec"
@ -26,11 +29,18 @@ func newCustomAlertCondition(config *Config) *monitoringalertpolicy.MonitoringAl
return &monitoringalertpolicy.MonitoringAlertPolicyConditions{
DisplayName: pointers.Ptr(config.Name),
ConditionPrometheusQueryLanguage: &monitoringalertpolicy.MonitoringAlertPolicyConditionsConditionPrometheusQueryLanguage{
Query: pointers.Ptr(config.CustomAlert.Query),
Query: pointers.Ptr(flattenPromQLQuery(config.CustomAlert.Query)),
Duration: pointers.Stringf("%ds", *config.CustomAlert.DurationMinutes*60),
},
}
default:
panic(fmt.Sprintf("unknown custom alert type %q", config.CustomAlert.Type))
}
return nil
}
// GCP monitoring expects PromQL queries to be on a single line, so we do that
// automatically and also strip extra spaces for readability of the condensed
// version.
func flattenPromQLQuery(query string) string {
return strings.Join(strings.Fields(strings.ReplaceAll(query, "\n", " ")), " ")
}

View File

@ -0,0 +1,53 @@
package alertpolicy
import (
"testing"
"github.com/hexops/autogold/v2"
)
func TestFlattenPromQLQuery(t *testing.T) {
for _, tc := range []struct {
name string
query string
want autogold.Value
}{{
name: "simple query",
query: "sum(rate(foo[1m]))",
want: autogold.Expect("sum(rate(foo[1m]))"),
}, {
name: "complex query",
query: ` (
sum by (rpc_error_service_method) (
label_join(
rate(workload_googleapis_com:rpc_server_requests_per_rpc_count{
monitored_resource="generic_task",
rpc_connect_rpc_error_code!=""
}[30m]),
"rpc_error_service_method",
"/",
"rpc_connect_rpc_error_code", "rpc_service", "rpc_method"
)
)
/
ignoring(rpc_error_service_method) group_left
sum by (rpc_error_service_method) (
label_join(
rate(workload_googleapis_com:rpc_server_requests_per_rpc_count{
monitored_resource="generic_task",
rpc_connect_rpc_error_code=""
}[30m]),
"rpc_service_method_error",
"/",
"rpc_service", "rpc_method", "rpc_connect_rpc_error_code"
)
)
) > 0.2`,
want: autogold.Expect(`( sum by (rpc_error_service_method) ( label_join( rate(workload_googleapis_com:rpc_server_requests_per_rpc_count{ monitored_resource="generic_task", rpc_connect_rpc_error_code!="" }[30m]), "rpc_error_service_method", "/", "rpc_connect_rpc_error_code", "rpc_service", "rpc_method" ) ) / ignoring(rpc_error_service_method) group_left sum by (rpc_error_service_method) ( label_join( rate(workload_googleapis_com:rpc_server_requests_per_rpc_count{ monitored_resource="generic_task", rpc_connect_rpc_error_code="" }[30m]), "rpc_service_method_error", "/", "rpc_service", "rpc_method", "rpc_connect_rpc_error_code" ) ) ) > 0.2`),
}} {
t.Run(tc.name, func(t *testing.T) {
got := flattenPromQLQuery(tc.query)
tc.want.Equal(t, got)
})
}
}