Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Kubernetes StatefulSet metricset #6236

Merged
merged 9 commits into from
Feb 2, 2018
1 change: 1 addition & 0 deletions CHANGELOG.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ https://github.com/elastic/beats/compare/v6.0.0-beta2...master[Check the HEAD di
- Add experimental uwsgi module. {pull}6006[6006]
- Docker and Kubernetes modules are now GA, instead of Beta. {pull}6105[6105]
- Add pct calculated fields for Pod and container CPU and memory usages. {pull}6158[6158]
- Add statefulset support to Kubernetes module. {pull}6236[6236]

*Packetbeat*

Expand Down
69 changes: 69 additions & 0 deletions metricbeat/docs/fields.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -6151,6 +6151,75 @@ type: long
The number of fully labeled replicas per ReplicaSet


[float]
== statefulset fields

kubernetes stateful set metrics



[float]
=== `kubernetes.statefulset.name`

type: keyword

Kubernetes stateful set name


[float]
=== `kubernetes.statefulset.created`

type: long

The creation timestamp (epoch) for StatefulSet


[float]
== replicas fields

Kubernetes stateful set replicas status



[float]
=== `kubernetes.statefulset.replicas.observed`

type: long

The number of observed replicas per StatefulSet


[float]
=== `kubernetes.statefulset.replicas.desired`

type: long

The number of desired replicas per StatefulSet


[float]
== generation fields

Kubernetes stateful set generation information



[float]
=== `kubernetes.statefulset.generation.observed`

type: long

The observed generation per StatefulSet


[float]
=== `kubernetes.statefulset.generation.desired`

type: long

The desired generation per StatefulSet


[float]
== system fields

Expand Down
5 changes: 5 additions & 0 deletions metricbeat/docs/modules/kubernetes.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ metricbeat.modules:
- state_node
- state_deployment
- state_replicaset
- state_statefulset
- state_pod
- state_container
period: 10s
Expand Down Expand Up @@ -77,6 +78,8 @@ The following metricsets are available:

* <<metricbeat-metricset-kubernetes-state_replicaset,state_replicaset>>

* <<metricbeat-metricset-kubernetes-state_statefulset,state_statefulset>>

* <<metricbeat-metricset-kubernetes-system,system>>

* <<metricbeat-metricset-kubernetes-volume,volume>>
Expand All @@ -99,6 +102,8 @@ include::kubernetes/state_pod.asciidoc[]

include::kubernetes/state_replicaset.asciidoc[]

include::kubernetes/state_statefulset.asciidoc[]

include::kubernetes/system.asciidoc[]

include::kubernetes/volume.asciidoc[]
Expand Down
21 changes: 21 additions & 0 deletions metricbeat/docs/modules/kubernetes/state_statefulset.asciidoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
////
This file is generated! See scripts/docs_collector.py
////

[[metricbeat-metricset-kubernetes-state_statefulset]]
=== Kubernetes state_statefulset metricset

include::../../../module/kubernetes/state_statefulset/_meta/docs.asciidoc[]


==== Fields

For a description of each field in the metricset, see the
<<exported-fields-kubernetes,exported fields>> section.

Here is an example document generated by this metricset:

[source,json]
----
include::../../../module/kubernetes/state_statefulset/_meta/data.json[]
----
3 changes: 2 additions & 1 deletion metricbeat/docs/modules_list.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ This file is generated! See scripts/docs_collector.py
|<<metricbeat-module-kibana,Kibana>> beta[] |
.1+| |<<metricbeat-metricset-kibana-status,status>> beta[]
|<<metricbeat-module-kubernetes,Kubernetes>> |
.11+| |<<metricbeat-metricset-kubernetes-container,container>>
.12+| |<<metricbeat-metricset-kubernetes-container,container>>
|<<metricbeat-metricset-kubernetes-event,event>> experimental[]
|<<metricbeat-metricset-kubernetes-node,node>>
|<<metricbeat-metricset-kubernetes-pod,pod>>
Expand All @@ -67,6 +67,7 @@ This file is generated! See scripts/docs_collector.py
|<<metricbeat-metricset-kubernetes-state_node,state_node>>
|<<metricbeat-metricset-kubernetes-state_pod,state_pod>>
|<<metricbeat-metricset-kubernetes-state_replicaset,state_replicaset>>
|<<metricbeat-metricset-kubernetes-state_statefulset,state_statefulset>>
|<<metricbeat-metricset-kubernetes-system,system>>
|<<metricbeat-metricset-kubernetes-volume,volume>>
|<<metricbeat-module-logstash,Logstash>> experimental[] |
Expand Down
1 change: 1 addition & 0 deletions metricbeat/include/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ import (
_ "github.com/elastic/beats/metricbeat/module/kubernetes/state_node"
_ "github.com/elastic/beats/metricbeat/module/kubernetes/state_pod"
_ "github.com/elastic/beats/metricbeat/module/kubernetes/state_replicaset"
_ "github.com/elastic/beats/metricbeat/module/kubernetes/state_statefulset"
_ "github.com/elastic/beats/metricbeat/module/kubernetes/system"
_ "github.com/elastic/beats/metricbeat/module/kubernetes/util"
_ "github.com/elastic/beats/metricbeat/module/kubernetes/volume"
Expand Down
1 change: 1 addition & 0 deletions metricbeat/metricbeat.reference.yml
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ metricbeat.modules:
- state_node
- state_deployment
- state_replicaset
- state_statefulset
- state_pod
- state_container
period: 10s
Expand Down
1 change: 1 addition & 0 deletions metricbeat/module/kubernetes/_meta/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
- state_node
- state_deployment
- state_replicaset
- state_statefulset
- state_pod
- state_container
period: 10s
Expand Down
31 changes: 31 additions & 0 deletions metricbeat/module/kubernetes/_meta/test/kube-state-metrics
Original file line number Diff line number Diff line change
Expand Up @@ -386,3 +386,34 @@ process_start_time_seconds 1.4939719827e+09
# HELP process_virtual_memory_bytes Virtual memory size in bytes.
# TYPE process_virtual_memory_bytes gauge
process_virtual_memory_bytes 5.2932608e+07
# HELP kube_statefulset_created Unix creation timestamp
# TYPE kube_statefulset_created gauge
kube_statefulset_created{namespace="default",statefulset="elasticsearch"} 1.511973651e+09
kube_statefulset_created{namespace="default",statefulset="mysql"} 1.511989697e+09
kube_statefulset_created{namespace="custom",statefulset="mysql"} 1.511999697e+09
# HELP kube_statefulset_labels Kubernetes labels converted to Prometheus labels.
# TYPE kube_statefulset_labels gauge
kube_statefulset_labels{label_app="oci",label_io_kompose_service="elasticsearch",namespace="default",statefulset="elasticsearch"} 1
kube_statefulset_labels{label_app="oci",label_custom_pod="true",label_io_kompose_service="s-mysql",namespace="default",statefulset="mysql"} 1
kube_statefulset_labels{label_app="oci",label_custom_pod="true",label_io_kompose_service="s-mysql",namespace="custom",statefulset="mysql"} 1
# HELP kube_statefulset_metadata_generation Sequence number representing a specific generation of the desired state for the StatefulSet.
# TYPE kube_statefulset_metadata_generation gauge
kube_statefulset_metadata_generation{namespace="default",statefulset="elasticsearch"} 3
kube_statefulset_metadata_generation{namespace="default",statefulset="mysql"} 4
kube_statefulset_metadata_generation{namespace="custom",statefulset="mysql"} 5
# HELP kube_statefulset_replicas Number of desired pods for a StatefulSet.
# TYPE kube_statefulset_replicas gauge
kube_statefulset_replicas{namespace="default",statefulset="elasticsearch"} 4
kube_statefulset_replicas{namespace="default",statefulset="mysql"} 5
kube_statefulset_replicas{namespace="custom",statefulset="mysql"} 6
# HELP kube_statefulset_status_observed_generation The generation observed by the StatefulSet controller.
# TYPE kube_statefulset_status_observed_generation gauge
kube_statefulset_status_observed_generation{namespace="default",statefulset="elasticsearch"} 1
kube_statefulset_status_observed_generation{namespace="default",statefulset="mysql"} 2
kube_statefulset_status_observed_generation{namespace="custom",statefulset="mysql"} 3
# HELP kube_statefulset_status_replicas The number of replicas per StatefulSet.
# TYPE kube_statefulset_status_replicas gauge
kube_statefulset_status_replicas{namespace="default",statefulset="elasticsearch"} 1
kube_statefulset_status_replicas{namespace="default",statefulset="mysql"} 2
kube_statefulset_status_replicas{namespace="custom",statefulset="mysql"} 3

30 changes: 30 additions & 0 deletions metricbeat/module/kubernetes/state_statefulset/_meta/data.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"@timestamp": "2017-05-10T16:46:37.821Z",
"beat": {
"hostname": "X1",
"name": "X1",
"version": "6.0.0-alpha1"
},
"kubernetes": {
"namespace": "jenkins",
"statefulset": {
"name": "wise-lynx-jenkins-1616735317",
"created": 123454,
"replicas": {
"desired": 1,
"observed": 1,
},
"generation": {
"desired": 1,
"observed": 1,
}
}
},
"metricset": {
"host": "192.168.99.100:18080",
"module": "kubernetes",
"name": "state_statefulset",
"namespace": "statefulset",
"rtt": 6719
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This is the `state_statefulset` metricset of the Kubernetes module.
40 changes: 40 additions & 0 deletions metricbeat/module/kubernetes/state_statefulset/_meta/fields.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
- name: statefulset
type: group
description: >
kubernetes stateful set metrics
release: ga
fields:
- name: name
type: keyword
description: >
Kubernetes stateful set name
- name: created
type: long
description: >
The creation timestamp (epoch) for StatefulSet
- name: replicas
type: group
description: >
Kubernetes stateful set replicas status
fields:
- name: observed
type: long
description: >
The number of observed replicas per StatefulSet
- name: desired
type: long
description: >
The number of desired replicas per StatefulSet
- name: generation
type: group
description: >
Kubernetes stateful set generation information
fields:
- name: observed
type: long
description: >
The observed generation per StatefulSet
- name: desired
type: long
description: >
The desired generation per StatefulSet
53 changes: 53 additions & 0 deletions metricbeat/module/kubernetes/state_statefulset/data.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package state_statefulset

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't use an underscore in package name

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following same pattern as other classes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, please ignore the bot on this.


import (
"github.com/elastic/beats/libbeat/common"
"github.com/elastic/beats/metricbeat/mb"
"github.com/elastic/beats/metricbeat/module/kubernetes/util"

dto "github.com/prometheus/client_model/go"
)

func eventMapping(families []*dto.MetricFamily) ([]common.MapStr, error) {
eventsMap := map[string]common.MapStr{}
for _, family := range families {
for _, metric := range family.GetMetric() {
statefulset := util.GetLabel(metric, "statefulset")
if statefulset == "" {
continue
}
namespace := util.GetLabel(metric, "namespace")
statefulsetKey := namespace + "::" + statefulset
event, ok := eventsMap[statefulsetKey]
if !ok {
event = common.MapStr{}
eventsMap[statefulsetKey] = event
}
switch family.GetName() {
case "kube_statefulset_metadata_generation":
event.Put(mb.ModuleDataKey+".namespace", util.GetLabel(metric, "namespace"))
event.Put(mb.NamespaceKey, "statefulset")
event.Put("name", util.GetLabel(metric, "statefulset"))
event.Put("generation.desired", metric.GetGauge().GetValue())
case "kube_statefulset_status_observed_generation":
event.Put("generation.observed", metric.GetGauge().GetValue())
case "kube_statefulset_created":
event.Put("created", metric.GetGauge().GetValue())
case "kube_statefulset_replicas":
event.Put("replicas.desired", metric.GetGauge().GetValue())
case "kube_statefulset_status_replicas":
event.Put("replicas.observed", metric.GetGauge().GetValue())
default:
// Ignore unknown metric
continue
}
}
}

// initialize, populate events array from values in eventsMap
events := make([]common.MapStr, 0, len(eventsMap))
for _, event := range eventsMap {
events = append(events, event)
}
return events, nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package state_statefulset

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't use an underscore in package name


import (
"github.com/elastic/beats/libbeat/common"
"github.com/elastic/beats/metricbeat/helper"
"github.com/elastic/beats/metricbeat/mb"
"github.com/elastic/beats/metricbeat/mb/parse"
)

const (
defaultScheme = "http"
defaultPath = "/metrics"
)

var (
hostParser = parse.URLHostParserBuilder{
DefaultScheme: defaultScheme,
DefaultPath: defaultPath,
}.Build()
)

// init registers the MetricSet with the central registry.
// The New method will be called after the setup of the module and before starting to fetch data
func init() {
if err := mb.Registry.AddMetricSet("kubernetes", "state_statefulset", New, hostParser); err != nil {
panic(err)
}
}

// MetricSet type defines all fields of the MetricSet
// As a minimum it must inherit the mb.BaseMetricSet fields, but can be extended with
// additional entries. These variables can be used to persist data or configuration between
// multiple fetch calls.
type MetricSet struct {
mb.BaseMetricSet
prometheus *helper.Prometheus
}

// New create a new instance of the MetricSet
// Part of new is also setting up the configuration by processing additional
// configuration entries if needed.
func New(base mb.BaseMetricSet) (mb.MetricSet, error) {
prometheus, err := helper.NewPrometheusClient(base)
if err != nil {
return nil, err
}
return &MetricSet{
BaseMetricSet: base,
prometheus: prometheus,
}, nil
}

// Fetch methods implements the data gathering and data conversion to the right format
// It returns the event which is then forward to the output. In case of an error, a
// descriptive error must be returned.
func (m *MetricSet) Fetch() ([]common.MapStr, error) {
families, err := m.prometheus.GetFamilies()
if err != nil {
return nil, err
}

return eventMapping(families)
}
Loading