pkg/exporter/probe/legacy.go (208 lines of code) (raw):
package probe
import (
"fmt"
"regexp"
"strings"
"github.com/alibaba/kubeskoop/pkg/exporter/bpfutil"
"github.com/alibaba/kubeskoop/pkg/exporter/nettop"
"github.com/prometheus/client_golang/prometheus"
log "github.com/sirupsen/logrus"
)
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 {
metaPodLabels := []string{nettop.GetNodeName(), entity.GetPodNamespace(), entity.GetPodName()}
return append(metaPodLabels, BuildAdditionalLabelsValues(entity.GetLabels())...)
}
type LegacyMetric struct {
Name string
Help string
}
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) {
var 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 {
module string
collector LegacyCollector
descs map[string]*prometheus.Desc
}
func newMetricsName(module, name string) string {
return prometheus.BuildFQName(MetricsNamespace, module, name)
}
type LegacyCollector func() (map[string]map[uint32]uint64, error)
func NewLegacyBatchMetrics(module string, metrics []LegacyMetric, collector LegacyCollector) prometheus.Collector {
return newLegacyBatchMetrics(module, metrics, collector)
}
func newLegacyBatchMetrics(module string, metrics []LegacyMetric, collector LegacyCollector) prometheus.Collector {
descs := make(map[string]*prometheus.Desc)
for _, m := range metrics {
newName := newMetricsName(module, m.Name)
descs[newName] = prometheus.NewDesc(newName, m.Help, StandardMetricsLabels, nil)
}
return &legacyBatchMetrics{
module: module,
collector: collector,
descs: descs,
}
}
func (l *legacyBatchMetrics) Describe(descs chan<- *prometheus.Desc) {
for _, desc := range l.descs {
descs <- desc
}
}
func (l *legacyBatchMetrics) Collect(metrics chan<- prometheus.Metric) {
log.Debugf("collect data from %s", l.module)
data, err := l.collector()
if err != nil {
log.Errorf("%s failed collect data, err: %v", l.module, err)
return
}
emit := func(name string, labelValues []string, value float64) {
desc, ok := l.descs[name]
if !ok {
return
}
metrics <- prometheus.MustNewConstMetric(desc, prometheus.GaugeValue, float64(value), labelValues...)
}
for key, namespaceData := range data {
for nsinum, value := range namespaceData {
et, err := nettop.GetEntityByNetns(int(nsinum))
if err != nil || et == nil {
continue
}
labelValues := BuildStandardMetricsLabelValues(et)
emit(newMetricsName(l.module, key), labelValues, float64(value))
}
}
}
func LegacyEventLabels(netns uint32) []Label {
et, err := nettop.GetEntityByNetns(int(netns))
if err != nil || et == nil {
log.Infof("nettop get entity failed, netns: %d, err: %v", netns, err)
return nil
}
return []Label{
{Name: "pod", Value: et.GetPodName()},
{Name: "namespace", Value: et.GetPodNamespace()},
{Name: "node", Value: nettop.GetNodeName()},
}
}
func BuildTupleMetricsLabels(tuple *Tuple) []string {
ipInfo := func(ip string) []string {
info := nettop.GetIPInfo(ip)
if info == nil {
return []string{"unknown", "", "", ""}
}
switch info.Type {
case nettop.IPTypeNode:
return []string{"node", info.NodeName, "", ""}
case nettop.IPTypePod:
return []string{"pod", "", info.PodNamespace, info.PodName}
default:
log.Warningf("unknown ip type %s for %s", ip, info.Type)
}
return []string{"unknown", "", "", ""}
}
labels := []string{bpfutil.GetProtoStr(tuple.Protocol)}
labels = append(labels, tuple.Src)
labels = append(labels, ipInfo(tuple.Src)...)
labels = append(labels, tuple.Dst)
labels = append(labels, ipInfo(tuple.Dst)...)
labels = append(labels, fmt.Sprintf("%d", tuple.Sport))
labels = append(labels, fmt.Sprintf("%d", tuple.Dport))
return labels
}
func BuildTupleEventLabels(tuple *Tuple) []Label {
ipInfo := func(prefix, ip string) (ret []Label) {
var values [4]string
defer func() {
ret = []Label{
{Name: prefix + "_type", Value: values[0]},
{Name: prefix + "_node", Value: values[1]},
{Name: prefix + "_namespace", Value: values[2]},
{Name: prefix + "_pod", Value: values[3]},
}
}()
info := nettop.GetIPInfo(ip)
if info == nil {
values = [...]string{"unknown", "", "", ""}
return
}
switch info.Type {
case nettop.IPTypeNode:
values = [...]string{"node", info.NodeName, "", ""}
case nettop.IPTypePod:
values = [...]string{"pod", "", info.PodNamespace, info.PodName}
default:
log.Warningf("unknown ip type %s for %s", ip, info.Type)
}
values = [...]string{"unknown", "", "", ""}
return
}
labels := []Label{
{Name: "protocol", Value: bpfutil.GetProtoStr(tuple.Protocol)},
}
labels = append(labels, Label{
Name: "src", Value: tuple.Src,
})
labels = append(labels, ipInfo("src", tuple.Src)...)
labels = append(labels, Label{
Name: "dst", Value: tuple.Dst,
})
labels = append(labels, ipInfo("dst", tuple.Dst)...)
labels = append(labels, Label{
Name: "sport", Value: fmt.Sprintf("%d", tuple.Sport),
})
labels = append(labels, Label{
Name: "dport", Value: fmt.Sprintf("%d", tuple.Dport),
})
return labels
}
func CopyLegacyMetricsMap(m map[string]map[uint32]uint64) map[string]map[uint32]uint64 {
ret := make(map[string]map[uint32]uint64)
for key, nsMap := range m {
ret[key] = make(map[uint32]uint64)
for ns, data := range nsMap {
ret[key][ns] = data
}
}
return ret
}