]> git.proxmox.com Git - pve-manager.git/blob - PVE/Status/Graphite.pm
status/metrics: make MTU configurable
[pve-manager.git] / PVE / Status / Graphite.pm
1 package PVE::Status::Graphite;
2
3 use strict;
4 use warnings;
5
6 use IO::Socket::IP;
7 use Socket qw(SOL_SOCKET SO_SNDTIMEO SO_RCVTIMEO);
8
9 use PVE::Status::Plugin;
10 use PVE::JSONSchema;
11
12 # example config (/etc/pve/status.cfg)
13 #graphite:
14 # server test
15 # port 2003
16 # proto udp
17 # path proxmox.mycluster
18 # disable 0
19 #
20
21 use base('PVE::Status::Plugin');
22
23 sub type {
24 return 'graphite';
25 }
26
27 sub properties {
28 return {
29 path => {
30 type => 'string', format => 'graphite-path',
31 description => "root graphite path (ex: proxmox.mycluster.mykey)",
32 },
33 timeout => {
34 type => 'integer',
35 description => "graphite TCP socket timeout (default=1)",
36 minimum => 0,
37 default => 1,
38 optional => 1
39 },
40 proto => {
41 type => 'string',
42 enum => ['udp', 'tcp'],
43 description => "Protocol to send graphite data. TCP or UDP (default)",
44 optional => 1,
45 },
46 };
47 }
48
49 sub options {
50 return {
51 server => {},
52 port => { optional => 1 },
53 mtu => { optional => 1 },
54 proto => { optional => 1 },
55 timeout => { optional => 1 },
56 path => { optional => 1 },
57 disable => { optional => 1 },
58 };
59 }
60
61 # Plugin implementation
62 sub update_node_status {
63 my ($class, $txn, $node, $data, $ctime) = @_;
64
65 return assemble($class, $txn, $data, $ctime, "nodes.$node");
66
67 }
68
69 sub update_qemu_status {
70 my ($class, $txn, $vmid, $data, $ctime, $nodename) = @_;
71
72 return assemble($class, $txn, $data, $ctime, "qemu.$vmid");
73 }
74
75 sub update_lxc_status {
76 my ($class, $txn, $vmid, $data, $ctime, $nodename) = @_;
77
78 return assemble($class, $txn, $data, $ctime, "lxc.$vmid");
79 }
80
81 sub update_storage_status {
82 my ($class, $txn, $nodename, $storeid, $data, $ctime) = @_;
83
84 return assemble($class, $txn, $data, $ctime, "storages.$nodename.$storeid");
85 }
86
87 sub _send_batch_size {
88 my ($class, $cfg) = @_;
89 my $proto = $cfg->{proto} || 'udp';
90 if ($proto eq 'tcp') {
91 return 56000;
92 }
93 return $class->SUPER::_send_batch_size($cfg);
94 }
95
96 sub _connect {
97 my ($class, $cfg) = @_;
98
99 my $host = $cfg->{server};
100 my $port = $cfg->{port} || 2003;
101 my $proto = $cfg->{proto} || 'udp';
102 my $timeout = $cfg->{timeout} // 1;
103
104 my $carbon_socket = IO::Socket::IP->new(
105 PeerAddr => $host,
106 PeerPort => $port,
107 Proto => $proto,
108 Timeout => $timeout,
109 ) || die "couldn't create carbon socket [$host]:$port - $@\n";
110
111 if ($proto eq 'tcp') {
112 # seconds and µs
113 my $timeout_struct = pack( 'l!l!', $timeout, 0);
114 setsockopt($carbon_socket, SOL_SOCKET, SO_SNDTIMEO, $timeout_struct);
115 setsockopt($carbon_socket, SOL_SOCKET, SO_RCVTIMEO, $timeout_struct);
116 }
117
118 return $carbon_socket;
119 }
120
121 sub assemble {
122 my ($class, $txn, $data, $ctime, $object) = @_;
123
124 my $path = $txn->{cfg}->{path} // 'proxmox';
125 $path .= ".$object";
126
127 # we do not want boolean/state information to export to graphite
128 my $key_blacklist = {
129 'template' => 1,
130 'pid' => 1,
131 'agent' => 1,
132 'serial' => 1,
133 };
134
135 my $assemble_graphite_data;
136 $assemble_graphite_data = sub {
137 my ($metric, $path) = @_;
138
139 for my $key (sort keys %$metric) {
140 my $value = $metric->{$key};
141 next if !defined($value);
142
143 $key =~ s/\./-/g;
144 my $metricpath = $path . ".$key";
145
146 if (ref($value) eq 'HASH') {
147 $assemble_graphite_data->($value, $metricpath);
148 } elsif ($value =~ m/^[+-]?[0-9]*\.?[0-9]+$/ && !$key_blacklist->{$key}) {
149 $class->add_metric_data($txn, "$metricpath $value $ctime\n");
150 }
151 }
152 };
153 $assemble_graphite_data->($data, $path);
154
155 $assemble_graphite_data = undef; # avoid cyclic reference!
156 }
157
158 PVE::JSONSchema::register_format('graphite-path', \&pve_verify_graphite_path);
159 sub pve_verify_graphite_path {
160 my ($path, $noerr) = @_;
161
162 my $regex = "([a-zA-Z0-9]([a-zA-Z0-9\-]*[a-zA-Z0-9])?)";
163
164 if ($path !~ /^(${regex}\.)*${regex}$/) {
165 return undef if $noerr;
166 die "value does not look like a valid graphite path\n";
167 }
168
169 return $path;
170 }
171
172
173 1;