in_node_exporter_metrics: add Linux sockstat collector#10718
Conversation
Signed-off-by: Eduardo Silva <eduardo@chronosphere.io>
WalkthroughA new "sockstat" collector has been integrated into the node_exporter_metrics plugin for Linux. This includes updating build configuration, plugin initialization, and metric structures, as well as introducing new source and header files for the collector. The Linux implementation reads and exposes detailed socket statistics from Changes
Sequence Diagram(s)sequenceDiagram
participant Plugin as node_exporter_metrics Plugin
participant SockstatCollector as sockstat_collector (Linux)
participant ProcFS as /proc/net/sockstat & /proc/net/sockstat6
Plugin->>SockstatCollector: Initialize (cb_init)
SockstatCollector->>SockstatCollector: Register Prometheus gauges
loop On scrape interval
Plugin->>SockstatCollector: Update (cb_update)
SockstatCollector->>ProcFS: Read socket statistics
ProcFS-->>SockstatCollector: Return file contents
SockstatCollector->>SockstatCollector: Parse and update metrics
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~15–20 minutes Poem
Note 🔌 MCP (Model Context Protocol) integration is now available in Early Access!Pro users can now connect to remote MCP servers under the Integrations page to get reviews and chat conversations that understand additional development context. ✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 8
🧹 Nitpick comments (5)
plugins/in_node_exporter_metrics/ne.c (1)
390-395: Config map entry for sockstat intervalNew "collector.sockstat.scrape_interval" key aligns with the dynamic interval lookup; default "0" defers to global scrape_interval.
Consider updating the plugin docs to mention the new collector and its config key. I can help draft that.
plugins/in_node_exporter_metrics/ne.h (1)
143-164: Sockstat gauge fields added; clarify units and consider platform guard
- Fields cover IPv4 and IPv6, including page-based mem and byte-converted variants. Good coverage.
- Nit: add a short comment clarifying units (pages vs bytes) for TCP/UDP mem to avoid misuse.
- Optional: wrap these members with an linux guard to reduce struct size on non-Linux builds (only if consistent with project conventions).
Example comment for unit clarity:
- struct cmt_gauge *sockstat_TCP_mem; - struct cmt_gauge *sockstat_TCP_mem_bytes; + struct cmt_gauge *sockstat_TCP_mem; /* pages */ + struct cmt_gauge *sockstat_TCP_mem_bytes; /* bytes */plugins/in_node_exporter_metrics/ne_sockstat_linux.c (3)
34-39: Metric help text: not IPv4-only.The sockets: used value in /proc/net/sockstat is total sockets, not IPv4-only. Adjust help string.
- "Number of IPv4 sockets in use.", + "Number of sockets in use.",
223-226: Minor: explicit cast for page_size multiplication.Cast page_size to double to avoid any chance of unintended integer promotion before FP math (clarity).
- cmt_gauge_set(ctx->sockstat_TCP_mem_bytes, ts, d_val * page_size, 0, NULL); + cmt_gauge_set(ctx->sockstat_TCP_mem_bytes, ts, d_val * (double) page_size, 0, NULL); ... - cmt_gauge_set(ctx->sockstat_UDP_mem_bytes, ts, d_val * page_size, 0, NULL); + cmt_gauge_set(ctx->sockstat_UDP_mem_bytes, ts, d_val * (double) page_size, 0, NULL);Also applies to: 246-248
157-378: Optional: reduce duplication with a small parsing helper.A helper to fetch a numeric value by key from a token list would cut repetition and potential mistakes across TCP/UDP/FRAG blocks.
I can draft a static helper like: int parse_kv_double(struct mk_list *tokens, const char *key, double *out), plus a thin wrapper to set gauges.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
plugins/in_node_exporter_metrics/CMakeLists.txt(1 hunks)plugins/in_node_exporter_metrics/ne.c(3 hunks)plugins/in_node_exporter_metrics/ne.h(2 hunks)plugins/in_node_exporter_metrics/ne_sockstat.c(1 hunks)plugins/in_node_exporter_metrics/ne_sockstat.h(1 hunks)plugins/in_node_exporter_metrics/ne_sockstat_linux.c(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (28)
- GitHub Check: pr-windows-build / call-build-windows-package (Windows 64bit, x64, x64-windows-static, 3.31.6)
- GitHub Check: pr-windows-build / call-build-windows-package (Windows 64bit (Arm64), amd64_arm64, -DCMAKE_SYSTEM_NAME=Windows -DCMA...
- GitHub Check: pr-windows-build / call-build-windows-package (Windows 32bit, x86, x86-windows-static, 3.31.6)
- GitHub Check: PR - fuzzing test
- GitHub Check: pr-compile-system-libs (-DFLB_PREFER_SYSTEM_LIBS=On, 3.31.6, clang, clang++, ubuntu-24.04, clang-14)
- GitHub Check: pr-compile-system-libs (-DFLB_PREFER_SYSTEM_LIBS=On, 3.31.6, clang, clang++, ubuntu-22.04, clang-12)
- GitHub Check: pr-compile-system-libs (-DFLB_PREFER_SYSTEM_LIBS=On, 3.31.6, gcc, g++, ubuntu-22.04, clang-12)
- GitHub Check: pr-compile-system-libs (-DFLB_PREFER_SYSTEM_LIBS=On, 3.31.6, gcc, g++, ubuntu-24.04, clang-14)
- GitHub Check: pr-compile-centos-7
- GitHub Check: run-ubuntu-unit-tests (-DFLB_SIMD=Off, 3.31.6, clang, clang++)
- GitHub Check: run-ubuntu-unit-tests (-DFLB_SANITIZE_MEMORY=On, 3.31.6, clang, clang++)
- GitHub Check: run-ubuntu-unit-tests (-DFLB_JEMALLOC=On, 3.31.6, clang, clang++)
- GitHub Check: run-ubuntu-unit-tests (-DFLB_JEMALLOC=Off, 3.31.6, clang, clang++)
- GitHub Check: run-ubuntu-unit-tests (-DFLB_SIMD=On, 3.31.6, gcc, g++)
- GitHub Check: run-ubuntu-unit-tests (-DFLB_SANITIZE_THREAD=On, 3.31.6, clang, clang++)
- GitHub Check: run-ubuntu-unit-tests (-DSANITIZE_ADDRESS=On, 3.31.6, clang, clang++)
- GitHub Check: run-ubuntu-unit-tests (-DFLB_SANITIZE_THREAD=On, 3.31.6, gcc, g++)
- GitHub Check: run-ubuntu-unit-tests (-DFLB_COVERAGE=On, 3.31.6, gcc, g++)
- GitHub Check: run-ubuntu-unit-tests (-DFLB_SIMD=On, 3.31.6, clang, clang++)
- GitHub Check: run-ubuntu-unit-tests (-DSANITIZE_UNDEFINED=On, 3.31.6, clang, clang++)
- GitHub Check: run-ubuntu-unit-tests (-DFLB_SANITIZE_MEMORY=On, 3.31.6, gcc, g++)
- GitHub Check: run-ubuntu-unit-tests (-DFLB_SMALL=On, 3.31.6, clang, clang++)
- GitHub Check: run-ubuntu-unit-tests (-DSANITIZE_UNDEFINED=On, 3.31.6, gcc, g++)
- GitHub Check: run-ubuntu-unit-tests (-DFLB_SIMD=Off, 3.31.6, gcc, g++)
- GitHub Check: run-ubuntu-unit-tests (-DSANITIZE_ADDRESS=On, 3.31.6, gcc, g++)
- GitHub Check: run-ubuntu-unit-tests (-DFLB_SMALL=On, 3.31.6, gcc, g++)
- GitHub Check: run-ubuntu-unit-tests (-DFLB_JEMALLOC=Off, 3.31.6, gcc, g++)
- GitHub Check: run-ubuntu-unit-tests (-DFLB_JEMALLOC=On, 3.31.6, gcc, g++)
🔇 Additional comments (9)
plugins/in_node_exporter_metrics/CMakeLists.txt (1)
10-10: Build integration for sockstat is correctAdding ne_sockstat.c to the src list is sufficient; it conditionally includes the Linux implementation and provides a stub elsewhere, so cross-platform builds remain clean.
plugins/in_node_exporter_metrics/ne_sockstat.h (1)
1-27: Header looks goodGuard, include, and extern declaration are consistent with existing collectors.
plugins/in_node_exporter_metrics/ne.c (2)
42-42: Include sockstat collector headerInclude placement is consistent with other collectors; no issues.
196-196: Register sockstat collectorCollector is appended alongside netdev and filefd, matching established order and activation flow.
plugins/in_node_exporter_metrics/ne_sockstat.c (3)
26-31: Graceful non-Linux fallbackStub collector with NULL callbacks ensures “not supported” behavior without activation. Good.
20-22: Consistency Confirmed: direct inclusion is used across all collectorsAll collectors in plugins/in_node_exporter_metrics (e.g. ne_vmstat.c, ne_thermalzone.c, ne_uname.c, etc.) follow the same pattern of
#ifdef __linux__and#include "ne_*_linux.c". Keeping the Linux-specific .c files in a single compilation unit here matches project precedent. No changes required. If you’d rather have separate compile units, consider switching to conditional CMake source selection in a future refactoring.
20-22: Linux sockstat: procfs path and page-size conversion verified
- The code uses
ctx->path_procfswith relative paths ("/net/sockstat"and"/net/sockstat6") rather than hard-coding/proc.- A call to
sysconf(_SC_PAGESIZE)retrieves the page size, and both TCP and UDP"mem"values (in pages) are multiplied bypage_sizeto produce byte metrics.No changes required.
plugins/in_node_exporter_metrics/ne.h (1)
36-36: Enable sockstat by default on LinuxAdding "sockstat" to NE_DEFAULT_ENABLED_METRICS (Linux) is consistent with other collectors.
plugins/in_node_exporter_metrics/ne_sockstat_linux.c (1)
30-153: Overall: solid parity with node_exporter; nice addition.Collector wiring, metric set, and parsing align well with /proc sockstat formats. Good coverage across IPv4/IPv6.
| #include <unistd.h> | ||
|
|
||
| #include <fluent-bit/flb_info.h> | ||
| #include <fluent-bit/flb_input_plugin.h> | ||
|
|
||
| #include "ne.h" | ||
| #include "ne_utils.h" | ||
|
|
There was a problem hiding this comment.
Add missing string.h include (prevents implicit decl warnings).
Functions strncmp/strcmp are used; include string.h explicitly to avoid build issues with -Werror.
#define _GNU_SOURCE
#include <unistd.h>
+#include <string.h>
#include <fluent-bit/flb_info.h>
#include <fluent-bit/flb_input_plugin.h>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| #include <unistd.h> | |
| #include <fluent-bit/flb_info.h> | |
| #include <fluent-bit/flb_input_plugin.h> | |
| #include "ne.h" | |
| #include "ne_utils.h" | |
| #define _GNU_SOURCE | |
| #include <unistd.h> | |
| #include <string.h> | |
| #include <fluent-bit/flb_info.h> | |
| #include <fluent-bit/flb_input_plugin.h> | |
| #include "ne.h" | |
| #include "ne_utils.h" |
🤖 Prompt for AI Agents
In plugins/in_node_exporter_metrics/ne_sockstat_linux.c around lines 22 to 29,
the code uses string functions like strncmp and strcmp but does not include the
string.h header, causing implicit declaration warnings. Add #include <string.h>
among the other includes at the top of the file to explicitly include the string
functions and prevent build errors with -Werror.
| static int sockstat_configure(struct flb_ne *ctx) | ||
| { | ||
| struct cmt_gauge *g; | ||
|
|
||
| /* node_sockstat_sockets_used */ | ||
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "sockets_used", | ||
| "Number of IPv4 sockets in use.", | ||
| 0, NULL); | ||
| ctx->sockstat_sockets_used = g; | ||
|
|
||
| /* node_sockstat_TCP_alloc */ | ||
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "TCP_alloc", | ||
| "Number of TCP sockets in state alloc.", | ||
| 0, NULL); | ||
| ctx->sockstat_TCP_alloc = g; | ||
|
|
||
| /* node_sockstat_TCP_inuse */ | ||
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "TCP_inuse", | ||
| "Number of TCP sockets in state inuse.", | ||
| 0, NULL); | ||
| ctx->sockstat_TCP_inuse = g; | ||
|
|
||
| /* node_sockstat_TCP_mem */ | ||
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "TCP_mem", | ||
| "Number of memory pages used by TCP sockets, in Kernel memory pages.", | ||
| 0, NULL); | ||
| ctx->sockstat_TCP_mem = g; | ||
|
|
||
| /* node_sockstat_TCP_mem_bytes */ | ||
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "TCP_mem_bytes", | ||
| "Number of bytes used by TCP sockets.", | ||
| 0, NULL); | ||
| ctx->sockstat_TCP_mem_bytes = g; | ||
|
|
||
| /* node_sockstat_TCP_orphan */ | ||
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "TCP_orphan", | ||
| "Number of orphaned TCP sockets in use.", | ||
| 0, NULL); | ||
| ctx->sockstat_TCP_orphan = g; | ||
|
|
||
| /* node_sockstat_TCP_tw */ | ||
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "TCP_tw", | ||
| "Number of TCP sockets in state TIME_WAIT.", | ||
| 0, NULL); | ||
| ctx->sockstat_TCP_tw = g; | ||
|
|
||
| /* node_sockstat_UDP_inuse */ | ||
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "UDP_inuse", | ||
| "Number of UDP sockets in state inuse.", | ||
| 0, NULL); | ||
| ctx->sockstat_UDP_inuse = g; | ||
|
|
||
| /* node_sockstat_UDP_mem */ | ||
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "UDP_mem", | ||
| "Number of memory pages used by UDP sockets, in Kernel memory pages.", | ||
| 0, NULL); | ||
| ctx->sockstat_UDP_mem = g; | ||
|
|
||
| /* node_sockstat_UDP_mem_bytes */ | ||
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "UDP_mem_bytes", | ||
| "Number of bytes used by UDP sockets.", | ||
| 0, NULL); | ||
| ctx->sockstat_UDP_mem_bytes = g; | ||
|
|
||
| /* node_sockstat_UDPLITE_inuse */ | ||
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "UDPLITE_inuse", | ||
| "Number of UDPLITE sockets in state inuse.", | ||
| 0, NULL); | ||
| ctx->sockstat_UDPLITE_inuse = g; | ||
|
|
||
| /* node_sockstat_RAW_inuse */ | ||
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "RAW_inuse", | ||
| "Number of RAW sockets in state inuse.", | ||
| 0, NULL); | ||
| ctx->sockstat_RAW_inuse = g; | ||
|
|
||
| /* node_sockstat_FRAG_inuse */ | ||
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "FRAG_inuse", | ||
| "Number of FRAG sockets in state inuse.", | ||
| 0, NULL); | ||
| ctx->sockstat_FRAG_inuse = g; | ||
|
|
||
| /* node_sockstat_FRAG_memory */ | ||
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "FRAG_memory", | ||
| "Memory currently used for fragment reassembly in bytes.", | ||
| 0, NULL); | ||
| ctx->sockstat_FRAG_memory = g; | ||
|
|
||
| /* node_sockstat_TCP6_inuse */ | ||
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "TCP6_inuse", | ||
| "Number of TCP6 sockets in state inuse.", | ||
| 0, NULL); | ||
| ctx->sockstat_TCP6_inuse = g; | ||
|
|
||
| /* node_sockstat_UDP6_inuse */ | ||
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "UDP6_inuse", | ||
| "Number of UDP6 sockets in state inuse.", | ||
| 0, NULL); | ||
| ctx->sockstat_UDP6_inuse = g; | ||
|
|
||
| /* node_sockstat_UDPLITE6_inuse */ | ||
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "UDPLITE6_inuse", | ||
| "Number of UDPLITE6 sockets in state inuse.", | ||
| 0, NULL); | ||
| ctx->sockstat_UDPLITE6_inuse = g; | ||
|
|
||
| /* node_sockstat_RAW6_inuse */ | ||
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "RAW6_inuse", | ||
| "Number of RAW6 sockets in state inuse.", | ||
| 0, NULL); | ||
| ctx->sockstat_RAW6_inuse = g; | ||
|
|
||
| /* node_sockstat_FRAG6_inuse */ | ||
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "FRAG6_inuse", | ||
| "Number of FRAG6 sockets in state inuse.", | ||
| 0, NULL); | ||
| ctx->sockstat_FRAG6_inuse = g; | ||
|
|
||
| /* node_sockstat_FRAG6_memory */ | ||
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "FRAG6_memory", | ||
| "Memory currently used for IPv6 fragment reassembly in bytes.", | ||
| 0, NULL); | ||
| ctx->sockstat_FRAG6_memory = g; | ||
|
|
||
| return 0; | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Handle gauge creation failures (avoid NULL deref later).
cmt_gauge_create can fail; check and bail early. Apply the same pattern to all gauge creations.
/* node_sockstat_sockets_used */
g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "sockets_used",
"Number of sockets in use.",
0, NULL);
+ if (g == NULL) {
+ return -1;
+ }
ctx->sockstat_sockets_used = g;Follow this for every gauge in this function. Then propagate the error in init (see separate comment).
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| static int sockstat_configure(struct flb_ne *ctx) | |
| { | |
| struct cmt_gauge *g; | |
| /* node_sockstat_sockets_used */ | |
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "sockets_used", | |
| "Number of IPv4 sockets in use.", | |
| 0, NULL); | |
| ctx->sockstat_sockets_used = g; | |
| /* node_sockstat_TCP_alloc */ | |
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "TCP_alloc", | |
| "Number of TCP sockets in state alloc.", | |
| 0, NULL); | |
| ctx->sockstat_TCP_alloc = g; | |
| /* node_sockstat_TCP_inuse */ | |
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "TCP_inuse", | |
| "Number of TCP sockets in state inuse.", | |
| 0, NULL); | |
| ctx->sockstat_TCP_inuse = g; | |
| /* node_sockstat_TCP_mem */ | |
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "TCP_mem", | |
| "Number of memory pages used by TCP sockets, in Kernel memory pages.", | |
| 0, NULL); | |
| ctx->sockstat_TCP_mem = g; | |
| /* node_sockstat_TCP_mem_bytes */ | |
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "TCP_mem_bytes", | |
| "Number of bytes used by TCP sockets.", | |
| 0, NULL); | |
| ctx->sockstat_TCP_mem_bytes = g; | |
| /* node_sockstat_TCP_orphan */ | |
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "TCP_orphan", | |
| "Number of orphaned TCP sockets in use.", | |
| 0, NULL); | |
| ctx->sockstat_TCP_orphan = g; | |
| /* node_sockstat_TCP_tw */ | |
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "TCP_tw", | |
| "Number of TCP sockets in state TIME_WAIT.", | |
| 0, NULL); | |
| ctx->sockstat_TCP_tw = g; | |
| /* node_sockstat_UDP_inuse */ | |
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "UDP_inuse", | |
| "Number of UDP sockets in state inuse.", | |
| 0, NULL); | |
| ctx->sockstat_UDP_inuse = g; | |
| /* node_sockstat_UDP_mem */ | |
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "UDP_mem", | |
| "Number of memory pages used by UDP sockets, in Kernel memory pages.", | |
| 0, NULL); | |
| ctx->sockstat_UDP_mem = g; | |
| /* node_sockstat_UDP_mem_bytes */ | |
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "UDP_mem_bytes", | |
| "Number of bytes used by UDP sockets.", | |
| 0, NULL); | |
| ctx->sockstat_UDP_mem_bytes = g; | |
| /* node_sockstat_UDPLITE_inuse */ | |
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "UDPLITE_inuse", | |
| "Number of UDPLITE sockets in state inuse.", | |
| 0, NULL); | |
| ctx->sockstat_UDPLITE_inuse = g; | |
| /* node_sockstat_RAW_inuse */ | |
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "RAW_inuse", | |
| "Number of RAW sockets in state inuse.", | |
| 0, NULL); | |
| ctx->sockstat_RAW_inuse = g; | |
| /* node_sockstat_FRAG_inuse */ | |
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "FRAG_inuse", | |
| "Number of FRAG sockets in state inuse.", | |
| 0, NULL); | |
| ctx->sockstat_FRAG_inuse = g; | |
| /* node_sockstat_FRAG_memory */ | |
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "FRAG_memory", | |
| "Memory currently used for fragment reassembly in bytes.", | |
| 0, NULL); | |
| ctx->sockstat_FRAG_memory = g; | |
| /* node_sockstat_TCP6_inuse */ | |
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "TCP6_inuse", | |
| "Number of TCP6 sockets in state inuse.", | |
| 0, NULL); | |
| ctx->sockstat_TCP6_inuse = g; | |
| /* node_sockstat_UDP6_inuse */ | |
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "UDP6_inuse", | |
| "Number of UDP6 sockets in state inuse.", | |
| 0, NULL); | |
| ctx->sockstat_UDP6_inuse = g; | |
| /* node_sockstat_UDPLITE6_inuse */ | |
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "UDPLITE6_inuse", | |
| "Number of UDPLITE6 sockets in state inuse.", | |
| 0, NULL); | |
| ctx->sockstat_UDPLITE6_inuse = g; | |
| /* node_sockstat_RAW6_inuse */ | |
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "RAW6_inuse", | |
| "Number of RAW6 sockets in state inuse.", | |
| 0, NULL); | |
| ctx->sockstat_RAW6_inuse = g; | |
| /* node_sockstat_FRAG6_inuse */ | |
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "FRAG6_inuse", | |
| "Number of FRAG6 sockets in state inuse.", | |
| 0, NULL); | |
| ctx->sockstat_FRAG6_inuse = g; | |
| /* node_sockstat_FRAG6_memory */ | |
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "FRAG6_memory", | |
| "Memory currently used for IPv6 fragment reassembly in bytes.", | |
| 0, NULL); | |
| ctx->sockstat_FRAG6_memory = g; | |
| return 0; | |
| } | |
| /* node_sockstat_sockets_used */ | |
| g = cmt_gauge_create(ctx->cmt, "node", "sockstat", "sockets_used", | |
| "Number of IPv4 sockets in use.", | |
| 0, NULL); | |
| if (g == NULL) { | |
| return -1; | |
| } | |
| ctx->sockstat_sockets_used = g; |
🤖 Prompt for AI Agents
In plugins/in_node_exporter_metrics/ne_sockstat_linux.c from lines 30 to 155,
the function sockstat_configure creates multiple gauges using cmt_gauge_create
but does not check if the creation failed (returns NULL), which can lead to NULL
pointer dereferences later. To fix this, after each cmt_gauge_create call, check
if the returned pointer is NULL; if so, return an error code immediately to bail
out early. Apply this NULL check and early return pattern consistently for every
gauge creation in this function.
| int ret; | ||
| uint64_t ts; | ||
| size_t page_size; | ||
| double d_val; | ||
| struct mk_list list; | ||
| struct mk_list *head; | ||
| struct flb_slist_entry *line; | ||
| struct mk_list tokens; | ||
| int parts; | ||
| int i; | ||
| struct flb_slist_entry *key; | ||
| struct flb_slist_entry *val; | ||
|
|
||
| mk_list_init(&list); | ||
| ret = ne_utils_file_read_lines(ctx->path_procfs, "/net/sockstat", &list); | ||
| if (ret == -1) { | ||
| return -1; | ||
| } |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Propagate update errors (or explicitly log/ignore).
sockstat_update returns -1 on IPv4 read failure, but ne_sockstat_update ignores it. Either propagate the error or add an explicit log and return 0 by design. Verify framework expectations for cb_update return values.
Option A: propagate error
static int ne_sockstat_update(struct flb_input_instance *ins, struct flb_config *config, void *in_context)
{
struct flb_ne *ctx = (struct flb_ne *) in_context;
- sockstat_update(ctx);
- return 0;
+ return sockstat_update(ctx);
}Option B: keep 0 but log (if logger available), e.g. flb_plg_warn(ctx->ins, ...) when ne_utils_file_read_lines() fails in sockstat_update().
Also applies to: 386-392
I’m going to inspect the update callback and helper definitions to confirm error-propagation behavior and see how other metrics plugins handle failures.
🏁 Script executed:
#!/bin/bash
# Locate the sockstat update callback
rg -n "ne_sockstat_update" -A3 -B3 plugins/in_node_exporter_metrics/ne_sockstat_linux.c
# Locate the inner helper and its return semantics
rg -n "static int sockstat_update" -A5 -B5 plugins/in_node_exporter_metrics/ne_sockstat_linux.c
# Find how ne_utils_file_read_lines signals errors
rg -n "ne_utils_file_read_lines" -A3 -B3 .
# Compare with other plugins’ update callbacks
rg -n "static int ne_.*_update" -A3 -B3 plugins/in_node_exporter_metricsLength of output: 28924
Add warning log on sockstat_update failures to surface errors
Currently, sockstat_update() will return -1 if it can’t read /net/sockstat, but its caller ne_sockstat_update() (like most other collectors) swallows that and unconditionally returns 0—so failures are silent. Instead of propagating an error code (which would disable the whole plugin), emit a warning and keep the 0 return to remain consistent with other collectors.
• File: plugins/in_node_exporter_metrics/ne_sockstat_linux.c
• Around lines 173–176 (IPv4 branch) and similarly in the IPv6 block at lines 300–303
Suggested diff inside sockstat_update():
mk_list_init(&list);
- ret = ne_utils_file_read_lines(ctx->path_procfs, "/net/sockstat", &list);
- if (ret == -1) {
- return -1;
- }
+ ret = ne_utils_file_read_lines(ctx->path_procfs, "/net/sockstat", &list);
+ if (ret == -1) {
+ flb_plg_warn(ctx->ins,
+ "sockstat: failed to read %s/net/sockstat",
+ ctx->path_procfs);
+ /* leave old metrics in place; skip this cycle */
+ return 0;
+ }And in the IPv6 block:
- if (ret != -1) {
+ if (ret != -1) {
/* parse IPv6 stats */
}
+ else {
+ flb_plg_warn(ctx->ins,
+ "sockstat: failed to read %s/net/sockstat6",
+ ctx->path_procfs);
+ }This surfaces read errors without breaking the existing pattern of always returning 0 from ne_sockstat_update().
🤖 Prompt for AI Agents
In plugins/in_node_exporter_metrics/ne_sockstat_linux.c around lines 159 to 176
and similarly around lines 300 to 303, sockstat_update() currently returns -1 on
failure to read /net/sockstat but this error is swallowed by
ne_sockstat_update() which always returns 0, hiding failures. Modify
sockstat_update() to log a warning message when it fails to read /net/sockstat
instead of returning -1, and ensure it returns 0 to keep consistent with other
collectors. This way, errors are surfaced via logs without changing the return
behavior of ne_sockstat_update().
| if (strncmp(line->str, "sockets:", 8) == 0) { | ||
| mk_list_init(&tokens); | ||
| ret = flb_slist_split_string(&tokens, line->str, ' ', -1); | ||
| if (ret >= 3) { | ||
| val = flb_slist_entry_get(&tokens, 2); | ||
| if (val) { | ||
| ne_utils_str_to_double(val->str, &d_val); | ||
| cmt_gauge_set(ctx->sockstat_sockets_used, ts, d_val, 0, NULL); | ||
| } | ||
| } | ||
| flb_slist_destroy(&tokens); | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Guard against failed numeric conversion for sockets: used.
If ne_utils_str_to_double fails, d_val is undefined; don’t set the gauge.
- if (val) {
- ne_utils_str_to_double(val->str, &d_val);
- cmt_gauge_set(ctx->sockstat_sockets_used, ts, d_val, 0, NULL);
- }
+ if (val && ne_utils_str_to_double(val->str, &d_val) == 0) {
+ cmt_gauge_set(ctx->sockstat_sockets_used, ts, d_val, 0, NULL);
+ }🤖 Prompt for AI Agents
In plugins/in_node_exporter_metrics/ne_sockstat_linux.c around lines 184 to 195,
the code sets the gauge metric without checking if the numeric conversion from
string to double succeeded. Modify the code to check the return value of
ne_utils_str_to_double and only call cmt_gauge_set if the conversion was
successful, preventing use of an undefined d_val.
| else if (strncmp(line->str, "TCP:", 4) == 0) { | ||
| mk_list_init(&tokens); | ||
| ret = flb_slist_split_string(&tokens, line->str, ' ', -1); | ||
| parts = ret; | ||
| for (i = 1; i + 1 < parts; i += 2) { | ||
| key = flb_slist_entry_get(&tokens, i); | ||
| val = flb_slist_entry_get(&tokens, i + 1); | ||
| if (!key || !val) { | ||
| continue; | ||
| } | ||
| if (strcmp(key->str, "inuse") == 0) { | ||
| ne_utils_str_to_double(val->str, &d_val); | ||
| cmt_gauge_set(ctx->sockstat_TCP_inuse, ts, d_val, 0, NULL); | ||
| } | ||
| else if (strcmp(key->str, "orphan") == 0) { | ||
| ne_utils_str_to_double(val->str, &d_val); | ||
| cmt_gauge_set(ctx->sockstat_TCP_orphan, ts, d_val, 0, NULL); | ||
| } | ||
| else if (strcmp(key->str, "tw") == 0) { | ||
| ne_utils_str_to_double(val->str, &d_val); | ||
| cmt_gauge_set(ctx->sockstat_TCP_tw, ts, d_val, 0, NULL); | ||
| } | ||
| else if (strcmp(key->str, "alloc") == 0) { | ||
| ne_utils_str_to_double(val->str, &d_val); | ||
| cmt_gauge_set(ctx->sockstat_TCP_alloc, ts, d_val, 0, NULL); | ||
| } | ||
| else if (strcmp(key->str, "mem") == 0) { | ||
| ne_utils_str_to_double(val->str, &d_val); | ||
| cmt_gauge_set(ctx->sockstat_TCP_mem, ts, d_val, 0, NULL); | ||
| cmt_gauge_set(ctx->sockstat_TCP_mem_bytes, ts, d_val * page_size, 0, NULL); | ||
| } | ||
| } | ||
| flb_slist_destroy(&tokens); | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Consistently check ne_utils_str_to_double() in TCP block.
Several branches set gauges without checking conversion result; this risks using stale/undefined d_val. Apply conversion checks in all branches.
- if (strcmp(key->str, "inuse") == 0) {
- ne_utils_str_to_double(val->str, &d_val);
- cmt_gauge_set(ctx->sockstat_TCP_inuse, ts, d_val, 0, NULL);
- }
+ if (strcmp(key->str, "inuse") == 0) {
+ if (ne_utils_str_to_double(val->str, &d_val) == 0) {
+ cmt_gauge_set(ctx->sockstat_TCP_inuse, ts, d_val, 0, NULL);
+ }
+ }
else if (strcmp(key->str, "orphan") == 0) {
- ne_utils_str_to_double(val->str, &d_val);
- cmt_gauge_set(ctx->sockstat_TCP_orphan, ts, d_val, 0, NULL);
+ if (ne_utils_str_to_double(val->str, &d_val) == 0) {
+ cmt_gauge_set(ctx->sockstat_TCP_orphan, ts, d_val, 0, NULL);
+ }
}
else if (strcmp(key->str, "tw") == 0) {
- ne_utils_str_to_double(val->str, &d_val);
- cmt_gauge_set(ctx->sockstat_TCP_tw, ts, d_val, 0, NULL);
+ if (ne_utils_str_to_double(val->str, &d_val) == 0) {
+ cmt_gauge_set(ctx->sockstat_TCP_tw, ts, d_val, 0, NULL);
+ }
}
else if (strcmp(key->str, "alloc") == 0) {
- ne_utils_str_to_double(val->str, &d_val);
- cmt_gauge_set(ctx->sockstat_TCP_alloc, ts, d_val, 0, NULL);
+ if (ne_utils_str_to_double(val->str, &d_val) == 0) {
+ cmt_gauge_set(ctx->sockstat_TCP_alloc, ts, d_val, 0, NULL);
+ }
}
else if (strcmp(key->str, "mem") == 0) {
- ne_utils_str_to_double(val->str, &d_val);
- cmt_gauge_set(ctx->sockstat_TCP_mem, ts, d_val, 0, NULL);
- cmt_gauge_set(ctx->sockstat_TCP_mem_bytes, ts, d_val * page_size, 0, NULL);
+ if (ne_utils_str_to_double(val->str, &d_val) == 0) {
+ cmt_gauge_set(ctx->sockstat_TCP_mem, ts, d_val, 0, NULL);
+ cmt_gauge_set(ctx->sockstat_TCP_mem_bytes, ts, d_val * (double) page_size, 0, NULL);
+ }
}Repeat a similar check pattern in UDP and FRAG blocks (see next comments).
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| else if (strncmp(line->str, "TCP:", 4) == 0) { | |
| mk_list_init(&tokens); | |
| ret = flb_slist_split_string(&tokens, line->str, ' ', -1); | |
| parts = ret; | |
| for (i = 1; i + 1 < parts; i += 2) { | |
| key = flb_slist_entry_get(&tokens, i); | |
| val = flb_slist_entry_get(&tokens, i + 1); | |
| if (!key || !val) { | |
| continue; | |
| } | |
| if (strcmp(key->str, "inuse") == 0) { | |
| ne_utils_str_to_double(val->str, &d_val); | |
| cmt_gauge_set(ctx->sockstat_TCP_inuse, ts, d_val, 0, NULL); | |
| } | |
| else if (strcmp(key->str, "orphan") == 0) { | |
| ne_utils_str_to_double(val->str, &d_val); | |
| cmt_gauge_set(ctx->sockstat_TCP_orphan, ts, d_val, 0, NULL); | |
| } | |
| else if (strcmp(key->str, "tw") == 0) { | |
| ne_utils_str_to_double(val->str, &d_val); | |
| cmt_gauge_set(ctx->sockstat_TCP_tw, ts, d_val, 0, NULL); | |
| } | |
| else if (strcmp(key->str, "alloc") == 0) { | |
| ne_utils_str_to_double(val->str, &d_val); | |
| cmt_gauge_set(ctx->sockstat_TCP_alloc, ts, d_val, 0, NULL); | |
| } | |
| else if (strcmp(key->str, "mem") == 0) { | |
| ne_utils_str_to_double(val->str, &d_val); | |
| cmt_gauge_set(ctx->sockstat_TCP_mem, ts, d_val, 0, NULL); | |
| cmt_gauge_set(ctx->sockstat_TCP_mem_bytes, ts, d_val * page_size, 0, NULL); | |
| } | |
| } | |
| flb_slist_destroy(&tokens); | |
| } | |
| else if (strncmp(line->str, "TCP:", 4) == 0) { | |
| mk_list_init(&tokens); | |
| ret = flb_slist_split_string(&tokens, line->str, ' ', -1); | |
| parts = ret; | |
| for (i = 1; i + 1 < parts; i += 2) { | |
| key = flb_slist_entry_get(&tokens, i); | |
| val = flb_slist_entry_get(&tokens, i + 1); | |
| if (!key || !val) { | |
| continue; | |
| } | |
| if (strcmp(key->str, "inuse") == 0) { | |
| if (ne_utils_str_to_double(val->str, &d_val) == 0) { | |
| cmt_gauge_set(ctx->sockstat_TCP_inuse, ts, d_val, 0, NULL); | |
| } | |
| } | |
| else if (strcmp(key->str, "orphan") == 0) { | |
| if (ne_utils_str_to_double(val->str, &d_val) == 0) { | |
| cmt_gauge_set(ctx->sockstat_TCP_orphan, ts, d_val, 0, NULL); | |
| } | |
| } | |
| else if (strcmp(key->str, "tw") == 0) { | |
| if (ne_utils_str_to_double(val->str, &d_val) == 0) { | |
| cmt_gauge_set(ctx->sockstat_TCP_tw, ts, d_val, 0, NULL); | |
| } | |
| } | |
| else if (strcmp(key->str, "alloc") == 0) { | |
| if (ne_utils_str_to_double(val->str, &d_val) == 0) { | |
| cmt_gauge_set(ctx->sockstat_TCP_alloc, ts, d_val, 0, NULL); | |
| } | |
| } | |
| else if (strcmp(key->str, "mem") == 0) { | |
| if (ne_utils_str_to_double(val->str, &d_val) == 0) { | |
| cmt_gauge_set(ctx->sockstat_TCP_mem, ts, d_val, 0, NULL); | |
| cmt_gauge_set(ctx->sockstat_TCP_mem_bytes, ts, d_val * (double) page_size, 0, NULL); | |
| } | |
| } | |
| } | |
| flb_slist_destroy(&tokens); | |
| } |
🤖 Prompt for AI Agents
In plugins/in_node_exporter_metrics/ne_sockstat_linux.c between lines 196 and
229, the TCP block calls ne_utils_str_to_double() to convert string values to
double but does not consistently check the return value to confirm successful
conversion before using d_val. To fix this, add a check after each
ne_utils_str_to_double() call to ensure it returns success before calling
cmt_gauge_set(). If the conversion fails, skip setting the gauge for that key to
avoid using stale or undefined d_val.
| else if (strncmp(line->str, "UDP:", 4) == 0) { | ||
| mk_list_init(&tokens); | ||
| ret = flb_slist_split_string(&tokens, line->str, ' ', -1); | ||
| parts = ret; | ||
| for (i = 1; i + 1 < parts; i += 2) { | ||
| key = flb_slist_entry_get(&tokens, i); | ||
| val = flb_slist_entry_get(&tokens, i + 1); | ||
| if (!key || !val) { | ||
| continue; | ||
| } | ||
| if (strcmp(key->str, "inuse") == 0) { | ||
| ne_utils_str_to_double(val->str, &d_val); | ||
| cmt_gauge_set(ctx->sockstat_UDP_inuse, ts, d_val, 0, NULL); | ||
| } | ||
| else if (strcmp(key->str, "mem") == 0) { | ||
| ne_utils_str_to_double(val->str, &d_val); | ||
| cmt_gauge_set(ctx->sockstat_UDP_mem, ts, d_val, 0, NULL); | ||
| cmt_gauge_set(ctx->sockstat_UDP_mem_bytes, ts, d_val * page_size, 0, NULL); | ||
| } | ||
| } | ||
| flb_slist_destroy(&tokens); | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Guard conversion in UDP block.
Same issue as TCP: check conversion before setting gauges.
- if (strcmp(key->str, "inuse") == 0) {
- ne_utils_str_to_double(val->str, &d_val);
- cmt_gauge_set(ctx->sockstat_UDP_inuse, ts, d_val, 0, NULL);
- }
+ if (strcmp(key->str, "inuse") == 0) {
+ if (ne_utils_str_to_double(val->str, &d_val) == 0) {
+ cmt_gauge_set(ctx->sockstat_UDP_inuse, ts, d_val, 0, NULL);
+ }
+ }
else if (strcmp(key->str, "mem") == 0) {
- ne_utils_str_to_double(val->str, &d_val);
- cmt_gauge_set(ctx->sockstat_UDP_mem, ts, d_val, 0, NULL);
- cmt_gauge_set(ctx->sockstat_UDP_mem_bytes, ts, d_val * page_size, 0, NULL);
+ if (ne_utils_str_to_double(val->str, &d_val) == 0) {
+ cmt_gauge_set(ctx->sockstat_UDP_mem, ts, d_val, 0, NULL);
+ cmt_gauge_set(ctx->sockstat_UDP_mem_bytes, ts, d_val * (double) page_size, 0, NULL);
+ }
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| else if (strncmp(line->str, "UDP:", 4) == 0) { | |
| mk_list_init(&tokens); | |
| ret = flb_slist_split_string(&tokens, line->str, ' ', -1); | |
| parts = ret; | |
| for (i = 1; i + 1 < parts; i += 2) { | |
| key = flb_slist_entry_get(&tokens, i); | |
| val = flb_slist_entry_get(&tokens, i + 1); | |
| if (!key || !val) { | |
| continue; | |
| } | |
| if (strcmp(key->str, "inuse") == 0) { | |
| ne_utils_str_to_double(val->str, &d_val); | |
| cmt_gauge_set(ctx->sockstat_UDP_inuse, ts, d_val, 0, NULL); | |
| } | |
| else if (strcmp(key->str, "mem") == 0) { | |
| ne_utils_str_to_double(val->str, &d_val); | |
| cmt_gauge_set(ctx->sockstat_UDP_mem, ts, d_val, 0, NULL); | |
| cmt_gauge_set(ctx->sockstat_UDP_mem_bytes, ts, d_val * page_size, 0, NULL); | |
| } | |
| } | |
| flb_slist_destroy(&tokens); | |
| } | |
| else if (strncmp(line->str, "UDP:", 4) == 0) { | |
| mk_list_init(&tokens); | |
| ret = flb_slist_split_string(&tokens, line->str, ' ', -1); | |
| parts = ret; | |
| for (i = 1; i + 1 < parts; i += 2) { | |
| key = flb_slist_entry_get(&tokens, i); | |
| val = flb_slist_entry_get(&tokens, i + 1); | |
| if (!key || !val) { | |
| continue; | |
| } | |
| if (strcmp(key->str, "inuse") == 0) { | |
| if (ne_utils_str_to_double(val->str, &d_val) == 0) { | |
| cmt_gauge_set(ctx->sockstat_UDP_inuse, ts, d_val, 0, NULL); | |
| } | |
| } | |
| else if (strcmp(key->str, "mem") == 0) { | |
| if (ne_utils_str_to_double(val->str, &d_val) == 0) { | |
| cmt_gauge_set(ctx->sockstat_UDP_mem, ts, d_val, 0, NULL); | |
| cmt_gauge_set(ctx->sockstat_UDP_mem_bytes, ts, d_val * (double) page_size, 0, NULL); | |
| } | |
| } | |
| } | |
| flb_slist_destroy(&tokens); | |
| } |
🤖 Prompt for AI Agents
In plugins/in_node_exporter_metrics/ne_sockstat_linux.c around lines 230 to 251,
the UDP block sets gauge values without verifying if the string-to-double
conversion succeeded. Modify the code to check the return value of
ne_utils_str_to_double before calling cmt_gauge_set, ensuring gauges are only
set when conversion is successful, similar to the TCP block.
| else if (strncmp(line->str, "FRAG:", 5) == 0) { | ||
| mk_list_init(&tokens); | ||
| ret = flb_slist_split_string(&tokens, line->str, ' ', -1); | ||
| parts = ret; | ||
| for (i = 1; i + 1 < parts; i += 2) { | ||
| key = flb_slist_entry_get(&tokens, i); | ||
| val = flb_slist_entry_get(&tokens, i + 1); | ||
| if (!key || !val) { | ||
| continue; | ||
| } | ||
| if (strcmp(key->str, "inuse") == 0) { | ||
| ne_utils_str_to_double(val->str, &d_val); | ||
| cmt_gauge_set(ctx->sockstat_FRAG_inuse, ts, d_val, 0, NULL); | ||
| } | ||
| else if (strcmp(key->str, "memory") == 0) { | ||
| ne_utils_str_to_double(val->str, &d_val); | ||
| cmt_gauge_set(ctx->sockstat_FRAG_memory, ts, d_val, 0, NULL); | ||
| } | ||
| } | ||
| flb_slist_destroy(&tokens); | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Guard conversion in FRAG block.
Check ne_utils_str_to_double() return before setting gauges.
if (strcmp(key->str, "inuse") == 0) {
- ne_utils_str_to_double(val->str, &d_val);
- cmt_gauge_set(ctx->sockstat_FRAG_inuse, ts, d_val, 0, NULL);
+ if (ne_utils_str_to_double(val->str, &d_val) == 0) {
+ cmt_gauge_set(ctx->sockstat_FRAG_inuse, ts, d_val, 0, NULL);
+ }
}
else if (strcmp(key->str, "memory") == 0) {
- ne_utils_str_to_double(val->str, &d_val);
- cmt_gauge_set(ctx->sockstat_FRAG_memory, ts, d_val, 0, NULL);
+ if (ne_utils_str_to_double(val->str, &d_val) == 0) {
+ cmt_gauge_set(ctx->sockstat_FRAG_memory, ts, d_val, 0, NULL);
+ }
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| else if (strncmp(line->str, "FRAG:", 5) == 0) { | |
| mk_list_init(&tokens); | |
| ret = flb_slist_split_string(&tokens, line->str, ' ', -1); | |
| parts = ret; | |
| for (i = 1; i + 1 < parts; i += 2) { | |
| key = flb_slist_entry_get(&tokens, i); | |
| val = flb_slist_entry_get(&tokens, i + 1); | |
| if (!key || !val) { | |
| continue; | |
| } | |
| if (strcmp(key->str, "inuse") == 0) { | |
| ne_utils_str_to_double(val->str, &d_val); | |
| cmt_gauge_set(ctx->sockstat_FRAG_inuse, ts, d_val, 0, NULL); | |
| } | |
| else if (strcmp(key->str, "memory") == 0) { | |
| ne_utils_str_to_double(val->str, &d_val); | |
| cmt_gauge_set(ctx->sockstat_FRAG_memory, ts, d_val, 0, NULL); | |
| } | |
| } | |
| flb_slist_destroy(&tokens); | |
| } | |
| else if (strncmp(line->str, "FRAG:", 5) == 0) { | |
| mk_list_init(&tokens); | |
| ret = flb_slist_split_string(&tokens, line->str, ' ', -1); | |
| parts = ret; | |
| for (i = 1; i + 1 < parts; i += 2) { | |
| key = flb_slist_entry_get(&tokens, i); | |
| val = flb_slist_entry_get(&tokens, i + 1); | |
| if (!key || !val) { | |
| continue; | |
| } | |
| if (strcmp(key->str, "inuse") == 0) { | |
| if (ne_utils_str_to_double(val->str, &d_val) == 0) { | |
| cmt_gauge_set(ctx->sockstat_FRAG_inuse, ts, d_val, 0, NULL); | |
| } | |
| } | |
| else if (strcmp(key->str, "memory") == 0) { | |
| if (ne_utils_str_to_double(val->str, &d_val) == 0) { | |
| cmt_gauge_set(ctx->sockstat_FRAG_memory, ts, d_val, 0, NULL); | |
| } | |
| } | |
| } | |
| flb_slist_destroy(&tokens); | |
| } |
🤖 Prompt for AI Agents
In plugins/in_node_exporter_metrics/ne_sockstat_linux.c around lines 274 to 294,
the code calls ne_utils_str_to_double() without checking its return value before
using the converted double to set gauges. Modify the code to check the return
value of ne_utils_str_to_double() and only call cmt_gauge_set() if the
conversion is successful, ensuring invalid conversions do not update the
metrics.
| static int ne_sockstat_init(struct flb_ne *ctx) | ||
| { | ||
| sockstat_configure(ctx); | ||
| return 0; | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Init: check and propagate configuration failure.
If any gauge creation fails, init should return error.
static int ne_sockstat_init(struct flb_ne *ctx)
{
- sockstat_configure(ctx);
- return 0;
+ if (sockstat_configure(ctx) != 0) {
+ return -1;
+ }
+ return 0;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| static int ne_sockstat_init(struct flb_ne *ctx) | |
| { | |
| sockstat_configure(ctx); | |
| return 0; | |
| } | |
| static int ne_sockstat_init(struct flb_ne *ctx) | |
| { | |
| if (sockstat_configure(ctx) != 0) { | |
| return -1; | |
| } | |
| return 0; | |
| } |
🤖 Prompt for AI Agents
In plugins/in_node_exporter_metrics/ne_sockstat_linux.c around lines 380 to 384,
the ne_sockstat_init function currently calls sockstat_configure but does not
check if it fails. Modify the function to check the return value of
sockstat_configure, and if it indicates failure, return an error code instead of
0. This ensures that initialization failures are properly propagated.
as requested in #10698 , fixed.
Implement Linux sockstat collector, same as the original Prometheus node exporter, it collects the data from
/proc/net/sockstatand/proc/net/sockstat6, the following metrics are generated:IPv4 Sockstat Metrics
node_sockstat_sockets_used: Total IPv4 sockets in usenode_sockstat_TCP_alloc: TCP sockets allocatednode_sockstat_TCP_inuse: TCP sockets in usenode_sockstat_TCP_mem: TCP memory pages usednode_sockstat_TCP_mem_bytes: TCP memory in bytesnode_sockstat_TCP_orphan: Orphaned TCP socketsnode_sockstat_TCP_tw: TCP sockets in TIME_WAIT statenode_sockstat_UDP_inuse: UDP sockets in usenode_sockstat_UDP_mem: UDP memory pages usednode_sockstat_UDP_mem_bytes: UDP memory in bytesnode_sockstat_UDPLITE_inuse: UDPLITE sockets in usenode_sockstat_RAW_inuse: RAW sockets in usenode_sockstat_FRAG_inuse: Fragment sockets in usenode_sockstat_FRAG_memory: Fragment memory in bytesIPv6 Sockstat Metrics
node_sockstat_TCP6_inuse: IPv6 TCP sockets in usenode_sockstat_UDP6_inuse: IPv6 UDP sockets in usenode_sockstat_UDPLITE6_inuse: IPv6 UDPLITE sockets in usenode_sockstat_RAW6_inuse: IPv6 RAW sockets in usenode_sockstat_FRAG6_inuse: IPv6 fragment sockets in usenode_sockstat_FRAG6_memory: IPv6 fragment memory in bytesFluent Bit is licensed under Apache 2.0, by submitting this pull request I understand that this code will be released under the terms of that license.
Summary by CodeRabbit
New Features
Compatibility