From a33b359a40f18bc536d5a9c468e669712384c643 Mon Sep 17 00:00:00 2001 From: qgarnier Date: Thu, 2 Nov 2023 17:54:02 +0100 Subject: [PATCH] enh(centreon/sql): add execution-time mode (#4614) --- .../centreon/sql/mode/countnotifications.pm | 47 +++--- src/apps/centreon/sql/mode/countproblems.pm | 38 +++-- src/apps/centreon/sql/mode/executiontime.pm | 140 ++++++++++++++++++ src/apps/centreon/sql/mode/partitioning.pm | 39 +++-- 4 files changed, 214 insertions(+), 50 deletions(-) create mode 100644 src/apps/centreon/sql/mode/executiontime.pm diff --git a/src/apps/centreon/sql/mode/countnotifications.pm b/src/apps/centreon/sql/mode/countnotifications.pm index b1e1914c9..6fe8d02e3 100644 --- a/src/apps/centreon/sql/mode/countnotifications.pm +++ b/src/apps/centreon/sql/mode/countnotifications.pm @@ -28,15 +28,15 @@ use centreon::plugins::statefile; sub new { my ($class, %options) = @_; - my $self = $class->SUPER::new(package => __PACKAGE__, %options); + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); bless $self, $class; - $options{options}->add_options(arguments => - { - "warning:s" => { name => 'warning' }, - "critical:s" => { name => 'critical' }, - "centreon-storage-database:s" => { name => 'centreon_storage_database', default => 'centreon_storage' }, - }); + $options{options}->add_options(arguments => { + 'warning:s' => { name => 'warning' }, + 'critical:s' => { name => 'critical' }, + 'centreon-storage-database:s' => { name => 'centreon_storage_database', default => 'centreon_storage' } + }); + $self->{statefile_cache} = centreon::plugins::statefile->new(%options); return $self; @@ -67,19 +67,26 @@ sub execute { while ((my $row = $self->{sql}->fetchrow_hashref())) { $self->{output}->output_add(long_msg => sprintf("%d sent notifications from %s", $row->{num}, $row->{name})); $total_notifications += $row->{num}; - $self->{output}->perfdata_add(label => 'notifications_' . $row->{name}, - value => $row->{num}, - min => 0); + $self->{output}->perfdata_add( + nlabel => 'notifications.sent.count', + instances => $row->{name}, + value => $row->{num}, + min => 0 + ); } my $exit_code = $self->{perfdata}->threshold_check(value => $total_notifications, threshold => [ { label => 'critical', exit_litteral => 'critical' }, { label => 'warning', exit_litteral => 'warning' } ]); - $self->{output}->output_add(severity => $exit_code, - short_msg => sprintf("%d total sent notifications", $total_notifications)); - $self->{output}->perfdata_add(label => 'total', - value => $total_notifications, - warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning'), - critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical'), - min => 0); + $self->{output}->output_add( + severity => $exit_code, + short_msg => sprintf("%d total sent notifications", $total_notifications) + ); + $self->{output}->perfdata_add( + nlabel => 'notifications.sent.count', + value => $total_notifications, + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning'), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical'), + min => 0 + ); } sub run { @@ -93,8 +100,10 @@ sub run { $self->{statefile_cache}->write(data => $new_datas); if (!defined($old_timestamp)) { - $self->{output}->output_add(severity => 'OK', - short_msg => "Buffer creation..."); + $self->{output}->output_add( + severity => 'OK', + short_msg => "Buffer creation..." + ); } else { $self->execute(time => $old_timestamp); } diff --git a/src/apps/centreon/sql/mode/countproblems.pm b/src/apps/centreon/sql/mode/countproblems.pm index 28e0c87bb..6ab91e8e5 100644 --- a/src/apps/centreon/sql/mode/countproblems.pm +++ b/src/apps/centreon/sql/mode/countproblems.pm @@ -28,13 +28,13 @@ use centreon::plugins::statefile; sub new { my ($class, %options) = @_; - my $self = $class->SUPER::new(package => __PACKAGE__, %options); + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); bless $self, $class; $options{options}->add_options(arguments => { 'warning:s' => { name => 'warning' }, 'critical:s' => { name => 'critical' }, - 'centreon-storage-database:s' => { name => 'centreon_storage_database', default => 'centreon_storage' }, + 'centreon-storage-database:s' => { name => 'centreon_storage_database', default => 'centreon_storage' } }); $self->{statefile_cache} = centreon::plugins::statefile->new(%options); @@ -68,10 +68,10 @@ sub execute { while ((my $row = $self->{sql}->fetchrow_hashref())) { if (!defined($total_problems_by_poller->{$row->{name}})) { $total_problems_by_poller->{$row->{name}} = { - '0_1' => { label_perf => 'host_down', label => 'host down', num => 0 }, - '1_1' => { label_perf => 'service_warning', label => 'service warning', num => 0 }, - '1_2' => { label_perf => 'service_critical', label => 'service critical', num => 0 }, - '1_3' => { label_perf => 'service_unknown', label => 'service unknown', num => 0 } + '0_1' => { label_perf => 'hosts.down.count', label => 'host down', num => 0 }, + '1_1' => { label_perf => 'services.warning.count', label => 'service warning', num => 0 }, + '1_2' => { label_perf => 'services.critical.count', label => 'service critical', num => 0 }, + '1_3' => { label_perf => 'services.unknown.count', label => 'service unknown', num => 0 } }; } @@ -98,8 +98,10 @@ sub execute { $poller ) ); + $self->{output}->perfdata_add( - label => $total_problems_by_poller->{$poller}->{$id}->{label_perf} . "_" . $poller, + label => $total_problems_by_poller->{$poller}->{$id}->{label_perf}, + instances => $poller, value => $total_problems_by_poller->{$poller}->{$id}->{num}, min => 0 ); @@ -107,21 +109,25 @@ sub execute { } my $exit_code = $self->{perfdata}->threshold_check(value => $total_problems->{total}, threshold => [ { label => 'critical', exit_litteral => 'critical' }, { label => 'warning', exit_litteral => 'warning' } ]); - $self->{output}->output_add(severity => $exit_code, - short_msg => sprintf("%d total problems", $total_problems->{total})); + $self->{output}->output_add( + severity => $exit_code, + short_msg => sprintf("%d total problems", $total_problems->{total}) + ); + $self->{output}->perfdata_add( - label => 'total', + nlabel => 'total.outage.count', value => $total_problems->{total}, warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning'), critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical'), min => 0 ); $self->{output}->perfdata_add( - label => 'total_hosts', + nlabel => 'hosts.outage.count', value => $total_problems->{hosts}, - min => 0); + min => 0 + ); $self->{output}->perfdata_add( - label => 'total_services', + nlabel => 'services.outage.count', value => $total_problems->{services}, min => 0 ); @@ -137,8 +143,10 @@ sub run { $self->{statefile_cache}->write(data => $new_datas); if (!defined($old_timestamp)) { - $self->{output}->output_add(severity => 'OK', - short_msg => "Buffer creation..."); + $self->{output}->output_add( + severity => 'OK', + short_msg => "Buffer creation..." + ); } else { $self->execute(time => $old_timestamp); } diff --git a/src/apps/centreon/sql/mode/executiontime.pm b/src/apps/centreon/sql/mode/executiontime.pm new file mode 100644 index 000000000..7a37f71fd --- /dev/null +++ b/src/apps/centreon/sql/mode/executiontime.pm @@ -0,0 +1,140 @@ +# +# Copyright 2023 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package apps::centreon::sql::mode::executiontime; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub custom_value_output { + my ($self, %options) = @_; + + return sprintf( + "Service '%s' of host '%s' execution time is '%.2fs'", + $self->{result_values}->{description}, + $self->{result_values}->{name}, + $self->{result_values}->{execution_time} + ); +} + + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'global', type => 0 }, + { name => 'services', type => 1 } + ]; + + $self->{maps_counters}->{global} = [ + { label => 'count', nlabel => 'services.execution.exceed.count', set => { + key_values => [ { name => 'count' } ], + output_template => 'Number of services exceeding execution time: %s', + perfdatas => [ + { template => '%s', min => 0 } + ] + } + } + ]; + + $self->{maps_counters}->{services} = [ + { label => 'list', set => { + key_values => [ { name => 'description' }, { name => 'name' } , { name => 'execution_time' } ], + closure_custom_output => $self->can('custom_value_output'), + closure_custom_perfdata => sub { return 0; } + } + } + ]; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); + bless $self, $class; + + $options{options}->add_options(arguments => { + 'filter-poller:s' => { name => 'filter_poller' }, + 'centreon-storage-database:s' => { name => 'centreon_storage_database', default => 'centreon_storage' }, + 'execution-time:s' => { name => 'execution_time', default => '20' } + }); + + return $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + $options{sql}->connect(); + $options{sql}->query( + query => 'SELECT h.name, s.description, s.execution_time + FROM ' . $self->{option_results}->{centreon_storage_database} . '.services s, ' . $self->{option_results}->{centreon_storage_database} . '.hosts h + WHERE s.execution_time > ' . $self->{option_results}->{execution_time} . ' + AND h.enabled = 1 + AND (h.name NOT LIKE "\_Module\_%" OR h.name LIKE "\_Module\_Meta%") + AND s.enabled = 1 + AND h.host_id = s.host_id' + ); + + $self->{global}->{count} = 0; + $self->{services} = {}; + while ((my $row = $options{sql}->fetchrow_hashref())) { + if (defined($self->{option_results}->{filter_poller}) && $self->{option_results}->{filter_poller} ne '' && + $row->{poller} !~ /$self->{option_results}->{filter_poller}/) { + $self->{output}->output_add(long_msg => "skipping '" . $row->{self} . "': no matching filter.", debug => 1); + next; + } + $self->{global}->{count}++; + $self->{services}->{ $row->{name} . "-" . $row->{description} } = $row; + } +} + +1; + +__END__ + +=head1 MODE + +Check the number of services exceeding defined execution time. + +=over 8 + +=item B<--execution-time> + +Set the number of seconds which defines the +limit of execution time (default: '20'). + +=item B<--centreon-storage-database> + +Centreon storage database name (default: 'centreon_storage'). + +=item B<--filter-poller> + +Filter by poller name (regexp can be used). + +=item B<--warning-count> B<--critical-count> + +Thresholds on the number of services exceeding +defined execution time. + +=back + +=cut diff --git a/src/apps/centreon/sql/mode/partitioning.pm b/src/apps/centreon/sql/mode/partitioning.pm index 2428b7a1c..611b98074 100644 --- a/src/apps/centreon/sql/mode/partitioning.pm +++ b/src/apps/centreon/sql/mode/partitioning.pm @@ -31,13 +31,12 @@ sub new { my $self = $class->SUPER::new(package => __PACKAGE__, %options); bless $self, $class; - $options{options}->add_options(arguments => - { - "tablename:s@" => { name => 'tablename' }, - "timezone:s" => { name => 'timezone' }, - "warning:s" => { name => 'warning' }, - "critical:s" => { name => 'critical' }, - }); + $options{options}->add_options(arguments => { + "tablename:s@" => { name => 'tablename' }, + "timezone:s" => { name => 'timezone' }, + "warning:s" => { name => 'warning' }, + "critical:s" => { name => 'critical' } + }); return $self; } @@ -70,24 +69,30 @@ sub run { $self->{sql}->connect(); - $self->{output}->output_add(severity => 'OK', - short_msg => sprintf("All table partitions are up to date")); + $self->{output}->output_add( + severity => 'OK', + short_msg => sprintf("All table partitions are up to date") + ); foreach my $value (@{$self->{option_results}->{tablename}}) { next if ($value eq ''); if ($value !~ /(\S+)\.(\S+)/) { - $self->{output}->output_add(severity => 'UNKNOWN', - short_msg => sprintf("Wrong table name '%s'", $value)); + $self->{output}->output_add( + severity => 'UNKNOWN', + short_msg => sprintf("Wrong table name '%s'", $value) + ); next; } my ($database, $table) = ($1, $2); $self->{sql}->query(query => "SELECT MAX(CONVERT(PARTITION_DESCRIPTION, SIGNED INTEGER)) as lastPart FROM INFORMATION_SCHEMA.PARTITIONS WHERE TABLE_NAME='" . $table . "' AND TABLE_SCHEMA='" . $database . "' GROUP BY TABLE_NAME;"); my ($last_time) = $self->{sql}->fetchrow_array(); if (!defined($last_time)) { - $self->{output}->output_add(severity => 'UNKNOWN', - short_msg => sprintf("Couldn't get partition infos for table '%s'", $value)); + $self->{output}->output_add( + severity => 'UNKNOWN', + short_msg => sprintf("Couldn't get partition infos for table '%s'", $value) + ); next; } - + my $retention_forward_current = 0; my ($day,$month,$year) = (localtime(time))[3,4,5]; my $current_time = mktime(0, 0, 0, $day, $month, $year); @@ -99,8 +104,10 @@ sub run { $self->{output}->output_add(long_msg => sprintf("Table '%s' last partition date is %s (current retention forward in days: %s)", $value, scalar(localtime($last_time)), $retention_forward_current)); my $exit = $self->{perfdata}->threshold_check(value => $retention_forward_current, threshold => [ { label => 'critical', exit_litteral => 'critical' }, { label => 'warning', exit_litteral => 'warning' } ]); if (!$self->{output}->is_status(value => $exit, compare => 'ok', litteral => 1)) { - $self->{output}->output_add(severity => $exit, - short_msg => sprintf("Partitions for table '%s' are not up to date (current retention forward in days: %s)", $value, $retention_forward_current)); + $self->{output}->output_add( + severity => $exit, + short_msg => sprintf("Partitions for table '%s' are not up to date (current retention forward in days: %s)", $value, $retention_forward_current) + ); } }