# # Copyright 2019 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 centreon::plugins::output; use centreon::plugins::misc; use strict; use warnings; sub new { my ($class, %options) = @_; my $self = {}; bless $self, $class; if (!defined($options{options})) { print "Class Output: Need to specify 'options' argument to load.\n"; exit 3; } $options{options}->add_options(arguments => { "explode-perfdata-max:s@" => { name => 'explode_perfdata_max' }, "range-perfdata:s" => { name => 'range_perfdata' }, "filter-perfdata:s" => { name => 'filter_perfdata' }, "change-perfdata:s@" => { name => 'change_perfdata' }, "extend-perfdata:s@" => { name => 'extend_perfdata' }, "filter-uom:s" => { name => 'filter_uom' }, "verbose" => { name => 'verbose' }, "debug" => { name => 'debug' }, "opt-exit:s" => { name => 'opt_exit', default => 'unknown' }, "output-xml" => { name => 'output_xml' }, "output-json" => { name => 'output_json' }, "output-file:s" => { name => 'output_file' }, "disco-format" => { name => 'disco_format' }, "disco-show" => { name => 'disco_show' }, }); %{$self->{option_results}} = (); $self->{option_msg} = []; $self->{is_output_xml} = 0; $self->{is_output_json} = 0; $self->{errors} = {OK => 0, WARNING => 1, CRITICAL => 2, UNKNOWN => 3, PENDING => 4}; $self->{errors_num} = {0 => 'OK', 1 => 'WARNING', 2 => 'CRITICAL', 3 => 'UNKNOWN', 4 => 'PENDING'}; $self->{myerrors} = {0 => "OK", 1 => "WARNING", 3 => "UNKNOWN", 7 => "CRITICAL"}; $self->{myerrors_mask} = {CRITICAL => 7, WARNING => 1, UNKNOWN => 3, OK => 0}; $self->{global_short_concat_outputs} = {OK => undef, WARNING => undef, CRITICAL => undef, UNKNOWN => undef, UNQUALIFIED_YET => undef}; $self->{global_short_outputs} = {OK => [], WARNING => [], CRITICAL => [], UNKNOWN => [], UNQUALIFIED_YET => []}; $self->{global_long_output} = []; $self->{perfdatas} = []; $self->{explode_perfdatas} = {}; $self->{change_perfdata} = {}; $self->{explode_perfdata_total} = 0; $self->{range_perfdata} = 0; $self->{global_status} = 0; $self->{encode_utf8_import} = 0; $self->{perlqq} = 0; $self->{disco_elements} = []; $self->{disco_entries} = []; $self->{plugin} = ''; $self->{mode} = ''; return $self; } sub check_options { my ($self, %options) = @_; # $options{option_results} = ref to options result %{$self->{option_results}} = %{$options{option_results}}; $self->{option_results}->{opt_exit} = lc($self->{option_results}->{opt_exit}); if (!$self->is_litteral_status(status => $self->{option_results}->{opt_exit})) { $self->add_option_msg(short_msg => "Unknown value '" . $self->{option_results}->{opt_exit} . "' for --opt-exit."); $self->option_exit(exit_litteral => 'unknown'); } # Go in XML Mode if ($self->is_disco_show() || $self->is_disco_format()) { # By Default XML if (!defined($self->{option_results}->{output_json})) { $self->{option_results}->{output_xml} = 1; } } if (defined($self->{option_results}->{range_perfdata})) { $self->{range_perfdata} = $self->{option_results}->{range_perfdata}; $self->{range_perfdata} = 1 if ($self->{range_perfdata} eq ''); if ($self->{range_perfdata} !~ /^[012]$/) { $self->add_option_msg(short_msg => "Wrong range-perfdata option '" . $self->{range_perfdata} . "'"); $self->option_exit(); } } if (defined($self->{option_results}->{explode_perfdata_max})) { if (${$self->{option_results}->{explode_perfdata_max}}[0] eq '') { $self->{explode_perfdata_total} = 2; } else { $self->{explode_perfdata_total} = 1; foreach (@{$self->{option_results}->{explode_perfdata_max}}) { my ($perf_match, $perf_result) = split /,/; if (!defined($perf_result)) { $self->add_option_msg(short_msg => "Wrong explode-perfdata-max option '" . $_ . "' (syntax: match,value)"); $self->option_exit(); } $self->{explode_perfdatas}->{$perf_match} = $perf_result; } } } $self->load_perfdata_extend_args(); } sub add_option_msg { my ($self, %options) = @_; # $options{short_msg} = string msg # $options{long_msg} = string msg $options{severity} = 'UNQUALIFIED_YET'; $self->output_add(%options); } sub set_status { my ($self, %options) = @_; # $options{exit_litteral} = string litteral exit # Nothing to do for 'UNQUALIFIED_YET' if (!$self->{myerrors_mask}->{uc($options{exit_litteral})}) { return ; } $self->{global_status} |= $self->{myerrors_mask}->{uc($options{exit_litteral})}; } sub output_add { my ($self, %params) = @_; my %args = ( severity => 'OK', separator => ' - ', debug => 0, short_msg => undef, long_msg => undef ); my $options = {%args, %params}; if (defined($options->{short_msg})) { chomp $options->{short_msg}; if (defined($self->{global_short_concat_outputs}->{uc($options->{severity})})) { $self->{global_short_concat_outputs}->{uc($options->{severity})} .= $options->{separator} . $options->{short_msg}; } else { $self->{global_short_concat_outputs}->{uc($options->{severity})} = $options->{short_msg}; } push @{$self->{global_short_outputs}->{uc($options->{severity})}}, $options->{short_msg}; $self->set_status(exit_litteral => $options->{severity}); } if (defined($options->{long_msg}) && ($options->{debug} == 0 || defined($self->{option_results}->{debug}))) { chomp $options->{long_msg}; push @{$self->{global_long_output}}, $options->{long_msg}; } } sub perfdata_add { my ($self, %options) = @_; my $perfdata = {label => '', value => '', unit => '', warning => '', critical => '', min => '', max => ''}; foreach (keys %options) { next if (!defined($options{$_})); $perfdata->{$_} = $options{$_}; } $perfdata->{label} =~ s/'/''/g; push @{$self->{perfdatas}}, $perfdata; } sub range_perfdata { my ($self, %options) = @_; return if ($self->{range_perfdata} == 0); if ($self->{range_perfdata} == 1) { for (my $i = 0; $i < scalar(@{$options{ranges}}); $i++) { ${${$options{ranges}}[$i]} =~ s/^(@?)-?[0\.]+:/$1/; } } else { for (my $i = 0; $i < scalar(@{$options{ranges}}); $i++) { ${${$options{ranges}}[$i]} = ''; } } } sub output_json { my ($self, %options) = @_; my $force_ignore_perfdata = (defined($options{force_ignore_perfdata}) && $options{force_ignore_perfdata} == 1) ? 1 : 0; my $force_long_output = (defined($options{force_long_output}) && $options{force_long_output} == 1) ? 1 : 0; my $json_content = {plugin => { name => $self->{plugin}, mode => $self->{mode}, exit => $options{exit_litteral}, outputs => [], perfdatas => [] } }; foreach my $code_litteral (keys %{$self->{global_short_outputs}}) { foreach (@{$self->{global_short_outputs}->{$code_litteral}}) { my ($child_output, $child_type, $child_msg, $child_exit); my $lcode_litteral = ($code_litteral eq 'UNQUALIFIED_YET' ? uc($options{exit_litteral}) : $code_litteral); push @{$json_content->{plugin}->{outputs}}, { type => 1, msg => ($options{nolabel} == 0 ? ($lcode_litteral . ': ') : '') . $_, exit => $lcode_litteral }; } } if (defined($self->{option_results}->{verbose}) || $force_long_output == 1) { foreach (@{$self->{global_long_output}}) { push @{$json_content->{plugin}->{outputs}}, { type => 2, msg => $_, }; } } if ($options{force_ignore_perfdata} == 0) { $self->change_perfdata(); foreach my $perf (@{$self->{perfdatas}}) { next if (defined($self->{option_results}->{filter_perfdata}) && $perf->{label} !~ /$self->{option_results}->{filter_perfdata}/); $self->range_perfdata(ranges => [\$perf->{warning}, \$perf->{critical}]); my %values = (); foreach my $key (keys %$perf) { $perf->{$key} = '' if (defined($self->{option_results}->{filter_uom}) && $key eq 'unit' && $perf->{$key} !~ /$self->{option_results}->{filter_uom}/); $values{$key} = $perf->{$key}; } push @{$json_content->{plugin}->{perfdatas}}, { %values }; } } print $self->{json_output}->encode($json_content); } sub output_xml { my ($self, %options) = @_; my $force_ignore_perfdata = (defined($options{force_ignore_perfdata}) && $options{force_ignore_perfdata} == 1) ? 1 : 0; my $force_long_output = (defined($options{force_long_output}) && $options{force_long_output} == 1) ? 1 : 0; my ($child_plugin_name, $child_plugin_mode, $child_plugin_exit, $child_plugin_output, $child_plugin_perfdata); my $root = $self->{xml_output}->createElement('plugin'); $self->{xml_output}->setDocumentElement($root); $child_plugin_name = $self->{xml_output}->createElement("name"); $child_plugin_name->appendText($self->{plugin}); $child_plugin_mode = $self->{xml_output}->createElement("mode"); $child_plugin_mode->appendText($self->{mode}); $child_plugin_exit = $self->{xml_output}->createElement("exit"); $child_plugin_exit->appendText($options{exit_litteral}); $child_plugin_output = $self->{xml_output}->createElement("outputs"); $child_plugin_perfdata = $self->{xml_output}->createElement("perfdatas"); $root->addChild($child_plugin_name); $root->addChild($child_plugin_mode); $root->addChild($child_plugin_exit); $root->addChild($child_plugin_output); $root->addChild($child_plugin_perfdata); foreach my $code_litteral (keys %{$self->{global_short_outputs}}) { foreach (@{$self->{global_short_outputs}->{$code_litteral}}) { my ($child_output, $child_type, $child_msg, $child_exit); my $lcode_litteral = ($code_litteral eq 'UNQUALIFIED_YET' ? uc($options{exit_litteral}) : $code_litteral); $child_output = $self->{xml_output}->createElement("output"); $child_plugin_output->addChild($child_output); $child_type = $self->{xml_output}->createElement("type"); $child_type->appendText(1); # short $child_msg = $self->{xml_output}->createElement("msg"); $child_msg->appendText(($options{nolabel} == 0 ? ($lcode_litteral . ': ') : '') . $_); $child_exit = $self->{xml_output}->createElement("exit"); $child_exit->appendText($lcode_litteral); $child_output->addChild($child_type); $child_output->addChild($child_exit); $child_output->addChild($child_msg); } } if (defined($self->{option_results}->{verbose}) || $force_long_output == 1) { foreach (@{$self->{global_long_output}}) { my ($child_output, $child_type, $child_msg); $child_output = $self->{xml_output}->createElement("output"); $child_plugin_output->addChild($child_output); $child_type = $self->{xml_output}->createElement("type"); $child_type->appendText(2); # long $child_msg = $self->{xml_output}->createElement("msg"); $child_msg->appendText($_); $child_output->addChild($child_type); $child_output->addChild($child_msg); } } if ($options{force_ignore_perfdata} == 0) { $self->change_perfdata(); foreach my $perf (@{$self->{perfdatas}}) { next if (defined($self->{option_results}->{filter_perfdata}) && $perf->{label} !~ /$self->{option_results}->{filter_perfdata}/); $self->range_perfdata(ranges => [\$perf->{warning}, \$perf->{critical}]); my ($child_perfdata); $child_perfdata = $self->{xml_output}->createElement("perfdata"); $child_plugin_perfdata->addChild($child_perfdata); foreach my $key (keys %$perf) { $perf->{$key} = '' if (defined($self->{option_results}->{filter_uom}) && $key eq 'unit' && $perf->{$key} !~ /$self->{option_results}->{filter_uom}/); my $child = $self->{xml_output}->createElement($key); $child->appendText($perf->{$key}); $child_perfdata->addChild($child); } } } print $self->{xml_output}->toString(1); } sub output_txt { my ($self, %options) = @_; my $force_ignore_perfdata = (defined($options{force_ignore_perfdata}) && $options{force_ignore_perfdata} == 1) ? 1 : 0; my $force_long_output = (defined($options{force_long_output}) && $options{force_long_output} == 1) ? 1 : 0; if (defined($self->{global_short_concat_outputs}->{UNQUALIFIED_YET})) { $self->output_add(severity => uc($options{exit_litteral}), short_msg => $self->{global_short_concat_outputs}->{UNQUALIFIED_YET}); } if (defined($self->{global_short_concat_outputs}->{CRITICAL})) { print (($options{nolabel} == 0 ? 'CRITICAL: ' : '') . $self->{global_short_concat_outputs}->{CRITICAL} . " "); } if (defined($self->{global_short_concat_outputs}->{WARNING})) { print (($options{nolabel} == 0 ? 'WARNING: ' : '') . $self->{global_short_concat_outputs}->{WARNING} . " "); } if (defined($self->{global_short_concat_outputs}->{UNKNOWN})) { print (($options{nolabel} == 0 ? 'UNKNOWN: ' : '') . $self->{global_short_concat_outputs}->{UNKNOWN} . " "); } if (uc($options{exit_litteral}) eq 'OK') { print (($options{nolabel} == 0 ? 'OK: ' : '') . (defined($self->{global_short_concat_outputs}->{OK}) ? $self->{global_short_concat_outputs}->{OK} : '') . " "); } if ($force_ignore_perfdata == 1) { print "\n"; } else { print "|"; $self->change_perfdata(); foreach my $perf (@{$self->{perfdatas}}) { next if (defined($self->{option_results}->{filter_perfdata}) && $perf->{label} !~ /$self->{option_results}->{filter_perfdata}/); $perf->{unit} = '' if (defined($self->{option_results}->{filter_uom}) && $perf->{unit} !~ /$self->{option_results}->{filter_uom}/); $self->range_perfdata(ranges => [\$perf->{warning}, \$perf->{critical}]); print " '" . $perf->{label} . "'=" . $perf->{value} . $perf->{unit} . ";" . $perf->{warning} . ";" . $perf->{critical} . ";" . $perf->{min} . ";" . $perf->{max}; } print "\n"; } if (defined($self->{option_results}->{verbose}) || $force_long_output == 1) { if (scalar(@{$self->{global_long_output}})) { print join("\n", @{$self->{global_long_output}}); print "\n"; } } } sub display { my ($self, %options) = @_; my $nolabel = defined($options{nolabel}) ? 1 : 0; my $force_ignore_perfdata = (defined($options{force_ignore_perfdata}) && $options{force_ignore_perfdata} == 1) ? 1 : 0; my $force_long_output = (defined($options{force_long_output}) && $options{force_long_output} == 1) ? 1 : 0; $force_long_output = 1 if (defined($self->{option_results}->{debug})); if (defined($self->{option_results}->{output_file})) { if (!open (STDOUT, '>', $self->{option_results}->{output_file})) { $self->output_add(severity => 'UNKNOWN', short_msg => "cannot open file '" . $self->{option_results}->{output_file} . "': $!"); } } if (defined($self->{option_results}->{output_xml})) { $self->create_xml_document(); if ($self->{is_output_xml}) { $self->output_xml(exit_litteral => $self->get_litteral_status(), nolabel => $nolabel, force_ignore_perfdata => $force_ignore_perfdata, force_long_output => $force_long_output); return ; } } elsif (defined($self->{option_results}->{output_json})) { $self->create_json_document(); if ($self->{is_output_json}) { $self->output_json(exit_litteral => $self->get_litteral_status(), nolabel => $nolabel, force_ignore_perfdata => $force_ignore_perfdata, force_long_output => $force_long_output); return ; } } $self->output_txt(exit_litteral => $self->get_litteral_status(), nolabel => $nolabel, force_ignore_perfdata => $force_ignore_perfdata, force_long_output => $force_long_output); } sub die_exit { my ($self, %options) = @_; # $options{exit_litteral} = string litteral exit # $options{nolabel} = interger label display my $exit_litteral = defined($options{exit_litteral}) ? $options{exit_litteral} : $self->{option_results}->{opt_exit}; my $nolabel = defined($options{nolabel}) ? 1 : 0; # ignore long output in the following case $self->{option_results}->{verbose} = undef; if (defined($self->{option_results}->{output_xml})) { $self->create_xml_document(); if ($self->{is_output_xml}) { $self->output_xml(exit_litteral => $exit_litteral, nolabel => $nolabel, force_ignore_perfdata => 1); $self->exit(exit_litteral => $exit_litteral); } } elsif (defined($self->{option_results}->{output_json})) { $self->create_json_document(); if ($self->{is_output_json}) { $self->output_json(exit_litteral => $exit_litteral, nolabel => $nolabel, force_ignore_perfdata => 1); $self->exit(exit_litteral => $exit_litteral); } } $self->output_txt(exit_litteral => $exit_litteral, nolabel => $nolabel, force_ignore_perfdata => 1); $self->exit(exit_litteral => $exit_litteral); } sub option_exit { my ($self, %options) = @_; # $options{exit_litteral} = string litteral exit # $options{nolabel} = interger label display my $exit_litteral = defined($options{exit_litteral}) ? $options{exit_litteral} : $self->{option_results}->{opt_exit}; my $nolabel = defined($options{nolabel}) ? 1 : 0; if (defined($self->{option_results}->{output_xml})) { $self->create_xml_document(); if ($self->{is_output_xml}) { $self->output_xml(exit_litteral => $exit_litteral, nolabel => $nolabel, force_ignore_perfdata => 1, force_long_output => 1); $self->exit(exit_litteral => $exit_litteral); } } elsif (defined($self->{option_results}->{output_json})) { $self->create_json_document(); if ($self->{is_output_json}) { $self->output_json(exit_litteral => $exit_litteral, nolabel => $nolabel, force_ignore_perfdata => 1, force_long_output => 1); $self->exit(exit_litteral => $exit_litteral); } } $self->output_txt(exit_litteral => $exit_litteral, nolabel => $nolabel, force_ignore_perfdata => 1, force_long_output => 1); $self->exit(exit_litteral => $exit_litteral); } sub exit { my ($self, %options) = @_; # $options{exit_litteral} = exit if (defined($options{exit_litteral})) { exit $self->{errors}->{uc($options{exit_litteral})}; } exit $self->{errors}->{$self->{myerrors}->{$self->{global_status}}}; } sub get_most_critical { my ($self, %options) = @_; my $current_status = 0; # For 'OK' foreach (@{$options{status}}) { if ($self->{myerrors_mask}->{uc($_)} > $current_status) { $current_status = $self->{myerrors_mask}->{uc($_)}; } } return $self->{myerrors}->{$current_status}; } sub get_litteral_status { my ($self, %options) = @_; if (defined($options{status})) { if (defined($self->{errors_num}->{$options{status}})) { return $self->{errors_num}->{$options{status}}; } return $options{status}; } else { return $self->{myerrors}->{$self->{global_status}}; } } sub is_status { my ($self, %options) = @_; # $options{value} = string status # $options{litteral} = value is litteral # $options{compare} = string status if (defined($options{litteral})) { my $value = defined($options{value}) ? $options{value} : $self->get_litteral_status(); if (uc($value) eq uc($options{compare})) { return 1; } return 0; } my $value = defined($options{value}) ? $options{value} : $self->{global_status}; my $dec_val = $self->{myerrors_mask}->{$value}; my $lresult = $value & $dec_val; # Need to manage 0 if ($lresult > 0 || ($dec_val == 0 && $value == 0)) { return 1; } return 0; } sub is_litteral_status { my ($self, %options) = @_; # $options{status} = string status if (defined($self->{errors}->{uc($options{status})})) { return 1; } return 0; } sub create_json_document { my ($self) = @_; if (centreon::plugins::misc::mymodule_load(no_quit => 1, module => 'JSON', error_msg => "Cannot load module 'JSON'.")) { print "Cannot load module 'JSON'\n"; $self->exit(exit_litteral => 'unknown'); } $self->{is_output_json} = 1; $self->{json_output} = JSON->new->utf8(); } sub create_xml_document { my ($self) = @_; if (centreon::plugins::misc::mymodule_load(no_quit => 1, module => 'XML::LibXML', error_msg => "Cannot load module 'XML::LibXML'.")) { print "Cannot load module 'XML::LibXML'\n"; $self->exit(exit_litteral => 'unknown'); } $self->{is_output_xml} = 1; $self->{xml_output} = XML::LibXML::Document->new('1.0', 'utf-8'); } sub plugin { my ($self, %options) = @_; # $options{name} = string name if (defined($options{name})) { $self->{plugin} = $options{name}; } return $self->{plugin}; } sub mode { my ($self, %options) = @_; # $options{name} = string name if (defined($options{name})) { $self->{mode} = $options{name}; } return $self->{mode}; } sub add_disco_format { my ($self, %options) = @_; push @{$self->{disco_elements}}, @{$options{elements}}; } sub display_disco_format { my ($self, %options) = @_; if (defined($self->{option_results}->{output_xml})) { $self->create_xml_document(); my $root = $self->{xml_output}->createElement('data'); $self->{xml_output}->setDocumentElement($root); foreach (@{$self->{disco_elements}}) { my $child = $self->{xml_output}->createElement("element"); $child->appendText($_); $root->addChild($child); } print $self->{xml_output}->toString(1); } elsif (defined($self->{option_results}->{output_json})) { $self->create_json_document(); my $json_content = {data => [] }; foreach (@{$self->{disco_elements}}) { push @{$json_content->{data}}, $_; } print $self->{json_output}->encode($json_content); } } sub display_disco_show { my ($self, %options) = @_; if (defined($self->{option_results}->{output_xml})) { $self->create_xml_document(); my $root = $self->{xml_output}->createElement('data'); $self->{xml_output}->setDocumentElement($root); foreach (@{$self->{disco_entries}}) { my $child = $self->{xml_output}->createElement("label"); foreach my $key (keys %$_) { $child->setAttribute($key, $_->{$key}); } $root->addChild($child); } print $self->{xml_output}->toString(1); } elsif (defined($self->{option_results}->{output_json})) { $self->create_json_document(); my $json_content = {data => [] }; foreach (@{$self->{disco_entries}}) { my %values = (); foreach my $key (keys %$_) { $values{$key} = $_->{$key}; } push @{$json_content->{data}}, {%values}; } print $self->{json_output}->encode($json_content); } } sub to_utf8 { my ($self, $value) = @_; if ($self->{encode_utf8_import} == 0) { # Some Perl version dont have the following module (like Perl 5.6.x) if (centreon::plugins::misc::mymodule_load(no_quit => 1, module => 'Encode', error_msg => "Cannot load module 'Encode'.")) { print "Cannot load module 'Encode'\n"; $self->exit(exit_litteral => 'unknown'); } $self->{encode_utf8_import} = 1; eval '$self->{perlqq} = Encode::PERLQQ'; } return centreon::plugins::misc::trim(Encode::decode('UTF-8', $value, $self->{perlqq})); } sub add_disco_entry { my ($self, %options) = @_; push @{$self->{disco_entries}}, {%options}; } sub is_disco_format { my ($self) = @_; if (defined($self->{option_results}->{disco_format})) { return 1; } return 0; } sub is_disco_show { my ($self) = @_; if (defined($self->{option_results}->{disco_show})) { return 1; } return 0; } sub parse_pfdata_scale { my ($self, %options) = @_; # --extend-perfdata=traffic_in,,scale(Mbps),mbps my $args = { unit => 'auto' }; if ($options{args} =~ /^([KMGTPEkmgtpe])?(B|b|bps|Bps|b\/s|auto)$/) { $args->{quantity} = defined($1) ? $1 : ''; $args->{unit} = $2; } elsif ($options{args} ne '') { return 1; } return (0, $args); } sub parse_pfdata_math { my ($self, %options) = @_; # --extend-perfdata=perfx,,math(current + 10 - 100, 1) my $args = { math => undef, apply_threshold => 0 }; my ($math, $apply_threshold) = split /\|/, $options{args}; if ($math =~ /^((?:[\s\.\-\+\*\/0-9\(\)]|current)+)$/) { $args->{math} = $1; } elsif ($options{args} ne '') { return 1; } if (defined($apply_threshold) && $apply_threshold =~ /^\s*(0|1)\s*$/ ) { $args->{apply_threshold} = $1; } return (0, $args); } sub apply_pfdata_scale { my ($self, %options) = @_; return if (${$options{perf}}->{unit} !~ /^([KMGTPEkmgtpe])?(B|b|bps|Bps|b\/s)$/); my ($src_quantity, $src_unit) = ($1, $2); my ($value, $dst_quantity, $dst_unit) = centreon::plugins::misc::scale_bytesbit(value => ${$options{perf}}->{value}, src_quantity => $src_quantity, src_unit => $src_unit, dst_quantity => $options{args}->{quantity}, dst_unit => $options{args}->{unit}); ${$options{perf}}->{value} = sprintf("%.2f", $value); if (defined($dst_unit)) { ${$options{perf}}->{unit} = $dst_quantity . $dst_unit; } else { ${$options{perf}}->{unit} = $options{args}->{quantity} . $options{args}->{unit}; } if (defined(${$options{perf}}->{max}) && ${$options{perf}}->{max} ne '') { ($value) = centreon::plugins::misc::scale_bytesbit(value => ${$options{perf}}->{max}, src_quantity => $src_quantity, src_unit => $src_unit, dst_quantity => defined($dst_unit) ? $dst_quantity : $options{args}->{quantity}, dst_unit => defined($dst_unit) ? $dst_unit : $options{args}->{unit}); ${$options{perf}}->{max} = sprintf("%.2f", $value); } foreach my $threshold ('warning', 'critical') { next if (${$options{perf}}->{$threshold} eq ''); my ($status, $result) = centreon::plugins::misc::parse_threshold(threshold => ${$options{perf}}->{$threshold}); next if ($status == 0); if ($result->{start} ne '' && $result->{infinite_neg} == 0) { ($result->{start}) = centreon::plugins::misc::scale_bytesbit(value => $result->{start}, src_quantity => $src_quantity, src_unit => $src_unit, dst_quantity => defined($dst_unit) ? $dst_quantity : $options{args}->{quantity}, dst_unit => defined($dst_unit) ? $dst_unit : $options{args}->{unit}); } if ($result->{end} ne '' && $result->{infinite_pos} == 0) { ($result->{end}) = centreon::plugins::misc::scale_bytesbit(value => $result->{end}, src_quantity => $src_quantity, src_unit => $src_unit, dst_quantity => defined($dst_unit) ? $dst_quantity : $options{args}->{quantity}, dst_unit => defined($dst_unit) ? $dst_unit : $options{args}->{unit}); } ${$options{perf}}->{$threshold} = centreon::plugins::misc::get_threshold_litteral(%$result); } } sub apply_pfdata_invert { my ($self, %options) = @_; return if (!defined(${$options{perf}}->{max}) || ${$options{perf}}->{max} eq ''); ${$options{perf}}->{value} = ${$options{perf}}->{max} - ${$options{perf}}->{value}; foreach my $threshold ('warning', 'critical') { next if (${$options{perf}}->{$threshold} eq ''); my ($status, $result) = centreon::plugins::misc::parse_threshold(threshold => ${$options{perf}}->{$threshold}); next if ($status == 0); my $tmp = { arobase => $result->{arobase}, infinite_pos => 0, infinite_neg => 0, start => $result->{start}, end => $result->{end} }; $tmp->{infinite_neg} = 1 if ($result->{infinite_pos} == 1); $tmp->{infinite_pos} = 1 if ($result->{infinite_neg} == 1); if ($result->{start} ne '' && $result->{infinite_neg} == 0) { $tmp->{end} = ${$options{perf}}->{max} - $result->{start}; } if ($result->{end} ne '' && $result->{infinite_pos} == 0) { $tmp->{start} = ${$options{perf}}->{max} - $result->{end}; } ${$options{perf}}->{$threshold} = centreon::plugins::misc::get_threshold_litteral(%$tmp); } } sub apply_pfdata_percent { my ($self, %options) = @_; return if (!defined(${$options{perf}}->{max}) || ${$options{perf}}->{max} eq ''); ${$options{perf}}->{value} = sprintf("%.2f", ${$options{perf}}->{value} * 100 / ${$options{perf}}->{max}); ${$options{perf}}->{unit} = '%'; foreach my $threshold ('warning', 'critical') { next if (${$options{perf}}->{$threshold} eq ''); my ($status, $result) = centreon::plugins::misc::parse_threshold(threshold => ${$options{perf}}->{$threshold}); next if ($status == 0); if ($result->{start} ne '' && $result->{infinite_neg} == 0) { $result->{start} = sprintf("%.2f", $result->{start} * 100 / ${$options{perf}}->{max}); } if ($result->{end} ne '' && $result->{infinite_pos} == 0) { $result->{end} = sprintf("%.2f", $result->{end} * 100 / ${$options{perf}}->{max}); } ${$options{perf}}->{$threshold} = centreon::plugins::misc::get_threshold_litteral(%$result); } ${$options{perf}}->{max} = 100; } sub apply_pfdata_math { my ($self, %options) = @_; my $math = $options{args}->{math}; $math =~ s/current/\$value/g; my $value = ${$options{perf}}->{value}; eval "\${\$options{perf}}->{value} = $math"; return if ($options{args}->{apply_threshold} == 0); foreach my $threshold ('warning', 'critical') { next if (${$options{perf}}->{$threshold} eq ''); my ($status, $result) = centreon::plugins::misc::parse_threshold(threshold => ${$options{perf}}->{$threshold}); next if ($status == 0); if ($result->{start} ne '' && $result->{infinite_neg} == 0) { $value = $result->{start}; eval "\$result->{start} = $math"; } if ($result->{end} ne '' && $result->{infinite_pos} == 0) { $value = $result->{end}; eval "\$result->{end} = $math"; } ${$options{perf}}->{$threshold} = centreon::plugins::misc::get_threshold_litteral(%$result); } ${$options{perf}}->{max} = 100; } sub load_perfdata_extend_args { my ($self, %options) = @_; foreach ([$self->{option_results}->{change_perfdata}, 1], [$self->{option_results}->{extend_perfdata}, 2]) { next if (!defined($_->[0])); foreach my $arg (@{$_->[0]}) { $self->parse_perfdata_extend_args(arg => $arg, type => $_->[1]); } } } sub parse_perfdata_extend_args { my ($self, %options) = @_; # --extend-perfdata=searchlabel,newlabel,method[,newuom] my ($pfdata_match, $pfdata_substitute, $method, $uom_substitute) = split /,/, $options{arg}; return if (!defined($pfdata_match) || $pfdata_match eq ''); $self->{pfdata_extends} = [] if (!defined($self->{pfdata_extends})); my $pfdata_extends = { pfdata_match => defined($pfdata_match) && $pfdata_match ne '' ? $pfdata_match : undef, pfdata_substitute => defined($pfdata_substitute) && $pfdata_substitute ne '' ? $pfdata_substitute : undef, uom_substitute => defined($uom_substitute) && $uom_substitute ne '' ? $uom_substitute : undef, type => $options{type} }; if (defined($method) && $method ne '') { if ($method !~ /^\s*(invert|percent|scale|math)\s*\(\s*(.*?)\s*\)\s*$/) { $self->output_add(long_msg => "method in argument '$options{arg}' is unknown", debug => 1); return ; } $pfdata_extends->{method_name} = $1; my $args = $2; if (my $func = $self->can('parse_pfdata_' . $pfdata_extends->{method_name})) { (my $status, $pfdata_extends->{method_args}) = $func->($self, args => $args); if ($status == 1) { $self->output_add(long_msg => "argument in method '$options{arg}' is unknown", debug => 1); return ; } } } push @{$self->{pfdata_extends}}, $pfdata_extends; } sub apply_perfdata_explode { my ($self, %options) = @_; return if ($self->{explode_perfdata_total} == 0); foreach (@{$self->{perfdatas}}) { next if ($_->{max} eq ''); if ($self->{explode_perfdata_total} == 2) { $self->perfdata_add(label => $_->{label} . '_max', value => $_->{max}); next; } foreach my $regexp (keys %{$self->{explode_perfdatas}}) { if ($_->{label} =~ /$regexp/) { $self->perfdata_add(label => $self->{explode_perfdatas}->{$regexp}, value => $_->{max}); last; } } } } sub apply_perfdata_extend { my ($self, %options) = @_; foreach my $extend (@{$self->{pfdata_extends}}) { my $new_pfdata = []; for (my $i = 0; $i < scalar(@{$self->{perfdatas}}); $i++) { next if ($self->{perfdatas}->[$i]->{label} !~ /$extend->{pfdata_match}/); my $new_perf = { %{$self->{perfdatas}->[$i]} }; if (defined($extend->{pfdata_substitute})) { eval "\$new_perf->{label} =~ s{$extend->{pfdata_match}}{$extend->{pfdata_substitute}}"; } if (defined($extend->{method_name})) { my $func = $self->can('apply_pfdata_' . $extend->{method_name}); $func->($self, perf => \$new_perf, args => $extend->{method_args}); } if (defined($extend->{uom_substitute})) { $new_perf->{unit} = $extend->{uom_substitute}; } if ($extend->{type} == 1) { $self->{perfdatas}->[$i] = $new_perf; } else { push @$new_pfdata, $new_perf; } } push @{$self->{perfdatas}}, @$new_pfdata; } } sub change_perfdata { my ($self, %options) = @_; $self->apply_perfdata_extend(); $self->apply_perfdata_explode(); } 1; __END__ =head1 NAME Output class =head1 SYNOPSIS - =head1 OUTPUT OPTIONS =over 8 =item B<--verbose> Display long output. =item B<--debug> Display also debug messages. =item B<--filter-perfdata> Filter perfdata that match the regexp. =item B<--explode-perfdata-max> Put max perfdata (if it exist) in a specific perfdata (without values: same with '_max' suffix) (Multiple options) =item B<--change-perfdata> B<--extend-perfdata> Change or extend perfdata. Syntax: --extend-perfdata=searchlabel,newlabel,target[,newuom] Common examples: =over 4 Change storage free perfdata in used: --change-perfdata=free,used,invert() Change storage free perfdata in used: --change-perfdata=used,free,invert() Scale traffic values automaticaly: --change-perfdata=traffic,,scale(auto) Scale traffic values in Mbps: --change-perfdata=traffic_in,,scale(Mbps),mbps Change traffic values in percent: --change-perfdata=traffic_in,,percent() =back =item B<--range-perfdata> Change perfdata range thresholds display: 1 = start value equals to '0' is removed, 2 = threshold range is not display. =item B<--filter-uom> Filter UOM that match the regexp. =item B<--opt-exit> Exit code for an option error, usage (default: unknown). =item B<--output-xml> Display output in XML Format. =item B<--output-json> Display output in JSON Format. =item B<--output-file> Write output in file (can be used with json and xml options) =item B<--disco-format> Display discovery arguments (if the mode manages it). =item B<--disco-show> Display discovery values (if the mode manages it). =head1 DESCRIPTION B. =cut