From 972a6b0523cc3c7bb6daa9c5a47c699bef8fd188 Mon Sep 17 00:00:00 2001 From: Colin GAGNAIRE Date: Wed, 27 Dec 2017 18:33:05 +0100 Subject: [PATCH] improve redis restapi --- apps/redis/restapi/custom/api.pm | 2 + apps/redis/restapi/mode/clusterstats.pm | 93 ++-- apps/redis/restapi/mode/databasesstats.pm | 507 +++++++++++++++++----- apps/redis/restapi/mode/nodesstats.pm | 187 ++++---- apps/redis/restapi/mode/shardsstats.pm | 264 ++++++++--- 5 files changed, 771 insertions(+), 282 deletions(-) diff --git a/apps/redis/restapi/custom/api.pm b/apps/redis/restapi/custom/api.pm index 41eb2496a..82cb71886 100644 --- a/apps/redis/restapi/custom/api.pm +++ b/apps/redis/restapi/custom/api.pm @@ -120,6 +120,8 @@ sub build_options_for_httplib { $self->{option_results}->{username} = $self->{username}; $self->{option_results}->{password} = $self->{password}; $self->{option_results}->{ssl} = $self->{ssl}; + $self->{option_results}->{warning_status} = ''; + $self->{option_results}->{critical_status} = ''; } sub settings { diff --git a/apps/redis/restapi/mode/clusterstats.pm b/apps/redis/restapi/mode/clusterstats.pm index 4cf053c34..8e2d960a1 100644 --- a/apps/redis/restapi/mode/clusterstats.pm +++ b/apps/redis/restapi/mode/clusterstats.pm @@ -120,51 +120,41 @@ sub set_counters { ], } }, - { label => 'requests', set => { - key_values => [ { name => 'total_req', diff => 1 } ], - output_template => 'Requests per seconds: %s', - per_second => 1, - perfdatas => [ - { label => 'requests', value => 'total_req_per_second', template => '%s', - min => 0, unit => '/s' }, - ], - } - }, - { label => 'memory-used', set => { + { label => 'memory', set => { key_values => [ { name => 'free_memory' }, { name => 'total_memory' } ], closure_custom_calc => $self->can('custom_usage_calc'), - closure_custom_calc_extra_options => { display => 'Ram', label => 'memory-used', perf => 'memory_used', + closure_custom_calc_extra_options => { display => 'Ram', label => 'memory', perf => 'memory', free => 'free_memory', total => 'total_memory' }, closure_custom_output => $self->can('custom_usage_output'), closure_custom_perfdata => $self->can('custom_usage_perfdata'), closure_custom_threshold_check => $self->can('custom_usage_threshold'), } }, - { label => 'persistent-storage-used', set => { + { label => 'persistent-storage', set => { key_values => [ { name => 'persistent_storage_free' }, { name => 'persistent_storage_size' } ], closure_custom_calc => $self->can('custom_usage_calc'), - closure_custom_calc_extra_options => { display => 'Persistent storage', label => 'persistent-storage-used', perf => 'persistent_storage_used', + closure_custom_calc_extra_options => { display => 'Persistent storage', label => 'persistent-storage', perf => 'persistent_storage', free => 'persistent_storage_free', total => 'persistent_storage_size' }, closure_custom_output => $self->can('custom_usage_output'), closure_custom_perfdata => $self->can('custom_usage_perfdata'), closure_custom_threshold_check => $self->can('custom_usage_threshold'), } }, - { label => 'ephemeral-storage-used', set => { + { label => 'ephemeral-storage', set => { key_values => [ { name => 'ephemeral_storage_free' }, { name => 'ephemeral_storage_size' } ], closure_custom_calc => $self->can('custom_usage_calc'), - closure_custom_calc_extra_options => { display => 'Ephemeral storage', label => 'ephemeral-storage-used', perf => 'ephemeral_storage_used', + closure_custom_calc_extra_options => { display => 'Ephemeral storage', label => 'ephemeral-storage', perf => 'ephemeral_storage', free => 'ephemeral_storage_free', total => 'ephemeral_storage_size' }, closure_custom_output => $self->can('custom_usage_output'), closure_custom_perfdata => $self->can('custom_usage_perfdata'), closure_custom_threshold_check => $self->can('custom_usage_threshold'), } }, - { label => 'flash-storage-used', set => { - key_values => [ { name => 'available_flash' }, { name => 'bigstore_size' } ], + { label => 'flash-storage', set => { + key_values => [ { name => 'bigstore_free' }, { name => 'bigstore_size' } ], closure_custom_calc => $self->can('custom_usage_calc'), - closure_custom_calc_extra_options => { display => 'Flash storage', label => 'flash-storage-used', perf => 'flash_storage_used', - free => 'available_flash', total => 'bigstore_size' }, + closure_custom_calc_extra_options => { display => 'Flash storage', label => 'flash-storage', perf => 'flash_storage', + free => 'bigstore_free', total => 'bigstore_size' }, closure_custom_output => $self->can('custom_usage_output'), closure_custom_perfdata => $self->can('custom_usage_perfdata'), closure_custom_threshold_check => $self->can('custom_usage_threshold'), @@ -172,10 +162,10 @@ sub set_counters { }, { label => 'flash-iops', set => { key_values => [ { name => 'bigstore_iops' } ], - output_template => 'Flash IOPS: %s', + output_template => 'Flash IOPS: %s ops/s', perfdatas => [ { label => 'flash_iops', value => 'bigstore_iops_absolute', template => '%s', - min => 0, unit => '/s' }, + min => 0, unit => 'ops/s' }, ], } }, @@ -198,6 +188,15 @@ sub set_counters { ], } }, + { label => 'requests', set => { + key_values => [ { name => 'total_req' } ], + output_template => 'Requests rate: %s ops/s', + perfdatas => [ + { label => 'requests', value => 'total_req_absolute', template => '%s', + min => 0, unit => 'ops/s' }, + ], + } + }, { label => 'traffic-in', set => { key_values => [ { name => 'ingress' } ], output_template => 'Traffic In: %s %s/s', @@ -221,12 +220,13 @@ sub set_counters { sub new { my ($class, %options) = @_; - my $self = $class->SUPER::new(package => __PACKAGE__, %options, statefile => 1); + my $self = $class->SUPER::new(package => __PACKAGE__, %options); bless $self, $class; $self->{version} = '1.0'; $options{options}->add_options(arguments => { + "interval:s" => { name => 'interval', default => '15min' }, "units:s" => { name => 'units', default => '%' }, "free" => { name => 'free' }, }); @@ -244,10 +244,7 @@ sub check_options { sub manage_selection { my ($self, %options) = @_; - $self->{cache_name} = "redis_restapi_" . $self->{mode} . '_' . $options{custom}->get_connection_info() . '_' . - (defined($self->{option_results}->{filter_counters}) ? md5_hex($self->{option_results}->{filter_counters}) : md5_hex('all')); - - my $result = $options{custom}->get(path => '/v1/cluster/stats/last'); + my $result = $options{custom}->get(path => '/v1/cluster/stats/last?interval='.$instance_mode->{option_results}->{interval}); my $result2 = $options{custom}->get(path => '/v1/cluster'); my $result3 = $options{custom}->get(path => '/v1/nodes'); @@ -256,10 +253,18 @@ sub manage_selection { my $ephemeral_storage_size = 0; my $bigstore_size = 0; foreach my $node (keys $result3) { - $total_memory = $total_memory + $result3->{$node}->{total_memory}; - $persistent_storage_size = $persistent_storage_size + $result3->{$node}->{persistent_storage_size}; - $ephemeral_storage_size = $ephemeral_storage_size + $result3->{$node}->{ephemeral_storage_size}; - $bigstore_size = $bigstore_size + $result3->{$node}->{bigstore_size}; + if (defined($result3->{$node}->{total_memory})) { + $total_memory = $total_memory + $result3->{$node}->{total_memory}; + } + if (defined($result3->{$node}->{persistent_storage_size})) { + $persistent_storage_size = $persistent_storage_size + $result3->{$node}->{persistent_storage_size}; + } + if (defined($result3->{$node}->{ephemeral_storage_size})) { + $ephemeral_storage_size = $ephemeral_storage_size + $result3->{$node}->{ephemeral_storage_size}; + } + if (defined($result3->{$node}->{bigstore_size})) { + $bigstore_size = $bigstore_size + $result3->{$node}->{bigstore_size}; + } } $self->{cluster}->{$result2->{name}} = { @@ -272,15 +277,15 @@ sub manage_selection { persistent_storage_size => $persistent_storage_size, ephemeral_storage_free => $result->{ephemeral_storage_free}, ephemeral_storage_size => $ephemeral_storage_size, - available_flash => $result->{available_flash}, + bigstore_free => $result->{bigstore_free}, bigstore_size => $bigstore_size, bigstore_iops => $result->{bigstore_iops}, bigstore_kv_ops => $result->{bigstore_kv_ops}, bigstore_throughput => $result->{bigstore_throughput}, conns => $result->{conns}, + total_req => $result->{total_req}, ingress => $result->{ingress_bytes} * 8, egress => $result->{egress_bytes} * 8, - total_req => $result->{total_req}, }; } @@ -299,12 +304,26 @@ Check RedisLabs Enterprise Cluster statistics. Only display some counters (regexp can be used). Example: --filter-counters='^cpu' +=item B<--interval> + +Time interval from which to retrieve statistics (Default: '15min'). +Can be : '1sec', '10sec', '5min', '15min', +'1hour', '12hour', '1week' + +=item B<--units> + +Units of thresholds (Default: '%') ('%', 'B'). + +=item B<--free> + +Thresholds are on free space left. + =item B<--warning-*> Threshold warning. Can be: 'cpu-system', 'cpu-user', -'requests', 'memory-used', 'flash-storage-used', -'persistent-storage-used', 'ephemeral-storage-used', +'requests', 'memory', 'flash-storage', +'persistent-storage', 'ephemeral-storage', 'flash-iops', 'flash-throughput', 'connections', 'traffic-in', 'traffic-out'. @@ -312,8 +331,8 @@ Can be: 'cpu-system', 'cpu-user', Threshold critical. Can be: 'cpu-system', 'cpu-user', -'requests', 'memory-used', 'flash-storage-used', -'persistent-storage-used', 'ephemeral-storage-used', +'requests', 'memory', 'flash-storage', +'persistent-storage', 'ephemeral-storage', 'flash-iops', 'flash-throughput', 'connections', 'traffic-in', 'traffic-out'. diff --git a/apps/redis/restapi/mode/databasesstats.pm b/apps/redis/restapi/mode/databasesstats.pm index 13af3b40a..4ef54baf0 100644 --- a/apps/redis/restapi/mode/databasesstats.pm +++ b/apps/redis/restapi/mode/databasesstats.pm @@ -28,6 +28,66 @@ use Digest::MD5 qw(md5_hex); my $instance_mode; +sub custom_usage_perfdata { + my ($self, %options) = @_; + + $self->{output}->perfdata_add(label => $self->{result_values}->{perf}, unit => 'B', + value => $self->{result_values}->{used}, + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{result_values}->{label}, total => $self->{result_values}->{total}, cast_int => 1), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{result_values}->{label}, total => $self->{result_values}->{total}, cast_int => 1), + min => 0, max => $self->{result_values}->{total}); +} + +sub custom_usage_threshold { + my ($self, %options) = @_; + + my ($exit, $threshold_value); + $threshold_value = $self->{result_values}->{used}; + $threshold_value = $self->{result_values}->{free} if (defined($instance_mode->{option_results}->{free})); + if ($instance_mode->{option_results}->{units} eq '%') { + $threshold_value = $self->{result_values}->{prct_used}; + $threshold_value = $self->{result_values}->{prct_free} if (defined($instance_mode->{option_results}->{free})); + } + $exit = $self->{perfdata}->threshold_check(value => $threshold_value, threshold => [ { label => 'critical-' . $self->{result_values}->{label}, exit_litteral => 'critical' }, { label => 'warning-' . $self->{result_values}->{label}, exit_litteral => 'warning' } ]); + return $exit; +} + +sub custom_usage_output { + my ($self, %options) = @_; + + my ($used_value, $used_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{used}); + my ($free_value, $free_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{free}); + my ($total_value, $total_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{total}); + + my $msg = sprintf("%s usage: Total: %s Used: %s (%.2f%%) Free: %s (%.2f%%)", $self->{result_values}->{display}, + $total_value . " " . $total_unit, + $used_value . " " . $used_unit, $self->{result_values}->{prct_used}, + $free_value . " " . $free_unit, $self->{result_values}->{prct_free}); + return $msg; +} + +sub custom_usage_calc { + my ($self, %options) = @_; + + $self->{result_values}->{label} = $options{extra_options}->{label}; + $self->{result_values}->{perf} = $options{extra_options}->{perf}; + $self->{result_values}->{display} = $options{extra_options}->{display}; + $self->{result_values}->{used} = $options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{used}}; + $self->{result_values}->{total} = $options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{total}}; + + if ($self->{result_values}->{total} != 0) { + $self->{result_values}->{free} = $self->{result_values}->{total} - $self->{result_values}->{used}; + $self->{result_values}->{prct_used} = $self->{result_values}->{used} * 100 / $self->{result_values}->{total}; + $self->{result_values}->{prct_free} = 100 - $self->{result_values}->{prct_used}; + } else { + $self->{result_values}->{used} = '0'; + $self->{result_values}->{prct_used} = '0'; + $self->{result_values}->{prct_free} = '0'; + } + + return 0; +} + sub custom_status_threshold { my ($self, %options) = @_; my $status = 'ok'; @@ -41,7 +101,7 @@ sub custom_status_threshold { eval "$instance_mode->{option_results}->{critical_status}") { $status = 'critical'; } elsif (defined($instance_mode->{option_results}->{warning_status}) && $instance_mode->{option_results}->{warning_status} ne '' && - eval "$instance_mode->{option_results}->{warning_status}") { + eval "$instance_mode->{option_results}->{warning_status}") { $status = 'warning'; } }; @@ -55,13 +115,13 @@ sub custom_status_threshold { sub custom_status_output { my ($self, %options) = @_; - my $msg = sprintf("Status is '%s' [type: %s] [sync: %s] [backup status: %s] [export status: %s] [shard list: %s]", + my $msg = sprintf("Status is '%s' [type: %s] [shard list: %s] [backup status: %s] [export status: %s] [import status: %s]", $self->{result_values}->{status}, - $self->{result_values}->{type}, - $self->{result_values}->{sync}, + $self->{result_values}->{type}, + $self->{result_values}->{shard_list}, $self->{result_values}->{backup_status}, $self->{result_values}->{export_status}, - $self->{result_values}->{shard_list}); + $self->{result_values}->{import_status}); return $msg; } @@ -70,10 +130,55 @@ sub custom_status_calc { $self->{result_values}->{type} = $options{new_datas}->{$self->{instance} . '_type'}; $self->{result_values}->{status} = $options{new_datas}->{$self->{instance} . '_status'}; - $self->{result_values}->{sync} = $options{new_datas}->{$self->{instance} . '_sync'}; $self->{result_values}->{backup_status} = $options{new_datas}->{$self->{instance} . '_backup_status'}; $self->{result_values}->{export_status} = $options{new_datas}->{$self->{instance} . '_export_status'}; + $self->{result_values}->{import_status} = $options{new_datas}->{$self->{instance} . '_import_status'}; $self->{result_values}->{shard_list} = $options{new_datas}->{$self->{instance} . '_shard_list'}; + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + return 0; +} + +sub custom_cpu_output { + my ($self, %options) = @_; + + my $msg = sprintf("%s CPU usage (user/system): %s/%s %%", + $self->{result_values}->{cpu}, + $self->{result_values}->{user}, + $self->{result_values}->{system}); + return $msg; +} + +sub custom_cpu_calc { + my ($self, %options) = @_; + + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{display}}; + $self->{result_values}->{cpu} = $options{extra_options}->{cpu}; + $self->{result_values}->{user} = $options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{user}}; + $self->{result_values}->{system} = $options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{system}}; + return 0; +} + +sub custom_operations_output { + my ($self, %options) = @_; + + my $msg = sprintf("%s operations rates (hits/misses/requests/responses): %s/%s/%s/%s ops/s", + $self->{result_values}->{operation}, + $self->{result_values}->{hits}, + $self->{result_values}->{misses}, + $self->{result_values}->{req}, + $self->{result_values}->{res}); + return $msg; +} + +sub custom_operations_calc { + my ($self, %options) = @_; + + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{display}}; + $self->{result_values}->{operation} = $options{extra_options}->{operation}; + $self->{result_values}->{hits} = $options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{hits}}; + $self->{result_values}->{misses} = $options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{misses}}; + $self->{result_values}->{req} = $options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{req}}; + $self->{result_values}->{res} = $options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{res}}; return 0; } @@ -92,93 +197,64 @@ sub set_counters { $self->{maps_counters}->{databases} = [ { label => 'status', threshold => 0, set => { - key_values => [ { name => 'status' }, { name => 'type' }, { name => 'sync' }, { name => 'backup_status' }, { name => 'export_status' }, { name => 'shard_list' } ], + key_values => [ { name => 'status' }, { name => 'type' }, { name => 'backup_status' }, + { name => 'export_status' }, { name => 'import_status' }, { name => 'shard_list' }, { name => 'display' } ], closure_custom_calc => $self->can('custom_status_calc'), closure_custom_output => $self->can('custom_status_output'), closure_custom_perfdata => sub { return 0; }, closure_custom_threshold_check => $self->can('custom_status_threshold'), } }, - { label => 'ops-per-sec', set => { - key_values => [ { name => 'instantaneous_ops_per_sec' }, { name => 'display' } ], - output_template => 'Operations: %s ops/s', + { label => 'total-cpu', set => { + key_values => [ { name => 'shard_cpu_user' }, { name => 'shard_cpu_system' }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_cpu_calc'), + closure_custom_calc_extra_options => { cpu => 'Total', user => 'shard_cpu_user', + system => 'shard_cpu_system', display => 'display' }, + closure_custom_output => $self->can('custom_cpu_output'), perfdatas => [ - { label => 'ops_per_sec', value => 'instantaneous_ops_per_sec_absolute', template => '%s', - min => 0, unit => 'ops/s', label_extra_instance => 1, instance_use => 'display_absolute' }, + { label => 'total_cpu_user', value => 'user', template => '%s', + min => 0, max => 100, unit => '%', label_extra_instance => 1, instance_use => 'display' }, + { label => 'total_cpu_system', value => 'system', template => '%s', + min => 0, max => 100, unit => '%', label_extra_instance => 1, instance_use => 'display' }, ], } }, - { label => 'memory-used', set => { - key_values => [ { name => 'used_memory' }, { name => 'display' } ], - output_template => 'Memory used: %s %s', - output_change_bytes => 1, + { label => 'fork-cpu', set => { + key_values => [ { name => 'fork_cpu_user' }, { name => 'fork_cpu_system' }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_cpu_calc'), + closure_custom_calc_extra_options => { cpu => 'Fork', user => 'fork_cpu_user', + system => 'fork_cpu_system', display => 'display' }, + closure_custom_output => $self->can('custom_cpu_output'), perfdatas => [ - { label => 'memory-used', value => 'used_memory_absolute', template => '%s', - min => 0, unit => 'B', label_extra_instance => 1, instance_use => 'display_absolute' }, + { label => 'fork_cpu_user', value => 'user', template => '%s', + min => 0, max => 100, unit => '%', label_extra_instance => 1, instance_use => 'display' }, + { label => 'fork_cpu_system', value => 'system', template => '%s', + min => 0, max => 100, unit => '%', label_extra_instance => 1, instance_use => 'display' }, ], } }, - { label => 'total-keys', set => { - key_values => [ { name => 'no_of_keys' }, { name => 'display' } ], - output_template => 'Total keys: %s', + { label => 'main-thread-cpu', set => { + key_values => [ { name => 'main_thread_cpu_user' }, { name => 'main_thread_cpu_system' }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_cpu_calc'), + closure_custom_calc_extra_options => { cpu => 'Main thread', user => 'main_thread_cpu_user', + system => 'main_thread_cpu_system', display => 'display' }, + closure_custom_output => $self->can('custom_cpu_output'), perfdatas => [ - { label => 'total-keys', value => 'no_of_keys_absolute', template => '%s', - min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, + { label => 'main_thread_cpu_user', value => 'user', template => '%s', + min => 0, max => 100, unit => '%', label_extra_instance => 1, instance_use => 'display' }, + { label => 'main_thread_cpu_system', value => 'system', template => '%s', + min => 0, max => 100, unit => '%', label_extra_instance => 1, instance_use => 'display' }, ], } }, - { label => 'read-hits', set => { - key_values => [ { name => 'read_hits' }, { name => 'display' } ], - output_template => 'Read hits: %s /s', - perfdatas => [ - { label => 'read_hits', value => 'read_hits_absolute', template => '%s', - min => 0, unit => '/s', label_extra_instance => 1, instance_use => 'display_absolute' }, - ], - } - }, - { label => 'read-misses', set => { - key_values => [ { name => 'read_misses' }, { name => 'display' } ], - output_template => 'Read misses: %s /s', - perfdatas => [ - { label => 'read_misses', value => 'read_misses_absolute', template => '%s', - min => 0, unit => '/s', label_extra_instance => 1, instance_use => 'display_absolute' }, - ], - } - }, - { label => 'write-hits', set => { - key_values => [ { name => 'write_hits' }, { name => 'display' } ], - output_template => 'Write hits: %s /s', - perfdatas => [ - { label => 'write_hits', value => 'write_hits_absolute', template => '%s', - min => 0, unit => '/s', label_extra_instance => 1, instance_use => 'display_absolute' }, - ], - } - }, - { label => 'write-misses', set => { - key_values => [ { name => 'write_misses' }, { name => 'display' } ], - output_template => 'Write misses: %s /s', - perfdatas => [ - { label => 'write_misses', value => 'write_misses_absolute', template => '%s', - min => 0, unit => '/s', label_extra_instance => 1, instance_use => 'display_absolute' }, - ], - } - }, - { label => 'evicted-objects', set => { - key_values => [ { name => 'evicted_objects' }, { name => 'display' } ], - output_template => 'Evicted objects: %s', - perfdatas => [ - { label => 'evicted_objects', value => 'evicted_objects_absolute', template => '%s', - min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, - ], - } - }, - { label => 'expired-objects', set => { - key_values => [ { name => 'expired_objects' }, { name => 'display' } ], - output_template => 'Evicted objects: %s', - perfdatas => [ - { label => 'expired_objects', value => 'expired_objects_absolute', template => '%s', - min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, - ], + { label => 'memory', set => { + key_values => [ { name => 'used_memory' }, { name => 'memory_size' } ], + closure_custom_calc => $self->can('custom_usage_calc'), + closure_custom_calc_extra_options => { display => 'Memory', label => 'memory', perf => 'memory', + used => 'used_memory', total => 'memory_size' }, + closure_custom_output => $self->can('custom_usage_output'), + closure_custom_perfdata => $self->can('custom_usage_perfdata'), + closure_custom_threshold_check => $self->can('custom_usage_threshold'), } }, { label => 'mem-frag-ratio', set => { @@ -190,18 +266,188 @@ sub set_counters { ], } }, + { label => 'connections', set => { + key_values => [ { name => 'conns' }, { name => 'display' } ], + output_template => 'Connections: %s', + perfdatas => [ + { label => 'connections', value => 'conns_absolute', template => '%s', + min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }, + { label => 'total-rates', set => { + key_values => [ { name => 'total_hits' }, { name => 'total_misses' }, + { name => 'total_req' }, { name => 'total_res' }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_operations_calc'), + closure_custom_calc_extra_options => { operation => 'Total', hits => 'total_hits', misses => 'total_misses', + req => 'total_req', res => 'total_res', display => 'display' }, + closure_custom_output => $self->can('custom_operations_output'), + perfdatas => [ + { label => 'total_hits', value => 'hits', template => '%s', + min => 0, unit => 'ops/s', label_extra_instance => 1, instance_use => 'display' }, + { label => 'total_misses', value => 'misses', template => '%s', + min => 0, unit => 'ops/s', label_extra_instance => 1, instance_use => 'display' }, + { label => 'total_req', value => 'req', template => '%s', + min => 0, unit => 'ops/s', label_extra_instance => 1, instance_use => 'display' }, + { label => 'total_res', value => 'res', template => '%s', + min => 0, unit => 'ops/s', label_extra_instance => 1, instance_use => 'display' }, + ], + } + }, + { label => 'latency', set => { + key_values => [ { name => 'avg_latency' }, { name => 'display' } ], + output_template => 'Average latency: %.2f ms', + perfdatas => [ + { label => 'latency', value => 'avg_latency_absolute', template => '%.2f', + min => 0, unit => 'ms', label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }, + { label => 'other-rates', set => { + key_values => [ { name => 'other_hits' }, { name => 'other_misses' }, + { name => 'other_req' }, { name => 'other_res' }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_operations_calc'), + closure_custom_calc_extra_options => { operation => 'Other', hits => 'other_hits', misses => 'other_misses', + req => 'other_req', res => 'other_res', display => 'display' }, + closure_custom_output => $self->can('custom_operations_output'), + perfdatas => [ + { label => 'other_req', value => 'req', template => '%s', + min => 0, unit => 'ops/s', label_extra_instance => 1, instance_use => 'display' }, + { label => 'other_res', value => 'res', template => '%s', + min => 0, unit => 'ops/s', label_extra_instance => 1, instance_use => 'display' }, + ], + } + }, + { label => 'other-latency', set => { + key_values => [ { name => 'avg_other_latency' }, { name => 'display' } ], + output_template => 'Other latency: %.2f ms', + perfdatas => [ + { label => 'other_latency', value => 'avg_other_latency_absolute', template => '%.2f', + min => 0, unit => 'ms', label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }, + { label => 'keys', set => { + key_values => [ { name => 'no_of_keys' }, { name => 'display' } ], + output_template => 'Total keys: %s', + perfdatas => [ + { label => 'keys', value => 'no_of_keys_absolute', template => '%s', + min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }, + { label => 'evicted-objects', set => { + key_values => [ { name => 'evicted_objects' }, { name => 'display' } ], + output_template => 'Evicted objects rate: %s evictions/sec', + perfdatas => [ + { label => 'evicted_objects', value => 'evicted_objects_absolute', template => '%s', + min => 0, unit => 'evictions/sec', label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }, + { label => 'expired-objects', set => { + key_values => [ { name => 'expired_objects' }, { name => 'display' } ], + output_template => 'Expired objects rate: %s expirations/sec', + perfdatas => [ + { label => 'expired_objects', value => 'expired_objects_absolute', template => '%s', + min => 0, unit => 'expirations/sec', label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }, + { label => 'read-rates', set => { + key_values => [ { name => 'read_hits' }, { name => 'read_misses' }, + { name => 'read_req' }, { name => 'read_res' }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_operations_calc'), + closure_custom_calc_extra_options => { operation => 'Read', hits => 'read_hits', misses => 'read_misses', + req => 'read_req', res => 'read_res', display => 'display' }, + closure_custom_output => $self->can('custom_operations_output'), + perfdatas => [ + { label => 'read_hits', value => 'hits', template => '%s', + min => 0, unit => 'ops/s', label_extra_instance => 1, instance_use => 'display' }, + { label => 'read_misses', value => 'misses', template => '%s', + min => 0, unit => 'ops/s', label_extra_instance => 1, instance_use => 'display' }, + { label => 'read_req', value => 'req', template => '%s', + min => 0, unit => 'ops/s', label_extra_instance => 1, instance_use => 'display' }, + { label => 'read_res', value => 'res', template => '%s', + min => 0, unit => 'ops/s', label_extra_instance => 1, instance_use => 'display' }, + ], + } + }, + { label => 'read-latency', set => { + key_values => [ { name => 'avg_read_latency' }, { name => 'display' } ], + output_template => 'Read latency: %.2f ms', + perfdatas => [ + { label => 'read_latency', value => 'avg_read_latency_absolute', template => '%.2f', + min => 0, unit => 'ms', label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }, + { label => 'write-rates', set => { + key_values => [ { name => 'write_hits' }, { name => 'write_misses' }, + { name => 'write_req' }, { name => 'write_res' }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_operations_calc'), + closure_custom_calc_extra_options => { operation => 'Write', hits => 'write_hits', misses => 'write_misses', + req => 'write_req', res => 'write_res', display => 'display' }, + closure_custom_output => $self->can('custom_operations_output'), + perfdatas => [ + { label => 'write_hits', value => 'hits', template => '%s', + min => 0, unit => 'ops/s', label_extra_instance => 1, instance_use => 'display' }, + { label => 'write_misses', value => 'misses', template => '%s', + min => 0, unit => 'ops/s', label_extra_instance => 1, instance_use => 'display' }, + { label => 'write_req', value => 'req', template => '%s', + min => 0, unit => 'ops/s', label_extra_instance => 1, instance_use => 'display' }, + { label => 'write_res', value => 'res', template => '%s', + min => 0, unit => 'ops/s', label_extra_instance => 1, instance_use => 'display' }, + ], + } + }, + { label => 'write-latency', set => { + key_values => [ { name => 'avg_write_latency' }, { name => 'display' } ], + output_template => 'Write latency: %.2f ms', + perfdatas => [ + { label => 'write_latency', value => 'avg_write_latency_absolute', template => '%.2f', + min => 0, unit => 'ms', label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }, + { label => 'traffic-in', set => { + key_values => [ { name => 'ingress' }, { name => 'display' } ], + output_template => 'Traffic In: %s %s/s', + output_change_bytes => 2, + perfdatas => [ + { label => 'traffic_in', value => 'ingress_absolute', template => '%d', + min => 0, unit => 'b/s', label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + }, + }, + { label => 'traffic-out', set => { + key_values => [ { name => 'egress' }, { name => 'display' } ], + output_template => 'Traffic Out: %s %s/s', + output_change_bytes => 2, + perfdatas => [ + { label => 'traffic_out', value => 'egress_absolute', template => '%d', + min => 0, unit => 'b/s', label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + }, + }, ]; } sub new { my ($class, %options) = @_; - my $self = $class->SUPER::new(package => __PACKAGE__, %options, statefile => 1); + my $self = $class->SUPER::new(package => __PACKAGE__, %options); bless $self, $class; $self->{version} = '1.0'; $options{options}->add_options(arguments => { + "interval:s" => { name => 'interval', default => '15min' }, "filter-database:s" => { name => 'filter_database' }, + "units:s" => { name => 'units', default => '%' }, + "free" => { name => 'free' }, + "warning-status:s" => { name => 'warning_status', default => '' }, + "critical-status:s" => { name => 'critical_status', default => '%{status} =~ /creation-failed/i | %{backup_status} =~ /failed/i | + %{export_status} =~ /failed/i | %{import_status} =~ /failed/i' }, }); return $self; @@ -210,17 +456,25 @@ sub new { sub check_options { my ($self, %options) = @_; $self->SUPER::check_options(%options); - + $instance_mode = $self; + $self->change_macros(); +} + +sub change_macros { + my ($self, %options) = @_; + + foreach (('warning_status', 'critical_status')) { + if (defined($self->{option_results}->{$_})) { + $self->{option_results}->{$_} =~ s/%\{(.*?)\}/\$self->{result_values}->{$1}/g; + } + } } sub manage_selection { my ($self, %options) = @_; - $self->{cache_name} = "redis_restapi_" . $self->{mode} . '_' . $options{custom}->get_connection_info() . '_' . - (defined($self->{option_results}->{filter_counters}) ? md5_hex($self->{option_results}->{filter_counters}) : md5_hex('all')); - - my $result = $options{custom}->get(path => '/v1/bdbs/stats/last'); + my $result = $options{custom}->get(path => '/v1/bdbs/stats/last?interval='.$instance_mode->{option_results}->{interval}); my $result2 = $options{custom}->get(path => '/v1/bdbs'); foreach my $database (keys $result) { @@ -231,26 +485,53 @@ sub manage_selection { } my $shard_list = '-'; - if (@{$result2->{$database}->{shard_list}}) { $shard_list = join(", ", @{$result2->{$database}->{shard_list}}); } + if (@{$result2->{$database}->{shard_list}}) { + $shard_list = join(", ", @{$result2->{$database}->{shard_list}}); + } $self->{databases}->{$database} = { display => $result2->{$database}->{name}, status => defined($result2->{$database}->{status}) ? $result2->{$database}->{status} : '-', type => defined($result2->{$database}->{type}) ? $result2->{$database}->{type} : '-', - sync => defined($result2->{$database}->{sync}) ? $result2->{$database}->{sync} : '-', backup_status => defined($result2->{$database}->{backup_status}) ? $result2->{$database}->{backup_status} : '-', export_status => defined($result2->{$database}->{export_status}) ? $result2->{$database}->{export_status} : '-', + import_status => defined($result2->{$database}->{import_status}) ? $result2->{$database}->{import_status} : '-', shard_list => $shard_list, + shard_cpu_user => $result->{$database}->{shard_cpu_user} * 100, + shard_cpu_system => $result->{$database}->{shard_cpu_system} * 100, + main_thread_cpu_user => $result->{$database}->{main_thread_cpu_user} * 100, + main_thread_cpu_system => $result->{$database}->{main_thread_cpu_system} * 100, + fork_cpu_user => $result->{$database}->{fork_cpu_user} * 100, + fork_cpu_system => $result->{$database}->{fork_cpu_system} * 100, used_memory => $result->{$database}->{used_memory}, - instantaneous_ops_per_sec => $result->{$database}->{instantaneous_ops_per_sec}, + memory_size => $result2->{$database}->{memory_size}, + mem_frag_ratio => $result->{$database}->{mem_frag_ratio}, + conns => $result->{$database}->{conns}, + total_req => $result->{$database}->{total_req}, + total_res => $result->{$database}->{total_res}, + total_hits => $result->{$database}->{read_hits} + $result->{$database}->{write_hits}, + total_misses => $result->{$database}->{read_misses} + $result->{$database}->{write_misses}, + avg_latency => defined($result2->{$database}->{avg_latency}) ? $result->{$database}->{avg_latency} * 1000 : '0', + other_req => $result->{$database}->{other_req}, + other_res => $result->{$database}->{other_res}, + other_hits => '-', + other_misses => '-', + avg_other_latency => defined($result2->{$database}->{avg_other_latency}) ? $result->{$database}->{avg_other_latency} * 1000 : '0', no_of_keys => $result->{$database}->{no_of_keys}, evicted_objects => $result->{$database}->{evicted_objects}, expired_objects => $result->{$database}->{expired_objects}, read_hits => $result->{$database}->{read_hits}, read_misses => $result->{$database}->{read_misses}, + read_req => $result->{$database}->{read_req}, + read_res => $result->{$database}->{read_res}, write_hits => $result->{$database}->{write_hits}, write_misses => $result->{$database}->{write_misses}, - mem_frag_ratio => $result->{$database}->{mem_frag_ratio}, + write_req => $result->{$database}->{write_req}, + write_res => $result->{$database}->{write_res}, + avg_read_latency => defined($result2->{$database}->{avg_read_latency}) ? $result->{$database}->{avg_read_latency} * 1000 : '0', + avg_write_latency => defined($result2->{$database}->{avg_write_latency}) ? $result->{$database}->{avg_write_latency} * 1000 : '0', + ingress => $result->{$database}->{ingress_bytes} * 8, + egress => $result->{$database}->{egress_bytes} * 8, }; if (scalar(keys %{$self->{databases}}) <= 0) { @@ -273,35 +554,63 @@ Check RedisLabs Enterprise Cluster databases statistics. =item B<--filter-counters> Only display some counters (regexp can be used). -Example: --filter-counters='clients' +Example: --filter-counters='rate|latency' + +=item B<--interval> + +Time interval from which to retrieve statistics (Default: '15min'). +Can be : '1sec', '10sec', '5min', '15min', +'1hour', '12hour', '1week' =item B<--warning-status> Set warning threshold for status. -Can used special variables like: %{status}, %{type}, %{sync}, -%{backup_status}, %{export_status}, %{shard_list} +Can used special variables like: %{status}, %{type}, +%{backup_status}, %{export_status}, %{shard_list}. +'status' can be: 'pending', 'active', 'active-change-pending', +'delete-pending', 'import-pending', 'creation-failed', 'recovery'. +'type' can be: 'redis', 'memcached'. +'backup_status' can be: 'exporting', 'succeeded', 'failed'. +'export_status' can be: 'exporting', 'succeeded', 'failed'. +'import_status' can be: 'idle', 'initializing', 'importing', +'succeeded', 'failed'. =item B<--critical-status> -Set critical threshold for status (Default: '%{status} !~ /active/i'). -Can used special variables like: %{status}, %{type}, %{sync}, -%{backup_status}, %{export_status}, %{shard_list} +Set critical threshold for status (Default: '%{status} =~ /creation-failed/i | +%{backup_status} =~ /failed/i | %{export_status} =~ /failed/i | +%{import_status} =~ /failed/i'). +Can used special variables like: %{status}, %{type}, +%{backup_status}, %{export_status}, %{shard_list}. +'status' can be: 'pending', 'active', 'active-change-pending', +'delete-pending', 'import-pending', 'creation-failed', 'recovery'. +'type' can be: 'redis', 'memcached'. +'backup_status' can be: 'exporting', 'succeeded', 'failed'. +'' can be: 'exporting', 'succeeded', 'failed'. +'import_status' can be: 'idle', 'initializing', 'importing', +'succeeded', 'failed'. =item B<--warning-*> Threshold warning. -Can be: 'ops-per-sec', 'memory-used', -'total-keys', 'read-hits', 'read-misses', -'write-hits', 'write-misses', 'evicted-objects', -'expired-objects', 'mem-frag-ratio'. +Can be: 'total-cpu', 'fork-cpu', 'main-thread-cpu', +'memory', 'mem-frag-ratio', 'connections', +'total-rates', 'latency', 'other-rates', 'other-latency', +'keys', 'evicted-objects', 'expired-objects', +'read-rates', 'read-latency', +'write-rates', 'write-latency', +'traffic-in', 'traffic-out'. =item B<--critical-*> Threshold critical. -Can be: 'ops-per-sec', 'memory-used', -'total-keys', 'read-hits', 'read-misses', -'write-hits', 'write-misses', 'evicted-objects', -'expired-objects', 'mem-frag-ratio'. +Can be: 'total-cpu', 'fork-cpu', 'main-thread-cpu', +'memory', 'mem-frag-ratio', 'connections', +'total-rates', 'latency', 'other-rates', 'other-latency', +'keys', 'evicted-objects', 'expired-objects', +'read-rates', 'read-latency', +'write-rates', 'write-latency', +'traffic-in', 'traffic-out'. =back diff --git a/apps/redis/restapi/mode/nodesstats.pm b/apps/redis/restapi/mode/nodesstats.pm index 3df536048..2a1c23a87 100644 --- a/apps/redis/restapi/mode/nodesstats.pm +++ b/apps/redis/restapi/mode/nodesstats.pm @@ -101,7 +101,7 @@ sub custom_status_threshold { eval "$instance_mode->{option_results}->{critical_status}") { $status = 'critical'; } elsif (defined($instance_mode->{option_results}->{warning_status}) && $instance_mode->{option_results}->{warning_status} ne '' && - eval "$instance_mode->{option_results}->{warning_status}") { + eval "$instance_mode->{option_results}->{warning_status}") { $status = 'warning'; } }; @@ -133,22 +133,6 @@ sub custom_status_calc { return 0; } -sub new { - my ($class, %options) = @_; - my $self = $class->SUPER::new(package => __PACKAGE__, %options, statefile => 1); - bless $self, $class; - - $self->{version} = '1.0'; - $options{options}->add_options(arguments => - { - "filter-node:s" => { name => 'filter_node' }, - "units:s" => { name => 'units', default => '%' }, - "free" => { name => 'free' }, - }); - - return $self; -} - sub prefix_output { my ($self, %options) = @_; @@ -171,6 +155,24 @@ sub set_counters { closure_custom_threshold_check => $self->can('custom_status_threshold'), } }, + { label => 'shard-count', set => { + key_values => [ { name => 'shard_count' }, { name => 'display' } ], + output_template => 'Shard count: %d', + perfdatas => [ + { label => 'shard_count', value => 'shard_count_absolute', template => '%d', + min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + }, + }, + { label => 'uptime', set => { + key_values => [ { name => 'uptime' }, { name => 'uptime_sec' }, { name => 'display' } ], + output_template => 'Uptime: %s', + perfdatas => [ + { label => 'uptime', value => 'uptime_sec_absolute', template => '%d', + min => 0, unit => 's', label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + }, + }, { label => 'cpu-system', set => { key_values => [ { name => 'cpu_system' }, { name => 'display' } ], output_template => 'Cpu system: %.2f %%', @@ -189,51 +191,41 @@ sub set_counters { ], } }, - { label => 'requests', set => { - key_values => [ { name => 'total_req', diff => 1 }, { name => 'display' } ], - output_template => 'Requests per seconds: %s', - per_second => 1, - perfdatas => [ - { label => 'requests', value => 'total_req_per_second', template => '%s', - min => 0, unit => '/s', label_extra_instance => 1, instance_use => 'display_absolute' }, - ], - } - }, - { label => 'memory-used', set => { + { label => 'memory', set => { key_values => [ { name => 'free_memory' }, { name => 'total_memory' } ], closure_custom_calc => $self->can('custom_usage_calc'), - closure_custom_calc_extra_options => { display => 'Ram', label => 'memory-used', perf => 'memory_used', + closure_custom_calc_extra_options => { display => 'Ram', label => 'memory', perf => 'memory', free => 'free_memory', total => 'total_memory' }, closure_custom_output => $self->can('custom_usage_output'), closure_custom_perfdata => $self->can('custom_usage_perfdata'), closure_custom_threshold_check => $self->can('custom_usage_threshold'), } }, - { label => 'persistent-storage-used', set => { + { label => 'persistent-storage', set => { key_values => [ { name => 'persistent_storage_free' }, { name => 'persistent_storage_size' } ], closure_custom_calc => $self->can('custom_usage_calc'), - closure_custom_calc_extra_options => { display => 'Persistent storage', label => 'persistent-storage-used', perf => 'persistent_storage_used', + closure_custom_calc_extra_options => { display => 'Persistent storage', label => 'persistent-storage', perf => 'persistent_storage', free => 'persistent_storage_free', total => 'persistent_storage_size' }, closure_custom_output => $self->can('custom_usage_output'), closure_custom_perfdata => $self->can('custom_usage_perfdata'), closure_custom_threshold_check => $self->can('custom_usage_threshold'), } }, - { label => 'ephemeral-storage-used', set => { + { label => 'ephemeral-storage', set => { key_values => [ { name => 'ephemeral_storage_free' }, { name => 'ephemeral_storage_size' } ], closure_custom_calc => $self->can('custom_usage_calc'), - closure_custom_calc_extra_options => { display => 'Ephemeral storage', label => 'ephemeral-storage-used', perf => 'ephemeral_storage_used', + closure_custom_calc_extra_options => { display => 'Ephemeral storage', label => 'ephemeral-storage', perf => 'ephemeral_storage', free => 'ephemeral_storage_free', total => 'ephemeral_storage_size' }, closure_custom_output => $self->can('custom_usage_output'), closure_custom_perfdata => $self->can('custom_usage_perfdata'), closure_custom_threshold_check => $self->can('custom_usage_threshold'), } }, - { label => 'flash-storage-used', set => { - key_values => [ { name => 'available_flash' }, { name => 'bigstore_size' } ], + { label => 'flash-storage', set => { + key_values => [ { name => 'bigstore_free' }, { name => 'bigstore_size' } ], closure_custom_calc => $self->can('custom_usage_calc'), - closure_custom_calc_extra_options => { display => 'Flash storage', label => 'flash-storage-used', perf => 'flash_storage_used', - free => 'available_flash', total => 'bigstore_size' }, + closure_custom_calc_extra_options => { display => 'Flash storage', label => 'flash-storage', perf => 'flash_storage', + free => 'bigstore_free', total => 'bigstore_size' }, closure_custom_output => $self->can('custom_usage_output'), closure_custom_perfdata => $self->can('custom_usage_perfdata'), closure_custom_threshold_check => $self->can('custom_usage_threshold'), @@ -241,10 +233,10 @@ sub set_counters { }, { label => 'flash-iops', set => { key_values => [ { name => 'bigstore_iops' }, { name => 'display' } ], - output_template => 'Flash IOPS: %s', + output_template => 'Flash IOPS: %s ops/s', perfdatas => [ { label => 'flash_iops', value => 'bigstore_iops_absolute', template => '%s', - min => 0, unit => '/s', label_extra_instance => 1, instance_use => 'display_absolute' }, + min => 0, unit => 'ops/s', label_extra_instance => 1, instance_use => 'display_absolute' }, ], } }, @@ -267,6 +259,15 @@ sub set_counters { ], } }, + { label => 'requests', set => { + key_values => [ { name => 'total_req' } ], + output_template => 'Requests rate: %s ops/s', + perfdatas => [ + { label => 'requests', value => 'total_req_absolute', template => '%s', + min => 0, unit => 'ops/s' }, + ], + } + }, { label => 'traffic-in', set => { key_values => [ { name => 'ingress' }, { name => 'display' } ], output_template => 'Traffic In: %s %s/s', @@ -287,41 +288,50 @@ sub set_counters { ], }, }, - { label => 'shard-count', set => { - key_values => [ { name => 'shard_count' }, { name => 'display' } ], - output_template => 'Shard count: %d', - perfdatas => [ - { label => 'shard_count', value => 'shard_count_absolute', template => '%d', - min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, - ], - }, - }, - { label => 'uptime', set => { - key_values => [ { name => 'uptime' }, { name => 'uptime_sec' }, { name => 'display' } ], - output_template => 'Uptime: %s', - perfdatas => [ - { label => 'uptime', value => 'uptime_sec_absolute', template => '%d', - min => 0, unit => 's', label_extra_instance => 1, instance_use => 'display_absolute' }, - ], - }, - }, ]; } +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "interval:s" => { name => 'interval', default => '15min' }, + "filter-node:s" => { name => 'filter_node' }, + "units:s" => { name => 'units', default => '%' }, + "free" => { name => 'free' }, + "warning-status:s" => { name => 'warning_status', default => '' }, + "critical-status:s" => { name => 'critical_status', default => '%{status} !~ /down/i' }, + }); + + return $self; +} + sub check_options { my ($self, %options) = @_; $self->SUPER::check_options(%options); - + $instance_mode = $self; + $self->change_macros(); +} + +sub change_macros { + my ($self, %options) = @_; + + foreach (('warning_status', 'critical_status')) { + if (defined($self->{option_results}->{$_})) { + $self->{option_results}->{$_} =~ s/%\{(.*?)\}/\$self->{result_values}->{$1}/g; + } + } } sub manage_selection { my ($self, %options) = @_; - $self->{cache_name} = "redis_restapi_" . $self->{mode} . '_' . $options{custom}->get_connection_info() . '_' . - (defined($self->{option_results}->{filter_counters}) ? md5_hex($self->{option_results}->{filter_counters}) : md5_hex('all')); - - my $result = $options{custom}->get(path => '/v1/nodes/stats/last'); + my $result = $options{custom}->get(path => '/v1/nodes/stats/last?interval='.$instance_mode->{option_results}->{interval}); my $result2 = $options{custom}->get(path => '/v1/nodes'); foreach my $node (keys $result) { @@ -332,16 +342,23 @@ sub manage_selection { } my $shard_list = '-'; - if (@{$result2->{$node}->{shard_list}}) { $shard_list = join(", ", @{$result2->{$node}->{shard_list}}); } + if (@{$result2->{$node}->{shard_list}}) { + $shard_list = join(", ", @{$result2->{$node}->{shard_list}}); + } my $ext_addr = '-'; - if (@{$result2->{$node}->{external_addr}}) { $ext_addr = join(", ", @{$result2->{$node}->{external_addr}}); } + if (@{$result2->{$node}->{external_addr}}) { + $ext_addr = join(", ", @{$result2->{$node}->{external_addr}}); + } $self->{nodes}->{$node} = { display => $node, status => defined($result2->{$node}->{status}) ? $result2->{$node}->{status} : '-', shard_list => $shard_list, + shard_count => $result2->{$node}->{shard_count}, int_addr => $result2->{$node}->{addr}, ext_addr => $ext_addr, + uptime => centreon::plugins::misc::change_seconds(value => $result2->{$node}->{uptime}), + uptime_sec => $result2->{$node}->{uptime}, cpu_system => $result->{$node}->{cpu_system} * 100, cpu_user => $result->{$node}->{cpu_user} * 100, free_memory => $result->{$node}->{free_memory}, @@ -350,17 +367,14 @@ sub manage_selection { persistent_storage_size => $result2->{$node}->{persistent_storage_size}, ephemeral_storage_free => $result->{$node}->{ephemeral_storage_free}, ephemeral_storage_size => $result2->{$node}->{ephemeral_storage_size}, - available_flash => $result->{$node}->{available_flash}, + bigstore_free => $result->{$node}->{bigstore_free}, bigstore_size => $result2->{$node}->{bigstore_size}, bigstore_iops => $result->{$node}->{bigstore_iops}, bigstore_throughput => $result->{$node}->{bigstore_throughput}, conns => $result->{$node}->{conns}, + total_req => $result->{$node}->{total_req}, ingress => $result->{$node}->{ingress_bytes} * 8, egress => $result->{$node}->{egress_bytes} * 8, - total_req => $result->{$node}->{total_req}, - shard_count => $result2->{$node}->{shard_count}, - uptime => centreon::plugins::misc::change_seconds(value => $result2->{$node}->{uptime}), - uptime_sec => $result2->{$node}->{uptime}, }; if (scalar(keys %{$self->{nodes}}) <= 0) { @@ -385,32 +399,51 @@ Check RedisLabs Enterprise Cluster nodes statistics. Only display some counters (regexp can be used). Example: --filter-counters='^cpu' +=item B<--interval> + +Time interval from which to retrieve statistics (Default: '15min'). +Can be : '1sec', '10sec', '5min', '15min', +'1hour', '12hour', '1week' + +=item B<--units> + +Units of thresholds (Default: '%') ('%', 'B'). + +=item B<--free> + +Thresholds are on free space left. =item B<--warning-status> Set warning threshold for status. -Can used special variables like: %{status}, %{shard_list}, %{int_addr}, %{ext_addr}. +Can used special variables like: %{status}, %{shard_list}, +%{int_addr}, %{ext_addr}. +'status' can be: 'active', 'going_offline', 'offline', +'provisioning', 'decommissioning', 'down'. =item B<--critical-status> -Set critical threshold for status (Default: '%{status} !~ /active/i'). -Can used special variables like: %{status}, %{shard_list}, %{int_addr}, %{ext_addr}. +Set critical threshold for status (Default: '%{status} !~ /down/i'). +Can used special variables like: %{status}, %{shard_list}, +%{int_addr}, %{ext_addr}. +'status' can be: 'active', 'going_offline', 'offline', +'provisioning', 'decommissioning', 'down'. =item B<--warning-*> Threshold warning. Can be: 'cpu-system', 'cpu-user', -'requests', 'memory-used', 'flash-storage-used', -'persistent-storage-used', 'ephemeral-storage-used', +'requests', 'memory', 'flash-storage', +'persistent-storage', 'ephemeral-storage', 'flash-iops', 'flash-throughput', 'connections', -'traffic-in', 'traffic-out', 'uptime'. +'traffic-in', 'traffic-out', 'shard-count', 'uptime'. =item B<--critical-*> Threshold critical. Can be: 'cpu-system', 'cpu-user', -'requests', 'memory-used', 'flash-storage-used', -'persistent-storage-used', 'ephemeral-storage-used', +'requests', 'memory', 'flash-storage', +'persistent-storage', 'ephemeral-storage', 'flash-iops', 'flash-throughput', 'connections', 'traffic-in', 'traffic-out', 'shard-count', 'uptime'. diff --git a/apps/redis/restapi/mode/shardsstats.pm b/apps/redis/restapi/mode/shardsstats.pm index a2d79f38d..097a9ba00 100644 --- a/apps/redis/restapi/mode/shardsstats.pm +++ b/apps/redis/restapi/mode/shardsstats.pm @@ -41,7 +41,7 @@ sub custom_status_threshold { eval "$instance_mode->{option_results}->{critical_status}") { $status = 'critical'; } elsif (defined($instance_mode->{option_results}->{warning_status}) && $instance_mode->{option_results}->{warning_status} ne '' && - eval "$instance_mode->{option_results}->{warning_status}") { + eval "$instance_mode->{option_results}->{warning_status}") { $status = 'warning'; } }; @@ -80,6 +80,46 @@ sub custom_status_calc { return 0; } +sub custom_operations_output { + my ($self, %options) = @_; + + my $msg = sprintf("%s operations rates (hits/misses): %s/%s ops/s", + $self->{result_values}->{operation}, + $self->{result_values}->{hits}, + $self->{result_values}->{misses}); + return $msg; +} + +sub custom_operations_calc { + my ($self, %options) = @_; + + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{display}}; + $self->{result_values}->{operation} = $options{extra_options}->{operation}; + $self->{result_values}->{hits} = $options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{hits}}; + $self->{result_values}->{misses} = $options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{misses}}; + return 0; +} + +sub custom_cpu_output { + my ($self, %options) = @_; + + my $msg = sprintf("%s CPU usage (user/system): %s/%s %%", + $self->{result_values}->{cpu}, + $self->{result_values}->{user}, + $self->{result_values}->{system}); + return $msg; +} + +sub custom_cpu_calc { + my ($self, %options) = @_; + + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{display}}; + $self->{result_values}->{cpu} = $options{extra_options}->{cpu}; + $self->{result_values}->{user} = $options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{user}}; + $self->{result_values}->{system} = $options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{system}}; + return 0; +} + sub prefix_output { my ($self, %options) = @_; @@ -95,37 +135,71 @@ sub set_counters { $self->{maps_counters}->{shards} = [ { label => 'status', threshold => 0, set => { - key_values => [ { name => 'status' }, { name => 'detailed_status' }, { name => 'role' }, { name => 'loading' }, { name => 'sync' }, { name => 'backup' } ], + key_values => [ { name => 'status' }, { name => 'detailed_status' }, { name => 'role' }, + { name => 'loading' }, { name => 'sync' }, { name => 'backup' } ], closure_custom_calc => $self->can('custom_status_calc'), closure_custom_output => $self->can('custom_status_output'), closure_custom_perfdata => sub { return 0; }, closure_custom_threshold_check => $self->can('custom_status_threshold'), } }, - { label => 'ops-per-sec', set => { - key_values => [ { name => 'instantaneous_ops_per_sec' }, { name => 'display' } ], - output_template => 'Operations: %s ops/s', + { label => 'total-cpu', set => { + key_values => [ { name => 'shard_cpu_user' }, { name => 'shard_cpu_system' }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_cpu_calc'), + closure_custom_calc_extra_options => { cpu => 'Total', user => 'shard_cpu_user', + system => 'shard_cpu_system', display => 'display' }, + closure_custom_output => $self->can('custom_cpu_output'), perfdatas => [ - { label => 'ops_per_sec', value => 'instantaneous_ops_per_sec_absolute', template => '%s', - min => 0, unit => 'ops/s', label_extra_instance => 1, instance_use => 'display_absolute' }, + { label => 'total_cpu_user', value => 'user', template => '%s', + min => 0, max => 100, unit => '%', label_extra_instance => 1, instance_use => 'display' }, + { label => 'total_cpu_system', value => 'system', template => '%s', + min => 0, max => 100, unit => '%', label_extra_instance => 1, instance_use => 'display' }, ], } }, - { label => 'memory-used', set => { + { label => 'fork-cpu', set => { + key_values => [ { name => 'fork_cpu_user' }, { name => 'fork_cpu_system' }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_cpu_calc'), + closure_custom_calc_extra_options => { cpu => 'Fork', user => 'fork_cpu_user', + system => 'fork_cpu_system', display => 'display' }, + closure_custom_output => $self->can('custom_cpu_output'), + perfdatas => [ + { label => 'fork_cpu_user', value => 'user', template => '%s', + min => 0, max => 100, unit => '%', label_extra_instance => 1, instance_use => 'display' }, + { label => 'fork_cpu_system', value => 'system', template => '%s', + min => 0, max => 100, unit => '%', label_extra_instance => 1, instance_use => 'display' }, + ], + } + }, + { label => 'main-thread-cpu', set => { + key_values => [ { name => 'main_thread_cpu_user' }, { name => 'main_thread_cpu_system' }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_cpu_calc'), + closure_custom_calc_extra_options => { cpu => 'Main thread', user => 'main_thread_cpu_user', + system => 'main_thread_cpu_system', display => 'display' }, + closure_custom_output => $self->can('custom_cpu_output'), + perfdatas => [ + { label => 'main_thread_cpu_user', value => 'user', template => '%s', + min => 0, max => 100, unit => '%', label_extra_instance => 1, instance_use => 'display' }, + { label => 'main_thread_cpu_system', value => 'system', template => '%s', + min => 0, max => 100, unit => '%', label_extra_instance => 1, instance_use => 'display' }, + ], + } + }, + { label => 'memory', set => { key_values => [ { name => 'used_memory' }, { name => 'display' } ], output_template => 'Memory used: %s %s', output_change_bytes => 1, perfdatas => [ - { label => 'memory-used', value => 'used_memory_absolute', template => '%s', + { label => 'memory', value => 'used_memory_absolute', template => '%s', min => 0, unit => 'B', label_extra_instance => 1, instance_use => 'display_absolute' }, ], } }, - { label => 'total-keys', set => { - key_values => [ { name => 'no_of_keys' }, { name => 'display' } ], - output_template => 'Total keys: %s', + { label => 'mem-frag-ratio', set => { + key_values => [ { name => 'mem_frag_ratio' }, { name => 'display' } ], + output_template => 'Memory fragmentation ratio: %s', perfdatas => [ - { label => 'total-keys', value => 'no_of_keys_absolute', template => '%s', + { label => 'mem_frag_ratio', value => 'mem_frag_ratio_absolute', template => '%s', min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, ], } @@ -148,57 +222,76 @@ sub set_counters { ], } }, - { label => 'read-hits', set => { - key_values => [ { name => 'read_hits' }, { name => 'display' } ], - output_template => 'Read hits: %s /s', + { label => 'requests', set => { + key_values => [ { name => 'total_req'}, { name => 'display' }], + output_template => 'Requests rate: %s ops/s', perfdatas => [ - { label => 'read_hits', value => 'read_hits_absolute', template => '%s', - min => 0, unit => '/s', label_extra_instance => 1, instance_use => 'display_absolute' }, + { label => 'requests', value => 'total_req_absolute', template => '%s', + min => 0, unit => 'ops/s', label_extra_instance => 1, instance_use => 'display_absolute' }, ], } }, - { label => 'read-misses', set => { - key_values => [ { name => 'read_misses' }, { name => 'display' } ], - output_template => 'Read misses: %s /s', + { label => 'keys', set => { + key_values => [ { name => 'no_of_keys' }, { name => 'display' } ], + output_template => 'Total keys: %s', perfdatas => [ - { label => 'read_misses', value => 'read_misses_absolute', template => '%s', - min => 0, unit => '/s', label_extra_instance => 1, instance_use => 'display_absolute' }, + { label => 'keys', value => 'no_of_keys_absolute', template => '%s', + min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, ], } }, - { label => 'write-hits', set => { - key_values => [ { name => 'write_hits' }, { name => 'display' } ], - output_template => 'Write hits: %s /s', + { label => 'volatile-keys', set => { + key_values => [ { name => 'no_of_expires' }, { name => 'display' } ], + output_template => 'Volatile keys: %s', perfdatas => [ - { label => 'write_hits', value => 'write_hits_absolute', template => '%s', - min => 0, unit => '/s', label_extra_instance => 1, instance_use => 'display_absolute' }, - ], - } - }, - { label => 'write-misses', set => { - key_values => [ { name => 'write_misses' }, { name => 'display' } ], - output_template => 'Write misses: %s /s', - perfdatas => [ - { label => 'write_misses', value => 'write_misses_absolute', template => '%s', - min => 0, unit => '/s', label_extra_instance => 1, instance_use => 'display_absolute' }, + { label => 'volatile-keys', value => 'no_of_expires_absolute', template => '%s', + min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, ], } }, { label => 'evicted-objects', set => { key_values => [ { name => 'evicted_objects' }, { name => 'display' } ], - output_template => 'Evicted objects: %s', + output_template => 'Evicted objects rate: %s evictions/sec', perfdatas => [ { label => 'evicted_objects', value => 'evicted_objects_absolute', template => '%s', - min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, + min => 0, unit => 'evictions/sec', label_extra_instance => 1, instance_use => 'display_absolute' }, ], } }, { label => 'expired-objects', set => { key_values => [ { name => 'expired_objects' }, { name => 'display' } ], - output_template => 'Evicted objects: %s', + output_template => 'Expired objects rate: %s expirations/sec', perfdatas => [ { label => 'expired_objects', value => 'expired_objects_absolute', template => '%s', - min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, + min => 0, unit => 'expirations/sec', label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }, + { label => 'read-rates', set => { + key_values => [ { name => 'read_hits' }, { name => 'read_misses' }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_operations_calc'), + closure_custom_calc_extra_options => { operation => 'Read', hits => 'read_hits', + misses => 'read_misses', display => 'display' }, + closure_custom_output => $self->can('custom_operations_output'), + perfdatas => [ + { label => 'read_hits', value => 'hits', template => '%s', + min => 0, unit => 'ops/s', label_extra_instance => 1, instance_use => 'display' }, + { label => 'read_misses', value => 'misses', template => '%s', + min => 0, unit => 'ops/s', label_extra_instance => 1, instance_use => 'display' }, + ], + } + }, + { label => 'write-rates', set => { + key_values => [ { name => 'write_hits' }, { name => 'write_misses' }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_operations_calc'), + closure_custom_calc_extra_options => { operation => 'Write', hits => 'write_hits', + misses => 'write_misses', display => 'display' }, + closure_custom_output => $self->can('custom_operations_output'), + perfdatas => [ + { label => 'write_hits', value => 'hits', template => '%s', + min => 0, unit => 'ops/s', label_extra_instance => 1, instance_use => 'display' }, + { label => 'write_misses', value => 'misses', template => '%s', + min => 0, unit => 'ops/s', label_extra_instance => 1, instance_use => 'display' }, ], } }, @@ -220,27 +313,22 @@ sub set_counters { ], } }, - { label => 'mem-frag-ratio', set => { - key_values => [ { name => 'mem_frag_ratio' }, { name => 'display' } ], - output_template => 'Memory fragmentation ratio: %s', - perfdatas => [ - { label => 'mem_frag_ratio', value => 'mem_frag_ratio_absolute', template => '%s', - min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, - ], - } - }, ]; } sub new { my ($class, %options) = @_; - my $self = $class->SUPER::new(package => __PACKAGE__, %options, statefile => 1); + my $self = $class->SUPER::new(package => __PACKAGE__, %options); bless $self, $class; $self->{version} = '1.0'; $options{options}->add_options(arguments => { + "interval:s" => { name => 'interval', default => '15min' }, "filter-shard:s" => { name => 'filter_shard' }, + "warning-status:s" => { name => 'warning_status', default => '' }, + "critical-status:s" => { name => 'critical_status', default => '%{status} =~ /inactive/i | %{backup} =~ /failed/i | + %{sync} =~ /link_down/i' }, }); return $self; @@ -249,17 +337,25 @@ sub new { sub check_options { my ($self, %options) = @_; $self->SUPER::check_options(%options); - + $instance_mode = $self; + $self->change_macros(); +} + +sub change_macros { + my ($self, %options) = @_; + + foreach (('warning_status', 'critical_status')) { + if (defined($self->{option_results}->{$_})) { + $self->{option_results}->{$_} =~ s/%\{(.*?)\}/\$self->{result_values}->{$1}/g; + } + } } sub manage_selection { my ($self, %options) = @_; - $self->{cache_name} = "redis_restapi_" . $self->{mode} . '_' . $options{custom}->get_connection_info() . '_' . - (defined($self->{option_results}->{filter_counters}) ? md5_hex($self->{option_results}->{filter_counters}) : md5_hex('all')); - - my $result = $options{custom}->get(path => '/v1/shards/stats/last'); + my $result = $options{custom}->get(path => '/v1/shards/stats/last?interval='.$instance_mode->{option_results}->{interval}); my $result2 = $options{custom}->get(path => '/v1/shards'); foreach my $shard (keys $result) { @@ -278,17 +374,24 @@ sub manage_selection { sync => defined($result2->{$shard}->{sync}->{status}) ? $result2->{$shard}->{sync}->{status} : '-', backup => defined($result2->{$shard}->{backup}->{status}) ? $result2->{$shard}->{backup}->{status} : '-', used_memory => $result->{$shard}->{used_memory}, - instantaneous_ops_per_sec => $result->{$shard}->{instantaneous_ops_per_sec}, - no_of_keys => $result->{$shard}->{no_of_keys}, + mem_frag_ratio => $result->{$shard}->{mem_frag_ratio}, + shard_cpu_user => $result->{$shard}->{shard_cpu_user} * 100, + shard_cpu_system => $result->{$shard}->{shard_cpu_system} * 100, + main_thread_cpu_user => $result->{$shard}->{main_thread_cpu_user} * 100, + main_thread_cpu_system => $result->{$shard}->{main_thread_cpu_system} * 100, + fork_cpu_user => $result->{$shard}->{fork_cpu_user} * 100, + fork_cpu_system => $result->{$shard}->{fork_cpu_system} * 100, connected_clients => $result->{$shard}->{connected_clients}, blocked_clients => $result->{$shard}->{blocked_clients}, + total_req => $result->{$shard}->{total_req}, + no_of_keys => $result->{$shard}->{no_of_keys}, + no_of_expires => $result->{$shard}->{no_of_expires}, evicted_objects => $result->{$shard}->{evicted_objects}, expired_objects => $result->{$shard}->{expired_objects}, read_hits => $result->{$shard}->{read_hits}, read_misses => $result->{$shard}->{read_misses}, write_hits => $result->{$shard}->{write_hits}, write_misses => $result->{$shard}->{write_misses}, - mem_frag_ratio => $result->{$shard}->{mem_frag_ratio}, rdb_changes_since_last_save => $result->{$shard}->{rdb_changes_since_last_save}, last_save_time => centreon::plugins::misc::change_seconds(value => time() - $result->{$shard}->{last_save_time}), last_save_time_sec => time() - $result->{$shard}->{last_save_time}, @@ -316,37 +419,60 @@ Check RedisLabs Enterprise Cluster shards statistics. Only display some counters (regexp can be used). Example: --filter-counters='clients' -=item B<--warning-status> +=item B<--interval> +Time interval from which to retrieve statistics (Default: '15min'). +Can be : '1sec', '10sec', '5min', '15min', +'1hour', '12hour', '1week' + +=item B<--warning-status> + Set warning threshold for status. Can used special variables like: %{status}, %{detailed_status}, %{role}, %{loading}, %{sync}, %{backup}. +'status' can be: 'active', 'inactive', 'trimming'. +'detailed_status' can be: 'ok', 'importing', 'timeout', +'loading', 'busy', 'down', 'trimming', 'unknown'. +'role' can be: 'slave', 'master'. +'loading' can be: 'in_progress', 'idle'. +'sync' can be: 'in_progress', 'idle', 'link_down'. +'backup' can be: 'exporting', 'succeeded', 'failed'. =item B<--critical-status> -Set critical threshold for status (Default: '%{status} !~ /active/i'). +Set critical threshold for status (Default: '%{status} =~ /inactive/i | +%{backup} =~ /failed/i | %{sync} =~ /link_down/i'). Can used special variables like: %{status}, %{detailed_status}, %{role}, %{loading}, %{sync}, %{backup}. +'status' can be: 'active', 'inactive', 'trimming'. +'detailed_status' can be: 'ok', 'importing', 'timeout', +'loading', 'busy', 'down', 'trimming', 'unknown'. +'role' can be: 'slave', 'master'. +'loading' can be: 'in_progress', 'idle'. +'sync' can be: 'in_progress', 'idle', 'link_down'. +'backup' can be: 'exporting', 'succeeded', 'failed'. =item B<--warning-*> Threshold warning. -Can be: 'ops-per-sec', 'memory-used', 'total-keys', +Can be: 'total-cpu', 'fork-cpu', 'main-thread-cpu', +'memory', 'mem-frag-ratio', 'connected-clients', 'blocked-clients', -'read-hits', 'read-misses', 'write-hits', -'write-misses', 'evicted-objects', 'expired-objects', +'request', 'keys', +'evicted-objects', 'expired-objects', +'read-rates', 'write-rates', 'rdb-changes-since-last-save', 'last-save-time', -'mem-frag-ratio'. =item B<--critical-*> Threshold critical. -Can be: 'ops-per-sec', 'memory-used', 'total-keys', +Can be: 'total-cpu', 'fork-cpu', 'main-thread-cpu', +'memory', 'mem-frag-ratio', 'connected-clients', 'blocked-clients', -'read-hits', 'read-misses', 'write-hits', -'write-misses', 'evicted-objects', 'expired-objects', +'request', 'keys', +'evicted-objects', 'expired-objects', +'read-rates', 'write-rates', 'rdb-changes-since-last-save', 'last-save-time', -'mem-frag-ratio'. =back