Skip to content

Commit

Permalink
Merge pull request #2 from appsignal/pods-no-switch
Browse files Browse the repository at this point in the history
Add pod metrics
  • Loading branch information
jeffkreeftmeijer authored May 3, 2024
2 parents 86cc747 + d07186c commit c977d21
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 1 deletion.
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@ AppSignal for Kubernetes will start sending Kubernetes automatically.

## Metrics

AppSignal for Kubernetes extracts metrics for all nodes running in a cluster every minute.
AppSignal for Kubernetes extracts metrics for all nodes and pods running in a cluster every minute.

It extracts the following metrics from the `/api/v1/nodes/<NODE>/proxy/stats/summary` endpoint:

### Node metrics

- node_cpu_usage_nano_cores
- node_cpu_usage_core_nano_seconds
- node_memory_usage_bytes
Expand All @@ -41,6 +43,14 @@ It extracts the following metrics from the `/api/v1/nodes/<NODE>/proxy/stats/sum
- node_swap_available_bytes
- node_swap_usage_bytes

### Pod metrics

- pod_cpu_usage_nano_cores
- pod_cpu_usage_core_nano_seconds
- pod_memory_working_set_bytes
- pod_swap_available_bytes
- pod_swap_usage_bytes

## Automated Dashboard

After installing AppSignal for Kubernetes into a cluster, an Automated Dashboard automatically appears on AppSignal showing you an overview of the nodes in your Kubernetes cluster.
Expand Down
78 changes: 78 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,18 @@ async fn run() -> Result<(), Error> {
.request::<serde_json::Value>(kube_request)
.await?;

if let Some(pods) = kube_response["pods"].as_array() {
for pod in pods {
extract_pod_metrics(
pod,
pod["podRef"]["name"]
.as_str()
.expect("Could not extract pod name"),
&mut out,
);
}
};

extract_node_metrics(kube_response, &name, &mut out);
}

Expand All @@ -94,6 +106,32 @@ async fn run() -> Result<(), Error> {
Ok(())
}

fn extract_pod_metrics(results: &Value, pod_name: &str, out: &mut Vec<AppsignalMetric>) {
for (metric_name, metric_value) in [
(
"pod_cpu_usage_nano_cores",
&results["cpu"]["usageNanoCores"],
),
(
"pod_cpu_usage_core_nano_seconds",
&results["cpu"]["usageCoreNanoSeconds"],
),
(
"pod_memory_working_set_bytes",
&results["memory"]["workingSetBytes"],
),
(
"pod_swap_available_bytes",
&results["swap"]["swapAvailableBytes"],
),
("pod_swap_usage_bytes", &results["swap"]["swapUsageBytes"]),
] {
let mut tags = HashMap::with_capacity(1);
tags.insert("pod".to_owned(), pod_name.to_owned());
out.push(AppsignalMetric::new(metric_name, tags, metric_value));
}
}

fn extract_node_metrics(results: Value, node_name: &str, out: &mut Vec<AppsignalMetric>) {
for (metric_name, metric_value) in [
(
Expand Down Expand Up @@ -176,6 +214,7 @@ fn extract_node_metrics(results: Value, node_name: &str, out: &mut Vec<Appsignal
#[cfg(test)]
mod tests {
use crate::extract_node_metrics;
use crate::extract_pod_metrics;
use crate::AppsignalMetric;
use crate::HashMap;
use serde_json::json;
Expand Down Expand Up @@ -220,4 +259,43 @@ mod tests {
out[0]
);
}

#[test]
fn extract_pod_metrics_with_empty_results() {
let mut out = Vec::new();
extract_pod_metrics(&json!([]), "pod", &mut out);
assert_eq!(
AppsignalMetric::new(
"pod_cpu_usage_nano_cores",
HashMap::from([("pod".to_string(), "pod".to_string())]),
&json!(0.0)
),
out[0]
);
}

#[test]
fn extract_pod_metrics_with_results() {
let mut out = Vec::new();
extract_pod_metrics(
&json!({
"cpu": {
"time": "2024-03-29T12:21:36Z",
"usageNanoCores": 232839439,
"usageCoreNanoSeconds": 1118592000000 as u64
},
}),
"pod",
&mut out,
);

assert_eq!(
AppsignalMetric::new(
"pod_cpu_usage_nano_cores",
HashMap::from([("pod".to_string(), "pod".to_string())]),
&json!(232839439)
),
out[0]
);
}
}

0 comments on commit c977d21

Please sign in to comment.