From 4578e297a8848d0c00535dae82478e7b0ecbd4d1 Mon Sep 17 00:00:00 2001 From: halleystar <1247920356@qq.com> Date: Thu, 9 May 2024 14:38:23 +0800 Subject: [PATCH] feat(metrics): add additional labels to metrics feat(metrics): change additionalLabelsArray to array and use regex to extract labels feat(metrics): add unit tests for BuildAdditionalLabelsValues function feat(metrics): add err return value check. --- pkg/exporter/cmd/config.go | 3 +- pkg/exporter/cmd/server.go | 6 +++ pkg/exporter/nettop/cache.go | 7 ++++ pkg/exporter/probe/legacy.go | 63 +++++++++++++++++++++++++++++-- pkg/exporter/probe/legacy_test.go | 38 +++++++++++++++++++ 5 files changed, 113 insertions(+), 4 deletions(-) create mode 100644 pkg/exporter/probe/legacy_test.go diff --git a/pkg/exporter/cmd/config.go b/pkg/exporter/cmd/config.go index 1902f2b7..0c2deadd 100644 --- a/pkg/exporter/cmd/config.go +++ b/pkg/exporter/cmd/config.go @@ -16,7 +16,8 @@ type InspServerConfig struct { } type MetricsConfig struct { - Probes []ProbeConfig `yaml:"probes" mapstructure:"probes" json:"probes"` + Probes []ProbeConfig `yaml:"probes" mapstructure:"probes" json:"probes"` + AdditionalLabels []string `yaml:"additionalLabels" mapstructure:"additionalLabels" json:"additionalLabels"` } type EventConfig struct { diff --git a/pkg/exporter/cmd/server.go b/pkg/exporter/cmd/server.go index 3bc88989..dcb92267 100644 --- a/pkg/exporter/cmd/server.go +++ b/pkg/exporter/cmd/server.go @@ -289,6 +289,12 @@ func (i *inspServer) start(cfg *InspServerConfig) error { var err error ctx := context.TODO() + err = probe.InitAdditionalLabels(cfg.MetricsConfig.AdditionalLabels) + if err != nil { + log.Errorf("failed init additional labels: %v", err) + return + } + log.Infof("start metrics server") i.metricsServer, err = NewMetricsServer() if err != nil { diff --git a/pkg/exporter/nettop/cache.go b/pkg/exporter/nettop/cache.go index bfef46de..e202cc5e 100644 --- a/pkg/exporter/nettop/cache.go +++ b/pkg/exporter/nettop/cache.go @@ -163,6 +163,7 @@ type Entity struct { podMeta initPid int pids []int + labels map[string]string } func (e *Entity) String() string { @@ -177,6 +178,10 @@ func (e *Entity) GetPodNamespace() string { return e.podMeta.namespace } +func (e *Entity) GetLabels() map[string]string { + return e.labels +} + func (e *Entity) IsHostNetwork() bool { return e.netnsMeta.isHostNetwork } @@ -353,6 +358,7 @@ func cacheNetTopology(ctx context.Context) error { namespace := sandbox.Metadata.Namespace name := sandbox.Metadata.Name + labels := sandbox.Labels sandboxStatus, err := criClient.PodSandboxStatus(sandbox.Id, true) if err != nil { @@ -411,6 +417,7 @@ func cacheNetTopology(ctx context.Context) error { namespace: namespace, }, initPid: info.Pid, + labels: labels, pids: pids, } diff --git a/pkg/exporter/probe/legacy.go b/pkg/exporter/probe/legacy.go index eedee500..c991a232 100644 --- a/pkg/exporter/probe/legacy.go +++ b/pkg/exporter/probe/legacy.go @@ -2,6 +2,8 @@ package probe import ( "fmt" + "regexp" + "strings" "github.com/alibaba/kubeskoop/pkg/exporter/bpfutil" "github.com/alibaba/kubeskoop/pkg/exporter/nettop" @@ -12,9 +14,63 @@ import ( var legacyMetricsLabels = []string{"target_node", "target_namespace", "target_pod", "node", "namespace", "pod"} var StandardMetricsLabels = []string{"k8s_node", "k8s_namespace", "k8s_pod"} var TupleMetricsLabels = []string{"protocol", "src", "src_type", "src_node", "src_namespace", "src_pod", "dst", "dst_type", "dst_node", "dst_namespace", "dst_pod", "sport", "dport"} +var AdditionalLabelValueExpr []string func BuildStandardMetricsLabelValues(entity *nettop.Entity) []string { - return []string{nettop.GetNodeName(), entity.GetPodNamespace(), entity.GetPodName()} + metaPodLabels := []string{nettop.GetNodeName(), entity.GetPodNamespace(), entity.GetPodName()} + return append(metaPodLabels, BuildAdditionalLabelsValues(entity.GetLabels())...) +} + +func InitAdditionalLabels(additionalLabels []string) error { + if len(additionalLabels) == 0 { + return nil + } + + //append to StandardMetricsLabels and AdditionalLabelValueExpr + for additionalKV := range additionalLabels { + labelKVPair := strings.Split(additionalLabels[additionalKV], "=") + StandardMetricsLabels = append(StandardMetricsLabels, strings.TrimSpace(labelKVPair[0])) + AdditionalLabelValueExpr = append(AdditionalLabelValueExpr, strings.TrimSpace(labelKVPair[1])) + } + + return nil +} + +func BuildAdditionalLabelsValues(podLabels map[string]string) []string { + if len(AdditionalLabelValueExpr) == 0 { + return []string{} + } + + var values []string + + var replaceAllStringSubmatchFunc = func(re *regexp.Regexp, str string, repl func([]string) string) string { + result := "" + lastIndex := 0 + + for _, v := range re.FindAllSubmatchIndex([]byte(str), -1) { + groups := []string{} + for i := 0; i < len(v); i += 2 { + groups = append(groups, str[v[i]:v[i+1]]) + } + + result += str[lastIndex:v[0]] + repl(groups) + lastIndex = v[1] + } + + return result + str[lastIndex:] + } + + for _, labelValueExpr := range AdditionalLabelValueExpr { + podLabelValue := replaceAllStringSubmatchFunc(regexp.MustCompile(`\${labels:(.*?)}`), labelValueExpr, func(groups []string) string { + if podLabelValue, ok := podLabels[groups[1]]; ok { + return podLabelValue + } + return "" + }) + values = append(values, podLabelValue) + } + + return values } type legacyBatchMetrics struct { @@ -89,11 +145,12 @@ func (l *legacyBatchMetrics) Collect(metrics chan<- prometheus.Metric) { if err != nil || et == nil { continue } - labelValues := []string{nettop.GetNodeName(), et.GetPodNamespace(), et.GetPodName()} + labelValues := BuildStandardMetricsLabelValues(et) // for legacy pod labels emit(newMetricsName(l.module, key), labelValues, float64(value)) - labelValues = append(labelValues, labelValues...) + var metaPodData = []string{nettop.GetNodeName(), et.GetPodNamespace(), et.GetPodName()} + labelValues = append(metaPodData, metaPodData...) emit(legacyMetricsName(l.module, key, l.underscore), labelValues, float64(value)) } } diff --git a/pkg/exporter/probe/legacy_test.go b/pkg/exporter/probe/legacy_test.go new file mode 100644 index 00000000..23d377d6 --- /dev/null +++ b/pkg/exporter/probe/legacy_test.go @@ -0,0 +1,38 @@ +package probe + +import ( + "reflect" + "testing" +) + +func TestBuildAdditionalLabelsValues1(t *testing.T) { + type args struct { + podLabels map[string]string + additionalLabels []string + } + tests := []struct { + name string + args args + want []string + }{ + {"common", args{map[string]string{"l1": "v1", "l2": "v2"}, []string{"n1=alv1", "n2=alv2"}}, []string{"alv1", "alv2"}}, + {"match", args{map[string]string{"l1": "v1", "l2": "v2"}, []string{"n1=${labels:l1}", "n2=alv2"}}, []string{"v1", "alv2"}}, + {"submatch", args{map[string]string{"l1": "v1", "l2": "v2"}, []string{"n1=prefix_${labels:l1}_${labels:l2}_suffix"}}, []string{"prefix_v1_v2_suffix"}}, + {"nomatch", args{map[string]string{"l1": "v1", "l2": "v2"}, []string{"n1=${labels:ln}"}}, []string{""}}, + {"empty", args{map[string]string{"l1": "v1", "l2": "v2"}, []string{}}, []string{}}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + AdditionalLabelValueExpr = []string{} + err := InitAdditionalLabels(tt.args.additionalLabels) + if err != nil { + t.Error(err) + return + } + + if got := BuildAdditionalLabelsValues(tt.args.podLabels); !reflect.DeepEqual(got, tt.want) { + t.Errorf("BuildAdditionalLabelsValues() = %v, want %v", got, tt.want) + } + }) + } +}