package PVE::ExtMetric; use strict; use warnings; use PVE::Status::Plugin; use PVE::Status::Graphite; use PVE::Status::InfluxDB; PVE::Status::Graphite->register(); PVE::Status::InfluxDB->register(); PVE::Status::Plugin->init(); sub foreach_plug($&) { my ($status_cfg, $code) = @_; for my $id (sort keys %{$status_cfg->{ids}}) { my $plugin_config = $status_cfg->{ids}->{$id}; next if $plugin_config->{disable}; my $plugin = PVE::Status::Plugin->lookup($plugin_config->{type}); $code->($plugin, $id, $plugin_config); } } sub update_all($$@) { my ($transactions, $subsystem, @params) = @_; my $method = "update_${subsystem}_status"; my (undef, $fn, $line, $subr) = caller(1); for my $txn (@$transactions) { my $plugin = PVE::Status::Plugin->lookup($txn->{cfg}->{type}); $plugin->$method($txn, @params); if (length($txn->{data}) > 48000) { # UDP stack cannot handle messages > 65k, if we've alot of data we # do smaller batch sends then, but keep the connection alive transaction_flush($txn, 1); } } } # must return a transaction hash with the format: # { # cfg => $plugin_config, # connection => ..., # the connected socket # data => '', # payload, will be sent at the trannsaction flush # } sub transactions_start { my ($cfg) = @_; my $transactions = []; foreach_plug($cfg, sub { my ($plugin, $id, $plugin_config) = @_; my $connection = $plugin->_connect($plugin_config); push @$transactions, { connection => $connection, cfg => $plugin_config, id => $id, data => '', }; }); return $transactions; } sub transaction_flush { my ($txn, $keepconnected) = @_; if (!$txn->{connection}) { return if !$txn->{data}; # OK, if data was already sent/flushed die "cannot flush metric data, no connection available!\n"; } return if !defined($txn->{data}) || $txn->{data} eq ''; my $plugin = PVE::Status::Plugin->lookup($txn->{cfg}->{type}); my $data = delete $txn->{data}; eval { $plugin->send($txn->{connection}, $data) }; my $senderr = $@; if (!$keepconnected) { $plugin->_disconnect($txn->{connection}); $txn->{connection} = undef; # avoid log spam, already got a send error; disconnect would fail too warn "disconnect failed: $@" if $@ && !$senderr; } die "metrics send error '$txn->{id}': $senderr" if $senderr; }; sub transactions_finish { my ($transactions) = @_; for my $txn (@$transactions) { eval { transaction_flush($txn) }; warn "$@" if $@; } } 1;