Page MenuHomePhabricator
Paste P17094

https://phabricator.wikimedia.org/T210137
ActivePublic

Authored by fgiunchedi on Aug 27 2021, 12:50 PM.
Tags
None
Referenced Files
F34621973: https://phabricator.wikimedia.org/T210137
Aug 27 2021, 12:50 PM
Subscribers
None
commit 397df33ef280b37c1680b5098c6355cc337bad37
Author: Filippo Giunchedi <filippo@wikimedia.org>
Date: Fri Aug 27 14:49:55 2021 +0200
Add mmkubernetes support
Change-Id: I8e8d4d49968dc0d2b637a2b9a4479b44580ad64e
diff --git a/exporter.go b/exporter.go
index c2a0630..eb4faad 100644
--- a/exporter.go
+++ b/exporter.go
@@ -23,6 +23,7 @@ const (
rsyslogDynafileCache
rsyslogInputIMDUP
rsyslogForward
+ rsyslogKubernetes
)
type rsyslogExporter struct {
@@ -121,6 +122,14 @@ func (re *rsyslogExporter) handleStatLine(rawbuf []byte) error {
for _, p := range f.toPoints() {
re.set(p)
}
+ case rsyslogKubernetes:
+ k, err := newKubernetesFromJSON(buf)
+ if err != nil {
+ return err
+ }
+ for _, p := range k.toPoints() {
+ re.set(p)
+ }
default:
return fmt.Errorf("unknown pstat type: %v", pstatType)
diff --git a/kubernetes.go b/kubernetes.go
new file mode 100644
index 0000000..8ce43ca
--- /dev/null
+++ b/kubernetes.go
@@ -0,0 +1,125 @@
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "regexp"
+)
+
+var (
+ apiNameRegexp = regexp.MustCompile(`mmkubernetes\((\S+)\)`)
+)
+
+type kubernetes struct {
+ Name string `json:"name"`
+ Url string
+ RecordSeen int64 `json:"recordseen"`
+ NamespaceMetaSuccess int64 `json:"namespacemetadatasuccess"`
+ NamespaceMetaNotFound int64 `json:"namespacemetadatanotfound"`
+ NamespaceMetaBusy int64 `json:"namespacemetadatabusy"`
+ NamespaceMetaError int64 `json:"namespacemetadataerror"`
+ PodMetaSuccess int64 `json:"podmetadatasuccess"`
+ PodMetaNotFound int64 `json:"podmetadatanotfound"`
+ PodMetaBusy int64 `json:"podmetadatabusy"`
+ PodMetaError int64 `json:"podmetadataerror"`
+}
+
+func newKubernetesFromJSON(b []byte) (*kubernetes, error) {
+ var pstat kubernetes
+ err := json.Unmarshal(b, &pstat)
+ if err != nil {
+ return nil, fmt.Errorf("failed to decode kubernetes stat `%v`: %v", string(b), err)
+ }
+ matches := apiNameRegexp.FindSubmatch([]byte(pstat.Name))
+ if matches != nil {
+ pstat.Url = string(matches[1])
+ }
+ return &pstat, nil
+}
+
+func (k *kubernetes) toPoints() []*point {
+ points := make([]*point, 9)
+
+ points[0] = &point{
+ Name: "kubernetes_namespace_metadata_success_total",
+ Type: counter,
+ Value: k.NamespaceMetaSuccess,
+ Description: "successful fetches of namespace metadata",
+ LabelName: "url",
+ LabelValue: k.Url,
+ }
+
+ points[1] = &point{
+ Name: "kubernetes_namespace_metadata_notfound_total",
+ Type: counter,
+ Value: k.NamespaceMetaNotFound,
+ Description: "notfound fetches of namespace metadata",
+ LabelName: "url",
+ LabelValue: k.Url,
+ }
+
+ points[2] = &point{
+ Name: "kubernetes_namespace_metadata_busy_total",
+ Type: counter,
+ Value: k.NamespaceMetaBusy,
+ Description: "busy fetches of namespace metadata",
+ LabelName: "url",
+ LabelValue: k.Url,
+ }
+
+ points[3] = &point{
+ Name: "kubernetes_namespace_metadata_error_total",
+ Type: counter,
+ Value: k.NamespaceMetaError,
+ Description: "error fetches of namespace metadata",
+ LabelName: "url",
+ LabelValue: k.Url,
+ }
+
+ points[4] = &point{
+ Name: "kubernetes_pod_metadata_success_total",
+ Type: counter,
+ Value: k.PodMetaSuccess,
+ Description: "successful fetches of pod metadata",
+ LabelName: "url",
+ LabelValue: k.Url,
+ }
+
+ points[5] = &point{
+ Name: "kubernetes_pod_metadata_notfound_total",
+ Type: counter,
+ Value: k.PodMetaNotFound,
+ Description: "notfound fetches of pod metadata",
+ LabelName: "url",
+ LabelValue: k.Url,
+ }
+
+ points[6] = &point{
+ Name: "kubernetes_pod_metadata_busy_total",
+ Type: counter,
+ Value: k.PodMetaBusy,
+ Description: "busy fetches of pod metadata",
+ LabelName: "url",
+ LabelValue: k.Url,
+ }
+
+ points[7] = &point{
+ Name: "kubernetes_pod_metadata_error_total",
+ Type: counter,
+ Value: k.PodMetaError,
+ Description: "error fetches of pod metadata",
+ LabelName: "url",
+ LabelValue: k.Url,
+ }
+
+ points[8] = &point{
+ Name: "kubernetes_record_seen_total",
+ Type: counter,
+ Value: k.RecordSeen,
+ Description: "records fetched from the api",
+ LabelName: "url",
+ LabelValue: k.Url,
+ }
+
+ return points
+}
diff --git a/kubernetes_test.go b/kubernetes_test.go
new file mode 100644
index 0000000..46d68fa
--- /dev/null
+++ b/kubernetes_test.go
@@ -0,0 +1,203 @@
+package main
+
+import "testing"
+
+var (
+ kubernetesLog = []byte(`{ "name": "mmkubernetes(https://host.domain.tld:6443)", "origin": "mmkubernetes", "recordseen": 477943, "namespacemetadatasuccess": 7, "namespacemetadatanotfound": 0, "namespacemetadatabusy": 0, "namespacemetadataerror": 0, "podmetadatasuccess": 26, "podmetadatanotfound": 0, "podmetadatabusy": 0, "podmetadataerror": 0 }`)
+)
+
+func TestNewKubernetesFromJSON(t *testing.T) {
+ logType := getStatType(kubernetesLog)
+ if logType != rsyslogKubernetes {
+ t.Errorf("detected pstat type should be %d but is %d", rsyslogKubernetes, logType)
+ }
+
+ pstat, err := newKubernetesFromJSON([]byte(kubernetesLog))
+ if err != nil {
+ t.Fatalf("expected parsing action not to fail, got: %v", err)
+ }
+
+ if want, got := "mmkubernetes(https://host.domain.tld:6443)", pstat.Name; want != got {
+ t.Errorf("wanted '%s', got '%s'", want, got)
+ }
+
+ if want, got := "https://host.domain.tld:6443", pstat.Url; want != got {
+ t.Errorf("wanted '%s', got '%s'", want, got)
+ }
+
+ if want, got := int64(477943), pstat.RecordSeen; want != got {
+ t.Errorf("wanted '%d', got '%d'", want, got)
+ }
+
+ if want, got := int64(7), pstat.NamespaceMetaSuccess; want != got {
+ t.Errorf("wanted '%d', got '%d'", want, got)
+ }
+
+ if want, got := int64(0), pstat.NamespaceMetaNotFound; want != got {
+ t.Errorf("wanted '%d', got '%d'", want, got)
+ }
+
+ if want, got := int64(0), pstat.NamespaceMetaBusy; want != got {
+ t.Errorf("wanted '%d', got '%d'", want, got)
+ }
+
+ if want, got := int64(0), pstat.NamespaceMetaError; want != got {
+ t.Errorf("wanted '%d', got '%d'", want, got)
+ }
+
+ if want, got := int64(26), pstat.PodMetaSuccess; want != got {
+ t.Errorf("wanted '%d', got '%d'", want, got)
+ }
+
+ if want, got := int64(0), pstat.PodMetaNotFound; want != got {
+ t.Errorf("wanted '%d', got '%d'", want, got)
+ }
+
+ if want, got := int64(0), pstat.PodMetaBusy; want != got {
+ t.Errorf("wanted '%d', got '%d'", want, got)
+ }
+
+ if want, got := int64(0), pstat.PodMetaError; want != got {
+ t.Errorf("wanted '%d', got '%d'", want, got)
+ }
+
+}
+
+func TestKubernetesToPoints(t *testing.T) {
+ pstat, err := newKubernetesFromJSON([]byte(kubernetesLog))
+ if err != nil {
+ t.Fatalf("expected parsing action not to fail, got: %v", err)
+ }
+ points := pstat.toPoints()
+
+ point := points[0]
+ if want, got := "kubernetes_namespace_metadata_success_total", point.Name; want != got {
+ t.Errorf("wanted '%s', got '%s'", want, got)
+ }
+
+ if want, got := "https://host.domain.tld:6443", point.LabelValue; want != got {
+ t.Errorf("wanted '%s', got '%s'", want, got)
+ }
+
+ point = points[1]
+ if want, got := "kubernetes_namespace_metadata_notfound_total", point.Name; want != got {
+ t.Errorf("wanted '%s', got '%s'", want, got)
+ }
+
+ point = points[2]
+ if want, got := "kubernetes_namespace_metadata_busy_total", point.Name; want != got {
+ t.Errorf("wanted '%s', got '%s'", want, got)
+ }
+
+ point = points[3]
+ if want, got := "kubernetes_namespace_metadata_error_total", point.Name; want != got {
+ t.Errorf("wanted '%s', got '%s'", want, got)
+ }
+
+ point = points[4]
+ if want, got := "kubernetes_pod_metadata_success_total", point.Name; want != got {
+ t.Errorf("wanted '%s', got '%s'", want, got)
+ }
+
+ point = points[5]
+ if want, got := "kubernetes_pod_metadata_notfound_total", point.Name; want != got {
+ t.Errorf("wanted '%s', got '%s'", want, got)
+ }
+
+ point = points[6]
+ if want, got := "kubernetes_pod_metadata_busy_total", point.Name; want != got {
+ t.Errorf("wanted '%s', got '%s'", want, got)
+ }
+
+ point = points[7]
+ if want, got := "kubernetes_pod_metadata_error_total", point.Name; want != got {
+ t.Errorf("wanted '%s', got '%s'", want, got)
+ }
+
+ point = points[8]
+ if want, got := "kubernetes_record_seen_total", point.Name; want != got {
+ t.Errorf("wanted '%s', got '%s'", want, got)
+ }
+
+ /*
+ if want, got := int64(100000), point.Value; want != got {
+ t.Errorf("wanted '%d', got '%d'", want, got)
+ }
+
+ if want, got := counter, point.Type; want != got {
+ t.Errorf("wanted '%d', got '%d'", want, got)
+ }
+
+ if want, got := "test_action", point.LabelValue; want != got {
+ t.Errorf("wanted '%s', got '%s'", want, got)
+ }
+
+ point = points[1]
+ if want, got := "action_failed", point.Name; want != got {
+ t.Errorf("wanted '%s', got '%s'", want, got)
+ }
+
+ if want, got := int64(2), point.Value; want != got {
+ t.Errorf("wanted '%d', got '%d'", want, got)
+ }
+
+ if want, got := counter, point.Type; want != got {
+ t.Errorf("wanted '%d', got '%d'", want, got)
+ }
+
+ if want, got := "test_action", point.LabelValue; want != got {
+ t.Errorf("wanted '%s', got '%s'", want, got)
+ }
+
+ point = points[2]
+ if want, got := "action_suspended", point.Name; want != got {
+ t.Errorf("wanted '%s', got '%s'", want, got)
+ }
+
+ if want, got := int64(1), point.Value; want != got {
+ t.Errorf("wanted '%d', got '%d'", want, got)
+ }
+
+ if want, got := counter, point.Type; want != got {
+ t.Errorf("wanted '%d', got '%d'", want, got)
+ }
+
+ if want, got := "test_action", point.LabelValue; want != got {
+ t.Errorf("wanted '%s', got '%s'", want, got)
+ }
+
+ point = points[3]
+ if want, got := "action_suspended_duration", point.Name; want != got {
+ t.Errorf("wanted '%s', got '%s'", want, got)
+ }
+
+ if want, got := int64(1000), point.Value; want != got {
+ t.Errorf("wanted '%d', got '%d'", want, got)
+ }
+
+ if want, got := counter, point.Type; want != got {
+ t.Errorf("wanted '%d', got '%d'", want, got)
+ }
+
+ if want, got := "test_action", point.LabelValue; want != got {
+ t.Errorf("wanted '%s', got '%s'", want, got)
+ }
+
+ point = points[4]
+ if want, got := "action_resumed", point.Name; want != got {
+ t.Errorf("wanted '%s', got '%s'", want, got)
+ }
+
+ if want, got := int64(1), point.Value; want != got {
+ t.Errorf("wanted '%d', got '%d'", want, got)
+ }
+
+ if want, got := counter, point.Type; want != got {
+ t.Errorf("wanted '%d', got '%d'", want, got)
+ }
+
+ if want, got := "test_action", point.LabelValue; want != got {
+ t.Errorf("wanted '%s', got '%s'", want, got)
+ }
+ */
+}
diff --git a/utils.go b/utils.go
index 624fd28..3bbaa4a 100644
--- a/utils.go
+++ b/utils.go
@@ -20,6 +20,8 @@ func getStatType(buf []byte) rsyslogType {
return rsyslogDynafileCache
} else if strings.Contains(line, "omfwd") {
return rsyslogForward
+ } else if strings.Contains(line, "mmkubernetes") {
+ return rsyslogKubernetes
}
return rsyslogUnknown
}