mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2024-12-27 07:02:11 +00:00
[MAJOR] proto_uxst rework -> SNMP support
Currently there is a ~16KB limit for a data size passed via unix socket. It is caused by a trivial bug ttat is going to fixed soon, however in most cases there is no need to dump a full stats. This patch makes possible to select a scope of dumped data by extending current "show stat" to "show stat [<iid> <type> <sid>]": - iid is a proxy id, -1 to dump all proxies - type selects type of dumpable objects: 1 for frontend, 2 for backend, 4 for server, -1 for all types. Values can be ORed, for example: 1+2=3 -> frontend+backend. 1+2+4=7 -> frontend+backend+server. - sid is a service id, -1 to dump everything from the selected proxy. To do this I implemented a new session flag (SN_STAT_BOUND), added three variables in data_ctx.stats (iid, type, sid), modified dumpstats.c and completely revorked the process_uxst_stats: now it waits for a "\n" terminated string, splits args and uses them. BTW: It should be quite easy to add new commands, for example to enable/disable servers, the only problem I can see is a not very lucky config name (*stats* socket). :| During the work I also fixed two bug: - s->flags were not initialized for proto_uxst - missing comma if throttling not enabled (caused by a stupid change in "Implement persistent id for proxies and servers") Other changes: - No more magic type valuse, use STATS_TYPE_FE/STATS_TYPE_BE/STATS_TYPE_SV - Don't memset full s->data_ctx (it was clearing s->data_ctx.stats.{iid/type/sid}, instead initialize stats.sv & stats.sv_st (stats.px and stats.px_st were already initialized) With all that changes it was extremely easy to write a short perl plugin for a perl-enabled net-snmp (also included in this patch). 29385 is my PEN (Private Enterprise Number) and I'm willing to donate the SNMPv2-SMI::enterprises.29385.106.* OIDs for HAProxy if there is nothing assigned already.
This commit is contained in:
parent
5a329cf017
commit
2c6962c3c0
111
contrib/netsnmp-perl/README
Normal file
111
contrib/netsnmp-perl/README
Normal file
@ -0,0 +1,111 @@
|
||||
SNMP support for HAProxy
|
||||
Copyright 2007-2008 Krzysztof Piotr Oledzki <ole@ans.pl>
|
||||
|
||||
Root OID: 1.3.6.1.4.1.29385.106
|
||||
|
||||
Files:
|
||||
- README: this file
|
||||
- haproxy.pl: Net-SNMP embedded perl module
|
||||
- haproxy_backend.xml: Cacti snmp-query definition for backends
|
||||
- haproxy_frontend.xml: Cacti snmp-query definition for frontends
|
||||
|
||||
Install:
|
||||
cp haproxy.pl /etc/snmp/
|
||||
grep -q "disablePerl false" /etc/snmp/snmpd.conf || echo "disablePerl false" >> /etc/snmp/snmpd.conf
|
||||
echo "perl do '/etc/snmp/haproxy.pl';" >> /etc/snmp/snmpd.conf
|
||||
|
||||
Supported commands:
|
||||
- GET (snmpget, snmpbulkget): quite fast.
|
||||
- GETNEXT (snmpwalk, snmpbulkwalk): not so fast as requires to transfer
|
||||
and parse a lot of data during each step. Always use "get" instead of "walk"
|
||||
if that's possible.
|
||||
|
||||
Supported OIDs:
|
||||
- 1.3.6.1.4.1.29385.106.1: get a variable from stats
|
||||
Usage: 1.3.6.1.4.1.29385.106.1.$type.$field.$iid.$sid
|
||||
|
||||
- type is one of:
|
||||
0) frontend
|
||||
1) backend
|
||||
2) server
|
||||
|
||||
- field is one of:
|
||||
0..32) CSV format variable
|
||||
10001) index
|
||||
10002) unique name
|
||||
|
||||
- iid is a proxy id
|
||||
|
||||
- sid is a service id (sid): 0 for frontends and backends, >= 1 for servers
|
||||
|
||||
- 1.3.6.1.4.1.29385.106.2: get a variable from info
|
||||
Usage: 1.3.6.1.4.1.29385.106.2.$req.$varnr
|
||||
|
||||
- req is one of:
|
||||
0) get variable name
|
||||
1) gat variable value
|
||||
|
||||
Examples:
|
||||
|
||||
- Get a list of frontends (type: 0) with status (field: 17):
|
||||
$ snmpbulkwalk -c public -v2c 192.168.0.1 1.3.6.1.4.1.29385.106.1.0.17
|
||||
SNMPv2-SMI::enterprises.29385.106.1.0.17.1.0 = STRING: "OPEN"
|
||||
SNMPv2-SMI::enterprises.29385.106.1.0.17.47.0 = STRING: "OPEN"
|
||||
|
||||
- Get a list of backends (type: 1) with index (field: 10001):
|
||||
$ snmpbulkwalk -c public -v2c 192.168.0.1 1.3.6.1.4.1.29385.106.1.1.10001
|
||||
SNMPv2-SMI::enterprises.29385.106.1.1.10001.1.0 = STRING: "1.0"
|
||||
SNMPv2-SMI::enterprises.29385.106.1.1.10001.1100.0 = STRING: "1100.0"
|
||||
SNMPv2-SMI::enterprises.29385.106.1.1.10001.1101.0 = STRING: "1101.0"
|
||||
SNMPv2-SMI::enterprises.29385.106.1.1.10001.1200.0 = STRING: "1200.0"
|
||||
SNMPv2-SMI::enterprises.29385.106.1.1.10001.1201.0 = STRING: "1201.0"
|
||||
SNMPv2-SMI::enterprises.29385.106.1.1.10001.1300.0 = STRING: "1300.0"
|
||||
SNMPv2-SMI::enterprises.29385.106.1.1.10001.1400.0 = STRING: "1400.0"
|
||||
SNMPv2-SMI::enterprises.29385.106.1.1.10001.1401.0 = STRING: "1401.0"
|
||||
SNMPv2-SMI::enterprises.29385.106.1.1.10001.1500.0 = STRING: "1500.0"
|
||||
(...)
|
||||
|
||||
- Get a list of servers (type: 2) with unique name (field: 10002):
|
||||
$ snmpbulkwalk -c public -v2c 192.168.0.1 1.3.6.1.4.1.29385.106.1.2.10002
|
||||
SNMPv2-SMI::enterprises.29385.106.1.2.10002.1100.1001 = STRING: "backend1/s2"
|
||||
SNMPv2-SMI::enterprises.29385.106.1.2.10002.1100.1002 = STRING: "backend1/s5"
|
||||
SNMPv2-SMI::enterprises.29385.106.1.2.10002.1100.1003 = STRING: "backend1/s6"
|
||||
SNMPv2-SMI::enterprises.29385.106.1.2.10002.1100.1012 = STRING: "backend1/s7"
|
||||
SNMPv2-SMI::enterprises.29385.106.1.2.10002.1101.1001 = STRING: "backend2/s9"
|
||||
SNMPv2-SMI::enterprises.29385.106.1.2.10002.1101.1002 = STRING: "backend2/s10"
|
||||
SNMPv2-SMI::enterprises.29385.106.1.2.10002.1101.1003 = STRING: "backend2/s11"
|
||||
SNMPv2-SMI::enterprises.29385.106.1.2.10002.1101.1012 = STRING: "backend2/s12"
|
||||
SNMPv2-SMI::enterprises.29385.106.1.2.10002.1200.1001 = STRING: "backend3/s8"
|
||||
(...)
|
||||
|
||||
- Get a list of servers (type: 2) with weight (field: 18) in proxy 4300:
|
||||
$ snmpbulkwalk -c public -v2c 192.168.0.1 1.3.6.1.4.1.29385.106.1.2.18.4300
|
||||
SNMPv2-SMI::enterprises.29385.106.1.2.18.4300.1001 = STRING: "40"
|
||||
SNMPv2-SMI::enterprises.29385.106.1.2.18.4300.1002 = STRING: "25"
|
||||
SNMPv2-SMI::enterprises.29385.106.1.2.18.4300.1003 = STRING: "40"
|
||||
SNMPv2-SMI::enterprises.29385.106.1.2.18.4300.1012 = STRING: "80"
|
||||
|
||||
- Get total sessions count (field: 7) in frontend (type: 1), sid.iid: 47.0 (proxy #47):
|
||||
snmpget -c public -v2c 192.168.0.1 enterprises.29385.106.1.0.7.47.0
|
||||
SNMPv2-SMI::enterprises.29385.106.1.0.7.47.0 = STRING: "1014019"
|
||||
|
||||
- Get a list of available variables (req: 0):
|
||||
$ snmpbulkwalk -c public -v2c 192.168.0.1 1.3.6.1.4.1.29385.106.2.0
|
||||
SNMPv2-SMI::enterprises.29385.106.2.0.0 = STRING: "Name"
|
||||
SNMPv2-SMI::enterprises.29385.106.2.0.1 = STRING: "Version"
|
||||
SNMPv2-SMI::enterprises.29385.106.2.0.2 = STRING: "Release_date"
|
||||
SNMPv2-SMI::enterprises.29385.106.2.0.3 = STRING: "Nbproc"
|
||||
SNMPv2-SMI::enterprises.29385.106.2.0.4 = STRING: "Process_num"
|
||||
SNMPv2-SMI::enterprises.29385.106.2.0.5 = STRING: "Pid"
|
||||
SNMPv2-SMI::enterprises.29385.106.2.0.6 = STRING: "Uptime"
|
||||
SNMPv2-SMI::enterprises.29385.106.2.0.7 = STRING: "Uptime_sec"
|
||||
SNMPv2-SMI::enterprises.29385.106.2.0.8 = STRING: "Memmax_MB"
|
||||
SNMPv2-SMI::enterprises.29385.106.2.0.9 = STRING: "Ulimit-n"
|
||||
SNMPv2-SMI::enterprises.29385.106.2.0.10 = STRING: "Maxsock"
|
||||
SNMPv2-SMI::enterprises.29385.106.2.0.11 = STRING: "Maxconn"
|
||||
SNMPv2-SMI::enterprises.29385.106.2.0.12 = STRING: "CurrConns"
|
||||
|
||||
- Get a variable (req: 1), varnr: 7 (Uptime_sec):
|
||||
$ snmpget -c public -v2c 192.168.0.1 1.3.6.1.4.1.29385.106.2.1.7
|
||||
SNMPv2-SMI::enterprises.29385.106.2.1.7 = STRING: "18761"
|
||||
|
242
contrib/netsnmp-perl/haproxy.pl
Normal file
242
contrib/netsnmp-perl/haproxy.pl
Normal file
@ -0,0 +1,242 @@
|
||||
#
|
||||
# Net-SNMP perl plugin for Haproxy
|
||||
# Version 0.27
|
||||
#
|
||||
# Copyright 2007-2008 Krzysztof Piotr Oledzki <ole@ans.pl>
|
||||
#
|
||||
# 1. get a variable from stat:
|
||||
# 1.3.6.1.4.1.29385.106.1.$type.$field.$iid.$sid
|
||||
# type: 0->frontend, 1->backend, 2->server
|
||||
#
|
||||
# 2. get a variable from info
|
||||
# 1.3.6.1.4.1.29385.106.2.$req.$varnr
|
||||
#
|
||||
# TODO:
|
||||
# - implement read timeout
|
||||
#
|
||||
|
||||
use NetSNMP::agent (':all');
|
||||
use NetSNMP::ASN qw(:all);
|
||||
use IO::Socket::UNIX;
|
||||
|
||||
use strict;
|
||||
|
||||
my $agent = new NetSNMP::agent('Name' => 'Haproxy');
|
||||
my $sa = "/var/run/haproxy.stat";
|
||||
|
||||
use constant OID_HAPROXY => '1.3.6.1.4.1.29385.106';
|
||||
use constant OID_HAPROXY_STATS => OID_HAPROXY . '.1';
|
||||
use constant OID_HAPROXY_INFO => OID_HAPROXY . '.2';
|
||||
|
||||
my $oid_stat = new NetSNMP::OID(OID_HAPROXY_STATS);
|
||||
my $oid_info = new NetSNMP::OID(OID_HAPROXY_INFO);
|
||||
|
||||
use constant STATS_PXNAME => 0;
|
||||
use constant STATS_SVNAME => 1;
|
||||
use constant STATS_IID => 27;
|
||||
use constant STATS_SID => 28;
|
||||
use constant STATS_TYPE => 32;
|
||||
|
||||
use constant FIELD_INDEX => 10001;
|
||||
use constant FIELD_NAME => 10002;
|
||||
|
||||
my %info_vars = (
|
||||
0 => 'Name',
|
||||
1 => 'Version',
|
||||
2 => 'Release_date',
|
||||
3 => 'Nbproc',
|
||||
4 => 'Process_num',
|
||||
5 => 'Pid',
|
||||
6 => 'Uptime',
|
||||
7 => 'Uptime_sec',
|
||||
8 => 'Memmax_MB',
|
||||
9 => 'Ulimit-n',
|
||||
10 => 'Maxsock',
|
||||
11 => 'Maxconn',
|
||||
12 => 'CurrConns',
|
||||
);
|
||||
|
||||
sub find_next_stat_id {
|
||||
my($type, $field, $proxyid, $sid) = @_;
|
||||
|
||||
my $obj = 1 << $type;
|
||||
|
||||
my $np = -1;
|
||||
my $nl = -1;
|
||||
|
||||
my $sock = new IO::Socket::UNIX (Peer => $sa, Type => SOCK_STREAM, Timeout => 1);
|
||||
next if !$sock;
|
||||
|
||||
print $sock "show stat -1 $obj -1\n";
|
||||
|
||||
while(<$sock>) {
|
||||
chomp;
|
||||
my @d = split(',');
|
||||
|
||||
last if !$d[$field] && $field != FIELD_INDEX && $field != FIELD_NAME && /^#/;
|
||||
next if /^#/;
|
||||
|
||||
next if $d[STATS_TYPE] != $type;
|
||||
|
||||
next if ($d[STATS_IID] < $proxyid) || ($d[STATS_IID] == $proxyid && $d[STATS_SID] <= $sid);
|
||||
|
||||
if ($np == -1 || $d[STATS_IID] < $np || ($d[STATS_IID] == $np && $d[STATS_SID] < $nl)) {
|
||||
$np = $d[STATS_IID];
|
||||
$nl = $d[STATS_SID];
|
||||
next;
|
||||
}
|
||||
}
|
||||
|
||||
close($sock);
|
||||
|
||||
return 0 if ($np == -1);
|
||||
|
||||
return "$type.$field.$np.$nl"
|
||||
}
|
||||
|
||||
sub haproxy_stat {
|
||||
my($handler, $registration_info, $request_info, $requests) = @_;
|
||||
|
||||
for(my $request = $requests; $request; $request = $request->next()) {
|
||||
my $oid = $request->getOID();
|
||||
|
||||
$oid =~ s/$oid_stat//;
|
||||
$oid =~ s/^\.//;
|
||||
|
||||
my $mode = $request_info->getMode();
|
||||
|
||||
my($type, $field, $proxyid, $sid, $or) = split('\.', $oid, 5);
|
||||
|
||||
next if $type > 2 || defined($or);
|
||||
|
||||
if ($mode == MODE_GETNEXT) {
|
||||
|
||||
$type = 0 if !$type;
|
||||
$field = 0 if !$field;
|
||||
$proxyid = 0 if !$proxyid;
|
||||
$sid = 0 if !$sid;
|
||||
|
||||
my $nextid = find_next_stat_id($type, $field, $proxyid, $sid);
|
||||
$nextid = find_next_stat_id($type, $field+1, 0, 0) if !$nextid;
|
||||
$nextid = find_next_stat_id($type+1, 0, 0, 0) if !$nextid;
|
||||
|
||||
if ($nextid) {
|
||||
($type, $field, $proxyid, $sid) = split('\.', $nextid);
|
||||
$request->setOID(sprintf("%s.%s", OID_HAPROXY_STATS, $nextid));
|
||||
$mode = MODE_GET;
|
||||
}
|
||||
}
|
||||
|
||||
if ($mode == MODE_GET) {
|
||||
next if !defined($proxyid) || !defined($type) || !defined($sid) || !defined($field);
|
||||
|
||||
my $obj = 1 << $type;
|
||||
|
||||
my $sock = new IO::Socket::UNIX (Peer => $sa, Type => SOCK_STREAM, Timeout => 1);
|
||||
next if !$sock;
|
||||
|
||||
print $sock "show stat $proxyid $obj $sid\n";
|
||||
|
||||
while(<$sock>) {
|
||||
chomp;
|
||||
my @data = split(',');
|
||||
|
||||
last if !defined($data[$field]) && $field != FIELD_INDEX && $field != FIELD_NAME;
|
||||
|
||||
if ($proxyid) {
|
||||
next if $data[STATS_IID] ne $proxyid;
|
||||
next if $data[STATS_SID] ne $sid;
|
||||
next if $data[STATS_TYPE] ne $type;
|
||||
}
|
||||
|
||||
if ($field == FIELD_INDEX) {
|
||||
$request->setValue(ASN_OCTET_STR,
|
||||
sprintf("%s.%s", $data[STATS_IID],
|
||||
$data[STATS_SID]));
|
||||
} elsif ($field == FIELD_NAME) {
|
||||
$request->setValue(ASN_OCTET_STR,
|
||||
sprintf("%s/%s", $data[STATS_PXNAME],
|
||||
$data[STATS_SVNAME]));
|
||||
} else {
|
||||
$request->setValue(ASN_OCTET_STR, $data[$field]);
|
||||
}
|
||||
|
||||
close($sock);
|
||||
last;
|
||||
}
|
||||
|
||||
close($sock);
|
||||
next;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
sub haproxy_info {
|
||||
my($handler, $registration_info, $request_info, $requests) = @_;
|
||||
|
||||
for(my $request = $requests; $request; $request = $request->next()) {
|
||||
my $oid = $request->getOID();
|
||||
|
||||
$oid =~ s/$oid_info//;
|
||||
$oid =~ s/^\.//;
|
||||
|
||||
my $mode = $request_info->getMode();
|
||||
|
||||
my($req, $nr, $or) = split('\.', $oid, 3);
|
||||
|
||||
next if $req >= 2 || defined($or);
|
||||
|
||||
if ($mode == MODE_GETNEXT) {
|
||||
$req = 0 if !defined($req);
|
||||
$nr = -1 if !defined($nr);
|
||||
|
||||
if (!defined($info_vars{$nr+1})) {
|
||||
$req++;
|
||||
$nr = -1;
|
||||
}
|
||||
|
||||
next if $req >= 2;
|
||||
|
||||
$request->setOID(sprintf("%s.%s.%s", OID_HAPROXY_INFO, $req, ++$nr));
|
||||
$mode = MODE_GET;
|
||||
|
||||
}
|
||||
|
||||
if ($mode == MODE_GET) {
|
||||
|
||||
next if !defined($req) || !defined($nr);
|
||||
|
||||
if ($req == 0) {
|
||||
next if !defined($info_vars{$nr});
|
||||
$request->setValue(ASN_OCTET_STR, $info_vars{$nr});
|
||||
next;
|
||||
}
|
||||
|
||||
if ($req == 1) {
|
||||
next if !defined($info_vars{$nr});
|
||||
|
||||
my $sock = new IO::Socket::UNIX (Peer => $sa, Type => SOCK_STREAM, Timeout => 1);
|
||||
next if !$sock;
|
||||
|
||||
print $sock "show info\n";
|
||||
|
||||
while(<$sock>) {
|
||||
chomp;
|
||||
my ($key, $val) = /(.*):\s*(.*)/;
|
||||
|
||||
next if $info_vars{$nr} ne $key;
|
||||
|
||||
$request->setValue(ASN_OCTET_STR, $val);
|
||||
last;
|
||||
}
|
||||
|
||||
close($sock);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$agent->register('Haproxy stat', OID_HAPROXY_STATS, \&haproxy_stat);
|
||||
$agent->register('Haproxy info', OID_HAPROXY_INFO, \&haproxy_info);
|
||||
|
62
contrib/netsnmp-perl/haproxy_backend.xml
Normal file
62
contrib/netsnmp-perl/haproxy_backend.xml
Normal file
@ -0,0 +1,62 @@
|
||||
<interface>
|
||||
<name>Haproxy - backend</name>
|
||||
<oid_index>.1.3.6.1.4.1.29385.106.1.1.10001</oid_index>
|
||||
<fields>
|
||||
<beIID>
|
||||
<name>Proxy ID</name>
|
||||
<method>get</method>
|
||||
<source>value</source>
|
||||
<direction>input</direction>
|
||||
<oid>.1.3.6.1.4.1.29385.106.1.1.27</oid>
|
||||
</beIID>
|
||||
<beSID>
|
||||
<name>Service ID</name>
|
||||
<method>get</method>
|
||||
<source>value</source>
|
||||
<direction>input</direction>
|
||||
<oid>.1.3.6.1.4.1.29385.106.1.1.28</oid>
|
||||
</beSID>
|
||||
<bePxName>
|
||||
<name>Proxy Name</name>
|
||||
<method>get</method>
|
||||
<source>value</source>
|
||||
<direction>input</direction>
|
||||
<oid>.1.3.6.1.4.1.29385.106.1.1.0</oid>
|
||||
</bePxName>
|
||||
<beSvName>
|
||||
<name>Service Name</name>
|
||||
<method>get</method>
|
||||
<source>value</source>
|
||||
<direction>input</direction>
|
||||
<oid>.1.3.6.1.4.1.29385.106.1.1.1</oid>
|
||||
</beSvName>
|
||||
<beSTot>
|
||||
<name>Total Sessions</name>
|
||||
<method>get</method>
|
||||
<source>value</source>
|
||||
<direction>output</direction>
|
||||
<oid>.1.3.6.1.4.1.29385.106.1.1.7</oid>
|
||||
</beSTot>
|
||||
<beEResp>
|
||||
<name>Response Errors</name>
|
||||
<method>get</method>
|
||||
<source>value</source>
|
||||
<direction>output</direction>
|
||||
<oid>.1.3.6.1.4.1.29385.106.1.1.14</oid>
|
||||
</beEResp>
|
||||
<beBIn>
|
||||
<name>Bytes In</name>
|
||||
<method>get</method>
|
||||
<source>value</source>
|
||||
<direction>output</direction>
|
||||
<oid>.1.3.6.1.4.1.29385.106.1.1.8</oid>
|
||||
</beBIn>
|
||||
<beBOut>
|
||||
<name>Bytes Out</name>
|
||||
<method>get</method>
|
||||
<source>value</source>
|
||||
<direction>output</direction>
|
||||
<oid>.1.3.6.1.4.1.29385.106.1.1.9</oid>
|
||||
</beBOut>
|
||||
</fields>
|
||||
</interface>
|
62
contrib/netsnmp-perl/haproxy_frontend.xml
Normal file
62
contrib/netsnmp-perl/haproxy_frontend.xml
Normal file
@ -0,0 +1,62 @@
|
||||
<interface>
|
||||
<name>Haproxy - frontend</name>
|
||||
<oid_index>.1.3.6.1.4.1.29385.106.1.0.10001</oid_index>
|
||||
<fields>
|
||||
<feIID>
|
||||
<name>Proxy ID</name>
|
||||
<method>get</method>
|
||||
<source>value</source>
|
||||
<direction>input</direction>
|
||||
<oid>.1.3.6.1.4.1.29385.106.1.0.27</oid>
|
||||
</feIID>
|
||||
<feSID>
|
||||
<name>Service ID</name>
|
||||
<method>get</method>
|
||||
<source>value</source>
|
||||
<direction>input</direction>
|
||||
<oid>.1.3.6.1.4.1.29385.106.1.0.28</oid>
|
||||
</feSID>
|
||||
<fePxName>
|
||||
<name>Proxy Name</name>
|
||||
<method>get</method>
|
||||
<source>value</source>
|
||||
<direction>input</direction>
|
||||
<oid>.1.3.6.1.4.1.29385.106.1.0.0</oid>
|
||||
</fePxName>
|
||||
<feSvName>
|
||||
<name>Service Name</name>
|
||||
<method>get</method>
|
||||
<source>value</source>
|
||||
<direction>input</direction>
|
||||
<oid>.1.3.6.1.4.1.29385.106.1.0.1</oid>
|
||||
</feSvName>
|
||||
<feSTot>
|
||||
<name>Total Sessions</name>
|
||||
<method>get</method>
|
||||
<source>value</source>
|
||||
<direction>output</direction>
|
||||
<oid>.1.3.6.1.4.1.29385.106.1.0.7</oid>
|
||||
</feSTot>
|
||||
<feEReq>
|
||||
<name>Request Errors</name>
|
||||
<method>get</method>
|
||||
<source>value</source>
|
||||
<direction>output</direction>
|
||||
<oid>.1.3.6.1.4.1.29385.106.1.0.12</oid>
|
||||
</feEReq>
|
||||
<feBIn>
|
||||
<name>Bytes In</name>
|
||||
<method>get</method>
|
||||
<source>value</source>
|
||||
<direction>output</direction>
|
||||
<oid>.1.3.6.1.4.1.29385.106.1.0.8</oid>
|
||||
</feBIn>
|
||||
<feBOut>
|
||||
<name>Bytes Out</name>
|
||||
<method>get</method>
|
||||
<source>value</source>
|
||||
<direction>output</direction>
|
||||
<oid>.1.3.6.1.4.1.29385.106.1.0.9</oid>
|
||||
</feBOut>
|
||||
</fields>
|
||||
</interface>
|
@ -4035,10 +4035,10 @@ Notes related to these keywords :
|
||||
8. bin: bytes in
|
||||
9. bout: bytes out
|
||||
10. dreq: denied requests
|
||||
11. dresp: denied responces
|
||||
11. dresp: denied responses
|
||||
12. ereq: request errors
|
||||
13. econ: connection errors
|
||||
14. eresp: responce errors
|
||||
14. eresp: response errors
|
||||
15. wretr: retries (warning)
|
||||
16. wredis: redispatches (warning)
|
||||
17. status: status (UP/DOWN/...)
|
||||
@ -4058,6 +4058,19 @@ Notes related to these keywords :
|
||||
31. tracked: id of proxy/server if tracking is enabled
|
||||
32. type (0=frontend, 1=backend, 2=server)
|
||||
|
||||
2.8) Unix Socket commands
|
||||
|
||||
- "show stat [<iid> <type> <sid>]": dump statistics in the cvs format. By
|
||||
passing id, type and sid it is possible to dump only selected items:
|
||||
- iid is a proxy id, -1 to dump everything
|
||||
- type selects type of dumpable objects: 1 for frontend, 2 for backend, 4 for
|
||||
server, -1 for everything. Values can be ORed, for example:
|
||||
1+2=3 -> frontend+backend.
|
||||
1+2+4=7 -> frontend+backend+server.
|
||||
- sid is a service id, -1 to dump everything from the selected proxy.
|
||||
|
||||
- "show info": dump info about current haproxy status.
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* fill-column: 79
|
||||
|
@ -51,6 +51,9 @@
|
||||
// max # args on a configuration line
|
||||
#define MAX_LINE_ARGS 64
|
||||
|
||||
// max # args on a uxts socket
|
||||
#define MAX_UXST_ARGS 16
|
||||
|
||||
// max # of added headers per request
|
||||
#define MAX_NEWHDR 10
|
||||
|
||||
|
@ -31,6 +31,10 @@
|
||||
#define STAT_SHOW_STAT 0x2
|
||||
#define STAT_SHOW_INFO 0x4
|
||||
|
||||
#define STATS_TYPE_FE 0
|
||||
#define STATS_TYPE_BE 1
|
||||
#define STATS_TYPE_SV 2
|
||||
|
||||
int stats_parse_global(const char **args, char *err, int errlen);
|
||||
int stats_dump_raw(struct session *s, struct uri_auth *uri, int flags);
|
||||
int stats_dump_http(struct session *s, struct uri_auth *uri, int flags);
|
||||
|
@ -82,6 +82,7 @@
|
||||
#define SN_STAT_HIDEDWN 0x00100000 /* hide 'down' servers in the stats page */
|
||||
#define SN_STAT_NORFRSH 0x00200000 /* do not automatically refresh the stats page */
|
||||
#define SN_STAT_FMTCSV 0x00400000 /* dump the stats in CSV format instead of HTML */
|
||||
#define SN_STAT_BOUND 0x00800000 /* bound statistics to selected proxies/types/services */
|
||||
|
||||
|
||||
/* WARNING: if new fields are added, they must be initialized in event_accept()
|
||||
@ -126,6 +127,7 @@ struct session {
|
||||
struct proxy *px;
|
||||
struct server *sv;
|
||||
short px_st, sv_st; /* DATA_ST_INIT or DATA_ST_DATA */
|
||||
int iid, type, sid; /* proxy id, type and service id if bounding of stats is enabled */
|
||||
} stats;
|
||||
} data_ctx; /* used by produce_content to dump the stats right now */
|
||||
unsigned int uniq_id; /* unique ID used for the traces */
|
||||
|
@ -213,7 +213,6 @@ int stats_dump_raw(struct session *s, struct uri_auth *uri, int flags)
|
||||
|
||||
case DATA_ST_INFO:
|
||||
up = (now.tv_sec - start_date.tv_sec);
|
||||
memset(&s->data_ctx, 0, sizeof(s->data_ctx));
|
||||
|
||||
if (flags & STAT_SHOW_INFO) {
|
||||
chunk_printf(&msg, sizeof(trash),
|
||||
@ -248,6 +247,10 @@ int stats_dump_raw(struct session *s, struct uri_auth *uri, int flags)
|
||||
|
||||
s->data_ctx.stats.px = proxy;
|
||||
s->data_ctx.stats.px_st = DATA_ST_PX_INIT;
|
||||
|
||||
s->data_ctx.stats.sv = NULL;
|
||||
s->data_ctx.stats.sv_st = 0;
|
||||
|
||||
s->data_state = DATA_ST_LIST;
|
||||
/* fall through */
|
||||
|
||||
@ -621,6 +624,10 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri,
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((s->flags & SN_STAT_BOUND) && (s->data_ctx.stats.iid != -1) &&
|
||||
(px->uuid != s->data_ctx.stats.iid))
|
||||
return 1;
|
||||
|
||||
s->data_ctx.stats.px_st = DATA_ST_PX_TH;
|
||||
/* fall through */
|
||||
|
||||
@ -660,7 +667,7 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri,
|
||||
|
||||
case DATA_ST_PX_FE:
|
||||
/* print the frontend */
|
||||
if (px->cap & PR_CAP_FE) {
|
||||
if ((px->cap & PR_CAP_FE) && (!(s->flags & SN_STAT_BOUND) || (s->data_ctx.stats.type & (1 << STATS_TYPE_FE)))) {
|
||||
if (flags & STAT_FMT_HTML) {
|
||||
chunk_printf(&msg, sizeof(trash),
|
||||
/* name, queue */
|
||||
@ -706,8 +713,8 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri,
|
||||
"%s,"
|
||||
/* rest of server: nothing */
|
||||
",,,,,,,,"
|
||||
/* pid, iid, sid, throttle, lbtot, tracked, type (0=server)*/
|
||||
"%d,%d,0,,,,0,"
|
||||
/* pid, iid, sid, throttle, lbtot, tracked, type */
|
||||
"%d,%d,0,,,,%d,"
|
||||
"\n",
|
||||
px->id,
|
||||
px->feconn, px->feconn_max, px->maxconn, px->cum_feconn,
|
||||
@ -716,7 +723,7 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri,
|
||||
px->failed_req,
|
||||
px->state == PR_STRUN ? "OPEN" :
|
||||
px->state == PR_STIDLE ? "FULL" : "STOP",
|
||||
relative_pid, px->uuid);
|
||||
relative_pid, px->uuid, STATS_TYPE_FE);
|
||||
}
|
||||
|
||||
if (buffer_write_chunk(rep, &msg) != 0)
|
||||
@ -729,11 +736,20 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri,
|
||||
|
||||
case DATA_ST_PX_SV:
|
||||
/* stats.sv has been initialized above */
|
||||
while (s->data_ctx.stats.sv != NULL) {
|
||||
for (; s->data_ctx.stats.sv != NULL; s->data_ctx.stats.sv = sv->next) {
|
||||
|
||||
int sv_state; /* 0=DOWN, 1=going up, 2=going down, 3=UP, 4,5=NOLB, 6=unchecked */
|
||||
|
||||
sv = s->data_ctx.stats.sv;
|
||||
|
||||
if (s->flags & SN_STAT_BOUND) {
|
||||
if (!(s->data_ctx.stats.type & (1 << STATS_TYPE_SV)))
|
||||
break;
|
||||
|
||||
if (s->data_ctx.stats.sid != -1 && sv->puid != s->data_ctx.stats.sid)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sv->tracked)
|
||||
svs = sv->tracked;
|
||||
else
|
||||
@ -911,11 +927,11 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri,
|
||||
now.tv_sec >= sv->last_change) {
|
||||
unsigned int ratio;
|
||||
ratio = MAX(1, 100 * (now.tv_sec - sv->last_change) / sv->slowstart);
|
||||
chunk_printf(&msg, sizeof(trash), "%d,", ratio);
|
||||
chunk_printf(&msg, sizeof(trash), "%d", ratio);
|
||||
}
|
||||
|
||||
/* sessions: lbtot */
|
||||
chunk_printf(&msg, sizeof(trash), "%d,", sv->cum_lbconn);
|
||||
chunk_printf(&msg, sizeof(trash), ",%d,", sv->cum_lbconn);
|
||||
|
||||
/* tracked */
|
||||
if (sv->tracked)
|
||||
@ -924,21 +940,19 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri,
|
||||
else
|
||||
chunk_printf(&msg, sizeof(trash), ",");
|
||||
|
||||
/* type (2=server), then EOL */
|
||||
chunk_printf(&msg, sizeof(trash), "2,\n");
|
||||
/* type, then EOL */
|
||||
chunk_printf(&msg, sizeof(trash), "%d,\n", STATS_TYPE_SV);
|
||||
}
|
||||
if (buffer_write_chunk(rep, &msg) != 0)
|
||||
return 0;
|
||||
|
||||
s->data_ctx.stats.sv = sv->next;
|
||||
} /* while sv */
|
||||
} /* for sv */
|
||||
|
||||
s->data_ctx.stats.px_st = DATA_ST_PX_BE;
|
||||
/* fall through */
|
||||
|
||||
case DATA_ST_PX_BE:
|
||||
/* print the backend */
|
||||
if (px->cap & PR_CAP_BE) {
|
||||
if ((px->cap & PR_CAP_BE) && (!(s->flags & SN_STAT_BOUND) || (s->data_ctx.stats.type & (1 << STATS_TYPE_BE)))) {
|
||||
if (flags & STAT_FMT_HTML) {
|
||||
chunk_printf(&msg, sizeof(trash),
|
||||
/* name */
|
||||
@ -1007,8 +1021,8 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri,
|
||||
"%d,%d,%d,"
|
||||
/* rest of backend: nothing, down transitions, last change, total downtime */
|
||||
",%d,%d,%d,,"
|
||||
/* pid, iid, sid, throttle, lbtot, tracked, type (1=backend) */
|
||||
"%d,%d,0,,%d,,1,"
|
||||
/* pid, iid, sid, throttle, lbtot, tracked, type */
|
||||
"%d,%d,0,,%d,,%d,"
|
||||
"\n",
|
||||
px->id,
|
||||
px->nbpend /* or px->totpend ? */, px->nbpend_max,
|
||||
@ -1023,7 +1037,7 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri,
|
||||
px->down_trans, now.tv_sec - px->last_change,
|
||||
px->srv?be_downtime(px):0,
|
||||
relative_pid, px->uuid,
|
||||
px->cum_lbconn);
|
||||
px->cum_lbconn, STATS_TYPE_BE);
|
||||
}
|
||||
if (buffer_write_chunk(rep, &msg) != 0)
|
||||
return 0;
|
||||
|
@ -416,6 +416,8 @@ int uxst_event_accept(int fd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
s->flags = 0;
|
||||
|
||||
if ((t = pool_alloc2(pool2_task)) == NULL) {
|
||||
Alert("out of memory in uxst_event_accept().\n");
|
||||
close(cfd);
|
||||
@ -1381,31 +1383,75 @@ void process_uxst_stats(struct task *t, struct timeval *next)
|
||||
}
|
||||
|
||||
if (s->data_state == DATA_ST_INIT) {
|
||||
if ((s->req->l >= 10) && (memcmp(s->req->data, "show stat\n", 10) == 0)) {
|
||||
/* send the stats, and changes the data_state */
|
||||
if (stats_dump_raw(s, NULL, STAT_SHOW_STAT) != 0) {
|
||||
s->srv_state = SV_STCLOSE;
|
||||
fsm_resync |= 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ((s->req->l >= 10) && (memcmp(s->req->data, "show info\n", 10) == 0)) {
|
||||
/* send the stats, and changes the data_state */
|
||||
if (stats_dump_raw(s, NULL, STAT_SHOW_INFO) != 0) {
|
||||
s->srv_state = SV_STCLOSE;
|
||||
fsm_resync |= 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (s->cli_state == CL_STSHUTR || (s->req->l >= s->req->rlim - s->req->data)) {
|
||||
s->srv_state = SV_STCLOSE;
|
||||
fsm_resync |= 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (s->data_state == DATA_ST_INIT)
|
||||
char *args[MAX_UXST_ARGS + 1];
|
||||
char *line, *p;
|
||||
int arg;
|
||||
|
||||
line = s->req->data;
|
||||
p = memchr(line, '\n', s->req->l);
|
||||
|
||||
if (!p)
|
||||
continue;
|
||||
|
||||
*p = '\0';
|
||||
|
||||
while (isspace((unsigned char)*line))
|
||||
line++;
|
||||
|
||||
arg = 0;
|
||||
args[arg] = line;
|
||||
|
||||
while (*line && arg < MAX_UXST_ARGS) {
|
||||
if (isspace((unsigned char)*line)) {
|
||||
*line++ = '\0';
|
||||
|
||||
while (isspace((unsigned char)*line))
|
||||
line++;
|
||||
|
||||
args[++arg] = line;
|
||||
continue;
|
||||
}
|
||||
|
||||
line++;
|
||||
}
|
||||
|
||||
while (++arg <= MAX_UXST_ARGS)
|
||||
args[arg] = line;
|
||||
|
||||
if (!strcmp(args[0], "show")) {
|
||||
if (!strcmp(args[1], "stat")) {
|
||||
if (*args[2] && *args[3] && *args[4]) {
|
||||
s->flags |= SN_STAT_BOUND;
|
||||
s->data_ctx.stats.iid = atoi(args[2]);
|
||||
s->data_ctx.stats.type = atoi(args[3]);
|
||||
s->data_ctx.stats.sid = atoi(args[4]);
|
||||
}
|
||||
|
||||
/* send the stats, and changes the data_state */
|
||||
if (stats_dump_raw(s, NULL, STAT_SHOW_STAT) != 0) {
|
||||
s->srv_state = SV_STCLOSE;
|
||||
fsm_resync |= 1;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!strcmp(args[1], "info")) {
|
||||
/* send the stats, and changes the data_state */
|
||||
if (stats_dump_raw(s, NULL, STAT_SHOW_INFO) != 0) {
|
||||
s->srv_state = SV_STCLOSE;
|
||||
fsm_resync |= 1;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
s->srv_state = SV_STCLOSE;
|
||||
fsm_resync |= 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* OK we have some remaining data to process. Just for the
|
||||
* sake of an exercice, we copy the req into the resp,
|
||||
|
Loading…
Reference in New Issue
Block a user