Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Input output traffic stats and command process count for each client. #327

Merged
merged 8 commits into from May 6, 2024
1 change: 1 addition & 0 deletions src/blocked.c
Expand Up @@ -107,6 +107,7 @@ void updateStatsOnUnblock(client *c, long blocked_us, long reply_us, int had_err
const ustime_t total_cmd_duration = c->duration + blocked_us + reply_us;
c->lastcmd->microseconds += total_cmd_duration;
c->lastcmd->calls++;
c->commands_processed++;
server.stat_numcommands++;
if (had_errors)
c->lastcmd->failed_calls++;
Expand Down
10 changes: 9 additions & 1 deletion src/networking.c
Expand Up @@ -214,6 +214,9 @@ client *createClient(connection *conn) {
c->mem_usage_bucket_node = NULL;
if (conn) linkClient(c);
initClientMultiState(c);
c->net_input_bytes = 0;
c->net_output_bytes = 0;
c->commands_processed = 0;
return c;
}

Expand Down Expand Up @@ -1991,6 +1994,7 @@ int writeToClient(client *c, int handler_installed) {
} else {
atomicIncr(server.stat_net_output_bytes, totwritten);
}
c->net_output_bytes += totwritten;

if (nwritten == -1) {
if (connGetState(c->conn) != CONN_STATE_CONNECTED) {
Expand Down Expand Up @@ -2718,6 +2722,7 @@ void readQueryFromClient(connection *conn) {
} else {
atomicIncr(server.stat_net_input_bytes, nread);
}
c->net_input_bytes += nread;

if (!(c->flags & CLIENT_MASTER) &&
/* The commands cached in the MULTI/EXEC queue have not been executed yet,
Expand Down Expand Up @@ -2874,7 +2879,10 @@ sds catClientInfoString(sds s, client *client) {
" redir=%I", (client->flags & CLIENT_TRACKING) ? (long long) client->client_tracking_redirection : -1,
" resp=%i", client->resp,
" lib-name=%s", client->lib_name ? (char*)client->lib_name->ptr : "",
" lib-ver=%s", client->lib_ver ? (char*)client->lib_ver->ptr : ""));
" lib-ver=%s", client->lib_ver ? (char*)client->lib_ver->ptr : "",
" tot-net-in=%U", client->net_input_bytes,
" tot-net-out=%U", client->net_output_bytes,
" tot-cmds=%U", client->commands_processed));
madolson marked this conversation as resolved.
Show resolved Hide resolved
return ret;
}

Expand Down
8 changes: 7 additions & 1 deletion src/server.c
Expand Up @@ -3716,8 +3716,14 @@ void call(client *c, int flags) {
}
}

if (!(c->flags & CLIENT_BLOCKED))
if (!(c->flags & CLIENT_BLOCKED)) {
/* Modules may call commands in cron, in which case server.current_client
* is not set. */
if (server.current_client) {
server.current_client->commands_processed++;
}
server.stat_numcommands++;
}

/* Record peak memory after each command and before the eviction that runs
* before the next command. */
Expand Down
3 changes: 3 additions & 0 deletions src/server.h
Expand Up @@ -1282,6 +1282,9 @@ typedef struct client {
#ifdef LOG_REQ_RES
clientReqResInfo reqres;
#endif
unsigned long long net_input_bytes; /* Total network input bytes read from this client. */
unsigned long long net_output_bytes; /* Total network output bytes sent to this client. */
unsigned long long commands_processed; /* Total count of commands this client executed. */
} client;

/* ACL information */
Expand Down
73 changes: 71 additions & 2 deletions tests/unit/introspection.tcl
Expand Up @@ -7,7 +7,7 @@ start_server {tags {"introspection"}} {

test {CLIENT LIST} {
r client list
} {id=* addr=*:* laddr=*:* fd=* name=* age=* idle=* flags=N db=* sub=0 psub=0 ssub=0 multi=-1 watch=0 qbuf=26 qbuf-free=* argv-mem=* multi-mem=0 rbs=* rbp=* obl=0 oll=0 omem=0 tot-mem=* events=r cmd=client|list user=* redir=-1 resp=* lib-name=* lib-ver=*}
} {id=* addr=*:* laddr=*:* fd=* name=* age=* idle=* flags=N db=* sub=0 psub=0 ssub=0 multi=-1 watch=0 qbuf=26 qbuf-free=* argv-mem=* multi-mem=0 rbs=* rbp=* obl=0 oll=0 omem=0 tot-mem=* events=r cmd=client|list user=* redir=-1 resp=* lib-name=* lib-ver=* tot-net-in=* tot-net-out=* tot-cmds=*}

test {CLIENT LIST with IDs} {
set myid [r client id]
Expand All @@ -17,7 +17,76 @@ start_server {tags {"introspection"}} {

test {CLIENT INFO} {
r client info
} {id=* addr=*:* laddr=*:* fd=* name=* age=* idle=* flags=N db=* sub=0 psub=0 ssub=0 multi=-1 watch=0 qbuf=26 qbuf-free=* argv-mem=* multi-mem=0 rbs=* rbp=* obl=0 oll=0 omem=0 tot-mem=* events=r cmd=client|info user=* redir=-1 resp=* lib-name=* lib-ver=*}
} {id=* addr=*:* laddr=*:* fd=* name=* age=* idle=* flags=N db=* sub=0 psub=0 ssub=0 multi=-1 watch=0 qbuf=26 qbuf-free=* argv-mem=* multi-mem=0 rbs=* rbp=* obl=0 oll=0 omem=0 tot-mem=* events=r cmd=client|info user=* redir=-1 resp=* lib-name=* lib-ver=* tot-net-in=* tot-net-out=* tot-cmds=*}

proc get_field_in_client_info {info field} {
set info [string trim $info]
foreach item [split $info " "] {
set kv [split $item "="]
set k [lindex $kv 0]
if {[string match $field $k]} {
return [lindex $kv 1]
}
}
return ""
}

proc get_field_in_client_list {id client_list filed} {
set list [split $client_list "\r\n"]
foreach info $list {
if {[string match "id=$id *" $info] } {
return [get_field_in_client_info $info $filed]
}
}
return ""
}

test {client input output and command process statistics} {
madolson marked this conversation as resolved.
Show resolved Hide resolved
set info1 [r client info]
set input1 [get_field_in_client_info $info1 "tot-net-in"]
set output1 [get_field_in_client_info $info1 "tot-net-out"]
set cmd1 [get_field_in_client_info $info1 "tot-cmds"]
set info2 [r client info]
set input2 [get_field_in_client_info $info2 "tot-net-in"]
set output2 [get_field_in_client_info $info2 "tot-net-out"]
set cmd2 [get_field_in_client_info $info2 "tot-cmds"]
assert_equal [expr $input1+26] $input2
assert {[expr $output1+300] < $output2}
assert_equal [expr $cmd1+1] $cmd2
# test blocking command
r del mylist
set rd [valkey_deferring_client]
$rd client id
set rd_id [$rd read]
set info_list [r client list]
set input3 [get_field_in_client_list $rd_id $info_list "tot-net-in"]
set output3 [get_field_in_client_list $rd_id $info_list "tot-net-out"]
set cmd3 [get_field_in_client_list $rd_id $info_list "tot-cmds"]
$rd blpop mylist 0
set info_list [r client list]
set input4 [get_field_in_client_list $rd_id $info_list "tot-net-in"]
set output4 [get_field_in_client_list $rd_id $info_list "tot-net-out"]
set cmd4 [get_field_in_client_list $rd_id $info_list "tot-cmds"]
assert_equal [expr $input3+34] $input4
assert_equal $output3 $output4
assert_equal $cmd3 $cmd4
r lpush mylist a
set info_list [r client list]
set input5 [get_field_in_client_list $rd_id $info_list "tot-net-in"]
set output5 [get_field_in_client_list $rd_id $info_list "tot-net-out"]
set cmd5 [get_field_in_client_list $rd_id $info_list "tot-cmds"]
assert_equal $input4 $input5
assert_equal [expr $output4+23] $output5
assert_equal [expr $cmd4+1] $cmd5
$rd close
# test recursive command
set info [r client info]
set cmd6 [get_field_in_client_info $info "tot-cmds"]
r eval "server.call('ping')" 0
set info [r client info]
set cmd7 [get_field_in_client_info $info "tot-cmds"]
assert_equal [expr $cmd6+3] $cmd7
}

test {CLIENT KILL with illegal arguments} {
assert_error "ERR wrong number of arguments for 'client|kill' command" {r client kill}
Expand Down