Use percentage and MB for CPU/Memory urls

And more DRY.
This commit is contained in:
Roland Schilter
2017-08-10 18:46:07 +01:00
parent 87efac0b1d
commit bf0bc41b36
2 changed files with 55 additions and 47 deletions

View File

@@ -2,6 +2,7 @@ package detailed
import (
"bytes"
"fmt"
"net/url"
"strings"
@@ -11,8 +12,13 @@ import (
"github.com/ugorji/go/codec"
)
// Replacement variable name for the query in the metrics graph url
const urlQueryVarName = ":query"
const (
// Replacement variable name for the query in the metrics graph url
urlQueryVarName = ":query"
idReceiveBytes = "receive_bytes"
idTransmitBytes = "transmit_bytes"
)
var (
// As configured by the user
@@ -32,54 +38,32 @@ var (
Label: "Memory",
},
{
ID: "receive_bytes",
ID: idReceiveBytes,
Label: "Rx/s",
},
{
ID: "transmit_bytes",
ID: idTransmitBytes,
Label: "Tx/s",
},
}
// Prometheus queries for topologies
//
// Metrics
// - `container_cpu_usage_seconds_total` --> cAdvisor in Kubelets.
// - `container_memory_usage_bytes` --> cAdvisor in Kubelets.
topologyQueries = map[string]map[string]string{
// Containers
report.Container: {
docker.MemoryUsage: `sum(container_memory_usage_bytes{container_name="{{label}}"})`,
docker.CPUTotalUsage: `sum(rate(container_cpu_usage_seconds_total{container_name="{{label}}"}[1m]))`,
},
report.ContainerImage: {
docker.MemoryUsage: `sum(container_memory_usage_bytes{image="{{label}}"})`,
docker.CPUTotalUsage: `sum(rate(container_cpu_usage_seconds_total{image="{{label}}"}[1m]))`,
},
"group:container:docker_container_hostname": {
docker.MemoryUsage: `sum(container_memory_usage_bytes{pod_name="{{label}}"})`,
docker.CPUTotalUsage: `sum(rate(container_cpu_usage_seconds_total{pod_name="{{label}}"}[1m]))`,
},
report.Container: formatMetricQueries(`container_name="{{label}}"`, []string{docker.MemoryUsage, docker.CPUTotalUsage}),
report.ContainerImage: formatMetricQueries(`image="{{label}}"`, []string{docker.MemoryUsage, docker.CPUTotalUsage}),
"group:container:docker_container_hostname": formatMetricQueries(`pod_name="{{label}}"`, []string{docker.MemoryUsage, docker.CPUTotalUsage}),
// Kubernetes topologies
report.Pod: {
docker.MemoryUsage: `sum(container_memory_usage_bytes{pod_name="{{label}}"})`,
docker.CPUTotalUsage: `sum(rate(container_cpu_usage_seconds_total{pod_name="{{label}}"}[1m]))`,
"receive_bytes": `sum(rate(container_network_receive_bytes_total{pod_name="{{label}}"}[5m]))`,
"transmit_bytes": `sum(rate(container_network_transmit_bytes_total{pod_name="{{label}}"}[5m]))`,
},
// Pod naming:
// https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#pod-template-hash-label
"__k8s_controllers": {
docker.MemoryUsage: `sum(container_memory_usage_bytes{pod_name=~"^{{label}}-[^-]+-[^-]+$"})`,
docker.CPUTotalUsage: `sum(rate(container_cpu_usage_seconds_total{pod_name=~"^{{label}}-[^-]+-[^-]+$"}[1m]))`,
},
report.DaemonSet: {
docker.MemoryUsage: `sum(container_memory_usage_bytes{pod_name=~"^{{label}}-[^-]+$"})`,
docker.CPUTotalUsage: `sum(rate(container_cpu_usage_seconds_total{pod_name=~"^{{label}}-[^-]+$"}[1m]))`,
},
report.Pod: formatMetricQueries(
`pod_name="{{label}}"`,
[]string{docker.MemoryUsage, docker.CPUTotalUsage, idReceiveBytes, idTransmitBytes},
),
// Pod naming: // https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#pod-template-hash-label
"__k8s_controllers": formatMetricQueries(`pod_name=~"^{{label}}-[^-]+-[^-]+$"}`, []string{docker.MemoryUsage, docker.CPUTotalUsage}),
report.DaemonSet: formatMetricQueries(`pod_name=~"^{{label}}-[^-]+$"}`, []string{docker.MemoryUsage, docker.CPUTotalUsage}),
report.Service: {
// These recording rules must be defined in the prometheus config.
// NB: Pods need to be labeled and selected by their respective Service name, meaning:
@@ -90,12 +74,35 @@ var (
},
}
k8sControllers = map[string]struct{}{
report.Deployment: {},
"stateful_set": {},
"cron_job": {},
report.Deployment: {},
report.StatefulSet: {},
report.CronJob: {},
}
)
func formatMetricQueries(filter string, ids []string) map[string]string {
queries := make(map[string]string)
for _, id := range ids {
// All `container_*`metrics are provided by cAdvisor in Kubelets
switch id {
case docker.MemoryUsage:
queries[id] = fmt.Sprintf("sum(container_memory_usage_bytes{%s})/1024/1024", filter)
case docker.CPUTotalUsage:
queries[id] = fmt.Sprintf(
"sum(rate(container_cpu_usage_seconds_total{%s}[1m]))/count(container_cpu_usage_seconds_total{%s})*100",
filter,
filter,
)
case idReceiveBytes:
queries[id] = fmt.Sprintf(`sum(rate(container_network_receive_bytes_total{%s}[5m]))`, filter)
case idTransmitBytes:
queries[id] = fmt.Sprintf(`sum(rate(container_network_transmit_bytes_total{%s}[5m]))`, filter)
}
}
return queries
}
// SetMetricsGraphURL sets the URL we deduce our eventual metric link from.
// Supports placeholders such as `:orgID` and `:query`. An empty url disables
// this feature. If the `:query` part is missing, a JSON version will be

View File

@@ -1,6 +1,7 @@
package detailed_test
import (
"strings"
"testing"
"github.com/weaveworks/scope/probe/docker"
@@ -47,10 +48,10 @@ func TestRenderMetricURLs(t *testing.T) {
s := detailed.NodeSummary{Label: "foo", Metrics: sampleMetrics}
result := detailed.RenderMetricURLs(s, samplePodNode)
u := "/prom/:orgID/notebook/new/%7B%22cells%22%3A%5B%7B%22queries%22%3A%5B%22sum%28container_memory_usage_bytes%7Bpod_name%3D%5C%22foo%5C%22%7D%29%22%5D%7D%5D%7D"
assert.Equal(t, u, result.Metrics[0].URL)
u = "/prom/:orgID/notebook/new/%7B%22cells%22%3A%5B%7B%22queries%22%3A%5B%22sum%28rate%28container_cpu_usage_seconds_total%7Bpod_name%3D%5C%22foo%5C%22%7D%5B1m%5D%29%29%22%5D%7D%5D%7D"
assert.Equal(t, u, result.Metrics[1].URL)
assert.Equal(t, 0, strings.Index(result.Metrics[0].URL, sampleMetricsGraphURL))
assert.Contains(t, result.Metrics[0].URL, "container_memory_usage_bytes%7Bpod_name%3D%5C%22foo%5C%22%7D")
assert.Equal(t, 0, strings.Index(result.Metrics[1].URL, sampleMetricsGraphURL))
assert.Contains(t, result.Metrics[1].URL, "container_cpu_usage_seconds_total%7Bpod_name%3D%5C%22foo%5C%22%7D")
}
func TestRenderMetricURLs_EmptyMetrics(t *testing.T) {
@@ -94,8 +95,8 @@ func TestRenderMetricURLs_QueryReplacement(t *testing.T) {
s := detailed.NodeSummary{Label: "foo", Metrics: sampleMetrics}
result := detailed.RenderMetricURLs(s, samplePodNode)
u := "http://example.test/?q=sum%28container_memory_usage_bytes%7Bpod_name%3D%22foo%22%7D%29"
assert.Equal(t, u, result.Metrics[0].URL)
u = "http://example.test/?q=sum%28rate%28container_cpu_usage_seconds_total%7Bpod_name%3D%22foo%22%7D%5B1m%5D%29%29"
assert.Equal(t, u, result.Metrics[1].URL)
assert.Contains(t, result.Metrics[0].URL, "http://example.test/?q=")
assert.Contains(t, result.Metrics[0].URL, "container_memory_usage_bytes%7Bpod_name%3D%22foo%22%7D")
assert.Contains(t, result.Metrics[1].URL, "http://example.test/?q=")
assert.Contains(t, result.Metrics[1].URL, "container_cpu_usage_seconds_total%7Bpod_name%3D%22foo%22%7D")
}