diff --git a/cloud/prometheus/exporters/nodeexporter/mode/cpu.pm b/cloud/prometheus/exporters/nodeexporter/mode/cpu.pm index 8417a096b..c6a4ee5bf 100644 --- a/cloud/prometheus/exporters/nodeexporter/mode/cpu.pm +++ b/cloud/prometheus/exporters/nodeexporter/mode/cpu.pm @@ -30,7 +30,7 @@ sub set_counters { $self->{maps_counters_type} = [ { name => 'nodes', type => 3, cb_prefix_output => 'prefix_nodes_output', message_multiple => 'All nodes CPU usage are ok', - counters => [ { name => 'cpu', type => 1, cb_prefix_output => 'prefix_cpu_output' } ] }, + counters => [ { name => 'cpu', type => 1, cb_prefix_output => 'prefix_cpu_output', message_multiple => 'All CPU usage are ok' } ] }, ]; $self->{maps_counters}->{nodes} = [ @@ -82,11 +82,26 @@ sub new { { "node:s" => { name => 'node', default => '.*' }, "extra-filter:s@" => { name => 'extra_filter' }, + "metric-overload:s@" => { name => 'metric_overload' }, }); return $self; } +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + $self->{metrics} = { + 'cpu' => "^node_cpu.*", + }; + + foreach my $metric (@{$self->{option_results}->{metric_overload}}) { + next if ($metric !~ /(.*),(.*)/); + $self->{metrics}->{$1} = $2 if (defined($self->{metrics}->{$1})); + } +} + sub manage_selection { my ($self, %options) = @_; @@ -98,7 +113,7 @@ sub manage_selection { $extra_filter .= ',' . $filter; } - my $results = $options{custom}->query_range(queries => [ '(1 - irate(node_cpu_seconds_total{mode="idle",instance=~"' . $self->{option_results}->{node} . + my $results = $options{custom}->query_range(queries => [ '(1 - irate({__name__=~"' . $self->{metrics}->{cpu} . '",mode="idle",instance=~"' . $self->{option_results}->{node} . '"' . $extra_filter . '}[1m])) * 100' ]); foreach my $metric (@{$results}) { @@ -132,11 +147,7 @@ Check CPU usage for nodes and each of their cores. =item B<--node> -Filter on a specific node (Must be a regexp) - -=item B<--extra-filter> - -Set a PromQL filter (Can be multiple, Example : 'name=~".*pretty.*"') +Filter on a specific node (Must be a regexp, Default: '.*') =item B<--warning-*> @@ -148,6 +159,18 @@ Can be: 'node-usage', 'cpu-usage'. Threshold critical. Can be: 'node-usage', 'cpu-usage'. +=item B<--extra-filter> + +Add a PromQL filter (Can be multiple) + +Example : --extra-filter='name=~".*pretty.*"' + +=item B<--metric-overload> + +Overload default metrics name (Can be multiple, metric can be 'cpu') + +Example : --metric-overload='metric,^my_metric_name$' + =back =cut diff --git a/cloud/prometheus/exporters/nodeexporter/mode/cpudetailed.pm b/cloud/prometheus/exporters/nodeexporter/mode/cpudetailed.pm index 4cdae3343..065a5d1bd 100644 --- a/cloud/prometheus/exporters/nodeexporter/mode/cpudetailed.pm +++ b/cloud/prometheus/exporters/nodeexporter/mode/cpudetailed.pm @@ -30,7 +30,7 @@ sub set_counters { $self->{maps_counters_type} = [ { name => 'nodes', type => 3, cb_prefix_output => 'prefix_nodes_output', message_multiple => 'All nodes CPU usage are ok', - counters => [ { name => 'cpu', type => 1, cb_prefix_output => 'prefix_cpu_output' } ] }, + counters => [ { name => 'cpu', type => 1, cb_prefix_output => 'prefix_cpu_output', message_multiple => 'All CPU usage are ok' } ] }, ]; $self->{maps_counters}->{nodes} = [ @@ -221,23 +221,37 @@ sub new { { "node:s" => { name => 'node', default => '.*' }, "extra-filter:s@" => { name => 'extra_filter' }, + "metric-overload:s@" => { name => 'metric_overload' }, }); return $self; } +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + $self->{metrics} = { + 'cpu' => "^node_cpu.*", + }; + + foreach my $metric (@{$self->{option_results}->{metric_overload}}) { + next if ($metric !~ /(.*),(.*)/); + $self->{metrics}->{$1} = $2 if (defined($self->{metrics}->{$1})); + } +} + sub manage_selection { my ($self, %options) = @_; $self->{nodes} = {}; - $self->{cpu} = {}; my $extra_filter = ''; foreach my $filter (@{$self->{option_results}->{extra_filter}}) { $extra_filter .= ',' . $filter; } - my $results = $options{custom}->query_range(queries => [ '(irate(node_cpu_seconds_total{instance=~"' . $self->{option_results}->{node} . + my $results = $options{custom}->query_range(queries => [ '(irate({__name__=~"' . $self->{metrics}->{cpu} . '",instance=~"' . $self->{option_results}->{node} . '"' . $extra_filter . '}[1m])) * 100' ]); foreach my $metric (@{$results}) { @@ -274,11 +288,7 @@ Check CPU detailed usage for nodes and each of their cores. =item B<--node> -Filter on a specific node (Must be a regexp) - -=item B<--extra-filter> - -Set a PromQL filter (Can be multiple, Example : 'name=~".*pretty.*"') +Filter on a specific node (Must be a regexp, Default: '.*') =item B<--warning-*> @@ -296,6 +306,18 @@ Can be: 'node-idle', 'node-wait', 'node-irq', 'node-nice', 'cpu-idle', 'cpu-wait', 'cpu-irq', 'cpu-nice', 'cpu-softirq', 'cpu-steal', 'cpu-system', 'cpu-user'. +=item B<--extra-filter> + +Add a PromQL filter (Can be multiple) + +Example : --extra-filter='name=~".*pretty.*"' + +=item B<--metric-overload> + +Overload default metrics name (Can be multiple, metric can be 'cpu') + +Example : --metric-overload='metric,^my_metric_name$' + =back =cut diff --git a/cloud/prometheus/exporters/nodeexporter/mode/load.pm b/cloud/prometheus/exporters/nodeexporter/mode/load.pm index 40c27f36c..e73171b87 100644 --- a/cloud/prometheus/exporters/nodeexporter/mode/load.pm +++ b/cloud/prometheus/exporters/nodeexporter/mode/load.pm @@ -34,31 +34,31 @@ sub set_counters { $self->{maps_counters}->{nodes} = [ { label => 'load1', set => { - key_values => [ { name => 'node_load1' }, { name => 'display' } ], + key_values => [ { name => 'load1' }, { name => 'display' } ], output_template => 'Load 1 minute: %.2f', output_change_bytes => 1, perfdatas => [ - { label => 'load1', value => 'node_load1_absolute', template => '%.2f', + { label => 'load1', value => 'load1_absolute', template => '%.2f', min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, ], } }, { label => 'load5', set => { - key_values => [ { name => 'node_load5' }, { name => 'display' } ], + key_values => [ { name => 'load5' }, { name => 'display' } ], output_template => 'Load 5 minutes: %.2f', output_change_bytes => 1, perfdatas => [ - { label => 'load5', value => 'node_load5_absolute', template => '%.2f', + { label => 'load5', value => 'load5_absolute', template => '%.2f', min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, ], } }, { label => 'load15', set => { - key_values => [ { name => 'node_load15' }, { name => 'display' } ], + key_values => [ { name => 'load15' }, { name => 'display' } ], output_template => 'Load 15 minutes: %.2f', output_change_bytes => 1, perfdatas => [ - { label => 'load15', value => 'node_load15_absolute', template => '%.2f', + { label => 'load15', value => 'load15_absolute', template => '%.2f', min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, ], } @@ -82,29 +82,45 @@ sub new { { "node:s" => { name => 'node', default => '.*' }, "extra-filter:s@" => { name => 'extra_filter' }, + "metric-overload:s@" => { name => 'metric_overload' }, }); return $self; } +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + $self->{metrics} = { + 'load1' => '^node_load1$', + 'load5' => '^node_load5$', + 'load15' => '^node_load15$', + }; + + foreach my $metric (@{$self->{option_results}->{metric_overload}}) { + next if ($metric !~ /(.*),(.*)/); + $self->{metrics}->{$1} = $2 if (defined($self->{metrics}->{$1})); + } +} + sub manage_selection { my ($self, %options) = @_; $self->{nodes} = {}; - $self->{cpu} = {}; my $extra_filter = ''; foreach my $filter (@{$self->{option_results}->{extra_filter}}) { $extra_filter .= ',' . $filter; } - my $results = $options{custom}->query_range(queries => [ 'node_load1{instance=~"' . $self->{option_results}->{node} . - '"' . $extra_filter . '}', - 'node_load5{instance=~"' . $self->{option_results}->{node} . - '"' . $extra_filter . '}', - 'node_load15{instance=~"' . $self->{option_results}->{node} . - '"' . $extra_filter . '}' ]); - + my $results = $options{custom}->query_range(queries => [ 'label_replace({__name__=~"' . $self->{metrics}->{load1} . '",instance=~"' . $self->{option_results}->{node} . + '"' . $extra_filter . '}, "__name__", "load1", "", "")', + 'label_replace({__name__=~"' . $self->{metrics}->{load5} . '",instance=~"' . $self->{option_results}->{node} . + '"' . $extra_filter . '}, "__name__", "load5", "", "")', + 'label_replace({__name__=~"' . $self->{metrics}->{load15} . '",instance=~"' . $self->{option_results}->{node} . + '"' . $extra_filter . '}, "__name__", "load15", "", "")' ]); + foreach my $metric (@{$results}) { my $average = $options{custom}->compute(aggregation => 'average', values => $metric->{values}); $self->{nodes}->{$metric->{metric}->{instance}}->{display} = $metric->{metric}->{instance}; @@ -129,11 +145,7 @@ Check nodes load. =item B<--node> -Filter on a specific node (Must be a regexp) - -=item B<--extra-filter> - -Set a PromQL filter (Can be multiple, Example : 'name=~".*pretty.*"') +Filter on a specific node (Must be a regexp, Default: '.*') =item B<--warning-*> @@ -145,6 +157,18 @@ Can be: 'load1', 'load5', 'load15'. Threshold critical. Can be: 'load1', 'load5', 'load15'. +=item B<--extra-filter> + +Add a PromQL filter (Can be multiple) + +Example : --extra-filter='name=~".*pretty.*"' + +=item B<--metric-overload> + +Overload default metrics name (Can be multiple, metric can be 'load1', 'load5', 'load15') + +Example : --metric-overload='metric,^my_metric_name$' + =back =cut diff --git a/cloud/prometheus/exporters/nodeexporter/mode/memory.pm b/cloud/prometheus/exporters/nodeexporter/mode/memory.pm index 4f7c16354..c9ee0251b 100644 --- a/cloud/prometheus/exporters/nodeexporter/mode/memory.pm +++ b/cloud/prometheus/exporters/nodeexporter/mode/memory.pm @@ -75,12 +75,12 @@ sub custom_usage_calc { my ($self, %options) = @_; $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; - $self->{result_values}->{total} = $options{new_datas}->{$self->{instance} . '_node_memory_MemTotal_bytes'}; - $self->{result_values}->{available} = $options{new_datas}->{$self->{instance} . '_node_memory_MemAvailable_bytes'}; - $self->{result_values}->{buffer} = $options{new_datas}->{$self->{instance} . '_node_memory_Buffers_bytes'}; - $self->{result_values}->{cached} = $options{new_datas}->{$self->{instance} . '_node_memory_Cached_bytes'}; + $self->{result_values}->{total} = $options{new_datas}->{$self->{instance} . '_total'}; + $self->{result_values}->{available} = $options{new_datas}->{$self->{instance} . '_available'}; + $self->{result_values}->{buffer} = $options{new_datas}->{$self->{instance} . '_buffer'}; + $self->{result_values}->{cached} = $options{new_datas}->{$self->{instance} . '_cached'}; $self->{result_values}->{used} = $self->{result_values}->{total} - $self->{result_values}->{available} - $self->{result_values}->{buffer} - $self->{result_values}->{cached}; - $self->{result_values}->{prct_used} = $self->{result_values}->{used} * 100 / ($self->{result_values}->{total}); + $self->{result_values}->{prct_used} = ($self->{result_values}->{total} > 0) ? $self->{result_values}->{used} * 100 / $self->{result_values}->{total} : 0; return 0; } @@ -94,8 +94,8 @@ sub set_counters { $self->{maps_counters}->{nodes} = [ { label => 'usage', set => { - key_values => [ { name => 'node_memory_MemTotal_bytes' }, { name => 'node_memory_MemAvailable_bytes' }, - { name => 'node_memory_Buffers_bytes' }, { name => 'node_memory_Cached_bytes' }, { name => 'display' } ], + key_values => [ { name => 'total' }, { name => 'available' }, + { name => 'buffer' }, { name => 'cached' }, { name => 'display' } ], closure_custom_calc => $self->can('custom_usage_calc'), closure_custom_output => $self->can('custom_usage_output'), closure_custom_perfdata => $self->can('custom_usage_perfdata'), @@ -103,21 +103,21 @@ sub set_counters { } }, { label => 'buffer', set => { - key_values => [ { name => 'node_memory_Buffers_bytes' }, { name => 'display' } ], + key_values => [ { name => 'buffer' }, { name => 'display' } ], output_template => 'Buffer: %.2f %s', output_change_bytes => 1, perfdatas => [ - { label => 'buffer', value => 'node_memory_Buffers_bytes_absolute', template => '%s', + { label => 'buffer', value => 'buffer_absolute', template => '%s', min => 0, unit => 'B', label_extra_instance => 1, instance_use => 'display_absolute' }, ], } }, { label => 'cached', set => { - key_values => [ { name => 'node_memory_Cached_bytes' }, { name => 'display' } ], + key_values => [ { name => 'cached' }, { name => 'display' } ], output_template => 'Cached: %.2f %s', output_change_bytes => 1, perfdatas => [ - { label => 'cached', value => 'node_memory_Cached_bytes_absolute', template => '%s', + { label => 'cached', value => 'cached_absolute', template => '%s', min => 0, unit => 'B', label_extra_instance => 1, instance_use => 'display_absolute' }, ], } @@ -142,6 +142,7 @@ sub new { "node:s" => { name => 'node', default => '.*' }, "extra-filter:s@" => { name => 'extra_filter' }, "units:s" => { name => 'units', default => '%' }, + "metric-overload:s@" => { name => 'metric_overload' }, }); return $self; @@ -151,6 +152,18 @@ sub check_options { my ($self, %options) = @_; $self->SUPER::check_options(%options); + $self->{metrics} = { + 'total' => "^node_memory_MemTotal.*", + 'available' => "^node_memory_MemAvailable.*", + 'cached' => "^node_memory_Cached.*", + 'buffer' => "^node_memory_Buffers.*", + }; + + foreach my $metric (@{$self->{option_results}->{metric_overload}}) { + next if ($metric !~ /(.*),(.*)/); + $self->{metrics}->{$1} = $2 if (defined($self->{metrics}->{$1})); + } + $instance_mode = $self; } @@ -164,15 +177,15 @@ sub manage_selection { $extra_filter .= ',' . $filter; } - my $results = $options{custom}->query_range(queries => [ 'node_memory_MemTotal_bytes{instance=~"' . $self->{option_results}->{node} . - '"' . $extra_filter . '}', - 'node_memory_MemAvailable_bytes{instance=~"' . $self->{option_results}->{node} . - '"' . $extra_filter . '}', - 'node_memory_Cached_bytes{instance=~"' . $self->{option_results}->{node} . - '"' . $extra_filter . '}', - 'node_memory_Buffers_bytes{instance=~"' . $self->{option_results}->{node} . - '"' . $extra_filter . '}' ]); - + my $results = $options{custom}->query_range(queries => [ 'label_replace({__name__=~"' . $self->{metrics}->{total} . '",instance=~"' . $self->{option_results}->{node} . + '"' . $extra_filter . '}, "__name__", "total", "", "")', + 'label_replace({__name__=~"' . $self->{metrics}->{available} . '",instance=~"' . $self->{option_results}->{node} . + '"' . $extra_filter . '}, "__name__", "available", "", "")', + 'label_replace({__name__=~"' . $self->{metrics}->{cached} . '",instance=~"' . $self->{option_results}->{node} . + '"' . $extra_filter . '}, "__name__", "cached", "", "")', + 'label_replace({__name__=~"' . $self->{metrics}->{buffer} . '",instance=~"' . $self->{option_results}->{node} . + '"' . $extra_filter . '}, "__name__", "buffer", "", "")' ]); + foreach my $metric (@{$results}) { my $average = $options{custom}->compute(aggregation => 'average', values => $metric->{values}); $self->{nodes}->{$metric->{metric}->{instance}}->{display} = $metric->{metric}->{instance}; @@ -197,11 +210,7 @@ Check memory usage. =item B<--node> -Filter on a specific node (Must be a regexp) - -=item B<--extra-filter> - -Set a PromQL filter (Can be multiple, Example : 'name=~".*pretty.*"') +Filter on a specific node (Must be a regexp, Default: '.*') =item B<--warning-*> @@ -213,6 +222,18 @@ Can be: 'usage', 'buffer', 'cached'. Threshold critical. Can be: 'usage', 'buffer', 'cached'. +=item B<--extra-filter> + +Add a PromQL filter (Can be multiple) + +Example : --extra-filter='name=~".*pretty.*"' + +=item B<--metric-overload> + +Overload default metrics name (Can be multiple, metric can be 'total', 'available', 'cached', 'buffer') + +Example : --metric-overload='metric,^my_metric_name$' + =back =cut diff --git a/cloud/prometheus/exporters/nodeexporter/mode/storage.pm b/cloud/prometheus/exporters/nodeexporter/mode/storage.pm index 071bd3cc9..cc562040f 100644 --- a/cloud/prometheus/exporters/nodeexporter/mode/storage.pm +++ b/cloud/prometheus/exporters/nodeexporter/mode/storage.pm @@ -84,10 +84,10 @@ sub custom_usage_calc { $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; $self->{result_values}->{multi} = $options{new_datas}->{$self->{instance} . '_multi'}; - $self->{result_values}->{total} = $options{new_datas}->{$self->{instance} . '_node_filesystem_size_bytes'}; - $self->{result_values}->{free} = $options{new_datas}->{$self->{instance} . '_node_filesystem_free_bytes'}; + $self->{result_values}->{total} = $options{new_datas}->{$self->{instance} . '_size'}; + $self->{result_values}->{free} = $options{new_datas}->{$self->{instance} . '_free'}; $self->{result_values}->{used} = $self->{result_values}->{total} - $self->{result_values}->{free}; - $self->{result_values}->{prct_used} = $self->{result_values}->{used} * 100 / ($self->{result_values}->{total}); + $self->{result_values}->{prct_used} = ($self->{result_values}->{total} > 0) ? $self->{result_values}->{used} * 100 / $self->{result_values}->{total} : 0; $self->{result_values}->{prct_free} = 100 - $self->{result_values}->{prct_used}; # limit to 100. Better output. @@ -105,12 +105,12 @@ sub set_counters { $self->{maps_counters_type} = [ { name => 'nodes', type => 3, cb_prefix_output => 'prefix_nodes_output', message_multiple => 'All nodes storages usage are ok', - counters => [ { name => 'storage', type => 1, cb_prefix_output => 'prefix_storage_output' } ] }, + counters => [ { name => 'storage', type => 1, cb_prefix_output => 'prefix_storage_output', message_multiple => 'All storages usage are ok' } ] }, ]; $self->{maps_counters}->{storage} = [ { label => 'usage', set => { - key_values => [ { name => 'node_filesystem_free_bytes' }, { name => 'node_filesystem_size_bytes' }, { name => 'multi' }, { name => 'display' } ], + key_values => [ { name => 'free' }, { name => 'size' }, { name => 'multi' }, { name => 'display' } ], closure_custom_calc => $self->can('custom_usage_calc'), closure_custom_output => $self->can('custom_usage_output'), closure_custom_perfdata => $self->can('custom_usage_perfdata'), @@ -146,6 +146,7 @@ sub new { "extra-filter:s@" => { name => 'extra_filter' }, "units:s" => { name => 'units', default => '%' }, "free" => { name => 'free' }, + "metric-overload:s@" => { name => 'metric_overload' }, }); return $self; @@ -154,7 +155,17 @@ sub new { sub check_options { my ($self, %options) = @_; $self->SUPER::check_options(%options); + + $self->{metrics} = { + 'free' => "^node_filesystem_free.*", + 'size' => "^node_filesystem_size.*", + }; + foreach my $metric (@{$self->{option_results}->{metric_overload}}) { + next if ($metric !~ /(.*),(.*)/); + $self->{metrics}->{$1} = $2 if (defined($self->{metrics}->{$1})); + } + $instance_mode = $self; } @@ -162,21 +173,20 @@ sub manage_selection { my ($self, %options) = @_; $self->{nodes} = {}; - $self->{cpu} = {}; my $extra_filter = ''; foreach my $filter (@{$self->{option_results}->{extra_filter}}) { $extra_filter .= ',' . $filter; } - my $results = $options{custom}->query(queries => [ 'node_filesystem_free_bytes{instance=~"' . $self->{option_results}->{node} . + my $results = $options{custom}->query(queries => [ 'label_replace({__name__=~"' . $self->{metrics}->{free} . '",instance=~"' . $self->{option_results}->{node} . '",mountpoint=~"' . $self->{option_results}->{storage} . '",fstype!~"' . $self->{option_results}->{exclude_storage_type} . - '"' . $extra_filter . '}', - 'node_filesystem_size_bytes{instance=~".*' . $self->{option_results}->{node} . + '"' . $extra_filter . '}, "__name__", "free", "", "")', + 'label_replace({__name__=~"' . $self->{metrics}->{size} . '",instance=~"' . $self->{option_results}->{node} . '",mountpoint=~"' . $self->{option_results}->{storage} . '",fstype!~"' . $self->{option_results}->{exclude_storage_type} . - '"' . $extra_filter . '}' ]); + '"' . $extra_filter . '}, "__name__", "size", "", "")' ]); foreach my $metric (@{$results}) { $self->{nodes}->{$metric->{metric}->{instance}}->{display} = $metric->{metric}->{instance}; @@ -203,20 +213,16 @@ Check CPU usage for nodes and each of their cores. =item B<--node> -Filter on a specific node (Must be a regexp) +Filter on a specific node (Must be a regexp, Default: '.*') =item B<--storage> -Filter on a specific storage (Must be a regexp) +Filter on a specific storage (Must be a regexp, Default: '.*') =item B<--exclude-storage-type> Exclude storage types (Must be a regexp, Default: 'rootfs|tmpfs') -=item B<--extra-filter> - -Set a PromQL filter (Can be multiple, Example : 'name=~".*pretty.*"') - =item B<--units> Units of thresholds (Default: '%') ('%', 'B'). @@ -233,6 +239,18 @@ Threshold warning. Threshold critical. +=item B<--extra-filter> + +Add a PromQL filter (Can be multiple) + +Example : --extra-filter='name=~".*pretty.*"' + +=item B<--metric-overload> + +Overload default metrics name (Can be multiple, metric can be 'free', 'size') + +Example : --metric-overload='metric,^my_metric_name$' + =back =cut diff --git a/cloud/prometheus/restapi/custom/api.pm b/cloud/prometheus/restapi/custom/api.pm index effb3bd27..c802dfae2 100644 --- a/cloud/prometheus/restapi/custom/api.pm +++ b/cloud/prometheus/restapi/custom/api.pm @@ -176,6 +176,8 @@ sub query_range { my $uri = URI::Encode->new({encode_reserved => 1}); foreach my $query (@{$options{queries}}) { + $self->{output}->output_add(long_msg => sprintf("Query range: '/query_range?query=%s&start=%s&end=%s&step=%s'", + $query, $start_time, $end_time, $self->{step}), debug => 1); my $result = $self->get_endpoint(url_path => '/query_range?query=' . $uri->encode($query) . '&start=' . $start_time . '&end=' . $end_time . '&step=' . $self->{step}); push @{$data}, @{$result->{result}}; @@ -191,6 +193,7 @@ sub query { my $uri = URI::Encode->new({encode_reserved => 1}); foreach my $query (@{$options{queries}}) { + $self->{output}->output_add(long_msg => sprintf("Query: '/query?query=%s'", $query), debug => 1); my $result = $self->get_endpoint(url_path => '/query?query=' . $uri->encode($query)); push @{$data}, @{$result->{result}}; }