From 49868ee1a682a17b6c92ce9947bd0bad38dec9e8 Mon Sep 17 00:00:00 2001 From: Lucas Dousse Date: Sun, 7 Mar 2021 20:26:44 +0100 Subject: [PATCH] docker stats app (#12358) * docker stat app support * Add missing doc and app * stylci * styleci * styleci * Add test data * add snmpsim * Update docker.inc.php test with use Number::Bi * typo * Add tests * Add tests Co-authored-by: Jellyfrog --- doc/Extensions/Applications.md | 34 +++ .../graphs/application/docker-common.inc.php | 36 +++ .../application/docker_cpu_usage.inc.php | 7 + .../application/docker_mem_limit.inc.php | 6 + .../application/docker_mem_perc.inc.php | 7 + .../application/docker_mem_used.inc.php | 6 + .../graphs/application/docker_pids.inc.php | 6 + includes/html/pages/apps.inc.php | 7 + .../html/pages/device/apps/docker.inc.php | 60 +++++ includes/polling/applications/docker.inc.php | 69 ++++++ tests/data/linux_docker-v1.json | 219 ++++++++++++++++++ tests/snmpsim/linux_docker-v1.snmprec | 8 + 12 files changed, 465 insertions(+) create mode 100644 includes/html/graphs/application/docker-common.inc.php create mode 100644 includes/html/graphs/application/docker_cpu_usage.inc.php create mode 100644 includes/html/graphs/application/docker_mem_limit.inc.php create mode 100644 includes/html/graphs/application/docker_mem_perc.inc.php create mode 100644 includes/html/graphs/application/docker_mem_used.inc.php create mode 100644 includes/html/graphs/application/docker_pids.inc.php create mode 100644 includes/html/pages/device/apps/docker.inc.php create mode 100644 includes/polling/applications/docker.inc.php create mode 100644 tests/data/linux_docker-v1.json create mode 100644 tests/snmpsim/linux_docker-v1.snmprec diff --git a/doc/Extensions/Applications.md b/doc/Extensions/Applications.md index f196c3b372..75c91c4cf5 100644 --- a/doc/Extensions/Applications.md +++ b/doc/Extensions/Applications.md @@ -92,6 +92,7 @@ by following the steps under the `SNMP Extend` heading. 1. [Certificate](#certificate) - Certificate extend 1. [C.H.I.P.](#chip) - SNMP extend 1. [DHCP Stats](#dhcp-stats) - SNMP extend +1. [Docker Stats](#docker-stats) - SNMP extend 1. [Entropy](#entropy) - SNMP extend 1. [EXIM Stats](#exim-stats) - SNMP extend 1. [Fail2ban](#fail2ban) - SNMP extend @@ -468,6 +469,39 @@ The application should be auto-discovered as described at the top of the page. If it is not, please follow the steps set out under `SNMP Extend` heading top of page. +# Docker Stats + +It allows you to know which container docker run and their stats. + +This script require: jq + +## SNMP Extend + +1: Install jq +``` +sudo apt install jq +``` + +2: Copy the shell script to the desired host. + +``` +wget https://github.com/librenms/librenms-agent/raw/master/snmp/docker-stats.sh -O /etc/snmp/docker-stats.sh +``` + +3: Run `chmod +x /etc/snmp/docker-stats.sh` + + +4: Edit your snmpd.conf file (usually /etc/snmp/snmpd.conf) and add: + +``` +extend docker /etc/snmp/docker-stats.sh +``` + +5: Restart snmpd on your host +``` +systemctl restart snmpd +``` + # Entropy A small shell script that checks your system's available random entropy. diff --git a/includes/html/graphs/application/docker-common.inc.php b/includes/html/graphs/application/docker-common.inc.php new file mode 100644 index 0000000000..10d54e9c03 --- /dev/null +++ b/includes/html/graphs/application/docker-common.inc.php @@ -0,0 +1,36 @@ + $rrd_filename, + 'descr' => $container_name, + 'ds' => $rrdVar, + ]; + } + $int++; +} + +require 'includes/html/graphs/generic_multi_line_exact_numbers.inc.php'; diff --git a/includes/html/graphs/application/docker_cpu_usage.inc.php b/includes/html/graphs/application/docker_cpu_usage.inc.php new file mode 100644 index 0000000000..27be89c6a6 --- /dev/null +++ b/includes/html/graphs/application/docker_cpu_usage.inc.php @@ -0,0 +1,7 @@ +'; echo '
'; diff --git a/includes/html/pages/device/apps/docker.inc.php b/includes/html/pages/device/apps/docker.inc.php new file mode 100644 index 0000000000..f6c7b2e162 --- /dev/null +++ b/includes/html/pages/device/apps/docker.inc.php @@ -0,0 +1,60 @@ + 'device', + 'device' => $device['device_id'], + 'tab' => 'apps', + 'app' => 'docker', +]; + +$containers_list = []; + +foreach ($domain_list as $label) { + $container = $label; + + if ($vars['container'] == $container) { + $label = sprintf('⚫ %s', $label); + } + + array_push($containers_list, generate_link($label, $link_array, ['container' => $container])); +} + +printf('%s | containers: %s', generate_link('All Containers', $link_array), implode(', ', $containers_list)); + +print_optionbar_end(); + +$graphs = [ + 'docker_pids' => 'PIDs', + 'docker_mem_limit' => 'Container memory limit', + 'docker_mem_used' => 'Container memory used', + 'docker_cpu_usage' => 'Container CPU usage, %', + 'docker_mem_perc' => 'Container Memory usage, %', +]; + +foreach ($graphs as $key => $text) { + $graph_type = $key; + $graph_array['height'] = '100'; + $graph_array['width'] = '215'; + $graph_array['to'] = time(); + $graph_array['id'] = $app['app_id']; + $graph_array['type'] = 'application_' . $key; + + if (isset($vars['container'])) { + $graph_array['container'] = $vars['container']; + } + + echo '
+
+

' . $text . '

+
+
+
'; + include 'includes/html/print-graphrow.inc.php'; + echo '
'; + echo '
'; + echo '
'; +} diff --git a/includes/polling/applications/docker.inc.php b/includes/polling/applications/docker.inc.php new file mode 100644 index 0000000000..ecdac467d6 --- /dev/null +++ b/includes/polling/applications/docker.inc.php @@ -0,0 +1,69 @@ +getParsedJson(); +} catch (JsonAppException $e) { + echo PHP_EOL . $name . ':' . $e->getCode() . ':' . $e->getMessage() . PHP_EOL; + update_application($app, $e->getCode() . ':' . $e->getMessage(), []); // Set empty metrics and error message + + return; +} + +$rrd_name = ['app', $name, $app_id]; +$rrd_def = RrdDefinition::make() + ->addDataset('cpu_usage', 'GAUGE', 0, 100) + ->addDataset('pids', 'GAUGE', 0) + ->addDataset('mem_perc', 'GAUGE', 0, 100) + ->addDataset('mem_used', 'GAUGE', 0) + ->addDataset('mem_limit', 'GAUGE', 0); + +$metrics = []; +foreach ($docker_data as $data) { + $container = $data['container']; + + $rrd_name = ['app', $name, $app_id, $container]; + + $fields = [ + 'cpu_usage' => ((float) $data['cpu']) * 100, + 'pids' => $data['pids'], + 'mem_limit' => Number::formatBi($data['memory']['limit']), + 'mem_used' => Number::formatBi($data['memory']['used']), + 'mem_perc' => ((float) $data['memory']['perc']) * 100, + ]; + + $metrics[$container] = $fields; + $tags = ['name' => $container, 'app_id' => $app_id, 'rrd_def' => $rrd_def, 'rrd_name' => $rrd_name]; + data_update($device, 'app', $tags, $fields); +} + +update_application($app, $output, $metrics); diff --git a/tests/data/linux_docker-v1.json b/tests/data/linux_docker-v1.json new file mode 100644 index 0000000000..a0fb5339d3 --- /dev/null +++ b/tests/data/linux_docker-v1.json @@ -0,0 +1,219 @@ +{ + "applications": { + "discovery": { + "applications": [ + { + "app_type": "docker", + "app_state": "UNKNOWN", + "discovered": 1, + "app_state_prev": null, + "app_status": "", + "app_instance": "" + } + ], + "application_metrics": [] + }, + "poller": { + "applications": [ + { + "app_type": "docker", + "app_state": "OK", + "discovered": 1, + "app_state_prev": "UNKNOWN", + "app_status": "", + "app_instance": "" + } + ], + "application_metrics": [ + { + "metric": "foobar_dashboard_1_cpu_usage", + "value": 1, + "value_prev": null, + "app_type": "docker" + }, + { + "metric": "foobar_dashboard_1_mem_limit", + "value": 15.36, + "value_prev": null, + "app_type": "docker" + }, + { + "metric": "foobar_dashboard_1_mem_perc", + "value": 4, + "value_prev": null, + "app_type": "docker" + }, + { + "metric": "foobar_dashboard_1_mem_used", + "value": 6.93, + "value_prev": null, + "app_type": "docker" + }, + { + "metric": "foobar_dashboard_1_pids", + "value": 6, + "value_prev": null, + "app_type": "docker" + }, + { + "metric": "foobar_laravel.test_1_cpu_usage", + "value": 9, + "value_prev": null, + "app_type": "docker" + }, + { + "metric": "foobar_laravel.test_1_mem_limit", + "value": 15.36, + "value_prev": null, + "app_type": "docker" + }, + { + "metric": "foobar_laravel.test_1_mem_perc", + "value": 17, + "value_prev": null, + "app_type": "docker" + }, + { + "metric": "foobar_laravel.test_1_mem_used", + "value": 26.67, + "value_prev": null, + "app_type": "docker" + }, + { + "metric": "foobar_laravel.test_1_pids", + "value": 4, + "value_prev": null, + "app_type": "docker" + }, + { + "metric": "foobar_meilisearch_1_cpu_usage", + "value": 0, + "value_prev": null, + "app_type": "docker" + }, + { + "metric": "foobar_meilisearch_1_mem_limit", + "value": 15.36, + "value_prev": null, + "app_type": "docker" + }, + { + "metric": "foobar_meilisearch_1_mem_perc", + "value": 7, + "value_prev": null, + "app_type": "docker" + }, + { + "metric": "foobar_meilisearch_1_mem_used", + "value": 10.86, + "value_prev": null, + "app_type": "docker" + }, + { + "metric": "foobar_meilisearch_1_pids", + "value": 15, + "value_prev": null, + "app_type": "docker" + }, + { + "metric": "foobar_mysql_1_cpu_usage", + "value": 33, + "value_prev": null, + "app_type": "docker" + }, + { + "metric": "foobar_mysql_1_mem_limit", + "value": 15.36, + "value_prev": null, + "app_type": "docker" + }, + { + "metric": "foobar_mysql_1_mem_perc", + "value": 90, + "value_prev": null, + "app_type": "docker" + }, + { + "metric": "foobar_mysql_1_mem_used", + "value": 141.3, + "value_prev": null, + "app_type": "docker" + }, + { + "metric": "foobar_mysql_1_pids", + "value": 38, + "value_prev": null, + "app_type": "docker" + }, + { + "metric": "foobar_redis_1_cpu_usage", + "value": 23, + "value_prev": null, + "app_type": "docker" + }, + { + "metric": "foobar_redis_1_mem_limit", + "value": 15.36, + "value_prev": null, + "app_type": "docker" + }, + { + "metric": "foobar_redis_1_mem_perc", + "value": 3, + "value_prev": null, + "app_type": "docker" + }, + { + "metric": "foobar_redis_1_mem_used", + "value": 5.06, + "value_prev": null, + "app_type": "docker" + }, + { + "metric": "foobar_redis_1_pids", + "value": 5, + "value_prev": null, + "app_type": "docker" + } + ] + } + }, + "os": { + "discovery": { + "devices": [ + { + "sysName": "", + "sysObjectID": ".1.3.6.1.4.1.8072.3.2.10", + "sysDescr": "Linux server 3.10.0-693.5.2.el7.x86_64 #1 SMP Fri Oct 20 20:32:50 UTC 2017 x86_64", + "sysContact": "", + "version": "3.10.0-693.5.2.el7.x86_64", + "hardware": "Generic x86 64-bit", + "features": null, + "os": "linux", + "type": "server", + "serial": null, + "icon": "linux.svg", + "location": "" + } + ] + }, + "poller": { + "devices": [ + { + "sysName": "", + "sysObjectID": ".1.3.6.1.4.1.8072.3.2.10", + "sysDescr": "Linux server 3.10.0-693.5.2.el7.x86_64 #1 SMP Fri Oct 20 20:32:50 UTC 2017 x86_64", + "sysContact": "", + "version": "3.10.0-693.5.2.el7.x86_64", + "hardware": "Generic x86 64-bit", + "features": null, + "os": "linux", + "type": "server", + "serial": null, + "icon": "linux.svg", + "location": "" + } + ] + } + } +} diff --git a/tests/snmpsim/linux_docker-v1.snmprec b/tests/snmpsim/linux_docker-v1.snmprec new file mode 100644 index 0000000000..3809210019 --- /dev/null +++ b/tests/snmpsim/linux_docker-v1.snmprec @@ -0,0 +1,8 @@ +1.3.6.1.2.1.1.1.0|4|Linux server 3.10.0-693.5.2.el7.x86_64 #1 SMP Fri Oct 20 20:32:50 UTC 2017 x86_64 +1.3.6.1.2.1.1.2.0|6|1.3.6.1.4.1.8072.3.2.10 +1.3.6.1.2.1.1.3.0|67|77550514 +1.3.6.1.2.1.1.4.0|4| +1.3.6.1.2.1.1.5.0|4| +1.3.6.1.2.1.1.6.0|4| +1.3.6.1.4.1.8072.1.3.2.2.1.21.6.100.111.99.107.101.114|2|1 +1.3.6.1.4.1.8072.1.3.2.3.1.2.6.100.111.99.107.101.114|4|{"version":"1","data":[{"container":"foobar_laravel.test_1","pids":4,"memory":{"used":"26.67MiB","limit":"15.36GiB","perc":"0.17%"},"cpu":"0.09%"},{"container":"foobar_dashboard_1","pids":6,"memory":{"used":"6.934MiB","limit":"15.36GiB","perc":"0.04%"},"cpu":"0.01%"},{"container":"foobar_meilisearch_1","pids":15,"memory":{"used":"10.86MiB","limit":"15.36GiB","perc":"0.07%"},"cpu":"0.00%"},{"container":"foobar_mysql_1","pids":38,"memory":{"used":"141.3MiB","limit":"15.36GiB","perc":"0.90%"},"cpu":"0.33%"},{"container":"foobar_redis_1","pids":5,"memory":{"used":"5.055MiB","limit":"15.36GiB","perc":"0.03%"},"cpu":"0.23%"}],"error":"0","errorString":""}