Skip to content

in_node_exporter_metrics: add Linux sockstat collector#10718

Merged
edsiper merged 1 commit intomasterfrom
node_exporter-socket-metrics
Aug 10, 2025
Merged

in_node_exporter_metrics: add Linux sockstat collector#10718
edsiper merged 1 commit intomasterfrom
node_exporter-socket-metrics

Conversation

@edsiper
Copy link
Member

@edsiper edsiper commented Aug 10, 2025

as requested in #10698 , fixed.

Implement Linux sockstat collector, same as the original Prometheus node exporter, it collects the data from /proc/net/sockstat and /proc/net/sockstat6, the following metrics are generated:

IPv4 Sockstat Metrics

  • node_sockstat_sockets_used: Total IPv4 sockets in use
  • node_sockstat_TCP_alloc: TCP sockets allocated
  • node_sockstat_TCP_inuse: TCP sockets in use
  • node_sockstat_TCP_mem: TCP memory pages used
  • node_sockstat_TCP_mem_bytes: TCP memory in bytes
  • node_sockstat_TCP_orphan: Orphaned TCP sockets
  • node_sockstat_TCP_tw: TCP sockets in TIME_WAIT state
  • node_sockstat_UDP_inuse: UDP sockets in use
  • node_sockstat_UDP_mem: UDP memory pages used
  • node_sockstat_UDP_mem_bytes: UDP memory in bytes
  • node_sockstat_UDPLITE_inuse: UDPLITE sockets in use
  • node_sockstat_RAW_inuse: RAW sockets in use
  • node_sockstat_FRAG_inuse: Fragment sockets in use
  • node_sockstat_FRAG_memory: Fragment memory in bytes

IPv6 Sockstat Metrics

  • node_sockstat_TCP6_inuse: IPv6 TCP sockets in use
  • node_sockstat_UDP6_inuse: IPv6 UDP sockets in use
  • node_sockstat_UDPLITE6_inuse: IPv6 UDPLITE sockets in use
  • node_sockstat_RAW6_inuse: IPv6 RAW sockets in use
  • node_sockstat_FRAG6_inuse: IPv6 fragment sockets in use
  • node_sockstat_FRAG6_memory: IPv6 fragment memory in bytes

Fluent 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

    • Added support for collecting and exposing detailed Linux socket statistics (sockstat) in the node exporter metrics plugin, including metrics for various socket types and memory usage.
    • Introduced configuration options for the sockstat collector, including customizable scrape intervals.
    • Expanded the default set of enabled metrics to include sockstat on Linux systems.
  • Compatibility

    • Sockstat metrics are available on Linux platforms; a stub collector is provided for other systems.

Signed-off-by: Eduardo Silva <eduardo@chronosphere.io>
@coderabbitai
Copy link

coderabbitai bot commented Aug 10, 2025

Walkthrough

A 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 /proc/net/sockstat and /proc/net/sockstat6.

Changes

Cohort / File(s) Change Summary
Build System Update
plugins/in_node_exporter_metrics/CMakeLists.txt
Added ne_sockstat.c to the plugin's source files, ensuring the new sockstat collector is compiled and linked into the node_exporter_metrics plugin.
Plugin Integration
plugins/in_node_exporter_metrics/ne.c
Registered the sockstat collector within the plugin, included its header, and added a configuration map entry for its scrape interval. This enables the plugin to recognize and manage the new collector alongside existing ones.
Metric Structure Extension
plugins/in_node_exporter_metrics/ne.h
Updated the default enabled metrics to include "sockstat" and extended the flb_ne struct with new gauge pointers for various socket statistics, covering both IPv4 and IPv6.
Sockstat Collector Stub
plugins/in_node_exporter_metrics/ne_sockstat.c
Introduced a new source file that includes the Linux-specific implementation if on Linux, or provides a stub collector with null callbacks for other platforms.
Sockstat Collector Header
plugins/in_node_exporter_metrics/ne_sockstat.h
Added a new header declaring the external sockstat_collector variable for use by the plugin.
Linux Sockstat Implementation
plugins/in_node_exporter_metrics/ne_sockstat_linux.c
Implemented the Linux-specific collector. This file defines and registers Prometheus gauges for a wide range of socket statistics, parses /proc/net/sockstat and /proc/net/sockstat6, and updates the metrics. It includes initialization and update routines, and exposes the collector structure for plugin registration.

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
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~15–20 minutes

Poem

A new stat hops in, with sockets in tow,
From procfs it reads, where the Linux stats grow.
Gauges for TCP, UDP, and more,
Now tracked and exposed, richer than before!
With every new metric, our burrow expands—
A rabbit’s delight in these metric lands! 🐇✨

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 Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch node_exporter-socket-metrics

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (5)
plugins/in_node_exporter_metrics/ne.c (1)

390-395: Config map entry for sockstat interval

New "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

📥 Commits

Reviewing files that changed from the base of the PR and between 4e62817 and 080821c.

📒 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 correct

Adding 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 good

Guard, include, and extern declaration are consistent with existing collectors.

plugins/in_node_exporter_metrics/ne.c (2)

42-42: Include sockstat collector header

Include placement is consistent with other collectors; no issues.


196-196: Register sockstat collector

Collector 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 fallback

Stub collector with NULL callbacks ensures “not supported” behavior without activation. Good.


20-22: Consistency Confirmed: direct inclusion is used across all collectors

All 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_procfs with 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 by page_size to produce byte metrics.

No changes required.

plugins/in_node_exporter_metrics/ne.h (1)

36-36: Enable sockstat by default on Linux

Adding "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.

Comment on lines +22 to +29
#include <unistd.h>

#include <fluent-bit/flb_info.h>
#include <fluent-bit/flb_input_plugin.h>

#include "ne.h"
#include "ne_utils.h"

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

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.

Suggested change
#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.

Comment on lines +30 to +155
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;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ 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.

Suggested change
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.

Comment on lines +159 to +176
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;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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_metrics

Length 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().

Comment on lines +184 to +195
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);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ 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.

Comment on lines +196 to +229
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);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ 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.

Suggested change
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.

Comment on lines +230 to +251
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);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ 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.

Suggested change
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.

Comment on lines +274 to +294
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);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ 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.

Suggested change
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.

Comment on lines +380 to +384
static int ne_sockstat_init(struct flb_ne *ctx)
{
sockstat_configure(ctx);
return 0;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ 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.

Suggested change
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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant