gVisor metric library: Verify path-style metric names.

The `unimplemented_syscalls` metric did not conform (whoops), so fix that one.

PiperOrigin-RevId: 539767799
This commit is contained in:
Etienne Perot
2023-06-12 14:53:17 -07:00
committed by gVisor bot
parent bb105d7a4e
commit 0d246232ab
3 changed files with 48 additions and 1 deletions
+21
View File
@@ -19,6 +19,7 @@ import (
"errors"
"fmt"
"math"
re "regexp"
"sort"
"strings"
"time"
@@ -486,6 +487,20 @@ func nameToPrometheusName(name string) string {
return strings.ReplaceAll(strings.TrimPrefix(name, "/"), "/", "_")
}
var validMetricNameRegexp = re.MustCompile("^(?:/[_\\w]+)+$")
// verifyName verifies that the given metric name is a valid path-style metric
// name.
func verifyName(name string) error {
if !strings.HasPrefix(name, "/") {
return fmt.Errorf("metric name must start with a '/': %q", name)
}
if !validMetricNameRegexp.MatchString(name) {
return fmt.Errorf("invalid metric name: %q", name)
}
return nil
}
// RegisterCustomUint64Metric registers a metric with the given name.
//
// Register must only be called at init and will return and error if called
@@ -555,6 +570,9 @@ func MustRegisterCustomUint64Metric(name string, cumulative, sync bool, descript
//
// Metrics must be statically defined (i.e., at init).
func NewUint64Metric(name string, sync bool, units pb.MetricMetadata_Units, description string, fields ...Field) (*Uint64Metric, error) {
if err := verifyName(name); err != nil {
return nil, err
}
f, err := newFieldMapper(fields...)
if err != nil {
return nil, err
@@ -832,6 +850,9 @@ type DistributionMetric struct {
// NewDistributionMetric creates and registers a new distribution metric.
func NewDistributionMetric(name string, sync bool, bucketer Bucketer, unit pb.MetricMetadata_Units, description string, fields ...Field) (*DistributionMetric, error) {
if err := verifyName(name); err != nil {
return nil, err
}
if initialized.Load() {
return nil, ErrInitializationDone
}
+26
View File
@@ -66,6 +66,32 @@ func verifyPrometheusParsing(t *testing.T) {
}
}
func TestVerifyName(t *testing.T) {
for name, wantErr := range map[string]bool{
"": true,
"/": true,
"/foo": false,
"/foo/bar": false,
"/foo/bar/baz": false,
"/foo/bar/bar": false,
"/foo//bar/baz": true,
"//foo/bar": true,
"//": true,
"foo": true,
"foo/bar": true,
"/foo-bar": true,
"/foo bar": true,
"/foo_bar": false,
} {
t.Run(name, func(t *testing.T) {
err := verifyName(name)
if gotErr := (err != nil); gotErr != wantErr {
t.Errorf("verifyName(%q) got err=%v wantErr=%v", name, err, wantErr)
}
})
}
}
func TestInitialize(t *testing.T) {
defer resetTest()
+1 -1
View File
@@ -402,7 +402,7 @@ func RegisterSyscallTable(s *SyscallTable) {
unimplementedSyscallNumbers[i] = []*metric.FieldValue{s}
}
allowedValues[len(allowedValues)-1] = outOfRangeSyscallNumber[0]
unimplementedSyscallCounter = metric.MustCreateNewUint64Metric("unimplemented_syscalls", true, "Number of times the application tried to call an unimplemented syscall, broken down by syscall number", metric.NewField("sysno", allowedValues...))
unimplementedSyscallCounter = metric.MustCreateNewUint64Metric("/unimplemented_syscalls", true, "Number of times the application tried to call an unimplemented syscall, broken down by syscall number", metric.NewField("sysno", allowedValues...))
})
s.Init()
}