mirror of
https://github.com/weaveworks/scope.git
synced 2026-05-06 01:08:03 +00:00
Use percentage and MB for CPU/Memory urls
And more DRY.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user