fritshoogland-yugabyte / yb_stats

Apache License 2.0
15 stars 10 forks source link

The --print-rpcs <snapshot no> not workingafter 0.8.10 version #8

Open ag26jan opened 5 months ago

ag26jan commented 5 months ago

Any help regarding this error?

[ec2-user@host ~]$ cat yb_stats.snapshots/3/rpcs.json | jq | head
[
  {},
  {
    "hostname_port": "<IP>:13000",
    "timestamp": "2024-04-08T16:50:35.520727317+00:00",
    "connections": [
      {
        "process_start_time": "2024-04-08 16:38:05.66537+00",
        "application_name": "",
        "backend_type": "checkpointer",

[ec2-user@host ~]$ yb_stats --print-rpcs 3

------------------------------------------------------------------------------------------------------------------------
thread 'main' panicked at 'hostname:port should be set', src/rpcs/functions.rs:344:30
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Seems bug introduced in 0.9.x versions: https://github.com/fritshoogland-yugabyte/yb_stats/commit/9f7c8bc7e65ecae6399a43b86d503ae16e35b47f

Not sure what to look and fix.

See the older version :

[ec2-user@IP-Address ~]$ yb_stats --version
yb_stats 0.8.10
[ec2-user@IP-Address~]$ yb_stats --hosts IP1,IP2,IP3 --snapshot
snapshot number 11
[ec2-user@IP-Address ~]$ yb_stats --print-rpcs 11

----------------------------------------------------------------------------------------------------
Host: IP-Address ; port: 13000, count: 1; port: 7000, count: 96; port: 9000, count: 50
----------------------------------------------------------------------------------------------------
ag26jan commented 4 months ago

@fritshoogland-yugabyte Shall I close it?

ag26jan commented 4 months ago

@fritshoogland-yugabyte The rpcs.json now collects the node:port information for all default ports 7000,9000,12000,13000,9300.

After initial debugging, I found that the node_exporter's node:port details is not being fetched correctly by yb_stats.

Notice the first blank json entry in rpcs.json I sent above {}.

[ec2-user@host ~]$ cat yb_stats.snapshots/3/rpcs.json | jq | head
[
  {},

So, the actual issue is with the collection of the data. Older version did not use the node_exporter endpoint and hence is able to work.

With new version, if you take the snapshot by specifying the ports(excluding the 9300 port of node exporter, it will work)

yb_stats --hosts IP1,IP2,IP3 --ports 7000,9000,12000,13000 --snapshot
ag26jan commented 4 months ago

The bug in this code appears to be related to the unwrapping of hostname_port in the RPCs > function.rs file. The code tries to clone and then immediately unwrap hostname_port in multiple places without checking if it's Some or None. This can lead to a panic if hostname_port happens to be None.

Here's the problematic part:

if hostname_port
    .clone()
    .expect("hostname:port should be set") // <-- This line
    .split(':')
    .next()
    .unwrap() == hostname
    && hostname_filter.is_match(&hostname_port.clone().expect("hostname:port should be set")) // <-- And this line
{
    // Code block
}

ChatGPT says this can be handle as:

Instead of using expect() to unwrap hostname_port, it's better to handle the None case gracefully. One common approach is to use pattern matching with if let or match statements to handle both the Some and None cases.

Here's how you could refactor the code to handle hostname_port being None:

if let Some(hostname_port) = hostname_port.clone() {
    if hostname_port.split(':').next().unwrap() == hostname
        && hostname_filter.is_match(&hostname_port)
    {
        // Code block
    }
} else {
    // Handle the case where hostname_port is None
    println!("Error: hostname_port is not set");
}

This way, the code won't panic if hostname_port is None, and you have the opportunity to handle that situation appropriately.

@fritshoogland-yugabyte is that true?

ag26jan commented 4 months ago

@fritshoogland-yugabyte This seems something else. So I put a dummy value in first array which was empty and this failed as well.

[centos@yb-demo-agangwar-test-n1 ~]$ vim yb_stats.snapshots/16/rpcs.json
[centos@yb-demo-agangwar-test-n1 ~]$ RUST_BACKTRACE=debug yb_stats --print-rpcs 16

------------------------------------------------------------------------------------------------------------------------
thread 'main' panicked at 'hostname:port should be set', src/rpcs/functions.rs:344:30
stack backtrace:
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
[centos@yb-demo-agangwar-test-n1 ~]$ vim yb_stats.snapshots/16/rpcs.json
[centos@yb-demo-agangwar-test-n1 ~]$ cat yb_stats.snapshots/16/rpcs.json | jq
[
  {
    "hostname_port": "example_host:7000"
  },
  {
    "hostname_port": "IP1:13000",
    "timestamp": "2024-05-01T14:23:57.946734061+00:00",
    "connections": [
      {

Will something like this help?

if let Some(hostname_port) = &self.hostname_port {
    for rpc in &self.rpcs {
        match rpc {
            Ysql { connections, .. } | Rpc { inbound_connections, outbound_connections, .. } => {
                for inbound in inbound_connections.as_ref().unwrap_or(&Vec::new()) {
                    if let Some(remote_ip) = &inbound.remote_ip {
                        for (calls_in_flight_counter, calls_in_flight) in inbound.calls_in_flight
                            .as_ref()
                            .unwrap_or(&Vec::new())
                            .iter()
                            .enumerate()
                        {
                            // Handle active inbound YCQL or RPC requests
                            // Your existing code to print inbound details goes here
                        }
                    }
                }

                for outbound in outbound_connections.as_ref().unwrap_or(&Vec::new()) {
                    if let Some(remote_ip) = &outbound.remote_ip {
                        for (calls_in_flight_counter, calls_in_flight) in outbound.calls_in_flight
                            .as_ref()
                            .unwrap_or(&Vec::new())
                            .iter()
                            .enumerate()
                        {
                            // Handle active outbound YCQL or RPC requests
                            // Your existing code to print outbound details goes here
                        }
                    }
                }
            }
            _ => {}
        }
    }
} else {
    println!("hostname:port is not set.");
}