]> git.ipfire.org Git - collecty.git/commitdiff
Add a processor graph
authorMichael Tremer <michael.tremer@ipfire.org>
Sat, 4 Oct 2025 11:55:50 +0000 (11:55 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sat, 4 Oct 2025 12:00:48 +0000 (12:00 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
Makefile.am
src/daemon/colors.h
src/daemon/graphs.c
src/daemon/graphs/graph.h
src/daemon/graphs/processor.c [new file with mode: 0644]
src/daemon/graphs/processor.h [new file with mode: 0644]

index 68e7f2c1201f6ecaaec4e2f52657326b0259a13b..17da441ce2a7e37959d5cf251a601652b1481c91 100644 (file)
@@ -112,6 +112,8 @@ dist_collectyd_SOURCES = \
        src/daemon/graphs/graph.h \
        src/daemon/graphs/loadavg.c \
        src/daemon/graphs/loadavg.h \
+       src/daemon/graphs/processor.c \
+       src/daemon/graphs/processor.h \
        src/daemon/i18n.h \
        src/daemon/logging.c \
        src/daemon/logging.h \
index a6eda8a1b47d890d5d6b89a54d146132ec876684..083011e397d3bc94acc993e6d4073c57b952846a 100644 (file)
@@ -32,6 +32,8 @@
 #define LIGHT_GREEN            "#8bc34a"
 #define BLUE                   "#2196f3"
 #define LIGHT_BLUE             "#03a9f4"
+#define PINK                   "#e91e63"
+#define DEEP_PURPLE            "#673ab7"
 
 /*
        Define some colours with a special meaning...
index 6edea48d56959ab9ac77d39c2827bc1a693b70dd..d2dda708be18da75a4bd698ec331fbbb5ba6ec9a 100644 (file)
 #include "graphs/conntrack.h"
 #include "graphs/contextswitches.h"
 #include "graphs/loadavg.h"
+#include "graphs/processor.h"
 
 // Register all graphs
 static const collecty_graph_impl* graph_impls[] = {
        &conntrack_graph,
        &contextswitches_graph,
        &loadavg_graph,
+       &processor_graph,
        NULL,
 };
 
index 97181d3490cd5da84d95e3163cdb73d9b4fb448a..2e6c6f7815d26c5f57a48814320335adb4b30964 100644 (file)
@@ -49,6 +49,7 @@
 
 // A column is exactly 16 characters wide
 #define COLUMN                 "%16s"
+#define PERCENTAGE             "%%13.2lf%%%%"
 #define INTEGER                        "%%16.0lf"
 #define LARGE_INTEGER  "%%14.0lf %%s"
 #define FLOAT                  "%%14.2lf"
 #define DRAW_LINE3(args, field, color, ...) DRAW(args, "LINE3", field, color, __VA_ARGS__)
 #define DRAW_LINE3_WITH_LABEL(args, field, color, label, ...) DRAW_WITH_LABEL(args, "LINE3", field, color, label, __VA_ARGS__)
 
+// Macros to draw the background of an area
+#define DRAW_AREA_BACKGROUND(args, field, color, ...) \
+       DRAW(args, "AREA", field, COLOR_WITH_ALPHA(color, OPACITY_AREA), __VA_ARGS__)
+
+// Macros to draw the area's outline
+#define DRAW_AREA_OUTLINE_WITH_LABEL   DRAW_LINE1_WITH_LABEL
+
 // Areas are being drawn with an outline
 #define DRAW_AREA_WITH_LABEL(args, field, color, label, ...) \
        do { \
-               DRAW(args, "AREA", field, COLOR_WITH_ALPHA(color, OPACITY_AREA)); \
-               DRAW_LINE1_WITH_LABEL(args, field, color, label, __VA_ARGS__); \
+               DRAW_AREA_BACKGROUND(args, field, color); \
+               DRAW_AREA_OUTLINE_WITH_LABEL(args, field, color, label, __VA_ARGS__); \
        } while(0)
 
+// Modifiers
+#define STACK                  ":STACK"
+
 // Modifiers for lines
 #define DASHES                 ":dashes"
 #define SKIPSCALE              ":skipscale"
 
 // Add something to the legend of the graph
 #define PRINT(args, field, ...)                                        SCRIPT(args, "GPRINT:" field ":" __VA_ARGS__)
+#define PRINT_EMPTY_LINE(args)                                 SCRIPT(args, "COMMENT: \\n")
 #define PRINT_HEADER(args, label, ...)                 SCRIPT(args, "COMMENT:" COLUMN __VA_ARGS__, label)
+#define PRINT_LABEL(args, label, ...)                  SCRIPT(args, "COMMENT: %-31s" __VA_ARGS__, label)
 #define PRINT_EMPTY_LABEL(args, ...)                   SCRIPT(args, "COMMENT:                                " __VA_ARGS__)
 #define PRINT_NOTHING(args, ...)                               SCRIPT(args, "COMMENT:                " __VA_ARGS__)
+#define PRINT_PERCENTAGE(args, field, ...)             PRINT(args, field, PERCENTAGE __VA_ARGS__)
 #define PRINT_INTEGER(args, field, ...)                        PRINT(args, field, INTEGER __VA_ARGS__)
 #define PRINT_LARGE_INTEGER(args, field, ...)  PRINT(args, field, LARGE_INTEGER __VA_ARGS__)
 #define PRINT_FLOAT(args, field, ...)                  PRINT(args, field, FLOAT __VA_ARGS__)
                PRINT_HEADER(args, header4, EOL); \
        } while (0)
 
+// Handles for fields
+#define FIELD_CURRENT(field)                           field "_cur"
+#define FIELD_AVERAGE(field)                           field "_avg"
+#define FIELD_MINIMUM(field)                           field "_min"
+#define FIELD_MAXIMUM(field)                           field "_max"
+#define FIELD_PERCENT(field)                           field "_p"
+
+#define VALUE_CURRENT(args, field)                     SCRIPT(args, "VDEF:" FIELD_CURRENT(field) "=" field ",LAST")
+#define VALUE_AVERAGE(args, field)                     SCRIPT(args, "VDEF:" FIELD_AVERAGE(field) "=" field ",AVERAGE")
+#define VALUE_MINIMUM(args, field)                     SCRIPT(args, "VDEF:" FIELD_MINIMUM(field) "=" field ",MINIMUM")
+#define VALUE_MAXIMUM(args, field)                     SCRIPT(args, "VDEF:" FIELD_MAXIMUM(field) "=" field ",MAXIMUM")
+
+// Computes all values
+#define VALUE_ALL(args, field) \
+       do { \
+               VALUE_CURRENT(args, field); \
+               VALUE_AVERAGE(args, field); \
+               VALUE_MINIMUM(args, field); \
+               VALUE_MAXIMUM(args, field); \
+       } while (0)
+
+#define COMPUTE_SUM(args, sum, summand1, summand2) \
+       do { \
+               SCRIPT(args, "CDEF:" sum "=" summand1 "," summand2 ",+"); \
+               VALUE_ALL(args, sum); \
+       } while (0)
+
+#define COMPUTE_PERCENTAGE(args, field, total) \
+       do { \
+               SCRIPT(args, "CDEF:" FIELD_PERCENT(field) "=100," field ",*," total ",/"); \
+               VALUE_ALL(args, FIELD_PERCENT(field)); \
+       } while (0)
+
+
 #endif /* COLLECTY_GRAPHS_GRAPH_H */
diff --git a/src/daemon/graphs/processor.c b/src/daemon/graphs/processor.c
new file mode 100644 (file)
index 0000000..b005808
--- /dev/null
@@ -0,0 +1,176 @@
+/*#############################################################################
+#                                                                             #
+# collecty - A system statistics collection daemon for IPFire                 #
+# Copyright (C) 2025 IPFire Development Team                                  #
+#                                                                             #
+# This program is free software: you can redistribute it and/or modify        #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation, either version 3 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# This program is distributed in the hope that it will be useful,             #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+# GNU General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+#############################################################################*/
+
+#include "graph.h"
+#include "processor.h"
+
+// Set some colors
+#define COLOR_USER                     LIGHT_GREEN
+#define COLOR_NICE                     BLUE
+#define COLOR_SYS                      RED
+#define COLOR_WAIT                     DEEP_PURPLE
+#define COLOR_IRQ                      ORANGE
+#define COLOR_SOFTIRQ          YELLOW
+#define COLOR_STEAL                    LIGHT_BLUE
+#define COLOR_GUEST                    PINK
+#define COLOR_GUEST_NICE       PINK
+#define COLOR_IDLE                     LIGHT_GREY
+
+static int processor_title(collecty_ctx* ctx, collecty_graph* graph,
+               const char* object, char** title) {
+       return collecty_format_title(title, "%s", _("Processor Usage"));
+}
+
+static int processor_vlabel(collecty_ctx* ctx, collecty_graph* graph,
+               const char* object, char** title) {
+       return collecty_format_title(title, "%s", _("Percent"));
+}
+
+
+static int processor_render(collecty_ctx* ctx,
+               collecty_graph* graph, collecty_args* args, const char* object) {
+       int r;
+
+       // This requires the loadavg source
+       r = collecty_graph_require_source(graph, args, "processor", object);
+       if (r < 0)
+               return r;
+
+       // Add up all used cycles
+       r = collecty_args_push(args,
+               "CDEF:usage=user,nice,+,sys,+,wait,+,irq,+,softirq,+,steal,+,guest,+,guest_nice,+");
+       if (r < 0)
+               return r;
+
+       // Add idle to get the total number of cycles
+       COMPUTE_SUM(args, "total", "usage", "idle");
+
+       // Compute usage in percent
+       COMPUTE_PERCENTAGE(args, "usage", "total");
+       COMPUTE_PERCENTAGE(args, "user", "total");
+       COMPUTE_PERCENTAGE(args, "nice", "total");
+       COMPUTE_PERCENTAGE(args, "sys", "total");
+       COMPUTE_PERCENTAGE(args, "wait", "total");
+       COMPUTE_PERCENTAGE(args, "irq", "total");
+       COMPUTE_PERCENTAGE(args, "softirq", "total");
+       COMPUTE_PERCENTAGE(args, "steal", "total");
+       COMPUTE_PERCENTAGE(args, "guest", "total");
+       COMPUTE_PERCENTAGE(args, "guest_nice", "total");
+
+       // Header
+       PRINT_HEADER4(args, _("Current"), _("Average"), _("Minimum"), _("Maximum"));
+
+       // Show the total usage
+       PRINT_LABEL(args, _("Total"));
+       PRINT_PERCENTAGE(args, FIELD_CURRENT(FIELD_PERCENT("usage")));
+       PRINT_PERCENTAGE(args, FIELD_AVERAGE(FIELD_PERCENT("usage")));
+       PRINT_PERCENTAGE(args, FIELD_MINIMUM(FIELD_PERCENT("usage")));
+       PRINT_PERCENTAGE(args, FIELD_MAXIMUM(FIELD_PERCENT("usage")), EOL);
+
+       PRINT_EMPTY_LINE(args);
+
+       // Draw the stacked background first
+       DRAW_AREA_BACKGROUND(args, FIELD_PERCENT("user"), COLOR_USER);
+       DRAW_AREA_BACKGROUND(args, FIELD_PERCENT("nice"), COLOR_NICE, STACK);
+       DRAW_AREA_BACKGROUND(args, FIELD_PERCENT("sys"), COLOR_SYS, STACK);
+       DRAW_AREA_BACKGROUND(args, FIELD_PERCENT("wait"), COLOR_WAIT, STACK);
+       DRAW_AREA_BACKGROUND(args, FIELD_PERCENT("irq"), COLOR_IRQ, STACK);
+       DRAW_AREA_BACKGROUND(args, FIELD_PERCENT("softirq"), COLOR_SOFTIRQ, STACK);
+       DRAW_AREA_BACKGROUND(args, FIELD_PERCENT("steal"), COLOR_STEAL, STACK);
+       DRAW_AREA_BACKGROUND(args, FIELD_PERCENT("guest"), COLOR_GUEST, STACK);
+       DRAW_AREA_BACKGROUND(args, FIELD_PERCENT("guest_nice"), COLOR_GUEST_NICE, STACK);
+
+       // Draw the area outlines afterwards
+       DRAW_AREA_OUTLINE_WITH_LABEL(args,
+               FIELD_PERCENT("user"), COLOR_USER, _("User"));
+       PRINT_PERCENTAGE(args, FIELD_CURRENT(FIELD_PERCENT("user")));
+       PRINT_PERCENTAGE(args, FIELD_AVERAGE(FIELD_PERCENT("user")));
+       PRINT_PERCENTAGE(args, FIELD_MINIMUM(FIELD_PERCENT("user")));
+       PRINT_PERCENTAGE(args, FIELD_MAXIMUM(FIELD_PERCENT("user")), EOL);
+
+       DRAW_AREA_OUTLINE_WITH_LABEL(args,
+               FIELD_PERCENT("nice"), COLOR_NICE, _("Nice"), STACK);
+       PRINT_PERCENTAGE(args, FIELD_CURRENT(FIELD_PERCENT("nice")));
+       PRINT_PERCENTAGE(args, FIELD_AVERAGE(FIELD_PERCENT("nice")));
+       PRINT_PERCENTAGE(args, FIELD_MINIMUM(FIELD_PERCENT("nice")));
+       PRINT_PERCENTAGE(args, FIELD_MAXIMUM(FIELD_PERCENT("nice")), EOL);
+
+       DRAW_AREA_OUTLINE_WITH_LABEL(args,
+               FIELD_PERCENT("sys"), COLOR_SYS, _("Sys"), STACK);
+       PRINT_PERCENTAGE(args, FIELD_CURRENT(FIELD_PERCENT("sys")));
+       PRINT_PERCENTAGE(args, FIELD_AVERAGE(FIELD_PERCENT("sys")));
+       PRINT_PERCENTAGE(args, FIELD_MINIMUM(FIELD_PERCENT("sys")));
+       PRINT_PERCENTAGE(args, FIELD_MAXIMUM(FIELD_PERCENT("sys")), EOL);
+
+       DRAW_AREA_OUTLINE_WITH_LABEL(args,
+               FIELD_PERCENT("wait"), COLOR_WAIT, _("Wait"), STACK);
+       PRINT_PERCENTAGE(args, FIELD_CURRENT(FIELD_PERCENT("wait")));
+       PRINT_PERCENTAGE(args, FIELD_AVERAGE(FIELD_PERCENT("wait")));
+       PRINT_PERCENTAGE(args, FIELD_MINIMUM(FIELD_PERCENT("wait")));
+       PRINT_PERCENTAGE(args, FIELD_MAXIMUM(FIELD_PERCENT("wait")), EOL);
+
+       DRAW_AREA_OUTLINE_WITH_LABEL(args,
+               FIELD_PERCENT("irq"), COLOR_IRQ, _("Interrupt"), STACK);
+       PRINT_PERCENTAGE(args, FIELD_CURRENT(FIELD_PERCENT("irq")));
+       PRINT_PERCENTAGE(args, FIELD_AVERAGE(FIELD_PERCENT("irq")));
+       PRINT_PERCENTAGE(args, FIELD_MINIMUM(FIELD_PERCENT("irq")));
+       PRINT_PERCENTAGE(args, FIELD_MAXIMUM(FIELD_PERCENT("irq")), EOL);
+
+       DRAW_AREA_OUTLINE_WITH_LABEL(args,
+               FIELD_PERCENT("softirq"), COLOR_SOFTIRQ, _("Soft Interrupt"), STACK);
+       PRINT_PERCENTAGE(args, FIELD_CURRENT(FIELD_PERCENT("softirq")));
+       PRINT_PERCENTAGE(args, FIELD_AVERAGE(FIELD_PERCENT("softirq")));
+       PRINT_PERCENTAGE(args, FIELD_MINIMUM(FIELD_PERCENT("softirq")));
+       PRINT_PERCENTAGE(args, FIELD_MAXIMUM(FIELD_PERCENT("softirq")), EOL);
+
+       DRAW_AREA_OUTLINE_WITH_LABEL(args,
+               FIELD_PERCENT("steal"), COLOR_STEAL, _("Steal"), STACK);
+       PRINT_PERCENTAGE(args, FIELD_CURRENT(FIELD_PERCENT("steal")));
+       PRINT_PERCENTAGE(args, FIELD_AVERAGE(FIELD_PERCENT("steal")));
+       PRINT_PERCENTAGE(args, FIELD_MINIMUM(FIELD_PERCENT("steal")));
+       PRINT_PERCENTAGE(args, FIELD_MAXIMUM(FIELD_PERCENT("steal")), EOL);
+
+       DRAW_AREA_OUTLINE_WITH_LABEL(args,
+               FIELD_PERCENT("guest"), COLOR_GUEST, _("Guest"), STACK);
+       PRINT_PERCENTAGE(args, FIELD_CURRENT(FIELD_PERCENT("guest")));
+       PRINT_PERCENTAGE(args, FIELD_AVERAGE(FIELD_PERCENT("guest")));
+       PRINT_PERCENTAGE(args, FIELD_MINIMUM(FIELD_PERCENT("guest")));
+       PRINT_PERCENTAGE(args, FIELD_MAXIMUM(FIELD_PERCENT("guest")), EOL);
+
+       DRAW_AREA_OUTLINE_WITH_LABEL(args,
+               FIELD_PERCENT("guest_nice"), COLOR_GUEST_NICE, _("Guest Nice"), STACK);
+       PRINT_PERCENTAGE(args, FIELD_CURRENT(FIELD_PERCENT("guest_nice")));
+       PRINT_PERCENTAGE(args, FIELD_AVERAGE(FIELD_PERCENT("guest_nice")));
+       PRINT_PERCENTAGE(args, FIELD_MINIMUM(FIELD_PERCENT("guest_nice")));
+       PRINT_PERCENTAGE(args, FIELD_MAXIMUM(FIELD_PERCENT("guest_nice")), EOL);
+
+       return 0;
+}
+
+const collecty_graph_impl processor_graph = {
+       .name    = "Processor",
+       .render  = processor_render,
+       .title   = processor_title,
+       .vlabel  = processor_vlabel,
+
+       // Limits
+       .lower_limit = 0,
+       .upper_limit = 100,
+};
diff --git a/src/daemon/graphs/processor.h b/src/daemon/graphs/processor.h
new file mode 100644 (file)
index 0000000..6df691d
--- /dev/null
@@ -0,0 +1,28 @@
+/*#############################################################################
+#                                                                             #
+# collecty - A system statistics collection daemon for IPFire                 #
+# Copyright (C) 2025 IPFire Development Team                                  #
+#                                                                             #
+# This program is free software: you can redistribute it and/or modify        #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation, either version 3 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# This program is distributed in the hope that it will be useful,             #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+# GNU General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+#############################################################################*/
+
+#ifndef COLLECTY_GRAPH_PROCESSOR_H
+#define COLLECTY_GRAPH_PROCESSOR_H
+
+#include "../graph.h"
+
+extern const collecty_graph_impl processor_graph;
+
+#endif /* COLLECTY_GRAPH_PROCESSOR_H */