diff --git a/contrib/netsnmp-perl/README b/contrib/netsnmp-perl/README new file mode 100644 index 000000000..f44eb5b8b --- /dev/null +++ b/contrib/netsnmp-perl/README @@ -0,0 +1,111 @@ +SNMP support for HAProxy +Copyright 2007-2008 Krzysztof Piotr Oledzki + +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" + diff --git a/contrib/netsnmp-perl/haproxy.pl b/contrib/netsnmp-perl/haproxy.pl new file mode 100644 index 000000000..61b693a9f --- /dev/null +++ b/contrib/netsnmp-perl/haproxy.pl @@ -0,0 +1,242 @@ +# +# Net-SNMP perl plugin for Haproxy +# Version 0.27 +# +# Copyright 2007-2008 Krzysztof Piotr Oledzki +# +# 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); + diff --git a/contrib/netsnmp-perl/haproxy_backend.xml b/contrib/netsnmp-perl/haproxy_backend.xml new file mode 100644 index 000000000..9bbde2fe8 --- /dev/null +++ b/contrib/netsnmp-perl/haproxy_backend.xml @@ -0,0 +1,62 @@ + + Haproxy - backend + .1.3.6.1.4.1.29385.106.1.1.10001 + + + Proxy ID + get + value + input + .1.3.6.1.4.1.29385.106.1.1.27 + + + Service ID + get + value + input + .1.3.6.1.4.1.29385.106.1.1.28 + + + Proxy Name + get + value + input + .1.3.6.1.4.1.29385.106.1.1.0 + + + Service Name + get + value + input + .1.3.6.1.4.1.29385.106.1.1.1 + + + Total Sessions + get + value + output + .1.3.6.1.4.1.29385.106.1.1.7 + + + Response Errors + get + value + output + .1.3.6.1.4.1.29385.106.1.1.14 + + + Bytes In + get + value + output + .1.3.6.1.4.1.29385.106.1.1.8 + + + Bytes Out + get + value + output + .1.3.6.1.4.1.29385.106.1.1.9 + + + diff --git a/contrib/netsnmp-perl/haproxy_frontend.xml b/contrib/netsnmp-perl/haproxy_frontend.xml new file mode 100644 index 000000000..09789c88e --- /dev/null +++ b/contrib/netsnmp-perl/haproxy_frontend.xml @@ -0,0 +1,62 @@ + + Haproxy - frontend + .1.3.6.1.4.1.29385.106.1.0.10001 + + + Proxy ID + get + value + input + .1.3.6.1.4.1.29385.106.1.0.27 + + + Service ID + get + value + input + .1.3.6.1.4.1.29385.106.1.0.28 + + + Proxy Name + get + value + input + .1.3.6.1.4.1.29385.106.1.0.0 + + + Service Name + get + value + input + .1.3.6.1.4.1.29385.106.1.0.1 + + + Total Sessions + get + value + output + .1.3.6.1.4.1.29385.106.1.0.7 + + + Request Errors + get + value + output + .1.3.6.1.4.1.29385.106.1.0.12 + + + Bytes In + get + value + output + .1.3.6.1.4.1.29385.106.1.0.8 + + + Bytes Out + get + value + output + .1.3.6.1.4.1.29385.106.1.0.9 + + + diff --git a/doc/configuration.txt b/doc/configuration.txt index a2c97e317..11360ba46 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -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 [ ]": 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 diff --git a/include/common/defaults.h b/include/common/defaults.h index 1a69f40d9..da9bdd8c7 100644 --- a/include/common/defaults.h +++ b/include/common/defaults.h @@ -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 diff --git a/include/proto/dumpstats.h b/include/proto/dumpstats.h index 198f0d793..362650567 100644 --- a/include/proto/dumpstats.h +++ b/include/proto/dumpstats.h @@ -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); diff --git a/include/types/session.h b/include/types/session.h index 9437198d9..18d5115f0 100644 --- a/include/types/session.h +++ b/include/types/session.h @@ -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 */ diff --git a/src/dumpstats.c b/src/dumpstats.c index c132246a5..99ac770f6 100644 --- a/src/dumpstats.c +++ b/src/dumpstats.c @@ -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; diff --git a/src/proto_uxst.c b/src/proto_uxst.c index 905472268..76709c137 100644 --- a/src/proto_uxst.c +++ b/src/proto_uxst.c @@ -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,