2007-10-17 11:06:05 -04:00
|
|
|
/*
|
2010-05-28 12:46:57 -04:00
|
|
|
* Functions dedicated to statistics output and the stats socket
|
2007-10-17 11:06:05 -04:00
|
|
|
*
|
2010-05-28 12:46:57 -04:00
|
|
|
* Copyright 2000-2010 Willy Tarreau <w@1wt.eu>
|
2009-09-23 16:09:24 -04:00
|
|
|
* Copyright 2007-2009 Krzysztof Piotr Oledzki <ole@ans.pl>
|
2007-10-17 11:06:05 -04:00
|
|
|
*
|
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
|
* as published by the Free Software Foundation; either version
|
|
|
|
|
* 2 of the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <fcntl.h>
|
2011-06-15 02:18:47 -04:00
|
|
|
#include <stdbool.h>
|
2007-10-17 11:06:05 -04:00
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
2007-10-18 07:53:22 -04:00
|
|
|
#include <pwd.h>
|
|
|
|
|
#include <grp.h>
|
2007-10-17 11:06:05 -04:00
|
|
|
|
|
|
|
|
#include <sys/socket.h>
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
|
2008-07-09 14:12:41 -04:00
|
|
|
#include <common/cfgparse.h>
|
2007-10-17 11:06:05 -04:00
|
|
|
#include <common/compat.h>
|
|
|
|
|
#include <common/config.h>
|
|
|
|
|
#include <common/debug.h>
|
|
|
|
|
#include <common/memory.h>
|
|
|
|
|
#include <common/mini-clist.h>
|
|
|
|
|
#include <common/standard.h>
|
2008-07-06 18:09:58 -04:00
|
|
|
#include <common/ticks.h>
|
2007-10-17 11:06:05 -04:00
|
|
|
#include <common/time.h>
|
|
|
|
|
#include <common/uri_auth.h>
|
|
|
|
|
#include <common/version.h>
|
|
|
|
|
|
|
|
|
|
#include <types/global.h>
|
|
|
|
|
|
|
|
|
|
#include <proto/backend.h>
|
2012-08-24 13:22:53 -04:00
|
|
|
#include <proto/channel.h>
|
2009-09-23 16:09:24 -04:00
|
|
|
#include <proto/checks.h>
|
2007-10-17 11:06:05 -04:00
|
|
|
#include <proto/dumpstats.h>
|
|
|
|
|
#include <proto/fd.h>
|
2009-03-05 12:43:00 -05:00
|
|
|
#include <proto/freq_ctr.h>
|
2010-05-28 12:46:57 -04:00
|
|
|
#include <proto/log.h>
|
2009-01-25 08:02:00 -05:00
|
|
|
#include <proto/pipe.h>
|
2011-08-02 05:49:05 -04:00
|
|
|
#include <proto/protocols.h>
|
2007-10-18 07:53:22 -04:00
|
|
|
#include <proto/proto_uxst.h>
|
2009-08-16 11:41:45 -04:00
|
|
|
#include <proto/proxy.h>
|
2007-10-17 11:06:05 -04:00
|
|
|
#include <proto/session.h>
|
[MEDIUM] stats: report server and backend cumulated downtime
Hello,
This patch implements new statistics for SLA calculation by adding new
field 'Dwntime' with total down time since restart (both HTTP/CSV) and
extending status field (HTTP) or inserting a new one (CSV) with time
showing how long each server/backend is in a current state. Additionaly,
down transations are also calculated and displayed for backends, so it is
possible to know how many times selected backend was down, generating "No
server is available to handle this request." error.
New information are presentetd in two different ways:
- for HTTP: a "human redable form", one of "100000d 23h", "23h 59m" or
"59m 59s"
- for CSV: seconds
I believe that seconds resolution is enough.
As there are more columns in the status page I decided to shrink some
names to make more space:
- Weight -> Wght
- Check -> Chk
- Down -> Dwn
Making described changes I also made some improvements and fixed some
small bugs:
- don't increment s->health above 's->rise + s->fall - 1'. Previously it
was incremented an then (re)set to 's->rise + s->fall - 1'.
- do not set server down if it is down already
- do not set server up if it is up already
- fix colspan in multiple places (mostly introduced by my previous patch)
- add missing "status" header to CSV
- fix order of retries/redispatches in server (CSV)
- s/Tthen/Then/
- s/server/backend/ in DATA_ST_PX_BE (dumpstats.c)
Changes from previous version:
- deal with negative time intervales
- don't relay on s->state (SRV_RUNNING)
- little reworked human_time + compacted format (no spaces). If needed it
can be used in the future for other purposes by optionally making "cnt"
as an argument
- leave set_server_down mostly unchanged
- only little reworked "process_chk: 9"
- additional fields in CSV are appended to the rigth
- fix "SEC" macro
- named arguments (human_time, be_downtime, srv_downtime)
Hope it is OK. If there are only cosmetic changes needed please fill free
to correct it, however if there are some bigger changes required I would
like to discuss it first or at last to know what exactly was changed
especially since I already put this patch into my production server. :)
Thank you,
Best regards,
Krzysztof Oledzki
2007-10-22 10:21:10 -04:00
|
|
|
#include <proto/server.h>
|
2012-08-20 11:01:35 -04:00
|
|
|
#include <proto/raw_sock.h>
|
2008-11-30 13:48:07 -05:00
|
|
|
#include <proto/stream_interface.h>
|
2009-03-07 11:25:21 -05:00
|
|
|
#include <proto/task.h>
|
2007-10-17 11:06:05 -04:00
|
|
|
|
2011-06-15 02:18:44 -04:00
|
|
|
static int stats_dump_raw_to_buffer(struct stream_interface *si);
|
|
|
|
|
static int stats_dump_full_sess_to_buffer(struct stream_interface *si);
|
|
|
|
|
static int stats_dump_sess_to_buffer(struct stream_interface *si);
|
|
|
|
|
static int stats_dump_errors_to_buffer(struct stream_interface *si);
|
2011-06-15 02:18:49 -04:00
|
|
|
static int stats_table_request(struct stream_interface *si, bool show);
|
2011-06-15 02:18:44 -04:00
|
|
|
static int stats_dump_proxy(struct stream_interface *si, struct proxy *px, struct uri_auth *uri);
|
|
|
|
|
static int stats_dump_http(struct stream_interface *si, struct uri_auth *uri);
|
|
|
|
|
|
|
|
|
|
static struct si_applet cli_applet;
|
|
|
|
|
|
|
|
|
|
static const char stats_sock_usage_msg[] =
|
2009-10-04 09:02:46 -04:00
|
|
|
"Unknown command. Please enter one of the following commands only :\n"
|
2009-10-10 09:26:26 -04:00
|
|
|
" clear counters : clear max statistics counters (add 'all' for all counters)\n"
|
2010-07-13 07:48:00 -04:00
|
|
|
" clear table : remove an entry from a table\n"
|
2009-10-04 09:02:46 -04:00
|
|
|
" help : this message\n"
|
|
|
|
|
" prompt : toggle interactive mode with prompt\n"
|
|
|
|
|
" quit : disconnect\n"
|
|
|
|
|
" show info : report information about the running process\n"
|
|
|
|
|
" show stat : report counters for each proxy and server\n"
|
|
|
|
|
" show errors : report last request and response errors for each proxy\n"
|
2010-03-05 11:53:32 -05:00
|
|
|
" show sess [id] : report the list of current sessions or dump this session\n"
|
2010-07-12 11:55:33 -04:00
|
|
|
" show table [id]: report table usage stats or dump this table's contents\n"
|
2009-10-10 12:37:29 -04:00
|
|
|
" get weight : report a server's current weight\n"
|
2009-10-10 13:30:08 -04:00
|
|
|
" set weight : change a server's weight\n"
|
2012-06-06 19:03:16 -04:00
|
|
|
" set table [id] : update or create a table entry's data\n"
|
2010-01-26 04:59:06 -05:00
|
|
|
" set timeout : change a timeout setting\n"
|
2011-08-02 05:49:05 -04:00
|
|
|
" set maxconn : change a maxconn setting\n"
|
2011-09-07 10:13:44 -04:00
|
|
|
" set rate-limit : change a rate limiting value\n"
|
2011-09-07 17:21:03 -04:00
|
|
|
" disable : put a server or frontend in maintenance mode\n"
|
|
|
|
|
" enable : re-enable a server or frontend which is in maintenance mode\n"
|
|
|
|
|
" shutdown : kill a session or a frontend (eg:to release listening ports)\n"
|
2009-09-22 13:31:03 -04:00
|
|
|
"";
|
2009-08-16 13:06:42 -04:00
|
|
|
|
2011-06-15 02:18:44 -04:00
|
|
|
static const char stats_permission_denied_msg[] =
|
2009-10-10 11:13:00 -04:00
|
|
|
"Permission denied\n"
|
|
|
|
|
"";
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
/* data transmission states for the stats responses */
|
|
|
|
|
enum {
|
|
|
|
|
STAT_ST_INIT = 0,
|
|
|
|
|
STAT_ST_HEAD,
|
|
|
|
|
STAT_ST_INFO,
|
|
|
|
|
STAT_ST_LIST,
|
|
|
|
|
STAT_ST_END,
|
|
|
|
|
STAT_ST_FIN,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* data transmission states for the stats responses inside a proxy */
|
|
|
|
|
enum {
|
|
|
|
|
STAT_PX_ST_INIT = 0,
|
|
|
|
|
STAT_PX_ST_TH,
|
|
|
|
|
STAT_PX_ST_FE,
|
|
|
|
|
STAT_PX_ST_LI,
|
|
|
|
|
STAT_PX_ST_SV,
|
|
|
|
|
STAT_PX_ST_BE,
|
|
|
|
|
STAT_PX_ST_END,
|
|
|
|
|
STAT_PX_ST_FIN,
|
|
|
|
|
};
|
|
|
|
|
|
2012-04-04 06:57:21 -04:00
|
|
|
extern const char *stat_status_codes[];
|
|
|
|
|
|
2010-06-01 12:03:19 -04:00
|
|
|
/* This function is called from the session-level accept() in order to instanciate
|
2010-05-28 12:46:57 -04:00
|
|
|
* a new stats socket. It returns a positive value upon success, 0 if the connection
|
|
|
|
|
* needs to be closed and ignored, or a negative value upon critical failure.
|
|
|
|
|
*/
|
2011-06-15 02:18:44 -04:00
|
|
|
static int stats_accept(struct session *s)
|
2010-05-28 12:46:57 -04:00
|
|
|
{
|
2010-06-01 12:03:19 -04:00
|
|
|
/* we have a dedicated I/O handler for the stats */
|
2011-02-13 07:16:36 -05:00
|
|
|
stream_int_register_handler(&s->si[1], &cli_applet);
|
2011-03-27 13:53:06 -04:00
|
|
|
copy_target(&s->target, &s->si[1].target); // for logging only
|
2012-05-21 11:09:48 -04:00
|
|
|
s->si[1].conn.data_ctx = s;
|
2011-02-13 07:25:14 -05:00
|
|
|
s->si[1].applet.st1 = 0;
|
|
|
|
|
s->si[1].applet.st0 = STAT_CLI_INIT;
|
2010-05-28 12:46:57 -04:00
|
|
|
|
2010-06-01 12:03:19 -04:00
|
|
|
tv_zero(&s->logs.tv_request);
|
|
|
|
|
s->logs.t_queue = 0;
|
|
|
|
|
s->logs.t_connect = 0;
|
|
|
|
|
s->logs.t_data = 0;
|
|
|
|
|
s->logs.t_close = 0;
|
|
|
|
|
s->logs.bytes_in = s->logs.bytes_out = 0;
|
|
|
|
|
s->logs.prx_queue_size = 0; /* we get the number of pending conns before us */
|
|
|
|
|
s->logs.srv_queue_size = 0; /* we will get this number soon */
|
2010-05-28 12:46:57 -04:00
|
|
|
|
|
|
|
|
s->req->flags |= BF_READ_DONTWAIT; /* we plan to read small requests */
|
|
|
|
|
|
2010-06-01 12:03:19 -04:00
|
|
|
if (s->listener->timeout) {
|
|
|
|
|
s->req->rto = *s->listener->timeout;
|
|
|
|
|
s->rep->wto = *s->listener->timeout;
|
2010-05-28 12:46:57 -04:00
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-17 15:48:17 -04:00
|
|
|
/* allocate a new stats frontend named <name>, and return it
|
|
|
|
|
* (or NULL in case of lack of memory).
|
|
|
|
|
*/
|
|
|
|
|
static struct proxy *alloc_stats_fe(const char *name)
|
|
|
|
|
{
|
|
|
|
|
struct proxy *fe;
|
|
|
|
|
|
|
|
|
|
fe = (struct proxy *)calloc(1, sizeof(struct proxy));
|
|
|
|
|
if (!fe)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2011-07-28 19:49:03 -04:00
|
|
|
init_new_proxy(fe);
|
2010-08-17 15:48:17 -04:00
|
|
|
|
|
|
|
|
fe->last_change = now.tv_sec;
|
|
|
|
|
fe->id = strdup("GLOBAL");
|
|
|
|
|
fe->cap = PR_CAP_FE;
|
2011-09-07 06:13:34 -04:00
|
|
|
fe->maxconn = 10; /* default to 10 concurrent connections */
|
|
|
|
|
fe->timeout.client = MS_TO_TICKS(10000); /* default timeout of 10 seconds */
|
|
|
|
|
|
2010-08-17 15:48:17 -04:00
|
|
|
return fe;
|
|
|
|
|
}
|
|
|
|
|
|
2007-10-18 07:53:22 -04:00
|
|
|
/* This function parses a "stats" statement in the "global" section. It returns
|
2012-05-08 13:47:01 -04:00
|
|
|
* -1 if there is any error, otherwise zero. If it returns -1, it will write an
|
|
|
|
|
* error message into the <err> buffer which will be preallocated. The trailing
|
|
|
|
|
* '\n' must not be written. The function must be called with <args> pointing to
|
|
|
|
|
* the first word after "stats".
|
2007-10-18 07:53:22 -04:00
|
|
|
*/
|
2008-07-09 14:12:41 -04:00
|
|
|
static int stats_parse_global(char **args, int section_type, struct proxy *curpx,
|
2012-05-08 13:47:01 -04:00
|
|
|
struct proxy *defpx, char **err)
|
2007-10-18 07:53:22 -04:00
|
|
|
{
|
2012-05-08 13:47:01 -04:00
|
|
|
if (!strcmp(args[1], "socket")) {
|
2011-01-19 14:29:32 -05:00
|
|
|
struct sockaddr_un *su;
|
2007-10-18 07:53:22 -04:00
|
|
|
int cur_arg;
|
|
|
|
|
|
2012-05-08 13:47:01 -04:00
|
|
|
if (*args[2] == 0) {
|
|
|
|
|
memprintf(err, "'%s %s' in global section expects a path to a UNIX socket", args[0], args[1]);
|
2007-10-18 07:53:22 -04:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (global.stats_sock.state != LI_NEW) {
|
2012-05-08 13:47:01 -04:00
|
|
|
memprintf(err, "'%s %s' already specified in global section", args[0], args[1]);
|
2007-10-18 07:53:22 -04:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-08 13:47:01 -04:00
|
|
|
su = str2sun(args[2]);
|
2011-01-19 14:29:32 -05:00
|
|
|
if (!su) {
|
2012-05-08 13:47:01 -04:00
|
|
|
memprintf(err, "'%s %s' : path would require truncation", args[0], args[1]);
|
2011-01-19 14:29:32 -05:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
memcpy(&global.stats_sock.addr, su, sizeof(struct sockaddr_un)); // guaranteed to fit
|
2007-10-18 07:53:22 -04:00
|
|
|
|
2009-08-16 11:41:45 -04:00
|
|
|
if (!global.stats_fe) {
|
2010-08-17 15:48:17 -04:00
|
|
|
if ((global.stats_fe = alloc_stats_fe("GLOBAL")) == NULL) {
|
2012-05-08 13:47:01 -04:00
|
|
|
memprintf(err, "'%s %s' : out of memory trying to allocate a frontend", args[0], args[1]);
|
2009-08-16 11:41:45 -04:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2007-10-18 07:53:22 -04:00
|
|
|
global.stats_sock.state = LI_INIT;
|
2011-09-07 12:00:47 -04:00
|
|
|
global.stats_sock.options = LI_O_UNLIMITED;
|
2010-06-01 12:03:19 -04:00
|
|
|
global.stats_sock.accept = session_accept;
|
|
|
|
|
global.stats_fe->accept = stats_accept;
|
2009-08-16 12:51:29 -04:00
|
|
|
global.stats_sock.handler = process_session;
|
2009-09-22 13:31:03 -04:00
|
|
|
global.stats_sock.analysers = 0;
|
2009-08-16 13:12:36 -04:00
|
|
|
global.stats_sock.nice = -64; /* we want to boost priority for local stats */
|
2010-05-28 12:46:57 -04:00
|
|
|
global.stats_sock.frontend = global.stats_fe;
|
2009-10-10 11:13:00 -04:00
|
|
|
global.stats_sock.perm.ux.level = ACCESS_LVL_OPER; /* default access level */
|
2011-09-07 06:13:34 -04:00
|
|
|
global.stats_sock.maxconn = global.stats_fe->maxconn;
|
2009-08-16 11:41:45 -04:00
|
|
|
global.stats_sock.timeout = &global.stats_fe->timeout.client;
|
|
|
|
|
|
|
|
|
|
global.stats_sock.next = global.stats_fe->listen;
|
|
|
|
|
global.stats_fe->listen = &global.stats_sock;
|
2007-10-18 07:53:22 -04:00
|
|
|
|
2012-05-08 13:47:01 -04:00
|
|
|
cur_arg = 3;
|
2007-10-18 07:53:22 -04:00
|
|
|
while (*args[cur_arg]) {
|
|
|
|
|
if (!strcmp(args[cur_arg], "uid")) {
|
|
|
|
|
global.stats_sock.perm.ux.uid = atol(args[cur_arg + 1]);
|
|
|
|
|
cur_arg += 2;
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp(args[cur_arg], "gid")) {
|
|
|
|
|
global.stats_sock.perm.ux.gid = atol(args[cur_arg + 1]);
|
|
|
|
|
cur_arg += 2;
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp(args[cur_arg], "mode")) {
|
|
|
|
|
global.stats_sock.perm.ux.mode = strtol(args[cur_arg + 1], NULL, 8);
|
|
|
|
|
cur_arg += 2;
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp(args[cur_arg], "user")) {
|
|
|
|
|
struct passwd *user;
|
|
|
|
|
user = getpwnam(args[cur_arg + 1]);
|
|
|
|
|
if (!user) {
|
2012-05-08 13:47:01 -04:00
|
|
|
memprintf(err, "'%s %s' : unknown user '%s'", args[0], args[1], args[cur_arg + 1]);
|
2007-10-18 07:53:22 -04:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
global.stats_sock.perm.ux.uid = user->pw_uid;
|
|
|
|
|
cur_arg += 2;
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp(args[cur_arg], "group")) {
|
|
|
|
|
struct group *group;
|
|
|
|
|
group = getgrnam(args[cur_arg + 1]);
|
|
|
|
|
if (!group) {
|
2012-05-08 13:47:01 -04:00
|
|
|
memprintf(err, "'%s %s' : unknown group '%s'", args[0], args[1], args[cur_arg + 1]);
|
2007-10-18 07:53:22 -04:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
global.stats_sock.perm.ux.gid = group->gr_gid;
|
|
|
|
|
cur_arg += 2;
|
|
|
|
|
}
|
2009-10-10 11:13:00 -04:00
|
|
|
else if (!strcmp(args[cur_arg], "level")) {
|
|
|
|
|
if (!strcmp(args[cur_arg+1], "user"))
|
|
|
|
|
global.stats_sock.perm.ux.level = ACCESS_LVL_USER;
|
|
|
|
|
else if (!strcmp(args[cur_arg+1], "operator"))
|
|
|
|
|
global.stats_sock.perm.ux.level = ACCESS_LVL_OPER;
|
|
|
|
|
else if (!strcmp(args[cur_arg+1], "admin"))
|
|
|
|
|
global.stats_sock.perm.ux.level = ACCESS_LVL_ADMIN;
|
|
|
|
|
else {
|
2012-05-08 13:47:01 -04:00
|
|
|
memprintf(err, "'%s %s' : '%s' only supports 'user', 'operator', and 'admin' (got '%s')",
|
|
|
|
|
args[0], args[1], args[cur_arg], args[cur_arg+1]);
|
2009-10-10 11:13:00 -04:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
cur_arg += 2;
|
|
|
|
|
}
|
2007-10-18 07:53:22 -04:00
|
|
|
else {
|
2012-05-08 13:47:01 -04:00
|
|
|
memprintf(err, "'%s %s' only supports 'user', 'uid', 'group', 'gid', 'level', and 'mode' (got '%s')",
|
|
|
|
|
args[0], args[1], args[cur_arg]);
|
2007-10-18 07:53:22 -04:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-12-07 10:06:43 -05:00
|
|
|
|
2012-08-24 12:12:41 -04:00
|
|
|
global.stats_sock.data = &raw_sock;
|
2007-10-18 07:53:22 -04:00
|
|
|
uxst_add_listener(&global.stats_sock);
|
|
|
|
|
global.maxsock++;
|
|
|
|
|
}
|
2012-05-08 13:47:01 -04:00
|
|
|
else if (!strcmp(args[1], "timeout")) {
|
2007-12-02 16:15:14 -05:00
|
|
|
unsigned timeout;
|
2012-05-08 13:47:01 -04:00
|
|
|
const char *res = parse_time_err(args[2], &timeout, TIME_UNIT_MS);
|
2007-10-18 07:53:22 -04:00
|
|
|
|
2007-12-02 16:15:14 -05:00
|
|
|
if (res) {
|
2012-05-08 13:47:01 -04:00
|
|
|
memprintf(err, "'%s %s' : unexpected character '%c'", args[0], args[1], *res);
|
2007-12-02 16:15:14 -05:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!timeout) {
|
2012-05-08 13:47:01 -04:00
|
|
|
memprintf(err, "'%s %s' expects a positive value", args[0], args[1]);
|
2007-10-18 07:53:22 -04:00
|
|
|
return -1;
|
|
|
|
|
}
|
2010-08-17 15:48:17 -04:00
|
|
|
if (!global.stats_fe) {
|
|
|
|
|
if ((global.stats_fe = alloc_stats_fe("GLOBAL")) == NULL) {
|
2012-05-08 13:47:01 -04:00
|
|
|
memprintf(err, "'%s %s' : out of memory trying to allocate a frontend", args[0], args[1]);
|
2010-08-17 15:48:17 -04:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-08-16 11:41:45 -04:00
|
|
|
global.stats_fe->timeout.client = MS_TO_TICKS(timeout);
|
2007-10-18 07:53:22 -04:00
|
|
|
}
|
2012-05-08 13:47:01 -04:00
|
|
|
else if (!strcmp(args[1], "maxconn")) {
|
|
|
|
|
int maxconn = atol(args[2]);
|
2007-10-18 07:53:22 -04:00
|
|
|
|
|
|
|
|
if (maxconn <= 0) {
|
2012-05-08 13:47:01 -04:00
|
|
|
memprintf(err, "'%s %s' expects a positive value", args[0], args[1]);
|
2007-10-18 07:53:22 -04:00
|
|
|
return -1;
|
|
|
|
|
}
|
2011-09-07 06:13:34 -04:00
|
|
|
|
|
|
|
|
if (!global.stats_fe) {
|
|
|
|
|
if ((global.stats_fe = alloc_stats_fe("GLOBAL")) == NULL) {
|
2012-05-08 13:47:01 -04:00
|
|
|
memprintf(err, "'%s %s' : out of memory trying to allocate a frontend", args[0], args[1]);
|
2011-09-07 06:13:34 -04:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
global.stats_fe->maxconn = maxconn;
|
2007-10-18 07:53:22 -04:00
|
|
|
}
|
|
|
|
|
else {
|
2012-05-08 13:47:01 -04:00
|
|
|
memprintf(err, "'%s' only supports 'socket', 'maxconn' and 'timeout' (got '%s')", args[0], args[1]);
|
2007-10-18 07:53:22 -04:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-15 02:18:44 -04:00
|
|
|
static int print_csv_header(struct chunk *msg)
|
2007-11-30 12:16:29 -05:00
|
|
|
{
|
2009-09-27 07:23:20 -04:00
|
|
|
return chunk_printf(msg,
|
2007-11-30 12:16:29 -05:00
|
|
|
"# pxname,svname,"
|
|
|
|
|
"qcur,qmax,"
|
|
|
|
|
"scur,smax,slim,stot,"
|
|
|
|
|
"bin,bout,"
|
|
|
|
|
"dreq,dresp,"
|
|
|
|
|
"ereq,econ,eresp,"
|
|
|
|
|
"wretr,wredis,"
|
|
|
|
|
"status,weight,act,bck,"
|
|
|
|
|
"chkfail,chkdown,lastchg,downtime,qlimit,"
|
2009-05-10 13:01:49 -04:00
|
|
|
"pid,iid,sid,throttle,lbtot,tracked,type,"
|
|
|
|
|
"rate,rate_lim,rate_max,"
|
2009-09-23 16:09:24 -04:00
|
|
|
"check_status,check_code,check_duration,"
|
2009-12-15 16:31:24 -05:00
|
|
|
"hrsp_1xx,hrsp_2xx,hrsp_3xx,hrsp_4xx,hrsp_5xx,hrsp_other,hanafail,"
|
2010-03-04 14:34:23 -05:00
|
|
|
"req_rate,req_rate_max,req_tot,"
|
|
|
|
|
"cli_abrt,srv_abrt,"
|
2007-11-30 12:16:29 -05:00
|
|
|
"\n");
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-15 02:18:45 -04:00
|
|
|
/* print a string of text buffer to <out>. The format is :
|
|
|
|
|
* Non-printable chars \t, \n, \r and \e are * encoded in C format.
|
|
|
|
|
* Other non-printable chars are encoded "\xHH". Space and '\' are also escaped.
|
|
|
|
|
* Print stopped if null char or <bsize> is reached, or if no more place in the chunk.
|
|
|
|
|
*/
|
|
|
|
|
static int dump_text(struct chunk *out, const char *buf, int bsize)
|
|
|
|
|
{
|
|
|
|
|
unsigned char c;
|
|
|
|
|
int ptr = 0;
|
|
|
|
|
|
|
|
|
|
while (buf[ptr] && ptr < bsize) {
|
|
|
|
|
c = buf[ptr];
|
|
|
|
|
if (isprint(c) && isascii(c) && c != '\\' && c != ' ') {
|
|
|
|
|
if (out->len > out->size - 1)
|
|
|
|
|
break;
|
|
|
|
|
out->str[out->len++] = c;
|
|
|
|
|
}
|
|
|
|
|
else if (c == '\t' || c == '\n' || c == '\r' || c == '\e' || c == '\\' || c == ' ') {
|
|
|
|
|
if (out->len > out->size - 2)
|
|
|
|
|
break;
|
|
|
|
|
out->str[out->len++] = '\\';
|
|
|
|
|
switch (c) {
|
|
|
|
|
case ' ': c = ' '; break;
|
|
|
|
|
case '\t': c = 't'; break;
|
|
|
|
|
case '\n': c = 'n'; break;
|
|
|
|
|
case '\r': c = 'r'; break;
|
|
|
|
|
case '\e': c = 'e'; break;
|
|
|
|
|
case '\\': c = '\\'; break;
|
|
|
|
|
}
|
|
|
|
|
out->str[out->len++] = c;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (out->len > out->size - 4)
|
|
|
|
|
break;
|
|
|
|
|
out->str[out->len++] = '\\';
|
|
|
|
|
out->str[out->len++] = 'x';
|
|
|
|
|
out->str[out->len++] = hextab[(c >> 4) & 0xF];
|
|
|
|
|
out->str[out->len++] = hextab[c & 0xF];
|
|
|
|
|
}
|
|
|
|
|
ptr++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* print a buffer in hexa.
|
|
|
|
|
* Print stopped if <bsize> is reached, or if no more place in the chunk.
|
|
|
|
|
*/
|
|
|
|
|
static int dump_binary(struct chunk *out, const char *buf, int bsize)
|
|
|
|
|
{
|
|
|
|
|
unsigned char c;
|
|
|
|
|
int ptr = 0;
|
|
|
|
|
|
|
|
|
|
while (ptr < bsize) {
|
|
|
|
|
c = buf[ptr];
|
|
|
|
|
|
|
|
|
|
if (out->len > out->size - 2)
|
|
|
|
|
break;
|
|
|
|
|
out->str[out->len++] = hextab[(c >> 4) & 0xF];
|
|
|
|
|
out->str[out->len++] = hextab[c & 0xF];
|
|
|
|
|
|
|
|
|
|
ptr++;
|
|
|
|
|
}
|
|
|
|
|
return ptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Dump the status of a table to a stream interface's
|
|
|
|
|
* read buffer. It returns 0 if the output buffer is full
|
|
|
|
|
* and needs to be called again, otherwise non-zero.
|
|
|
|
|
*/
|
|
|
|
|
static int stats_dump_table_head_to_buffer(struct chunk *msg, struct stream_interface *si,
|
|
|
|
|
struct proxy *proxy, struct proxy *target)
|
|
|
|
|
{
|
2012-05-21 11:09:48 -04:00
|
|
|
struct session *s = si->conn.data_ctx;
|
2011-06-15 02:18:45 -04:00
|
|
|
|
|
|
|
|
chunk_printf(msg, "# table: %s, type: %s, size:%d, used:%d\n",
|
|
|
|
|
proxy->id, stktable_types[proxy->table.type].kw, proxy->table.size, proxy->table.current);
|
|
|
|
|
|
|
|
|
|
/* any other information should be dumped here */
|
|
|
|
|
|
|
|
|
|
if (target && s->listener->perm.ux.level < ACCESS_LVL_OPER)
|
|
|
|
|
chunk_printf(msg, "# contents not dumped due to insufficient privileges\n");
|
|
|
|
|
|
2012-05-07 05:56:55 -04:00
|
|
|
if (bi_putchk(si->ib, msg) == -1)
|
2011-06-15 02:18:45 -04:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Dump the a table entry to a stream interface's
|
|
|
|
|
* read buffer. It returns 0 if the output buffer is full
|
|
|
|
|
* and needs to be called again, otherwise non-zero.
|
|
|
|
|
*/
|
|
|
|
|
static int stats_dump_table_entry_to_buffer(struct chunk *msg, struct stream_interface *si,
|
|
|
|
|
struct proxy *proxy, struct stksess *entry)
|
|
|
|
|
{
|
|
|
|
|
int dt;
|
|
|
|
|
|
|
|
|
|
chunk_printf(msg, "%p:", entry);
|
|
|
|
|
|
|
|
|
|
if (proxy->table.type == STKTABLE_TYPE_IP) {
|
|
|
|
|
char addr[INET_ADDRSTRLEN];
|
|
|
|
|
inet_ntop(AF_INET, (const void *)&entry->key.key, addr, sizeof(addr));
|
|
|
|
|
chunk_printf(msg, " key=%s", addr);
|
|
|
|
|
}
|
|
|
|
|
else if (proxy->table.type == STKTABLE_TYPE_IPV6) {
|
|
|
|
|
char addr[INET6_ADDRSTRLEN];
|
|
|
|
|
inet_ntop(AF_INET6, (const void *)&entry->key.key, addr, sizeof(addr));
|
|
|
|
|
chunk_printf(msg, " key=%s", addr);
|
|
|
|
|
}
|
|
|
|
|
else if (proxy->table.type == STKTABLE_TYPE_INTEGER) {
|
|
|
|
|
chunk_printf(msg, " key=%u", *(unsigned int *)entry->key.key);
|
|
|
|
|
}
|
|
|
|
|
else if (proxy->table.type == STKTABLE_TYPE_STRING) {
|
|
|
|
|
chunk_printf(msg, " key=");
|
|
|
|
|
dump_text(msg, (const char *)entry->key.key, proxy->table.key_size);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
chunk_printf(msg, " key=");
|
|
|
|
|
dump_binary(msg, (const char *)entry->key.key, proxy->table.key_size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
chunk_printf(msg, " use=%d exp=%d", entry->ref_cnt - 1, tick_remain(now_ms, entry->expire));
|
|
|
|
|
|
|
|
|
|
for (dt = 0; dt < STKTABLE_DATA_TYPES; dt++) {
|
|
|
|
|
void *ptr;
|
|
|
|
|
|
|
|
|
|
if (proxy->table.data_ofs[dt] == 0)
|
|
|
|
|
continue;
|
|
|
|
|
if (stktable_data_types[dt].arg_type == ARG_T_DELAY)
|
|
|
|
|
chunk_printf(msg, " %s(%d)=", stktable_data_types[dt].name, proxy->table.data_arg[dt].u);
|
|
|
|
|
else
|
|
|
|
|
chunk_printf(msg, " %s=", stktable_data_types[dt].name);
|
|
|
|
|
|
|
|
|
|
ptr = stktable_data_ptr(&proxy->table, entry, dt);
|
|
|
|
|
switch (stktable_data_types[dt].std_type) {
|
|
|
|
|
case STD_T_SINT:
|
|
|
|
|
chunk_printf(msg, "%d", stktable_data_cast(ptr, std_t_sint));
|
|
|
|
|
break;
|
|
|
|
|
case STD_T_UINT:
|
|
|
|
|
chunk_printf(msg, "%u", stktable_data_cast(ptr, std_t_uint));
|
|
|
|
|
break;
|
|
|
|
|
case STD_T_ULL:
|
|
|
|
|
chunk_printf(msg, "%lld", stktable_data_cast(ptr, std_t_ull));
|
|
|
|
|
break;
|
|
|
|
|
case STD_T_FRQP:
|
|
|
|
|
chunk_printf(msg, "%d",
|
|
|
|
|
read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
|
|
|
|
|
proxy->table.data_arg[dt].u));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
chunk_printf(msg, "\n");
|
|
|
|
|
|
2012-05-07 05:56:55 -04:00
|
|
|
if (bi_putchk(si->ib, msg) == -1)
|
2011-06-15 02:18:45 -04:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-06-06 17:37:08 -04:00
|
|
|
static void stats_sock_table_key_request(struct stream_interface *si, char **args, int action)
|
2011-06-15 02:18:46 -04:00
|
|
|
{
|
2012-05-21 11:09:48 -04:00
|
|
|
struct session *s = si->conn.data_ctx;
|
2011-06-15 02:18:48 -04:00
|
|
|
struct proxy *px = si->applet.ctx.table.target;
|
2011-06-15 02:18:46 -04:00
|
|
|
struct stksess *ts;
|
2011-06-15 02:18:51 -04:00
|
|
|
uint32_t uint32_key;
|
2011-06-15 02:18:50 -04:00
|
|
|
unsigned char ip6_key[sizeof(struct in6_addr)];
|
2012-06-06 17:37:08 -04:00
|
|
|
struct chunk msg;
|
2012-06-06 19:03:16 -04:00
|
|
|
long long value;
|
|
|
|
|
int data_type;
|
|
|
|
|
void *ptr;
|
|
|
|
|
struct freq_ctr_period *frqp;
|
2011-06-15 02:18:46 -04:00
|
|
|
|
2011-06-15 02:18:48 -04:00
|
|
|
si->applet.st0 = STAT_CLI_OUTPUT;
|
2011-06-15 02:18:46 -04:00
|
|
|
|
|
|
|
|
if (!*args[4]) {
|
|
|
|
|
si->applet.ctx.cli.msg = "Key value expected\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-15 02:18:50 -04:00
|
|
|
switch (px->table.type) {
|
|
|
|
|
case STKTABLE_TYPE_IP:
|
2011-06-15 02:18:51 -04:00
|
|
|
uint32_key = htonl(inetaddr_host(args[4]));
|
|
|
|
|
static_table_key.key = &uint32_key;
|
2011-06-15 02:18:50 -04:00
|
|
|
break;
|
|
|
|
|
case STKTABLE_TYPE_IPV6:
|
|
|
|
|
inet_pton(AF_INET6, args[4], ip6_key);
|
|
|
|
|
static_table_key.key = &ip6_key;
|
|
|
|
|
break;
|
2011-06-15 02:18:51 -04:00
|
|
|
case STKTABLE_TYPE_INTEGER:
|
|
|
|
|
{
|
|
|
|
|
char *endptr;
|
|
|
|
|
unsigned long val;
|
|
|
|
|
errno = 0;
|
|
|
|
|
val = strtoul(args[4], &endptr, 10);
|
|
|
|
|
if ((errno == ERANGE && val == ULONG_MAX) ||
|
|
|
|
|
(errno != 0 && val == 0) || endptr == args[4] ||
|
|
|
|
|
val > 0xffffffff) {
|
|
|
|
|
si->applet.ctx.cli.msg = "Invalid key\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
uint32_key = (uint32_t) val;
|
|
|
|
|
static_table_key.key = &uint32_key;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
2011-06-15 02:18:52 -04:00
|
|
|
case STKTABLE_TYPE_STRING:
|
|
|
|
|
static_table_key.key = args[4];
|
|
|
|
|
static_table_key.key_len = strlen(args[4]);
|
|
|
|
|
break;
|
2011-06-15 02:18:50 -04:00
|
|
|
default:
|
2012-06-06 17:37:08 -04:00
|
|
|
switch (action) {
|
|
|
|
|
case STAT_CLI_O_TAB:
|
|
|
|
|
si->applet.ctx.cli.msg = "Showing keys from tables of type other than ip, ipv6, string and integer is not supported\n";
|
|
|
|
|
break;
|
|
|
|
|
case STAT_CLI_O_CLR:
|
|
|
|
|
si->applet.ctx.cli.msg = "Removing keys from ip tables of type other than ip, ipv6, string and integer is not supported\n";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
si->applet.ctx.cli.msg = "Unknown action\n";
|
|
|
|
|
break;
|
|
|
|
|
}
|
2011-06-15 02:18:46 -04:00
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* check permissions */
|
|
|
|
|
if (s->listener->perm.ux.level < ACCESS_LVL_OPER) {
|
|
|
|
|
si->applet.ctx.cli.msg = stats_permission_denied_msg;
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ts = stktable_lookup_key(&px->table, &static_table_key);
|
2011-06-15 02:18:47 -04:00
|
|
|
|
2012-06-06 17:37:08 -04:00
|
|
|
switch (action) {
|
|
|
|
|
case STAT_CLI_O_TAB:
|
|
|
|
|
if (!ts)
|
|
|
|
|
return;
|
2012-05-16 08:16:48 -04:00
|
|
|
chunk_init(&msg, trash, trashlen);
|
2011-06-15 02:18:47 -04:00
|
|
|
if (!stats_dump_table_head_to_buffer(&msg, si, px, px))
|
|
|
|
|
return;
|
|
|
|
|
stats_dump_table_entry_to_buffer(&msg, si, px, ts);
|
2011-06-15 02:18:46 -04:00
|
|
|
return;
|
2011-06-15 02:18:47 -04:00
|
|
|
|
2012-06-06 17:37:08 -04:00
|
|
|
case STAT_CLI_O_CLR:
|
|
|
|
|
if (!ts)
|
|
|
|
|
return;
|
|
|
|
|
if (ts->ref_cnt) {
|
|
|
|
|
/* don't delete an entry which is currently referenced */
|
|
|
|
|
si->applet.ctx.cli.msg = "Entry currently in use, cannot remove\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
stksess_kill(&px->table, ts);
|
|
|
|
|
break;
|
|
|
|
|
|
2012-06-06 19:03:16 -04:00
|
|
|
case STAT_CLI_O_SET:
|
|
|
|
|
if (strncmp(args[5], "data.", 5) != 0) {
|
|
|
|
|
si->applet.ctx.cli.msg = "\"data.<type>\" followed by a value expected\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
data_type = stktable_get_data_type(args[5] + 5);
|
|
|
|
|
if (data_type < 0) {
|
|
|
|
|
si->applet.ctx.cli.msg = "Unknown data type\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!px->table.data_ofs[data_type]) {
|
|
|
|
|
si->applet.ctx.cli.msg = "Data type not stored in this table\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!*args[6] || strl2llrc(args[6], strlen(args[6]), &value) != 0) {
|
|
|
|
|
si->applet.ctx.cli.msg = "Require a valid integer value to store\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ts)
|
|
|
|
|
stktable_touch(&px->table, ts, 1);
|
|
|
|
|
else {
|
|
|
|
|
ts = stksess_new(&px->table, &static_table_key);
|
|
|
|
|
if (!ts) {
|
|
|
|
|
/* don't delete an entry which is currently referenced */
|
|
|
|
|
si->applet.ctx.cli.msg = "Unable to allocate a new entry\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
stktable_store(&px->table, ts, 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ptr = stktable_data_ptr(&px->table, ts, data_type);
|
|
|
|
|
switch (stktable_data_types[data_type].std_type) {
|
|
|
|
|
case STD_T_SINT:
|
|
|
|
|
stktable_data_cast(ptr, std_t_sint) = value;
|
|
|
|
|
break;
|
|
|
|
|
case STD_T_UINT:
|
|
|
|
|
stktable_data_cast(ptr, std_t_uint) = value;
|
|
|
|
|
break;
|
|
|
|
|
case STD_T_ULL:
|
|
|
|
|
stktable_data_cast(ptr, std_t_ull) = value;
|
|
|
|
|
break;
|
|
|
|
|
case STD_T_FRQP:
|
|
|
|
|
/* We only reset the previous value so that it slowly fades out */
|
|
|
|
|
frqp = &stktable_data_cast(ptr, std_t_frqp);
|
|
|
|
|
frqp->curr_tick = now_ms;
|
|
|
|
|
frqp->prev_ctr = value;
|
|
|
|
|
frqp->curr_ctr = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2012-06-06 17:37:08 -04:00
|
|
|
default:
|
|
|
|
|
si->applet.ctx.cli.msg = "Unknown action\n";
|
2011-06-15 02:18:46 -04:00
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
2012-06-06 17:37:08 -04:00
|
|
|
break;
|
2011-06-15 02:18:46 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-06-06 19:03:16 -04:00
|
|
|
static void stats_sock_table_data_request(struct stream_interface *si, char **args, int action)
|
2011-06-15 02:18:48 -04:00
|
|
|
{
|
2012-06-06 19:03:16 -04:00
|
|
|
if (action != STAT_CLI_O_TAB) {
|
|
|
|
|
si->applet.ctx.cli.msg = "content-based lookup is only supported with the \"show\" action";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-15 02:18:48 -04:00
|
|
|
/* condition on stored data value */
|
|
|
|
|
si->applet.ctx.table.data_type = stktable_get_data_type(args[3] + 5);
|
|
|
|
|
if (si->applet.ctx.table.data_type < 0) {
|
|
|
|
|
si->applet.ctx.cli.msg = "Unknown data type\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!((struct proxy *)si->applet.ctx.table.target)->table.data_ofs[si->applet.ctx.table.data_type]) {
|
|
|
|
|
si->applet.ctx.cli.msg = "Data type not stored in this table\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
si->applet.ctx.table.data_op = get_std_op(args[4]);
|
|
|
|
|
if (si->applet.ctx.table.data_op < 0) {
|
|
|
|
|
si->applet.ctx.cli.msg = "Require and operator among \"eq\", \"ne\", \"le\", \"ge\", \"lt\", \"gt\"\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!*args[5] || strl2llrc(args[5], strlen(args[5]), &si->applet.ctx.table.value) != 0) {
|
|
|
|
|
si->applet.ctx.cli.msg = "Require a valid integer value to compare against\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-06-06 17:37:08 -04:00
|
|
|
static void stats_sock_table_request(struct stream_interface *si, char **args, int action)
|
2011-06-15 02:18:48 -04:00
|
|
|
{
|
|
|
|
|
si->applet.ctx.table.data_type = -1;
|
2012-05-21 11:09:48 -04:00
|
|
|
si->conn.data_st = STAT_ST_INIT;
|
2011-08-24 02:23:34 -04:00
|
|
|
si->applet.ctx.table.target = NULL;
|
2011-06-15 02:18:48 -04:00
|
|
|
si->applet.ctx.table.proxy = NULL;
|
|
|
|
|
si->applet.ctx.table.entry = NULL;
|
2012-06-06 17:37:08 -04:00
|
|
|
si->applet.st0 = action;
|
2011-06-15 02:18:48 -04:00
|
|
|
|
|
|
|
|
if (*args[2]) {
|
|
|
|
|
si->applet.ctx.table.target = find_stktable(args[2]);
|
|
|
|
|
if (!si->applet.ctx.table.target) {
|
|
|
|
|
si->applet.ctx.cli.msg = "No such table\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2012-06-06 17:37:08 -04:00
|
|
|
if (action != STAT_CLI_O_TAB)
|
2011-06-15 02:18:48 -04:00
|
|
|
goto err_args;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (strcmp(args[3], "key") == 0)
|
2012-06-06 17:37:08 -04:00
|
|
|
stats_sock_table_key_request(si, args, action);
|
2011-06-15 02:18:49 -04:00
|
|
|
else if (strncmp(args[3], "data.", 5) == 0)
|
2012-06-06 19:03:16 -04:00
|
|
|
stats_sock_table_data_request(si, args, action);
|
2011-06-15 02:18:49 -04:00
|
|
|
else if (*args[3])
|
2011-06-15 02:18:48 -04:00
|
|
|
goto err_args;
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
err_args:
|
2012-06-06 17:37:08 -04:00
|
|
|
switch (action) {
|
|
|
|
|
case STAT_CLI_O_TAB:
|
2011-06-15 02:18:48 -04:00
|
|
|
si->applet.ctx.cli.msg = "Optional argument only supports \"data.<store_data_type>\" <operator> <value> and key <key>\n";
|
2012-06-06 17:37:08 -04:00
|
|
|
break;
|
|
|
|
|
case STAT_CLI_O_CLR:
|
2011-06-15 02:18:49 -04:00
|
|
|
si->applet.ctx.cli.msg = "Required arguments: <table> \"data.<store_data_type>\" <operator> <value> or <table> key <key>\n";
|
2012-06-06 17:37:08 -04:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
si->applet.ctx.cli.msg = "Unknown action\n";
|
|
|
|
|
break;
|
|
|
|
|
}
|
2011-06-15 02:18:48 -04:00
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
}
|
|
|
|
|
|
2011-09-07 16:37:44 -04:00
|
|
|
/* Expects to find a frontend named <arg> and returns it, otherwise displays various
|
|
|
|
|
* adequate error messages and returns NULL. This function also expects the session
|
|
|
|
|
* level to be admin.
|
|
|
|
|
*/
|
|
|
|
|
static struct proxy *expect_frontend_admin(struct session *s, struct stream_interface *si, const char *arg)
|
|
|
|
|
{
|
|
|
|
|
struct proxy *px;
|
|
|
|
|
|
|
|
|
|
if (s->listener->perm.ux.level < ACCESS_LVL_ADMIN) {
|
|
|
|
|
si->applet.ctx.cli.msg = stats_permission_denied_msg;
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!*arg) {
|
|
|
|
|
si->applet.ctx.cli.msg = "A frontend name is expected.\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
px = findproxy(arg, PR_CAP_FE);
|
|
|
|
|
if (!px) {
|
|
|
|
|
si->applet.ctx.cli.msg = "No such frontend.\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
return px;
|
|
|
|
|
}
|
|
|
|
|
|
2011-09-07 17:41:01 -04:00
|
|
|
/* Expects to find a backend and a server in <arg> under the form <backend>/<server>,
|
|
|
|
|
* and returns the pointer to the server. Otherwise, display adequate error messages
|
|
|
|
|
* and returns NULL. This function also expects the session level to be admin. Note:
|
|
|
|
|
* the <arg> is modified to remove the '/'.
|
|
|
|
|
*/
|
|
|
|
|
static struct server *expect_server_admin(struct session *s, struct stream_interface *si, char *arg)
|
|
|
|
|
{
|
|
|
|
|
struct proxy *px;
|
|
|
|
|
struct server *sv;
|
|
|
|
|
char *line;
|
|
|
|
|
|
|
|
|
|
if (s->listener->perm.ux.level < ACCESS_LVL_ADMIN) {
|
|
|
|
|
si->applet.ctx.cli.msg = stats_permission_denied_msg;
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* split "backend/server" and make <line> point to server */
|
|
|
|
|
for (line = arg; *line; line++)
|
|
|
|
|
if (*line == '/') {
|
|
|
|
|
*line++ = '\0';
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!*line || !*arg) {
|
|
|
|
|
si->applet.ctx.cli.msg = "Require 'backend/server'.\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!get_backend_server(arg, line, &px, &sv)) {
|
|
|
|
|
si->applet.ctx.cli.msg = px ? "No such server.\n" : "No such backend.\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (px->state == PR_STSTOPPED) {
|
|
|
|
|
si->applet.ctx.cli.msg = "Proxy is disabled.\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sv;
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-22 13:31:03 -04:00
|
|
|
/* Processes the stats interpreter on the statistics socket. This function is
|
2009-10-04 08:22:18 -04:00
|
|
|
* called from an applet running in a stream interface. The function returns 1
|
2011-02-13 07:25:14 -05:00
|
|
|
* if the request was understood, otherwise zero. It sets si->applet.st0 to a value
|
2009-10-11 17:12:51 -04:00
|
|
|
* designating the function which will have to process the request, which can
|
|
|
|
|
* also be the print function to display the return message set into cli.msg.
|
2009-08-16 13:06:42 -04:00
|
|
|
*/
|
2011-06-15 02:18:44 -04:00
|
|
|
static int stats_sock_parse_request(struct stream_interface *si, char *line)
|
2009-08-16 13:06:42 -04:00
|
|
|
{
|
2012-05-21 11:09:48 -04:00
|
|
|
struct session *s = si->conn.data_ctx;
|
2009-08-16 13:06:42 -04:00
|
|
|
char *args[MAX_STATS_ARGS + 1];
|
|
|
|
|
int arg;
|
|
|
|
|
|
|
|
|
|
while (isspace((unsigned char)*line))
|
|
|
|
|
line++;
|
|
|
|
|
|
|
|
|
|
arg = 0;
|
|
|
|
|
args[arg] = line;
|
|
|
|
|
|
|
|
|
|
while (*line && arg < MAX_STATS_ARGS) {
|
|
|
|
|
if (isspace((unsigned char)*line)) {
|
|
|
|
|
*line++ = '\0';
|
|
|
|
|
|
|
|
|
|
while (isspace((unsigned char)*line))
|
|
|
|
|
line++;
|
|
|
|
|
|
|
|
|
|
args[++arg] = line;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
line++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (++arg <= MAX_STATS_ARGS)
|
|
|
|
|
args[arg] = line;
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.stats.flags = 0;
|
2009-08-16 13:06:42 -04:00
|
|
|
if (strcmp(args[0], "show") == 0) {
|
|
|
|
|
if (strcmp(args[1], "stat") == 0) {
|
|
|
|
|
if (*args[2] && *args[3] && *args[4]) {
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.stats.flags |= STAT_BOUND;
|
|
|
|
|
si->applet.ctx.stats.iid = atoi(args[2]);
|
|
|
|
|
si->applet.ctx.stats.type = atoi(args[3]);
|
|
|
|
|
si->applet.ctx.stats.sid = atoi(args[4]);
|
2009-08-16 13:06:42 -04:00
|
|
|
}
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.stats.flags |= STAT_SHOW_STAT;
|
|
|
|
|
si->applet.ctx.stats.flags |= STAT_FMT_CSV;
|
2012-05-21 11:09:48 -04:00
|
|
|
si->conn.data_st = STAT_ST_INIT;
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = STAT_CLI_O_INFO; // stats_dump_raw_to_buffer
|
2009-08-16 13:06:42 -04:00
|
|
|
}
|
|
|
|
|
else if (strcmp(args[1], "info") == 0) {
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.stats.flags |= STAT_SHOW_INFO;
|
|
|
|
|
si->applet.ctx.stats.flags |= STAT_FMT_CSV;
|
2012-05-21 11:09:48 -04:00
|
|
|
si->conn.data_st = STAT_ST_INIT;
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = STAT_CLI_O_INFO; // stats_dump_raw_to_buffer
|
2009-08-16 13:06:42 -04:00
|
|
|
}
|
|
|
|
|
else if (strcmp(args[1], "sess") == 0) {
|
2012-05-21 11:09:48 -04:00
|
|
|
si->conn.data_st = STAT_ST_INIT;
|
2009-10-10 11:13:00 -04:00
|
|
|
if (s->listener->perm.ux.level < ACCESS_LVL_OPER) {
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.cli.msg = stats_permission_denied_msg;
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
2009-10-10 11:13:00 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
2010-03-05 11:53:32 -05:00
|
|
|
if (*args[2])
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.sess.target = (void *)strtoul(args[2], NULL, 0);
|
2010-03-05 11:53:32 -05:00
|
|
|
else
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.sess.target = NULL;
|
|
|
|
|
si->applet.ctx.sess.section = 0; /* start with session status */
|
|
|
|
|
si->applet.ctx.sess.pos = 0;
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = STAT_CLI_O_SESS; // stats_dump_sess_to_buffer
|
2009-08-16 13:06:42 -04:00
|
|
|
}
|
|
|
|
|
else if (strcmp(args[1], "errors") == 0) {
|
2009-10-10 11:13:00 -04:00
|
|
|
if (s->listener->perm.ux.level < ACCESS_LVL_OPER) {
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.cli.msg = stats_permission_denied_msg;
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
2009-10-10 11:13:00 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
2009-08-16 13:06:42 -04:00
|
|
|
if (*args[2])
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.errors.iid = atoi(args[2]);
|
2009-08-16 13:06:42 -04:00
|
|
|
else
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.errors.iid = -1;
|
|
|
|
|
si->applet.ctx.errors.px = NULL;
|
2012-05-21 11:09:48 -04:00
|
|
|
si->conn.data_st = STAT_ST_INIT;
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = STAT_CLI_O_ERR; // stats_dump_errors_to_buffer
|
2009-08-16 13:06:42 -04:00
|
|
|
}
|
2010-07-12 11:55:33 -04:00
|
|
|
else if (strcmp(args[1], "table") == 0) {
|
2012-06-06 17:37:08 -04:00
|
|
|
stats_sock_table_request(si, args, STAT_CLI_O_TAB);
|
2010-07-12 11:55:33 -04:00
|
|
|
}
|
2012-04-02 21:57:54 -04:00
|
|
|
else { /* neither "stat" nor "info" nor "sess" nor "errors" nor "table" */
|
2009-08-16 13:06:42 -04:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-10-04 09:02:46 -04:00
|
|
|
else if (strcmp(args[0], "clear") == 0) {
|
|
|
|
|
if (strcmp(args[1], "counters") == 0) {
|
|
|
|
|
struct proxy *px;
|
|
|
|
|
struct server *sv;
|
2009-10-04 09:43:17 -04:00
|
|
|
struct listener *li;
|
2009-10-10 09:26:26 -04:00
|
|
|
int clrall = 0;
|
|
|
|
|
|
|
|
|
|
if (strcmp(args[2], "all") == 0)
|
|
|
|
|
clrall = 1;
|
2009-10-04 09:02:46 -04:00
|
|
|
|
2009-10-10 11:13:00 -04:00
|
|
|
/* check permissions */
|
|
|
|
|
if (s->listener->perm.ux.level < ACCESS_LVL_OPER ||
|
|
|
|
|
(clrall && s->listener->perm.ux.level < ACCESS_LVL_ADMIN)) {
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.cli.msg = stats_permission_denied_msg;
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
2009-10-10 11:13:00 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-10-04 09:02:46 -04:00
|
|
|
for (px = proxy; px; px = px->next) {
|
2011-03-10 17:25:56 -05:00
|
|
|
if (clrall) {
|
|
|
|
|
memset(&px->be_counters, 0, sizeof(px->be_counters));
|
|
|
|
|
memset(&px->fe_counters, 0, sizeof(px->fe_counters));
|
|
|
|
|
}
|
2009-10-10 09:26:26 -04:00
|
|
|
else {
|
2011-03-10 17:25:56 -05:00
|
|
|
px->be_counters.conn_max = 0;
|
|
|
|
|
px->be_counters.p.http.rps_max = 0;
|
|
|
|
|
px->be_counters.sps_max = 0;
|
|
|
|
|
px->be_counters.cps_max = 0;
|
|
|
|
|
px->be_counters.nbpend_max = 0;
|
|
|
|
|
|
|
|
|
|
px->fe_counters.conn_max = 0;
|
|
|
|
|
px->fe_counters.p.http.rps_max = 0;
|
|
|
|
|
px->fe_counters.sps_max = 0;
|
|
|
|
|
px->fe_counters.cps_max = 0;
|
|
|
|
|
px->fe_counters.nbpend_max = 0;
|
2009-10-10 09:26:26 -04:00
|
|
|
}
|
2009-10-04 09:02:46 -04:00
|
|
|
|
|
|
|
|
for (sv = px->srv; sv; sv = sv->next)
|
2009-10-10 09:26:26 -04:00
|
|
|
if (clrall)
|
|
|
|
|
memset(&sv->counters, 0, sizeof(sv->counters));
|
|
|
|
|
else {
|
|
|
|
|
sv->counters.cur_sess_max = 0;
|
|
|
|
|
sv->counters.nbpend_max = 0;
|
|
|
|
|
sv->counters.sps_max = 0;
|
|
|
|
|
}
|
2009-10-04 09:43:17 -04:00
|
|
|
|
|
|
|
|
for (li = px->listen; li; li = li->next)
|
2009-10-10 09:26:26 -04:00
|
|
|
if (li->counters) {
|
|
|
|
|
if (clrall)
|
|
|
|
|
memset(li->counters, 0, sizeof(*li->counters));
|
|
|
|
|
else
|
|
|
|
|
li->counters->conn_max = 0;
|
|
|
|
|
}
|
2009-10-04 09:02:46 -04:00
|
|
|
}
|
|
|
|
|
|
2011-09-07 09:17:21 -04:00
|
|
|
global.cps_max = 0;
|
2009-10-04 09:02:46 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
2010-07-13 07:48:00 -04:00
|
|
|
else if (strcmp(args[1], "table") == 0) {
|
2012-06-06 17:37:08 -04:00
|
|
|
stats_sock_table_request(si, args, STAT_CLI_O_CLR);
|
2010-07-13 07:48:00 -04:00
|
|
|
/* end of processing */
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2009-10-04 09:02:46 -04:00
|
|
|
else {
|
2010-07-13 07:48:00 -04:00
|
|
|
/* unknown "clear" argument */
|
2009-10-04 09:02:46 -04:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-10-10 12:37:29 -04:00
|
|
|
else if (strcmp(args[0], "get") == 0) {
|
|
|
|
|
if (strcmp(args[1], "weight") == 0) {
|
|
|
|
|
struct proxy *px;
|
|
|
|
|
struct server *sv;
|
|
|
|
|
|
|
|
|
|
/* split "backend/server" and make <line> point to server */
|
|
|
|
|
for (line = args[2]; *line; line++)
|
|
|
|
|
if (*line == '/') {
|
|
|
|
|
*line++ = '\0';
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!*line) {
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.cli.msg = "Require 'backend/server'.\n";
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
2009-10-10 12:37:29 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!get_backend_server(args[2], line, &px, &sv)) {
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.cli.msg = px ? "No such server.\n" : "No such backend.\n";
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
2009-10-10 12:37:29 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* return server's effective weight at the moment */
|
2012-05-16 08:16:48 -04:00
|
|
|
snprintf(trash, trashlen, "%d (initial %d)\n", sv->uweight, sv->iweight);
|
2012-05-07 05:56:55 -04:00
|
|
|
bi_putstr(si->ib, trash);
|
2009-10-10 12:37:29 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
else { /* not "get weight" */
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-10-10 13:30:08 -04:00
|
|
|
else if (strcmp(args[0], "set") == 0) {
|
|
|
|
|
if (strcmp(args[1], "weight") == 0) {
|
|
|
|
|
struct proxy *px;
|
|
|
|
|
struct server *sv;
|
|
|
|
|
int w;
|
|
|
|
|
|
2011-09-07 17:41:01 -04:00
|
|
|
sv = expect_server_admin(s, si, args[2]);
|
|
|
|
|
if (!sv)
|
2009-10-10 13:30:08 -04:00
|
|
|
return 1;
|
2011-09-07 17:41:01 -04:00
|
|
|
px = sv->proxy;
|
2009-10-10 13:30:08 -04:00
|
|
|
|
2011-09-07 17:41:01 -04:00
|
|
|
/* if the weight is terminated with '%', it is set relative to
|
|
|
|
|
* the initial weight, otherwise it is absolute.
|
|
|
|
|
*/
|
|
|
|
|
if (!*args[3]) {
|
|
|
|
|
si->applet.ctx.cli.msg = "Require <weight> or <weight%>.\n";
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
2011-03-03 14:49:04 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-10-10 13:30:08 -04:00
|
|
|
w = atoi(args[3]);
|
|
|
|
|
if (strchr(args[3], '%') != NULL) {
|
|
|
|
|
if (w < 0 || w > 100) {
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.cli.msg = "Relative weight can only be set between 0 and 100% inclusive.\n";
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
2009-10-10 13:30:08 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
w = sv->iweight * w / 100;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (w < 0 || w > 256) {
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.cli.msg = "Absolute weight can only be between 0 and 256 inclusive.\n";
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
2009-10-10 13:30:08 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (w && w != sv->iweight && !(px->lbprm.algo & BE_LB_PROP_DYN)) {
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.cli.msg = "Backend is using a static LB algorithm and only accepts weights '0%' and '100%'.\n";
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
2009-10-10 13:30:08 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sv->uweight = w;
|
|
|
|
|
|
|
|
|
|
if (px->lbprm.algo & BE_LB_PROP_DYN) {
|
|
|
|
|
/* we must take care of not pushing the server to full throttle during slow starts */
|
|
|
|
|
if ((sv->state & SRV_WARMINGUP) && (px->lbprm.algo & BE_LB_PROP_DYN))
|
|
|
|
|
sv->eweight = (BE_WEIGHT_SCALE * (now.tv_sec - sv->last_change) + sv->slowstart - 1) / sv->slowstart;
|
|
|
|
|
else
|
|
|
|
|
sv->eweight = BE_WEIGHT_SCALE;
|
|
|
|
|
sv->eweight *= sv->uweight;
|
|
|
|
|
} else {
|
|
|
|
|
sv->eweight = sv->uweight;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* static LB algorithms are a bit harder to update */
|
|
|
|
|
if (px->lbprm.update_server_eweight)
|
|
|
|
|
px->lbprm.update_server_eweight(sv);
|
2012-05-19 13:07:40 -04:00
|
|
|
else if (sv->eweight) {
|
|
|
|
|
if (px->lbprm.set_server_status_up)
|
|
|
|
|
px->lbprm.set_server_status_up(sv);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (px->lbprm.set_server_status_down)
|
|
|
|
|
px->lbprm.set_server_status_down(sv);
|
|
|
|
|
}
|
2009-10-10 13:30:08 -04:00
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2010-01-26 04:59:06 -05:00
|
|
|
else if (strcmp(args[1], "timeout") == 0) {
|
|
|
|
|
if (strcmp(args[2], "cli") == 0) {
|
|
|
|
|
unsigned timeout;
|
|
|
|
|
const char *res;
|
|
|
|
|
|
|
|
|
|
if (!*args[3]) {
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.cli.msg = "Expects an integer value.\n";
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
2010-01-26 04:59:06 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
res = parse_time_err(args[3], &timeout, TIME_UNIT_S);
|
|
|
|
|
if (res || timeout < 1) {
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.cli.msg = "Invalid timeout value.\n";
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
2010-01-26 04:59:06 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s->req->rto = s->rep->wto = 1 + MS_TO_TICKS(timeout*1000);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
else {
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.cli.msg = "'set timeout' only supports 'cli'.\n";
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
2010-01-26 04:59:06 -05:00
|
|
|
return 1;
|
2011-08-02 05:49:05 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (strcmp(args[1], "maxconn") == 0) {
|
|
|
|
|
if (strcmp(args[2], "frontend") == 0) {
|
|
|
|
|
struct proxy *px;
|
|
|
|
|
struct listener *l;
|
|
|
|
|
int v;
|
|
|
|
|
|
2011-09-07 16:37:44 -04:00
|
|
|
px = expect_frontend_admin(s, si, args[3]);
|
|
|
|
|
if (!px)
|
2011-08-02 05:49:05 -04:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
if (!*args[4]) {
|
|
|
|
|
si->applet.ctx.cli.msg = "Integer value expected.\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
v = atoi(args[4]);
|
|
|
|
|
/* check for unlimited values, we restore default setting (cfg_maxpconn) */
|
|
|
|
|
if (v < 1) {
|
|
|
|
|
si->applet.ctx.cli.msg = "Value out of range.\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* OK, the value is fine, so we assign it to the proxy and to all of
|
|
|
|
|
* its listeners. The blocked ones will be dequeued.
|
|
|
|
|
*/
|
|
|
|
|
px->maxconn = v;
|
|
|
|
|
for (l = px->listen; l != NULL; l = l->next) {
|
|
|
|
|
l->maxconn = v;
|
|
|
|
|
if (l->state == LI_FULL)
|
|
|
|
|
resume_listener(l);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (px->maxconn > px->feconn && !LIST_ISEMPTY(&s->fe->listener_queue))
|
|
|
|
|
dequeue_all_listeners(&s->fe->listener_queue);
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2011-09-07 08:38:31 -04:00
|
|
|
else if (strcmp(args[2], "global") == 0) {
|
|
|
|
|
int v;
|
|
|
|
|
|
|
|
|
|
if (s->listener->perm.ux.level < ACCESS_LVL_ADMIN) {
|
|
|
|
|
si->applet.ctx.cli.msg = stats_permission_denied_msg;
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!*args[3]) {
|
|
|
|
|
si->applet.ctx.cli.msg = "Expects an integer value.\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
v = atoi(args[3]);
|
|
|
|
|
if (v > global.hardmaxconn) {
|
|
|
|
|
si->applet.ctx.cli.msg = "Value out of range.\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* check for unlimited values */
|
|
|
|
|
if (v <= 0)
|
|
|
|
|
v = global.hardmaxconn;
|
|
|
|
|
|
|
|
|
|
global.maxconn = v;
|
|
|
|
|
|
|
|
|
|
/* Dequeues all of the listeners waiting for a resource */
|
|
|
|
|
if (!LIST_ISEMPTY(&global_listener_queue))
|
|
|
|
|
dequeue_all_listeners(&global_listener_queue);
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2011-08-02 05:49:05 -04:00
|
|
|
else {
|
2011-09-07 08:38:31 -04:00
|
|
|
si->applet.ctx.cli.msg = "'set maxconn' only supports 'frontend' and 'global'.\n";
|
2011-08-02 05:49:05 -04:00
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return 1;
|
2010-01-26 04:59:06 -05:00
|
|
|
}
|
|
|
|
|
}
|
2011-09-07 10:13:44 -04:00
|
|
|
else if (strcmp(args[1], "rate-limit") == 0) {
|
|
|
|
|
if (strcmp(args[2], "connections") == 0) {
|
|
|
|
|
if (strcmp(args[3], "global") == 0) {
|
|
|
|
|
int v;
|
|
|
|
|
|
|
|
|
|
if (s->listener->perm.ux.level < ACCESS_LVL_ADMIN) {
|
|
|
|
|
si->applet.ctx.cli.msg = stats_permission_denied_msg;
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!*args[4]) {
|
|
|
|
|
si->applet.ctx.cli.msg = "Expects an integer value.\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
v = atoi(args[4]);
|
|
|
|
|
if (v < 0) {
|
|
|
|
|
si->applet.ctx.cli.msg = "Value out of range.\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
global.cps_lim = v;
|
|
|
|
|
|
|
|
|
|
/* Dequeues all of the listeners waiting for a resource */
|
|
|
|
|
if (!LIST_ISEMPTY(&global_listener_queue))
|
|
|
|
|
dequeue_all_listeners(&global_listener_queue);
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
si->applet.ctx.cli.msg = "'set rate-limit connections' only supports 'global'.\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
si->applet.ctx.cli.msg = "'set rate-limit' only supports 'connections'.\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-06-06 19:03:16 -04:00
|
|
|
else if (strcmp(args[1], "table") == 0) {
|
|
|
|
|
stats_sock_table_request(si, args, STAT_CLI_O_SET);
|
|
|
|
|
}
|
2010-01-26 04:59:06 -05:00
|
|
|
else { /* unknown "set" parameter */
|
2009-10-10 13:30:08 -04:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-01-31 16:34:03 -05:00
|
|
|
else if (strcmp(args[0], "enable") == 0) {
|
|
|
|
|
if (strcmp(args[1], "server") == 0) {
|
|
|
|
|
struct server *sv;
|
|
|
|
|
|
2011-09-07 17:41:01 -04:00
|
|
|
sv = expect_server_admin(s, si, args[2]);
|
|
|
|
|
if (!sv)
|
2010-01-31 16:34:03 -05:00
|
|
|
return 1;
|
2011-03-03 14:49:04 -05:00
|
|
|
|
2010-01-31 16:34:03 -05:00
|
|
|
if (sv->state & SRV_MAINTAIN) {
|
|
|
|
|
/* The server is really in maintenance, we can change the server state */
|
2011-10-28 09:35:33 -04:00
|
|
|
if (sv->track) {
|
2010-01-31 16:34:03 -05:00
|
|
|
/* If this server tracks the status of another one,
|
|
|
|
|
* we must restore the good status.
|
|
|
|
|
*/
|
2011-10-28 09:35:33 -04:00
|
|
|
if (sv->track->state & SRV_RUNNING) {
|
2010-01-31 16:34:03 -05:00
|
|
|
set_server_up(sv);
|
2010-10-22 08:39:02 -04:00
|
|
|
sv->health = sv->rise; /* up, but will fall down at first failure */
|
2010-01-31 16:34:03 -05:00
|
|
|
} else {
|
|
|
|
|
sv->state &= ~SRV_MAINTAIN;
|
|
|
|
|
set_server_down(sv);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
set_server_up(sv);
|
2010-10-22 08:39:02 -04:00
|
|
|
sv->health = sv->rise; /* up, but will fall down at first failure */
|
2010-01-31 16:34:03 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2011-09-07 16:37:44 -04:00
|
|
|
else if (strcmp(args[1], "frontend") == 0) {
|
|
|
|
|
struct proxy *px;
|
|
|
|
|
|
|
|
|
|
px = expect_frontend_admin(s, si, args[2]);
|
|
|
|
|
if (!px)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
if (px->state == PR_STSTOPPED) {
|
|
|
|
|
si->applet.ctx.cli.msg = "Frontend was previously shut down, cannot enable.\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (px->state != PR_STPAUSED) {
|
|
|
|
|
si->applet.ctx.cli.msg = "Frontend is already enabled.\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!resume_proxy(px)) {
|
|
|
|
|
si->applet.ctx.cli.msg = "Failed to resume frontend, check logs for precise cause (port conflict?).\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2010-01-31 16:34:03 -05:00
|
|
|
else { /* unknown "enable" parameter */
|
2011-09-07 16:37:44 -04:00
|
|
|
si->applet.ctx.cli.msg = "'enable' only supports 'frontend' and 'server'.\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return 1;
|
2010-01-31 16:34:03 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (strcmp(args[0], "disable") == 0) {
|
|
|
|
|
if (strcmp(args[1], "server") == 0) {
|
|
|
|
|
struct server *sv;
|
|
|
|
|
|
2011-09-07 17:41:01 -04:00
|
|
|
sv = expect_server_admin(s, si, args[2]);
|
|
|
|
|
if (!sv)
|
2010-01-31 16:34:03 -05:00
|
|
|
return 1;
|
2011-03-03 14:49:04 -05:00
|
|
|
|
2010-01-31 16:34:03 -05:00
|
|
|
if (! (sv->state & SRV_MAINTAIN)) {
|
|
|
|
|
/* Not already in maintenance, we can change the server state */
|
|
|
|
|
sv->state |= SRV_MAINTAIN;
|
|
|
|
|
set_server_down(sv);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2011-09-07 16:37:44 -04:00
|
|
|
else if (strcmp(args[1], "frontend") == 0) {
|
|
|
|
|
struct proxy *px;
|
|
|
|
|
|
|
|
|
|
px = expect_frontend_admin(s, si, args[2]);
|
|
|
|
|
if (!px)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
if (px->state == PR_STSTOPPED) {
|
|
|
|
|
si->applet.ctx.cli.msg = "Frontend was previously shut down, cannot disable.\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (px->state == PR_STPAUSED) {
|
|
|
|
|
si->applet.ctx.cli.msg = "Frontend is already disabled.\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!pause_proxy(px)) {
|
|
|
|
|
si->applet.ctx.cli.msg = "Failed to pause frontend, check logs for precise cause.\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2010-01-31 16:34:03 -05:00
|
|
|
else { /* unknown "disable" parameter */
|
2011-09-07 16:37:44 -04:00
|
|
|
si->applet.ctx.cli.msg = "'disable' only supports 'frontend' and 'server'.\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (strcmp(args[0], "shutdown") == 0) {
|
|
|
|
|
if (strcmp(args[1], "frontend") == 0) {
|
|
|
|
|
struct proxy *px;
|
|
|
|
|
|
|
|
|
|
px = expect_frontend_admin(s, si, args[2]);
|
|
|
|
|
if (!px)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
if (px->state == PR_STSTOPPED) {
|
|
|
|
|
si->applet.ctx.cli.msg = "Frontend was already shut down.\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Warning("Proxy %s stopped (FE: %lld conns, BE: %lld conns).\n",
|
|
|
|
|
px->id, px->fe_counters.cum_conn, px->be_counters.cum_conn);
|
|
|
|
|
send_log(px, LOG_WARNING, "Proxy %s stopped (FE: %lld conns, BE: %lld conns).\n",
|
|
|
|
|
px->id, px->fe_counters.cum_conn, px->be_counters.cum_conn);
|
|
|
|
|
stop_proxy(px);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2011-09-07 17:21:03 -04:00
|
|
|
else if (strcmp(args[1], "session") == 0) {
|
|
|
|
|
struct session *sess, *ptr;
|
|
|
|
|
|
|
|
|
|
if (s->listener->perm.ux.level < ACCESS_LVL_ADMIN) {
|
|
|
|
|
si->applet.ctx.cli.msg = stats_permission_denied_msg;
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!*args[2]) {
|
|
|
|
|
si->applet.ctx.cli.msg = "Session pointer expected (use 'show sess').\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ptr = (void *)strtoul(args[2], NULL, 0);
|
|
|
|
|
|
|
|
|
|
/* first, look for the requested session in the session table */
|
|
|
|
|
list_for_each_entry(sess, &sessions, list) {
|
|
|
|
|
if (sess == ptr)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* do we have the session ? */
|
|
|
|
|
if (sess != ptr) {
|
|
|
|
|
si->applet.ctx.cli.msg = "No such session (use 'show sess').\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
session_shutdown(sess, SN_ERR_KILLED);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
2011-09-07 17:48:48 -04:00
|
|
|
else if (strcmp(args[1], "sessions") == 0) {
|
|
|
|
|
if (strcmp(args[2], "server") == 0) {
|
|
|
|
|
struct server *sv;
|
|
|
|
|
struct session *sess, *sess_bck;
|
|
|
|
|
|
|
|
|
|
sv = expect_server_admin(s, si, args[3]);
|
|
|
|
|
if (!sv)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
/* kill all the session that are on this server */
|
|
|
|
|
list_for_each_entry_safe(sess, sess_bck, &sv->actconns, by_srv)
|
|
|
|
|
if (sess->srv_conn == sv)
|
|
|
|
|
session_shutdown(sess, SN_ERR_KILLED);
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
si->applet.ctx.cli.msg = "'shutdown sessions' only supports 'server'.\n";
|
|
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-09-07 16:37:44 -04:00
|
|
|
else { /* unknown "disable" parameter */
|
2011-09-07 17:48:48 -04:00
|
|
|
si->applet.ctx.cli.msg = "'shutdown' only supports 'frontend', 'session' and 'sessions'.\n";
|
2011-09-07 16:37:44 -04:00
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
|
|
|
|
return 1;
|
2010-01-31 16:34:03 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else { /* not "show" nor "clear" nor "get" nor "set" nor "enable" nor "disable" */
|
2009-08-16 13:06:42 -04:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-22 13:31:03 -04:00
|
|
|
/* This I/O handler runs as an applet embedded in a stream interface. It is
|
2009-10-04 08:22:18 -04:00
|
|
|
* used to processes I/O from/to the stats unix socket. The system relies on a
|
|
|
|
|
* state machine handling requests and various responses. We read a request,
|
|
|
|
|
* then we process it and send the response, and we possibly display a prompt.
|
2011-02-13 07:25:14 -05:00
|
|
|
* Then we can read again. The state is stored in si->applet.st0 and is one of the
|
|
|
|
|
* STAT_CLI_* constants. si->applet.st1 is used to indicate whether prompt is enabled
|
2009-10-04 08:22:18 -04:00
|
|
|
* or not.
|
2009-08-16 13:06:42 -04:00
|
|
|
*/
|
2011-02-13 07:16:36 -05:00
|
|
|
static void cli_io_handler(struct stream_interface *si)
|
2009-08-16 13:06:42 -04:00
|
|
|
{
|
2012-07-02 09:11:27 -04:00
|
|
|
struct channel *req = si->ob;
|
|
|
|
|
struct channel *res = si->ib;
|
2009-09-22 13:31:03 -04:00
|
|
|
int reql;
|
|
|
|
|
int len;
|
|
|
|
|
|
|
|
|
|
if (unlikely(si->state == SI_ST_DIS || si->state == SI_ST_CLO))
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
while (1) {
|
2011-02-13 07:25:14 -05:00
|
|
|
if (si->applet.st0 == STAT_CLI_INIT) {
|
2009-09-22 13:31:03 -04:00
|
|
|
/* Stats output not initialized yet */
|
2011-03-10 05:25:07 -05:00
|
|
|
memset(&si->applet.ctx.stats, 0, sizeof(si->applet.ctx.stats));
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = STAT_CLI_GETREQ;
|
2009-09-22 13:31:03 -04:00
|
|
|
}
|
2011-02-13 07:25:14 -05:00
|
|
|
else if (si->applet.st0 == STAT_CLI_END) {
|
2009-10-04 08:22:18 -04:00
|
|
|
/* Let's close for real now. We just close the request
|
|
|
|
|
* side, the conditions below will complete if needed.
|
|
|
|
|
*/
|
2012-05-21 10:31:45 -04:00
|
|
|
si_shutw(si);
|
2009-10-04 08:22:18 -04:00
|
|
|
break;
|
|
|
|
|
}
|
2011-02-13 07:25:14 -05:00
|
|
|
else if (si->applet.st0 == STAT_CLI_GETREQ) {
|
2009-10-11 17:35:10 -04:00
|
|
|
/* ensure we have some output room left in the event we
|
|
|
|
|
* would want to return some info right after parsing.
|
|
|
|
|
*/
|
2012-07-02 11:01:20 -04:00
|
|
|
if (buffer_almost_full(&si->ib->buf))
|
2009-10-11 17:35:10 -04:00
|
|
|
break;
|
|
|
|
|
|
2012-05-16 08:16:48 -04:00
|
|
|
reql = bo_getline(si->ob, trash, trashlen);
|
2009-09-22 13:31:03 -04:00
|
|
|
if (reql <= 0) { /* closed or EOL not found */
|
|
|
|
|
if (reql == 0)
|
|
|
|
|
break;
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = STAT_CLI_END;
|
2009-09-22 13:31:03 -04:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* seek for a possible semi-colon. If we find one, we
|
|
|
|
|
* replace it with an LF and skip only this part.
|
|
|
|
|
*/
|
|
|
|
|
for (len = 0; len < reql; len++)
|
|
|
|
|
if (trash[len] == ';') {
|
|
|
|
|
trash[len] = '\n';
|
|
|
|
|
reql = len + 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2009-08-16 13:06:42 -04:00
|
|
|
|
2009-10-04 01:36:58 -04:00
|
|
|
/* now it is time to check that we have a full line,
|
|
|
|
|
* remove the trailing \n and possibly \r, then cut the
|
|
|
|
|
* line.
|
|
|
|
|
*/
|
|
|
|
|
len = reql - 1;
|
|
|
|
|
if (trash[len] != '\n') {
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = STAT_CLI_END;
|
2009-09-22 13:31:03 -04:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2009-10-04 01:36:58 -04:00
|
|
|
if (len && trash[len-1] == '\r')
|
|
|
|
|
len--;
|
|
|
|
|
|
2009-09-22 13:31:03 -04:00
|
|
|
trash[len] = '\0';
|
|
|
|
|
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = STAT_CLI_PROMPT;
|
2009-09-22 13:31:03 -04:00
|
|
|
if (len) {
|
|
|
|
|
if (strcmp(trash, "quit") == 0) {
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = STAT_CLI_END;
|
2009-09-22 13:31:03 -04:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
else if (strcmp(trash, "prompt") == 0)
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st1 = !si->applet.st1;
|
2009-09-22 13:31:03 -04:00
|
|
|
else if (strcmp(trash, "help") == 0 ||
|
2009-10-11 17:12:51 -04:00
|
|
|
!stats_sock_parse_request(si, trash)) {
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.cli.msg = stats_sock_usage_msg;
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
2009-10-11 17:12:51 -04:00
|
|
|
}
|
2009-10-04 08:22:18 -04:00
|
|
|
/* NB: stats_sock_parse_request() may have put
|
2011-02-13 07:25:14 -05:00
|
|
|
* another STAT_CLI_O_* into si->applet.st0.
|
2009-10-04 08:22:18 -04:00
|
|
|
*/
|
2009-09-22 13:31:03 -04:00
|
|
|
}
|
2011-02-13 07:25:14 -05:00
|
|
|
else if (!si->applet.st1) {
|
2009-09-22 13:31:03 -04:00
|
|
|
/* if prompt is disabled, print help on empty lines,
|
|
|
|
|
* so that the user at least knows how to enable
|
|
|
|
|
* prompt and find help.
|
|
|
|
|
*/
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.cli.msg = stats_sock_usage_msg;
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = STAT_CLI_PRINT;
|
2009-08-16 13:06:42 -04:00
|
|
|
}
|
2009-09-22 13:31:03 -04:00
|
|
|
|
|
|
|
|
/* re-adjust req buffer */
|
2012-05-07 05:56:55 -04:00
|
|
|
bo_skip(si->ob, reql);
|
2009-09-22 13:31:03 -04:00
|
|
|
req->flags |= BF_READ_DONTWAIT; /* we plan to read small requests */
|
2009-08-16 13:06:42 -04:00
|
|
|
}
|
2009-10-04 08:22:18 -04:00
|
|
|
else { /* output functions: first check if the output buffer is closed then abort */
|
2009-09-22 13:31:03 -04:00
|
|
|
if (res->flags & (BF_SHUTR_NOW|BF_SHUTR)) {
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = STAT_CLI_END;
|
2009-09-22 13:31:03 -04:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-13 07:25:14 -05:00
|
|
|
switch (si->applet.st0) {
|
2009-10-11 17:12:51 -04:00
|
|
|
case STAT_CLI_PRINT:
|
2012-05-07 05:56:55 -04:00
|
|
|
if (bi_putstr(si->ib, si->applet.ctx.cli.msg) != -1)
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = STAT_CLI_PROMPT;
|
2009-09-22 13:31:03 -04:00
|
|
|
break;
|
2009-10-04 08:22:18 -04:00
|
|
|
case STAT_CLI_O_INFO:
|
2011-02-13 09:27:22 -05:00
|
|
|
if (stats_dump_raw_to_buffer(si))
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = STAT_CLI_PROMPT;
|
2009-09-22 13:31:03 -04:00
|
|
|
break;
|
2009-10-04 08:22:18 -04:00
|
|
|
case STAT_CLI_O_SESS:
|
2011-02-13 09:27:22 -05:00
|
|
|
if (stats_dump_sess_to_buffer(si))
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = STAT_CLI_PROMPT;
|
2009-09-22 13:31:03 -04:00
|
|
|
break;
|
2009-10-04 08:22:18 -04:00
|
|
|
case STAT_CLI_O_ERR: /* errors dump */
|
2011-02-13 09:27:22 -05:00
|
|
|
if (stats_dump_errors_to_buffer(si))
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = STAT_CLI_PROMPT;
|
2009-09-22 13:31:03 -04:00
|
|
|
break;
|
2010-07-12 11:55:33 -04:00
|
|
|
case STAT_CLI_O_TAB:
|
2011-06-15 02:18:49 -04:00
|
|
|
case STAT_CLI_O_CLR:
|
2012-06-06 17:37:08 -04:00
|
|
|
if (stats_table_request(si, si->applet.st0))
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = STAT_CLI_PROMPT;
|
2010-07-12 11:55:33 -04:00
|
|
|
break;
|
2009-10-04 08:22:18 -04:00
|
|
|
default: /* abnormal state */
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = STAT_CLI_PROMPT;
|
2009-09-22 13:31:03 -04:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2009-10-04 08:22:18 -04:00
|
|
|
/* The post-command prompt is either LF alone or LF + '> ' in interactive mode */
|
2011-02-13 07:25:14 -05:00
|
|
|
if (si->applet.st0 == STAT_CLI_PROMPT) {
|
2012-05-07 05:56:55 -04:00
|
|
|
if (bi_putstr(si->ib, si->applet.st1 ? "\n> " : "\n") != -1)
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = STAT_CLI_GETREQ;
|
2009-09-22 13:31:03 -04:00
|
|
|
}
|
2009-08-16 13:06:42 -04:00
|
|
|
|
2009-10-04 08:22:18 -04:00
|
|
|
/* If the output functions are still there, it means they require more room. */
|
2011-02-13 07:25:14 -05:00
|
|
|
if (si->applet.st0 >= STAT_CLI_OUTPUT)
|
2009-09-22 13:31:03 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* Now we close the output if one of the writers did so,
|
|
|
|
|
* or if we're not in interactive mode and the request
|
|
|
|
|
* buffer is empty. This still allows pipelined requests
|
|
|
|
|
* to be sent in non-interactive mode.
|
|
|
|
|
*/
|
2012-07-02 11:01:20 -04:00
|
|
|
if ((res->flags & (BF_SHUTW|BF_SHUTW_NOW)) || (!si->applet.st1 && !req->buf.o)) {
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = STAT_CLI_END;
|
2009-09-22 13:31:03 -04:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2009-10-04 08:22:18 -04:00
|
|
|
/* switch state back to GETREQ to read next requests */
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = STAT_CLI_GETREQ;
|
2009-08-16 13:06:42 -04:00
|
|
|
}
|
2009-09-22 13:31:03 -04:00
|
|
|
}
|
2009-08-16 13:06:42 -04:00
|
|
|
|
2011-02-13 07:25:14 -05:00
|
|
|
if ((res->flags & BF_SHUTR) && (si->state == SI_ST_EST) && (si->applet.st0 != STAT_CLI_GETREQ)) {
|
2009-09-22 13:31:03 -04:00
|
|
|
DPRINTF(stderr, "%s@%d: si to buf closed. req=%08x, res=%08x, st=%d\n",
|
|
|
|
|
__FUNCTION__, __LINE__, req->flags, res->flags, si->state);
|
2012-04-02 21:57:54 -04:00
|
|
|
/* Other side has closed, let's abort if we have no more processing to do
|
2009-09-22 13:31:03 -04:00
|
|
|
* and nothing more to consume. This is comparable to a broken pipe, so
|
|
|
|
|
* we forward the close to the request side so that it flows upstream to
|
|
|
|
|
* the client.
|
|
|
|
|
*/
|
2012-05-21 10:31:45 -04:00
|
|
|
si_shutw(si);
|
2009-09-22 13:31:03 -04:00
|
|
|
}
|
|
|
|
|
|
2011-02-13 07:25:14 -05:00
|
|
|
if ((req->flags & BF_SHUTW) && (si->state == SI_ST_EST) && (si->applet.st0 < STAT_CLI_OUTPUT)) {
|
2009-09-22 13:31:03 -04:00
|
|
|
DPRINTF(stderr, "%s@%d: buf to si closed. req=%08x, res=%08x, st=%d\n",
|
|
|
|
|
__FUNCTION__, __LINE__, req->flags, res->flags, si->state);
|
|
|
|
|
/* We have no more processing to do, and nothing more to send, and
|
|
|
|
|
* the client side has closed. So we'll forward this state downstream
|
|
|
|
|
* on the response buffer.
|
|
|
|
|
*/
|
2012-05-21 10:31:45 -04:00
|
|
|
si_shutr(si);
|
2009-09-22 13:31:03 -04:00
|
|
|
res->flags |= BF_READ_NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* update all other flags and resync with the other side */
|
2012-05-21 10:31:45 -04:00
|
|
|
si_update(si);
|
2009-09-22 13:31:03 -04:00
|
|
|
|
|
|
|
|
/* we don't want to expire timeouts while we're processing requests */
|
|
|
|
|
si->ib->rex = TICK_ETERNITY;
|
|
|
|
|
si->ob->wex = TICK_ETERNITY;
|
2009-08-16 13:06:42 -04:00
|
|
|
|
2009-09-22 13:31:03 -04:00
|
|
|
out:
|
2012-03-01 12:19:58 -05:00
|
|
|
DPRINTF(stderr, "%s@%d: st=%d, rqf=%x, rpf=%x, rqh=%d, rqs=%d, rh=%d, rs=%d\n",
|
2009-09-22 13:31:03 -04:00
|
|
|
__FUNCTION__, __LINE__,
|
2012-03-01 12:19:58 -05:00
|
|
|
si->state, req->flags, res->flags, req->i, req->o, res->i, res->o);
|
2009-09-22 13:31:03 -04:00
|
|
|
|
|
|
|
|
if (unlikely(si->state == SI_ST_DIS || si->state == SI_ST_CLO)) {
|
|
|
|
|
/* check that we have released everything then unregister */
|
|
|
|
|
stream_int_unregister_handler(si);
|
2009-08-16 13:06:42 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-13 09:27:22 -05:00
|
|
|
/* This function dumps statistics onto the stream interface's read buffer.
|
|
|
|
|
* The data_ctx must have been zeroed first, and the flags properly set.
|
2009-10-04 05:54:04 -04:00
|
|
|
* It returns 0 as long as it does not complete, non-zero upon completion.
|
|
|
|
|
* Some states are not used but it makes the code more similar to other
|
|
|
|
|
* functions which handle stats too.
|
2007-10-17 12:57:38 -04:00
|
|
|
*/
|
2011-06-15 02:18:44 -04:00
|
|
|
static int stats_dump_raw_to_buffer(struct stream_interface *si)
|
2007-10-17 12:57:38 -04:00
|
|
|
{
|
|
|
|
|
struct proxy *px;
|
|
|
|
|
struct chunk msg;
|
2008-01-03 04:19:15 -05:00
|
|
|
unsigned int up;
|
2007-10-17 12:57:38 -04:00
|
|
|
|
2012-05-16 08:16:48 -04:00
|
|
|
chunk_init(&msg, trash, trashlen);
|
2007-10-17 12:57:38 -04:00
|
|
|
|
2012-05-21 11:09:48 -04:00
|
|
|
switch (si->conn.data_st) {
|
2011-03-10 05:25:07 -05:00
|
|
|
case STAT_ST_INIT:
|
2009-10-04 05:54:04 -04:00
|
|
|
/* the function had not been called yet */
|
2012-05-21 11:09:48 -04:00
|
|
|
si->conn.data_st = STAT_ST_HEAD;
|
2007-10-17 12:57:38 -04:00
|
|
|
/* fall through */
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
case STAT_ST_HEAD:
|
|
|
|
|
if (si->applet.ctx.stats.flags & STAT_SHOW_STAT) {
|
2009-09-27 07:23:20 -04:00
|
|
|
print_csv_header(&msg);
|
2012-05-07 05:56:55 -04:00
|
|
|
if (bi_putchk(si->ib, &msg) == -1)
|
2008-01-03 04:19:15 -05:00
|
|
|
return 0;
|
|
|
|
|
}
|
2007-10-17 12:57:38 -04:00
|
|
|
|
2012-05-21 11:09:48 -04:00
|
|
|
si->conn.data_st = STAT_ST_INFO;
|
2007-10-17 12:57:38 -04:00
|
|
|
/* fall through */
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
case STAT_ST_INFO:
|
2008-01-03 04:19:15 -05:00
|
|
|
up = (now.tv_sec - start_date.tv_sec);
|
2011-03-10 05:25:07 -05:00
|
|
|
if (si->applet.ctx.stats.flags & STAT_SHOW_INFO) {
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2008-01-03 04:19:15 -05:00
|
|
|
"Name: " PRODUCT_NAME "\n"
|
|
|
|
|
"Version: " HAPROXY_VERSION "\n"
|
|
|
|
|
"Release_date: " HAPROXY_DATE "\n"
|
|
|
|
|
"Nbproc: %d\n"
|
|
|
|
|
"Process_num: %d\n"
|
|
|
|
|
"Pid: %d\n"
|
|
|
|
|
"Uptime: %dd %dh%02dm%02ds\n"
|
|
|
|
|
"Uptime_sec: %d\n"
|
|
|
|
|
"Memmax_MB: %d\n"
|
|
|
|
|
"Ulimit-n: %d\n"
|
|
|
|
|
"Maxsock: %d\n"
|
|
|
|
|
"Maxconn: %d\n"
|
2011-09-07 08:38:31 -04:00
|
|
|
"Hard_maxconn: %d\n"
|
2009-01-25 08:02:00 -05:00
|
|
|
"Maxpipes: %d\n"
|
2008-01-03 04:19:15 -05:00
|
|
|
"CurrConns: %d\n"
|
2009-01-25 08:02:00 -05:00
|
|
|
"PipesUsed: %d\n"
|
|
|
|
|
"PipesFree: %d\n"
|
2011-09-07 09:26:48 -04:00
|
|
|
"ConnRate: %d\n"
|
|
|
|
|
"ConnRateLimit: %d\n"
|
|
|
|
|
"MaxConnRate: %d\n"
|
2009-03-21 13:33:52 -04:00
|
|
|
"Tasks: %d\n"
|
|
|
|
|
"Run_queue: %d\n"
|
2011-09-10 10:56:42 -04:00
|
|
|
"Idle_pct: %d\n"
|
2009-10-02 16:51:14 -04:00
|
|
|
"node: %s\n"
|
|
|
|
|
"description: %s\n"
|
2008-01-03 04:19:15 -05:00
|
|
|
"",
|
|
|
|
|
global.nbproc,
|
|
|
|
|
relative_pid,
|
|
|
|
|
pid,
|
|
|
|
|
up / 86400, (up % 86400) / 3600, (up % 3600) / 60, (up % 60),
|
|
|
|
|
up,
|
|
|
|
|
global.rlimit_memmax,
|
|
|
|
|
global.rlimit_nofile,
|
2011-09-07 08:38:31 -04:00
|
|
|
global.maxsock, global.maxconn, global.hardmaxconn, global.maxpipes,
|
2009-03-21 13:33:52 -04:00
|
|
|
actconn, pipes_used, pipes_free,
|
2011-09-07 09:26:48 -04:00
|
|
|
read_freq_ctr(&global.conn_per_sec), global.cps_lim, global.cps_max,
|
2011-09-10 10:56:42 -04:00
|
|
|
nb_tasks_cur, run_queue_cur, idle_pct,
|
2009-10-02 16:51:14 -04:00
|
|
|
global.node, global.desc?global.desc:""
|
2008-01-03 04:19:15 -05:00
|
|
|
);
|
2012-05-07 05:56:55 -04:00
|
|
|
if (bi_putchk(si->ib, &msg) == -1)
|
2008-01-03 04:19:15 -05:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.stats.px = proxy;
|
|
|
|
|
si->applet.ctx.stats.px_st = STAT_PX_ST_INIT;
|
|
|
|
|
si->applet.ctx.stats.sv = NULL;
|
2012-05-21 11:09:48 -04:00
|
|
|
si->conn.data_st = STAT_ST_LIST;
|
2007-10-17 12:57:38 -04:00
|
|
|
/* fall through */
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
case STAT_ST_LIST:
|
2007-10-17 12:57:38 -04:00
|
|
|
/* dump proxies */
|
2011-03-10 05:25:07 -05:00
|
|
|
if (si->applet.ctx.stats.flags & STAT_SHOW_STAT) {
|
|
|
|
|
while (si->applet.ctx.stats.px) {
|
|
|
|
|
px = si->applet.ctx.stats.px;
|
2008-01-03 04:19:15 -05:00
|
|
|
/* skip the disabled proxies and non-networked ones */
|
|
|
|
|
if (px->state != PR_STSTOPPED &&
|
2009-10-04 05:54:04 -04:00
|
|
|
(px->cap & (PR_CAP_FE | PR_CAP_BE))) {
|
2011-02-13 09:27:22 -05:00
|
|
|
if (stats_dump_proxy(si, px, NULL) == 0)
|
2008-01-03 04:19:15 -05:00
|
|
|
return 0;
|
2009-10-04 05:54:04 -04:00
|
|
|
}
|
2008-01-03 04:19:15 -05:00
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.stats.px = px->next;
|
|
|
|
|
si->applet.ctx.stats.px_st = STAT_PX_ST_INIT;
|
2008-01-03 04:19:15 -05:00
|
|
|
}
|
|
|
|
|
/* here, we just have reached the last proxy */
|
2007-10-17 12:57:38 -04:00
|
|
|
}
|
|
|
|
|
|
2012-05-21 11:09:48 -04:00
|
|
|
si->conn.data_st = STAT_ST_END;
|
2007-10-17 12:57:38 -04:00
|
|
|
/* fall through */
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
case STAT_ST_END:
|
2012-05-21 11:09:48 -04:00
|
|
|
si->conn.data_st = STAT_ST_FIN;
|
2008-12-07 12:30:00 -05:00
|
|
|
/* fall through */
|
2007-10-17 12:57:38 -04:00
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
case STAT_ST_FIN:
|
2007-10-17 12:57:38 -04:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
/* unknown state ! */
|
2012-05-21 11:09:48 -04:00
|
|
|
si->conn.data_st = STAT_ST_FIN;
|
2009-10-04 05:54:04 -04:00
|
|
|
return 1;
|
2007-10-17 12:57:38 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-10-11 18:14:35 -04:00
|
|
|
/* We don't want to land on the posted stats page because a refresh will
|
|
|
|
|
* repost the data. We don't want this to happen on accident so we redirect
|
|
|
|
|
* the browse to the stats page with a GET.
|
|
|
|
|
*/
|
2011-06-15 02:18:44 -04:00
|
|
|
static int stats_http_redir(struct stream_interface *si, struct uri_auth *uri)
|
2010-10-11 18:14:35 -04:00
|
|
|
{
|
2012-05-21 11:09:48 -04:00
|
|
|
struct session *s = si->conn.data_ctx;
|
2010-10-11 18:14:35 -04:00
|
|
|
struct chunk msg;
|
|
|
|
|
|
2012-05-16 08:16:48 -04:00
|
|
|
chunk_init(&msg, trash, trashlen);
|
2010-10-11 18:14:35 -04:00
|
|
|
|
2012-05-21 11:09:48 -04:00
|
|
|
switch (si->conn.data_st) {
|
2011-03-10 05:25:07 -05:00
|
|
|
case STAT_ST_INIT:
|
2010-10-11 18:14:35 -04:00
|
|
|
chunk_printf(&msg,
|
|
|
|
|
"HTTP/1.0 303 See Other\r\n"
|
|
|
|
|
"Cache-Control: no-cache\r\n"
|
|
|
|
|
"Content-Type: text/plain\r\n"
|
|
|
|
|
"Connection: close\r\n"
|
|
|
|
|
"Location: %s;st=%s",
|
2012-04-04 06:57:21 -04:00
|
|
|
uri->uri_prefix,
|
|
|
|
|
((si->applet.ctx.stats.st_code > STAT_STATUS_INIT) &&
|
|
|
|
|
(si->applet.ctx.stats.st_code < STAT_STATUS_SIZE) &&
|
|
|
|
|
stat_status_codes[si->applet.ctx.stats.st_code]) ?
|
|
|
|
|
stat_status_codes[si->applet.ctx.stats.st_code] :
|
|
|
|
|
stat_status_codes[STAT_STATUS_UNKN]);
|
2010-10-11 18:14:35 -04:00
|
|
|
chunk_printf(&msg, "\r\n\r\n");
|
|
|
|
|
|
2012-05-07 05:56:55 -04:00
|
|
|
if (bi_putchk(si->ib, &msg) == -1)
|
2010-10-11 18:14:35 -04:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
s->txn.status = 303;
|
|
|
|
|
|
|
|
|
|
if (!(s->flags & SN_ERR_MASK)) // this is not really an error but it is
|
|
|
|
|
s->flags |= SN_ERR_PRXCOND; // to mark that it comes from the proxy
|
|
|
|
|
if (!(s->flags & SN_FINST_MASK))
|
|
|
|
|
s->flags |= SN_FINST_R;
|
|
|
|
|
|
2012-05-21 11:09:48 -04:00
|
|
|
si->conn.data_st = STAT_ST_FIN;
|
2010-10-11 18:14:35 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-10-04 09:56:38 -04:00
|
|
|
/* This I/O handler runs as an applet embedded in a stream interface. It is
|
|
|
|
|
* used to send HTTP stats over a TCP socket. The mechanism is very simple.
|
2011-02-13 07:25:14 -05:00
|
|
|
* si->applet.st0 becomes non-zero once the transfer is finished. The handler
|
2009-10-04 09:56:38 -04:00
|
|
|
* automatically unregisters itself once transfer is complete.
|
|
|
|
|
*/
|
2011-02-13 07:16:36 -05:00
|
|
|
static void http_stats_io_handler(struct stream_interface *si)
|
2009-10-04 09:56:38 -04:00
|
|
|
{
|
2012-05-21 11:09:48 -04:00
|
|
|
struct session *s = si->conn.data_ctx;
|
2012-07-02 09:11:27 -04:00
|
|
|
struct channel *req = si->ob;
|
|
|
|
|
struct channel *res = si->ib;
|
2009-10-04 09:56:38 -04:00
|
|
|
|
|
|
|
|
if (unlikely(si->state == SI_ST_DIS || si->state == SI_ST_CLO))
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
/* check that the output is not closed */
|
|
|
|
|
if (res->flags & (BF_SHUTW|BF_SHUTW_NOW))
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = 1;
|
2009-10-04 09:56:38 -04:00
|
|
|
|
2011-02-13 07:25:14 -05:00
|
|
|
if (!si->applet.st0) {
|
2010-10-11 18:14:35 -04:00
|
|
|
if (s->txn.meth == HTTP_METH_POST) {
|
2011-02-13 09:27:22 -05:00
|
|
|
if (stats_http_redir(si, s->be->uri_auth)) {
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = 1;
|
2012-05-21 10:31:45 -04:00
|
|
|
si_shutw(si);
|
2010-10-11 18:14:35 -04:00
|
|
|
}
|
|
|
|
|
} else {
|
2011-02-13 09:27:22 -05:00
|
|
|
if (stats_dump_http(si, s->be->uri_auth)) {
|
2011-02-13 07:25:14 -05:00
|
|
|
si->applet.st0 = 1;
|
2012-05-21 10:31:45 -04:00
|
|
|
si_shutw(si);
|
2010-10-11 18:14:35 -04:00
|
|
|
}
|
2009-10-04 09:56:38 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((res->flags & BF_SHUTR) && (si->state == SI_ST_EST))
|
2012-05-21 10:31:45 -04:00
|
|
|
si_shutw(si);
|
2009-10-04 09:56:38 -04:00
|
|
|
|
2011-02-13 07:25:14 -05:00
|
|
|
if ((req->flags & BF_SHUTW) && (si->state == SI_ST_EST) && si->applet.st0) {
|
2012-05-21 10:31:45 -04:00
|
|
|
si_shutr(si);
|
2009-10-04 09:56:38 -04:00
|
|
|
res->flags |= BF_READ_NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* update all other flags and resync with the other side */
|
2012-05-21 10:31:45 -04:00
|
|
|
si_update(si);
|
2009-10-04 09:56:38 -04:00
|
|
|
|
|
|
|
|
/* we don't want to expire timeouts while we're processing requests */
|
|
|
|
|
si->ib->rex = TICK_ETERNITY;
|
|
|
|
|
si->ob->wex = TICK_ETERNITY;
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
if (unlikely(si->state == SI_ST_DIS || si->state == SI_ST_CLO)) {
|
|
|
|
|
/* check that we have released everything then unregister */
|
|
|
|
|
stream_int_unregister_handler(si);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-02-13 09:27:22 -05:00
|
|
|
/* This function dumps statistics in HTTP format onto the stream interface's
|
|
|
|
|
* read buffer. The data_ctx must have been zeroed first, and the flags
|
|
|
|
|
* properly set. It returns 0 if it had to stop writing data and an I/O is
|
|
|
|
|
* needed, 1 if the dump is finished and the session must be closed, or -1
|
|
|
|
|
* in case of any error.
|
2007-10-17 11:06:05 -04:00
|
|
|
*/
|
2011-06-15 02:18:44 -04:00
|
|
|
static int stats_dump_http(struct stream_interface *si, struct uri_auth *uri)
|
2007-10-17 11:06:05 -04:00
|
|
|
{
|
2012-05-21 11:09:48 -04:00
|
|
|
struct session *s = si->conn.data_ctx;
|
2012-07-02 09:11:27 -04:00
|
|
|
struct channel *rep = si->ib;
|
2007-10-17 11:06:05 -04:00
|
|
|
struct proxy *px;
|
|
|
|
|
struct chunk msg;
|
|
|
|
|
unsigned int up;
|
|
|
|
|
|
2012-05-16 08:16:48 -04:00
|
|
|
chunk_init(&msg, trash, trashlen);
|
2007-10-17 11:06:05 -04:00
|
|
|
|
2012-05-21 11:09:48 -04:00
|
|
|
switch (si->conn.data_st) {
|
2011-03-10 05:25:07 -05:00
|
|
|
case STAT_ST_INIT:
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2007-10-17 11:06:05 -04:00
|
|
|
"HTTP/1.0 200 OK\r\n"
|
|
|
|
|
"Cache-Control: no-cache\r\n"
|
|
|
|
|
"Connection: close\r\n"
|
2007-10-17 12:44:57 -04:00
|
|
|
"Content-Type: %s\r\n",
|
2011-03-10 05:25:07 -05:00
|
|
|
(si->applet.ctx.stats.flags & STAT_FMT_CSV) ? "text/plain" : "text/html");
|
2007-10-17 11:06:05 -04:00
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
if (uri->refresh > 0 && !(si->applet.ctx.stats.flags & STAT_NO_REFRESH))
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg, "Refresh: %d\r\n",
|
2007-10-17 11:06:05 -04:00
|
|
|
uri->refresh);
|
|
|
|
|
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg, "\r\n");
|
2007-10-17 11:06:05 -04:00
|
|
|
|
|
|
|
|
s->txn.status = 200;
|
2012-05-07 05:56:55 -04:00
|
|
|
if (bi_putchk(rep, &msg) == -1)
|
2009-09-22 13:27:35 -04:00
|
|
|
return 0;
|
|
|
|
|
|
2007-10-17 11:06:05 -04:00
|
|
|
if (!(s->flags & SN_ERR_MASK)) // this is not really an error but it is
|
|
|
|
|
s->flags |= SN_ERR_PRXCOND; // to mark that it comes from the proxy
|
|
|
|
|
if (!(s->flags & SN_FINST_MASK))
|
|
|
|
|
s->flags |= SN_FINST_R;
|
|
|
|
|
|
|
|
|
|
if (s->txn.meth == HTTP_METH_HEAD) {
|
|
|
|
|
/* that's all we return in case of HEAD request */
|
2012-05-21 11:09:48 -04:00
|
|
|
si->conn.data_st = STAT_ST_FIN;
|
2007-10-17 11:06:05 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-21 11:09:48 -04:00
|
|
|
si->conn.data_st = STAT_ST_HEAD; /* let's start producing data */
|
2007-10-17 11:06:05 -04:00
|
|
|
/* fall through */
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
case STAT_ST_HEAD:
|
|
|
|
|
if (!(si->applet.ctx.stats.flags & STAT_FMT_CSV)) {
|
2010-01-05 12:44:44 -05:00
|
|
|
/* WARNING! This must fit in the first buffer !!! */
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2009-10-12 17:09:08 -04:00
|
|
|
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\n"
|
|
|
|
|
"\"http://www.w3.org/TR/html4/loose.dtd\">\n"
|
2009-08-16 04:29:18 -04:00
|
|
|
"<html><head><title>Statistics Report for " PRODUCT_NAME "%s%s</title>\n"
|
2007-10-17 11:06:05 -04:00
|
|
|
"<meta http-equiv=\"content-type\" content=\"text/html; charset=iso-8859-1\">\n"
|
|
|
|
|
"<style type=\"text/css\"><!--\n"
|
|
|
|
|
"body {"
|
2009-05-10 14:08:10 -04:00
|
|
|
" font-family: arial, helvetica, sans-serif;"
|
2007-10-17 11:06:05 -04:00
|
|
|
" font-size: 12px;"
|
|
|
|
|
" font-weight: normal;"
|
|
|
|
|
" color: black;"
|
|
|
|
|
" background: white;"
|
|
|
|
|
"}\n"
|
|
|
|
|
"th,td {"
|
2009-05-10 14:08:10 -04:00
|
|
|
" font-size: 10px;"
|
2007-10-17 11:06:05 -04:00
|
|
|
"}\n"
|
|
|
|
|
"h1 {"
|
2009-07-15 04:07:05 -04:00
|
|
|
" font-size: x-large;"
|
2007-10-17 11:06:05 -04:00
|
|
|
" margin-bottom: 0.5em;"
|
|
|
|
|
"}\n"
|
|
|
|
|
"h2 {"
|
|
|
|
|
" font-family: helvetica, arial;"
|
|
|
|
|
" font-size: x-large;"
|
|
|
|
|
" font-weight: bold;"
|
|
|
|
|
" font-style: italic;"
|
|
|
|
|
" color: #6020a0;"
|
|
|
|
|
" margin-top: 0em;"
|
|
|
|
|
" margin-bottom: 0em;"
|
|
|
|
|
"}\n"
|
|
|
|
|
"h3 {"
|
|
|
|
|
" font-family: helvetica, arial;"
|
|
|
|
|
" font-size: 16px;"
|
|
|
|
|
" font-weight: bold;"
|
|
|
|
|
" color: #b00040;"
|
|
|
|
|
" background: #e8e8d0;"
|
|
|
|
|
" margin-top: 0em;"
|
|
|
|
|
" margin-bottom: 0em;"
|
|
|
|
|
"}\n"
|
|
|
|
|
"li {"
|
|
|
|
|
" margin-top: 0.25em;"
|
|
|
|
|
" margin-right: 2em;"
|
|
|
|
|
"}\n"
|
|
|
|
|
".hr {margin-top: 0.25em;"
|
|
|
|
|
" border-color: black;"
|
|
|
|
|
" border-bottom-style: solid;"
|
|
|
|
|
"}\n"
|
2009-10-12 17:09:08 -04:00
|
|
|
".titre {background: #20D0D0;color: #000000; font-weight: bold; text-align: center;}\n"
|
2007-10-17 11:06:05 -04:00
|
|
|
".total {background: #20D0D0;color: #ffff80;}\n"
|
|
|
|
|
".frontend {background: #e8e8d0;}\n"
|
2009-10-04 09:43:17 -04:00
|
|
|
".socket {background: #d0d0d0;}\n"
|
2007-10-17 11:06:05 -04:00
|
|
|
".backend {background: #e8e8d0;}\n"
|
|
|
|
|
".active0 {background: #ff9090;}\n"
|
|
|
|
|
".active1 {background: #ffd020;}\n"
|
|
|
|
|
".active2 {background: #ffffa0;}\n"
|
|
|
|
|
".active3 {background: #c0ffc0;}\n"
|
2007-11-30 06:04:38 -05:00
|
|
|
".active4 {background: #ffffa0;}\n" /* NOLB state shows same as going down */
|
|
|
|
|
".active5 {background: #a0e0a0;}\n" /* NOLB state shows darker than up */
|
|
|
|
|
".active6 {background: #e0e0e0;}\n"
|
2007-10-17 11:06:05 -04:00
|
|
|
".backup0 {background: #ff9090;}\n"
|
|
|
|
|
".backup1 {background: #ff80ff;}\n"
|
|
|
|
|
".backup2 {background: #c060ff;}\n"
|
|
|
|
|
".backup3 {background: #b0d0ff;}\n"
|
2007-11-30 06:04:38 -05:00
|
|
|
".backup4 {background: #c060ff;}\n" /* NOLB state shows same as going down */
|
|
|
|
|
".backup5 {background: #90b0e0;}\n" /* NOLB state shows same as going down */
|
|
|
|
|
".backup6 {background: #e0e0e0;}\n"
|
2010-01-31 16:34:03 -05:00
|
|
|
".maintain {background: #c07820;}\n"
|
2009-07-15 04:07:05 -04:00
|
|
|
".rls {letter-spacing: 0.2em; margin-right: 1px;}\n" /* right letter spacing (used for grouping digits) */
|
2009-10-12 17:09:08 -04:00
|
|
|
"\n"
|
2009-10-24 08:24:30 -04:00
|
|
|
"a.px:link {color: #ffff40; text-decoration: none;}"
|
|
|
|
|
"a.px:visited {color: #ffff40; text-decoration: none;}"
|
|
|
|
|
"a.px:hover {color: #ffffff; text-decoration: none;}"
|
|
|
|
|
"a.lfsb:link {color: #000000; text-decoration: none;}"
|
|
|
|
|
"a.lfsb:visited {color: #000000; text-decoration: none;}"
|
|
|
|
|
"a.lfsb:hover {color: #505050; text-decoration: none;}"
|
|
|
|
|
"\n"
|
2007-10-17 11:06:05 -04:00
|
|
|
"table.tbl { border-collapse: collapse; border-style: none;}\n"
|
2009-10-12 17:09:08 -04:00
|
|
|
"table.tbl td { text-align: right; border-width: 1px 1px 1px 1px; border-style: solid solid solid solid; padding: 2px 3px; border-color: gray; white-space: nowrap;}\n"
|
|
|
|
|
"table.tbl td.ac { text-align: center;}\n"
|
2007-10-17 11:06:05 -04:00
|
|
|
"table.tbl th { border-width: 1px; border-style: solid solid solid solid; border-color: gray;}\n"
|
2009-10-12 17:09:08 -04:00
|
|
|
"table.tbl th.pxname { background: #b00040; color: #ffff40; font-weight: bold; border-style: solid solid none solid; padding: 2px 3px; white-space: nowrap;}\n"
|
2009-07-15 04:07:05 -04:00
|
|
|
"table.tbl th.empty { border-style: none; empty-cells: hide; background: white;}\n"
|
2009-10-02 16:51:14 -04:00
|
|
|
"table.tbl th.desc { background: white; border-style: solid solid none solid; text-align: left; padding: 2px 3px;}\n"
|
2009-10-12 17:09:08 -04:00
|
|
|
"\n"
|
2007-10-17 11:06:05 -04:00
|
|
|
"table.lgd { border-collapse: collapse; border-width: 1px; border-style: none none none solid; border-color: black;}\n"
|
|
|
|
|
"table.lgd td { border-width: 1px; border-style: solid solid solid solid; border-color: gray; padding: 2px;}\n"
|
|
|
|
|
"table.lgd td.noborder { border-style: none; padding: 2px; white-space: nowrap;}\n"
|
2010-02-26 06:29:07 -05:00
|
|
|
"u {text-decoration:none; border-bottom: 1px dotted black;}\n"
|
2007-10-17 11:06:05 -04:00
|
|
|
"-->\n"
|
2009-08-16 04:29:18 -04:00
|
|
|
"</style></head>\n",
|
2009-10-02 16:51:14 -04:00
|
|
|
(uri->flags&ST_SHNODE) ? " on " : "",
|
|
|
|
|
(uri->flags&ST_SHNODE) ? (uri->node ? uri->node : global.node) : ""
|
2009-08-16 04:29:18 -04:00
|
|
|
);
|
2007-10-17 12:44:57 -04:00
|
|
|
} else {
|
2009-09-27 07:23:20 -04:00
|
|
|
print_csv_header(&msg);
|
2007-10-17 12:44:57 -04:00
|
|
|
}
|
2012-05-07 05:56:55 -04:00
|
|
|
if (bi_putchk(rep, &msg) == -1)
|
2007-10-17 11:06:05 -04:00
|
|
|
return 0;
|
|
|
|
|
|
2012-05-21 11:09:48 -04:00
|
|
|
si->conn.data_st = STAT_ST_INFO;
|
2007-10-17 11:06:05 -04:00
|
|
|
/* fall through */
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
case STAT_ST_INFO:
|
2007-10-17 11:06:05 -04:00
|
|
|
up = (now.tv_sec - start_date.tv_sec);
|
|
|
|
|
|
|
|
|
|
/* WARNING! this has to fit the first packet too.
|
|
|
|
|
* We are around 3.5 kB, add adding entries will
|
|
|
|
|
* become tricky if we want to support 4kB buffers !
|
|
|
|
|
*/
|
2011-03-10 05:25:07 -05:00
|
|
|
if (!(si->applet.ctx.stats.flags & STAT_FMT_CSV)) {
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2007-10-17 11:06:05 -04:00
|
|
|
"<body><h1><a href=\"" PRODUCT_URL "\" style=\"text-decoration: none;\">"
|
|
|
|
|
PRODUCT_NAME "%s</a></h1>\n"
|
2009-10-02 16:51:14 -04:00
|
|
|
"<h2>Statistics Report for pid %d%s%s%s%s</h2>\n"
|
2007-10-17 11:06:05 -04:00
|
|
|
"<hr width=\"100%%\" class=\"hr\">\n"
|
|
|
|
|
"<h3>> General process information</h3>\n"
|
2009-10-12 17:09:08 -04:00
|
|
|
"<table border=0><tr><td align=\"left\" nowrap width=\"1%%\">\n"
|
2008-01-03 04:19:15 -05:00
|
|
|
"<p><b>pid = </b> %d (process #%d, nbproc = %d)<br>\n"
|
2007-10-17 11:06:05 -04:00
|
|
|
"<b>uptime = </b> %dd %dh%02dm%02ds<br>\n"
|
2009-10-02 16:51:14 -04:00
|
|
|
"<b>system limits:</b> memmax = %s%s; ulimit-n = %d<br>\n"
|
|
|
|
|
"<b>maxsock = </b> %d; <b>maxconn = </b> %d; <b>maxpipes = </b> %d<br>\n"
|
2011-09-07 09:26:48 -04:00
|
|
|
"current conns = %d; current pipes = %d/%d; conn rate = %d/sec<br>\n"
|
2011-09-10 10:56:42 -04:00
|
|
|
"Running tasks: %d/%d; idle = %d %%<br>\n"
|
2007-10-17 11:06:05 -04:00
|
|
|
"</td><td align=\"center\" nowrap>\n"
|
|
|
|
|
"<table class=\"lgd\"><tr>\n"
|
|
|
|
|
"<td class=\"active3\"> </td><td class=\"noborder\">active UP </td>"
|
|
|
|
|
"<td class=\"backup3\"> </td><td class=\"noborder\">backup UP </td>"
|
|
|
|
|
"</tr><tr>\n"
|
|
|
|
|
"<td class=\"active2\"></td><td class=\"noborder\">active UP, going down </td>"
|
|
|
|
|
"<td class=\"backup2\"></td><td class=\"noborder\">backup UP, going down </td>"
|
|
|
|
|
"</tr><tr>\n"
|
|
|
|
|
"<td class=\"active1\"></td><td class=\"noborder\">active DOWN, going up </td>"
|
|
|
|
|
"<td class=\"backup1\"></td><td class=\"noborder\">backup DOWN, going up </td>"
|
|
|
|
|
"</tr><tr>\n"
|
|
|
|
|
"<td class=\"active0\"></td><td class=\"noborder\">active or backup DOWN </td>"
|
2007-11-30 06:04:38 -05:00
|
|
|
"<td class=\"active6\"></td><td class=\"noborder\">not checked </td>"
|
2010-01-31 16:34:03 -05:00
|
|
|
"</tr><tr>\n"
|
|
|
|
|
"<td class=\"maintain\"></td><td class=\"noborder\" colspan=\"3\">active or backup DOWN for maintenance (MAINT) </td>"
|
2007-10-17 11:06:05 -04:00
|
|
|
"</tr></table>\n"
|
2007-11-30 06:04:38 -05:00
|
|
|
"Note: UP with load-balancing disabled is reported as \"NOLB\"."
|
2007-10-17 11:06:05 -04:00
|
|
|
"</td>"
|
|
|
|
|
"<td align=\"left\" valign=\"top\" nowrap width=\"1%%\">"
|
|
|
|
|
"<b>Display option:</b><ul style=\"margin-top: 0.25em;\">"
|
|
|
|
|
"",
|
|
|
|
|
(uri->flags&ST_HIDEVER)?"":(STATS_VERSION_STRING),
|
2009-10-02 16:51:14 -04:00
|
|
|
pid, (uri->flags&ST_SHNODE) ? " on " : "", (uri->flags&ST_SHNODE) ? (uri->node ? uri->node : global.node) : "",
|
|
|
|
|
(uri->flags&ST_SHDESC)? ": " : "", (uri->flags&ST_SHDESC) ? (uri->desc ? uri->desc : global.desc) : "",
|
|
|
|
|
pid, relative_pid, global.nbproc,
|
2007-10-17 11:06:05 -04:00
|
|
|
up / 86400, (up % 86400) / 3600,
|
|
|
|
|
(up % 3600) / 60, (up % 60),
|
|
|
|
|
global.rlimit_memmax ? ultoa(global.rlimit_memmax) : "unlimited",
|
|
|
|
|
global.rlimit_memmax ? " MB" : "",
|
|
|
|
|
global.rlimit_nofile,
|
2009-01-25 08:02:00 -05:00
|
|
|
global.maxsock, global.maxconn, global.maxpipes,
|
2011-09-07 09:26:48 -04:00
|
|
|
actconn, pipes_used, pipes_used+pipes_free, read_freq_ctr(&global.conn_per_sec),
|
2011-09-10 10:56:42 -04:00
|
|
|
run_queue_cur, nb_tasks_cur, idle_pct
|
2007-10-17 11:06:05 -04:00
|
|
|
);
|
2008-12-07 10:06:43 -05:00
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
if (si->applet.ctx.stats.flags & STAT_HIDE_DOWN)
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2007-10-17 11:06:05 -04:00
|
|
|
"<li><a href=\"%s%s%s\">Show all servers</a><br>\n",
|
|
|
|
|
uri->uri_prefix,
|
|
|
|
|
"",
|
2011-03-10 05:25:07 -05:00
|
|
|
(si->applet.ctx.stats.flags & STAT_NO_REFRESH) ? ";norefresh" : "");
|
2007-10-17 12:44:57 -04:00
|
|
|
else
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2007-10-17 11:06:05 -04:00
|
|
|
"<li><a href=\"%s%s%s\">Hide 'DOWN' servers</a><br>\n",
|
|
|
|
|
uri->uri_prefix,
|
|
|
|
|
";up",
|
2011-03-10 05:25:07 -05:00
|
|
|
(si->applet.ctx.stats.flags & STAT_NO_REFRESH) ? ";norefresh" : "");
|
2007-10-17 11:06:05 -04:00
|
|
|
|
2007-10-17 12:44:57 -04:00
|
|
|
if (uri->refresh > 0) {
|
2011-03-10 05:25:07 -05:00
|
|
|
if (si->applet.ctx.stats.flags & STAT_NO_REFRESH)
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2007-10-17 11:06:05 -04:00
|
|
|
"<li><a href=\"%s%s%s\">Enable refresh</a><br>\n",
|
|
|
|
|
uri->uri_prefix,
|
2011-03-10 05:25:07 -05:00
|
|
|
(si->applet.ctx.stats.flags & STAT_HIDE_DOWN) ? ";up" : "",
|
2007-10-17 11:06:05 -04:00
|
|
|
"");
|
2007-10-17 12:44:57 -04:00
|
|
|
else
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2007-10-17 11:06:05 -04:00
|
|
|
"<li><a href=\"%s%s%s\">Disable refresh</a><br>\n",
|
|
|
|
|
uri->uri_prefix,
|
2011-03-10 05:25:07 -05:00
|
|
|
(si->applet.ctx.stats.flags & STAT_HIDE_DOWN) ? ";up" : "",
|
2007-10-17 11:06:05 -04:00
|
|
|
";norefresh");
|
2007-10-17 12:44:57 -04:00
|
|
|
}
|
2007-10-17 11:06:05 -04:00
|
|
|
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2007-10-17 11:06:05 -04:00
|
|
|
"<li><a href=\"%s%s%s\">Refresh now</a><br>\n",
|
|
|
|
|
uri->uri_prefix,
|
2011-03-10 05:25:07 -05:00
|
|
|
(si->applet.ctx.stats.flags & STAT_HIDE_DOWN) ? ";up" : "",
|
|
|
|
|
(si->applet.ctx.stats.flags & STAT_NO_REFRESH) ? ";norefresh" : "");
|
2007-10-17 11:06:05 -04:00
|
|
|
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2007-10-18 05:05:48 -04:00
|
|
|
"<li><a href=\"%s;csv%s\">CSV export</a><br>\n",
|
|
|
|
|
uri->uri_prefix,
|
|
|
|
|
(uri->refresh > 0) ? ";norefresh" : "");
|
|
|
|
|
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2009-10-12 17:09:08 -04:00
|
|
|
"</ul></td>"
|
2007-10-17 11:06:05 -04:00
|
|
|
"<td align=\"left\" valign=\"top\" nowrap width=\"1%%\">"
|
2012-03-19 19:36:42 -04:00
|
|
|
"<b>External resources:</b><ul style=\"margin-top: 0.25em;\">\n"
|
2007-10-17 11:06:05 -04:00
|
|
|
"<li><a href=\"" PRODUCT_URL "\">Primary site</a><br>\n"
|
|
|
|
|
"<li><a href=\"" PRODUCT_URL_UPD "\">Updates (v" PRODUCT_BRANCH ")</a><br>\n"
|
|
|
|
|
"<li><a href=\"" PRODUCT_URL_DOC "\">Online manual</a><br>\n"
|
|
|
|
|
"</ul>"
|
|
|
|
|
"</td>"
|
|
|
|
|
"</tr></table>\n"
|
|
|
|
|
""
|
|
|
|
|
);
|
2008-12-07 10:06:43 -05:00
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
if (si->applet.ctx.stats.st_code) {
|
2012-04-04 06:57:21 -04:00
|
|
|
switch (si->applet.ctx.stats.st_code) {
|
|
|
|
|
case STAT_STATUS_DONE:
|
2010-10-11 18:14:35 -04:00
|
|
|
chunk_printf(&msg,
|
|
|
|
|
"<p><div class=active3>"
|
|
|
|
|
"<a class=lfsb href=\"%s\" title=\"Remove this message\">[X]</a> "
|
|
|
|
|
"Action processed successfully."
|
|
|
|
|
"</div>\n", uri->uri_prefix);
|
2012-04-04 06:57:21 -04:00
|
|
|
break;
|
|
|
|
|
case STAT_STATUS_NONE:
|
2010-10-11 18:14:35 -04:00
|
|
|
chunk_printf(&msg,
|
|
|
|
|
"<p><div class=active2>"
|
|
|
|
|
"<a class=lfsb href=\"%s\" title=\"Remove this message\">[X]</a> "
|
|
|
|
|
"Nothing has changed."
|
|
|
|
|
"</div>\n", uri->uri_prefix);
|
2012-04-04 06:57:21 -04:00
|
|
|
break;
|
|
|
|
|
case STAT_STATUS_PART:
|
2012-04-04 06:57:18 -04:00
|
|
|
chunk_printf(&msg,
|
|
|
|
|
"<p><div class=active2>"
|
|
|
|
|
"<a class=lfsb href=\"%s\" title=\"Remove this message\">[X]</a> "
|
|
|
|
|
"Action partially processed.<br>"
|
|
|
|
|
"Some server names are probably unknown or ambiguous (duplicated names in the backend)."
|
|
|
|
|
"</div>\n", uri->uri_prefix);
|
2012-04-04 06:57:21 -04:00
|
|
|
break;
|
|
|
|
|
case STAT_STATUS_ERRP:
|
2012-04-04 06:57:18 -04:00
|
|
|
chunk_printf(&msg,
|
|
|
|
|
"<p><div class=active0>"
|
|
|
|
|
"<a class=lfsb href=\"%s\" title=\"Remove this message\">[X]</a> "
|
|
|
|
|
"Action not processed because of invalid parameters."
|
|
|
|
|
"<ul>"
|
|
|
|
|
"<li>The action is maybe unknown.</li>"
|
|
|
|
|
"<li>The backend name is probably unknown or ambiguous (duplicated names).</li>"
|
|
|
|
|
"<li>Some server names are probably unknown or ambiguous (duplicated names in the backend).</li>"
|
|
|
|
|
"</ul>"
|
|
|
|
|
"</div>\n", uri->uri_prefix);
|
2012-04-04 06:57:21 -04:00
|
|
|
break;
|
|
|
|
|
case STAT_STATUS_EXCD:
|
2010-10-11 18:14:35 -04:00
|
|
|
chunk_printf(&msg,
|
|
|
|
|
"<p><div class=active0>"
|
|
|
|
|
"<a class=lfsb href=\"%s\" title=\"Remove this message\">[X]</a> "
|
|
|
|
|
"<b>Action not processed : the buffer couldn't store all the data.<br>"
|
|
|
|
|
"You should retry with less servers at a time.</b>"
|
|
|
|
|
"</div>\n", uri->uri_prefix);
|
2012-04-04 06:57:21 -04:00
|
|
|
break;
|
|
|
|
|
case STAT_STATUS_DENY:
|
2010-10-11 18:14:36 -04:00
|
|
|
chunk_printf(&msg,
|
|
|
|
|
"<p><div class=active0>"
|
|
|
|
|
"<a class=lfsb href=\"%s\" title=\"Remove this message\">[X]</a> "
|
|
|
|
|
"<b>Action denied.</b>"
|
|
|
|
|
"</div>\n", uri->uri_prefix);
|
2012-04-04 06:57:21 -04:00
|
|
|
break;
|
|
|
|
|
default:
|
2010-10-11 18:14:35 -04:00
|
|
|
chunk_printf(&msg,
|
|
|
|
|
"<p><div class=active6>"
|
|
|
|
|
"<a class=lfsb href=\"%s\" title=\"Remove this message\">[X]</a> "
|
|
|
|
|
"Unexpected result."
|
|
|
|
|
"</div>\n", uri->uri_prefix);
|
|
|
|
|
}
|
|
|
|
|
chunk_printf(&msg,"<p>\n");
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-07 05:56:55 -04:00
|
|
|
if (bi_putchk(rep, &msg) == -1)
|
2007-10-17 12:44:57 -04:00
|
|
|
return 0;
|
|
|
|
|
}
|
2007-10-17 11:06:05 -04:00
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.stats.px = proxy;
|
|
|
|
|
si->applet.ctx.stats.px_st = STAT_PX_ST_INIT;
|
2012-05-21 11:09:48 -04:00
|
|
|
si->conn.data_st = STAT_ST_LIST;
|
2007-10-17 11:06:05 -04:00
|
|
|
/* fall through */
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
case STAT_ST_LIST:
|
2007-10-17 11:06:05 -04:00
|
|
|
/* dump proxies */
|
2011-03-10 05:25:07 -05:00
|
|
|
while (si->applet.ctx.stats.px) {
|
2012-07-02 11:01:20 -04:00
|
|
|
if (buffer_almost_full(&rep->buf))
|
2009-10-11 17:35:10 -04:00
|
|
|
return 0;
|
2011-03-10 05:25:07 -05:00
|
|
|
px = si->applet.ctx.stats.px;
|
2007-10-17 11:06:05 -04:00
|
|
|
/* skip the disabled proxies and non-networked ones */
|
|
|
|
|
if (px->state != PR_STSTOPPED && (px->cap & (PR_CAP_FE | PR_CAP_BE)))
|
2011-02-13 09:27:22 -05:00
|
|
|
if (stats_dump_proxy(si, px, uri) == 0)
|
2007-10-17 11:06:05 -04:00
|
|
|
return 0;
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.stats.px = px->next;
|
|
|
|
|
si->applet.ctx.stats.px_st = STAT_PX_ST_INIT;
|
2007-10-17 11:06:05 -04:00
|
|
|
}
|
|
|
|
|
/* here, we just have reached the last proxy */
|
|
|
|
|
|
2012-05-21 11:09:48 -04:00
|
|
|
si->conn.data_st = STAT_ST_END;
|
2007-10-17 11:06:05 -04:00
|
|
|
/* fall through */
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
case STAT_ST_END:
|
|
|
|
|
if (!(si->applet.ctx.stats.flags & STAT_FMT_CSV)) {
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg, "</body></html>\n");
|
2012-05-07 05:56:55 -04:00
|
|
|
if (bi_putchk(rep, &msg) == -1)
|
2007-10-17 12:44:57 -04:00
|
|
|
return 0;
|
|
|
|
|
}
|
2007-10-17 11:06:05 -04:00
|
|
|
|
2012-05-21 11:09:48 -04:00
|
|
|
si->conn.data_st = STAT_ST_FIN;
|
2007-10-17 11:06:05 -04:00
|
|
|
/* fall through */
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
case STAT_ST_FIN:
|
2007-10-17 11:06:05 -04:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
/* unknown state ! */
|
2012-05-21 11:09:48 -04:00
|
|
|
si->conn.data_st = STAT_ST_FIN;
|
2007-10-17 11:06:05 -04:00
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Dumps statistics for a proxy.
|
|
|
|
|
* Returns 0 if it had to stop dumping data because of lack of buffer space,
|
|
|
|
|
* ot non-zero if everything completed.
|
|
|
|
|
*/
|
2011-06-15 02:18:44 -04:00
|
|
|
static int stats_dump_proxy(struct stream_interface *si, struct proxy *px, struct uri_auth *uri)
|
2007-10-17 11:06:05 -04:00
|
|
|
{
|
2012-05-21 11:09:48 -04:00
|
|
|
struct session *s = si->conn.data_ctx;
|
2012-07-02 09:11:27 -04:00
|
|
|
struct channel *rep = si->ib;
|
2011-10-28 09:35:33 -04:00
|
|
|
struct server *sv, *svs; /* server and server-state, server-state=server or server->track */
|
2009-10-04 09:43:17 -04:00
|
|
|
struct listener *l;
|
2007-10-17 11:06:05 -04:00
|
|
|
struct chunk msg;
|
|
|
|
|
|
2012-05-16 08:16:48 -04:00
|
|
|
chunk_init(&msg, trash, trashlen);
|
2007-10-17 11:06:05 -04:00
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
switch (si->applet.ctx.stats.px_st) {
|
|
|
|
|
case STAT_PX_ST_INIT:
|
2007-10-17 11:06:05 -04:00
|
|
|
/* we are on a new proxy */
|
|
|
|
|
|
|
|
|
|
if (uri && uri->scope) {
|
|
|
|
|
/* we have a limited scope, we have to check the proxy name */
|
|
|
|
|
struct stat_scope *scope;
|
|
|
|
|
int len;
|
|
|
|
|
|
|
|
|
|
len = strlen(px->id);
|
|
|
|
|
scope = uri->scope;
|
|
|
|
|
|
|
|
|
|
while (scope) {
|
|
|
|
|
/* match exact proxy name */
|
|
|
|
|
if (scope->px_len == len && !memcmp(px->id, scope->px_id, len))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* match '.' which means 'self' proxy */
|
2007-10-18 10:38:37 -04:00
|
|
|
if (!strcmp(scope->px_id, ".") && px == s->be)
|
2007-10-17 11:06:05 -04:00
|
|
|
break;
|
|
|
|
|
scope = scope->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* proxy name not found : don't dump anything */
|
|
|
|
|
if (scope == NULL)
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
if ((si->applet.ctx.stats.flags & STAT_BOUND) && (si->applet.ctx.stats.iid != -1) &&
|
|
|
|
|
(px->uuid != si->applet.ctx.stats.iid))
|
[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.
2008-03-01 20:42:14 -05:00
|
|
|
return 1;
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.stats.px_st = STAT_PX_ST_TH;
|
2007-10-17 11:06:05 -04:00
|
|
|
/* fall through */
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
case STAT_PX_ST_TH:
|
|
|
|
|
if (!(si->applet.ctx.stats.flags & STAT_FMT_CSV)) {
|
|
|
|
|
if (px->cap & PR_CAP_BE && px->srv && (si->applet.ctx.stats.flags & STAT_ADMIN)) {
|
2010-10-11 18:14:35 -04:00
|
|
|
/* A form to enable/disable this proxy servers */
|
|
|
|
|
chunk_printf(&msg,
|
|
|
|
|
"<form action=\"%s\" method=\"post\">",
|
|
|
|
|
uri->uri_prefix);
|
|
|
|
|
}
|
|
|
|
|
|
2007-10-17 12:44:57 -04:00
|
|
|
/* print a new table */
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2009-10-02 16:51:14 -04:00
|
|
|
"<table class=\"tbl\" width=\"100%%\">\n"
|
2009-10-12 17:09:08 -04:00
|
|
|
"<tr class=\"titre\">"
|
2010-01-04 10:03:09 -05:00
|
|
|
"<th class=\"pxname\" width=\"10%%\"");
|
|
|
|
|
|
|
|
|
|
if (uri->flags&ST_SHLGNDS) {
|
|
|
|
|
/* cap, mode, id */
|
|
|
|
|
chunk_printf(&msg, " title=\"cap: %s, mode: %s, id: %d",
|
|
|
|
|
proxy_cap_str(px->cap), proxy_mode_str(px->mode),
|
|
|
|
|
px->uuid);
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg, "\"");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg,
|
2010-02-26 06:29:07 -05:00
|
|
|
">%s<a name=\"%s\"></a>"
|
|
|
|
|
"<a class=px href=\"#%s\">%s</a>%s</th>"
|
2009-10-02 16:51:14 -04:00
|
|
|
"<th class=\"%s\" width=\"90%%\">%s</th>"
|
2007-10-17 12:44:57 -04:00
|
|
|
"</tr>\n"
|
2009-10-02 16:51:14 -04:00
|
|
|
"</table>\n"
|
2009-10-12 17:09:08 -04:00
|
|
|
"<table class=\"tbl\" width=\"100%%\">\n"
|
2010-10-11 18:14:35 -04:00
|
|
|
"<tr class=\"titre\">",
|
|
|
|
|
(uri->flags & ST_SHLGNDS)?"<u>":"",
|
|
|
|
|
px->id, px->id, px->id,
|
|
|
|
|
(uri->flags & ST_SHLGNDS)?"</u>":"",
|
|
|
|
|
px->desc ? "desc" : "empty", px->desc ? px->desc : "");
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
if (px->cap & PR_CAP_BE && px->srv && (si->applet.ctx.stats.flags & STAT_ADMIN)) {
|
2010-10-11 18:14:35 -04:00
|
|
|
/* Column heading for Enable or Disable server */
|
|
|
|
|
chunk_printf(&msg, "<th rowspan=2 width=1></th>");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg,
|
2007-10-17 12:44:57 -04:00
|
|
|
"<th rowspan=2></th>"
|
2009-05-10 13:19:41 -04:00
|
|
|
"<th colspan=3>Queue</th>"
|
|
|
|
|
"<th colspan=3>Session rate</th><th colspan=5>Sessions</th>"
|
2007-10-17 12:44:57 -04:00
|
|
|
"<th colspan=2>Bytes</th><th colspan=2>Denied</th>"
|
2007-10-18 13:12:30 -04:00
|
|
|
"<th colspan=3>Errors</th><th colspan=2>Warnings</th>"
|
2009-09-23 16:09:24 -04:00
|
|
|
"<th colspan=9>Server</th>"
|
2007-10-17 12:44:57 -04:00
|
|
|
"</tr>\n"
|
2009-10-12 17:09:08 -04:00
|
|
|
"<tr class=\"titre\">"
|
2009-05-10 13:19:41 -04:00
|
|
|
"<th>Cur</th><th>Max</th><th>Limit</th>"
|
2007-10-25 14:15:38 -04:00
|
|
|
"<th>Cur</th><th>Max</th><th>Limit</th><th>Cur</th><th>Max</th>"
|
2009-05-10 13:19:41 -04:00
|
|
|
"<th>Limit</th><th>Total</th><th>LbTot</th><th>In</th><th>Out</th>"
|
2007-10-17 12:44:57 -04:00
|
|
|
"<th>Req</th><th>Resp</th><th>Req</th><th>Conn</th>"
|
2007-10-18 13:12:30 -04:00
|
|
|
"<th>Resp</th><th>Retr</th><th>Redis</th>"
|
2009-09-23 16:09:24 -04:00
|
|
|
"<th>Status</th><th>LastChk</th><th>Wght</th><th>Act</th>"
|
2007-11-30 12:16:29 -05:00
|
|
|
"<th>Bck</th><th>Chk</th><th>Dwn</th><th>Dwntme</th>"
|
|
|
|
|
"<th>Thrtle</th>\n"
|
2010-10-11 18:14:35 -04:00
|
|
|
"</tr>");
|
2007-10-17 12:44:57 -04:00
|
|
|
|
2012-05-07 05:56:55 -04:00
|
|
|
if (bi_putchk(rep, &msg) == -1)
|
2007-10-17 12:44:57 -04:00
|
|
|
return 0;
|
|
|
|
|
}
|
2007-10-17 11:06:05 -04:00
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.stats.px_st = STAT_PX_ST_FE;
|
2007-10-17 11:06:05 -04:00
|
|
|
/* fall through */
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
case STAT_PX_ST_FE:
|
2007-10-17 11:06:05 -04:00
|
|
|
/* print the frontend */
|
[MEDIUM] fix stats socket limitation to 16 kB
Due to the way the stats socket work, it was not possible to
maintain the information related to the command entered, so
after filling a whole buffer, the request was lost and it was
considered that there was nothing to write anymore.
The major reason was that some flags were passed directly
during the first call to stats_dump_raw() instead of being
stored persistently in the session.
To definitely fix this problem, flags were added to the stats
member of the session structure.
A second problem appeared. When the stats were produced, a first
call to client_retnclose() was performed, then one or multiple
subsequent calls to buffer_write_chunks() were done. But once the
stats buffer was full and a reschedule operated, the buffer was
flushed, the write flag cleared from the buffer and nothing was
done to re-arm it.
For this reason, a check was added in the proto_uxst_stats()
function in order to re-call the client FSM when data were added
by stats_dump_raw(). Finally, the whole unix stats dump FSM was
rewritten to avoid all the magics it depended on. It is now
simpler and looks more like the HTTP one.
2008-03-17 16:38:24 -04:00
|
|
|
if ((px->cap & PR_CAP_FE) &&
|
2011-03-10 05:25:07 -05:00
|
|
|
(!(si->applet.ctx.stats.flags & STAT_BOUND) || (si->applet.ctx.stats.type & (1 << STATS_TYPE_FE)))) {
|
|
|
|
|
if (!(si->applet.ctx.stats.flags & STAT_FMT_CSV)) {
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2007-10-17 11:06:05 -04:00
|
|
|
/* name, queue */
|
2010-10-11 18:14:35 -04:00
|
|
|
"<tr class=\"frontend\">");
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
if (px->cap & PR_CAP_BE && px->srv && (si->applet.ctx.stats.flags & STAT_ADMIN)) {
|
2010-10-11 18:14:35 -04:00
|
|
|
/* Column sub-heading for Enable or Disable server */
|
|
|
|
|
chunk_printf(&msg, "<td></td>");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg,
|
|
|
|
|
"<td class=ac>"
|
2009-10-24 08:24:30 -04:00
|
|
|
"<a name=\"%s/Frontend\"></a>"
|
2010-10-11 18:14:35 -04:00
|
|
|
"<a class=lfsb href=\"#%s/Frontend\">Frontend</a></td>"
|
|
|
|
|
"<td colspan=3></td>"
|
2010-02-26 05:35:39 -05:00
|
|
|
"",
|
|
|
|
|
px->id, px->id);
|
|
|
|
|
|
|
|
|
|
if (px->mode == PR_MODE_HTTP) {
|
|
|
|
|
chunk_printf(&msg,
|
|
|
|
|
/* sessions rate : current, max, limit */
|
2010-02-26 06:29:07 -05:00
|
|
|
"<td title=\"Cur: %u req/s\"><u>%s</u></td><td title=\"Max: %u req/s\"><u>%s</u></td><td>%s</td>"
|
2010-02-26 05:35:39 -05:00
|
|
|
"",
|
|
|
|
|
read_freq_ctr(&px->fe_req_per_sec),
|
|
|
|
|
U2H0(read_freq_ctr(&px->fe_sess_per_sec)),
|
2011-03-10 17:25:56 -05:00
|
|
|
px->fe_counters.p.http.rps_max,
|
|
|
|
|
U2H1(px->fe_counters.sps_max),
|
2010-02-26 05:35:39 -05:00
|
|
|
LIM2A2(px->fe_sps_lim, "-"));
|
|
|
|
|
} else {
|
|
|
|
|
chunk_printf(&msg,
|
|
|
|
|
/* sessions rate : current, max, limit */
|
|
|
|
|
"<td>%s</td><td>%s</td><td>%s</td>"
|
|
|
|
|
"",
|
|
|
|
|
U2H0(read_freq_ctr(&px->fe_sess_per_sec)),
|
2011-03-10 17:25:56 -05:00
|
|
|
U2H1(px->fe_counters.sps_max), LIM2A2(px->fe_sps_lim, "-"));
|
2010-02-26 05:35:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg,
|
2009-10-24 09:36:15 -04:00
|
|
|
/* sessions: current, max, limit */
|
2009-10-12 17:09:08 -04:00
|
|
|
"<td>%s</td><td>%s</td><td>%s</td>"
|
2009-10-24 09:36:15 -04:00
|
|
|
"<td"
|
2009-03-29 08:46:01 -04:00
|
|
|
"",
|
2011-03-10 17:25:56 -05:00
|
|
|
U2H3(px->feconn), U2H4(px->fe_counters.conn_max), U2H5(px->maxconn));
|
2009-10-24 09:36:15 -04:00
|
|
|
|
|
|
|
|
/* http response (via td title): 1xx, 2xx, 3xx, 4xx, 5xx, other */
|
|
|
|
|
if (px->mode == PR_MODE_HTTP) {
|
|
|
|
|
int i;
|
|
|
|
|
|
2011-03-10 17:25:56 -05:00
|
|
|
chunk_printf(&msg, " title=\"%lld requests:", px->fe_counters.p.http.cum_req);
|
2009-10-24 09:36:15 -04:00
|
|
|
|
|
|
|
|
for (i = 1; i < 6; i++)
|
2011-03-10 17:25:56 -05:00
|
|
|
chunk_printf(&msg, " %dxx=%lld,", i, px->fe_counters.p.http.rsp[i]);
|
2009-10-24 09:36:15 -04:00
|
|
|
|
2011-09-10 17:29:44 -04:00
|
|
|
chunk_printf(&msg, " other=%lld,", px->fe_counters.p.http.rsp[0]);
|
|
|
|
|
chunk_printf(&msg, " intercepted=%lld\"", px->fe_counters.intercepted_req);
|
2009-10-24 09:36:15 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg,
|
|
|
|
|
/* sessions: total, lbtot */
|
2010-02-26 06:29:07 -05:00
|
|
|
">%s%s%s</td><td></td>"
|
2009-10-24 09:36:15 -04:00
|
|
|
/* bytes : in, out */
|
|
|
|
|
"<td>%s</td><td>%s</td>"
|
|
|
|
|
"",
|
2010-02-26 06:29:07 -05:00
|
|
|
(px->mode == PR_MODE_HTTP)?"<u>":"",
|
2011-03-10 17:25:56 -05:00
|
|
|
U2H6(px->fe_counters.cum_sess),
|
2010-02-26 06:29:07 -05:00
|
|
|
(px->mode == PR_MODE_HTTP)?"</u>":"",
|
2011-03-10 17:25:56 -05:00
|
|
|
U2H7(px->fe_counters.bytes_in), U2H8(px->fe_counters.bytes_out));
|
2009-03-29 08:46:01 -04:00
|
|
|
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2007-10-17 11:06:05 -04:00
|
|
|
/* denied: req, resp */
|
2009-10-12 17:09:08 -04:00
|
|
|
"<td>%s</td><td>%s</td>"
|
2007-10-17 11:06:05 -04:00
|
|
|
/* errors : request, connect, response */
|
2009-10-12 17:09:08 -04:00
|
|
|
"<td>%s</td><td></td><td></td>"
|
2007-10-18 13:12:30 -04:00
|
|
|
/* warnings: retries, redispatches */
|
2009-10-12 17:09:08 -04:00
|
|
|
"<td></td><td></td>"
|
2007-10-17 12:44:57 -04:00
|
|
|
/* server status : reflect frontend status */
|
2009-10-12 17:09:08 -04:00
|
|
|
"<td class=ac>%s</td>"
|
2007-10-17 11:06:05 -04:00
|
|
|
/* rest of server: nothing */
|
2009-10-12 17:09:08 -04:00
|
|
|
"<td class=ac colspan=8></td></tr>"
|
2007-10-17 11:06:05 -04:00
|
|
|
"",
|
2011-03-10 17:25:56 -05:00
|
|
|
U2H0(px->fe_counters.denied_req), U2H1(px->fe_counters.denied_resp),
|
|
|
|
|
U2H2(px->fe_counters.failed_req),
|
2011-07-25 02:11:52 -04:00
|
|
|
px->state == PR_STREADY ? "OPEN" :
|
|
|
|
|
px->state == PR_STFULL ? "FULL" : "STOP");
|
2007-10-17 12:44:57 -04:00
|
|
|
} else {
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2007-10-17 12:44:57 -04:00
|
|
|
/* pxid, name, queue cur, queue max, */
|
|
|
|
|
"%s,FRONTEND,,,"
|
2007-12-05 04:34:49 -05:00
|
|
|
/* sessions : current, max, limit, total */
|
2009-04-11 14:44:08 -04:00
|
|
|
"%d,%d,%d,%lld,"
|
2007-10-17 12:44:57 -04:00
|
|
|
/* bytes : in, out */
|
|
|
|
|
"%lld,%lld,"
|
|
|
|
|
/* denied: req, resp */
|
2009-04-11 14:44:08 -04:00
|
|
|
"%lld,%lld,"
|
2007-10-17 12:44:57 -04:00
|
|
|
/* errors : request, connect, response */
|
2009-04-11 14:44:08 -04:00
|
|
|
"%lld,,,"
|
2007-10-18 13:12:30 -04:00
|
|
|
/* warnings: retries, redispatches */
|
|
|
|
|
",,"
|
2007-10-17 12:44:57 -04:00
|
|
|
/* server status : reflect frontend status */
|
|
|
|
|
"%s,"
|
|
|
|
|
/* rest of server: nothing */
|
2007-10-25 14:15:38 -04: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.
2008-03-01 20:42:14 -05:00
|
|
|
/* pid, iid, sid, throttle, lbtot, tracked, type */
|
|
|
|
|
"%d,%d,0,,,,%d,"
|
2009-09-23 16:09:24 -04:00
|
|
|
/* rate, rate_lim, rate_max */
|
2009-05-10 13:01:49 -04:00
|
|
|
"%u,%u,%u,"
|
2009-09-23 16:09:24 -04:00
|
|
|
/* check_status, check_code, check_duration */
|
2009-10-24 09:36:15 -04:00
|
|
|
",,,",
|
2007-10-17 12:44:57 -04:00
|
|
|
px->id,
|
2011-03-10 17:25:56 -05:00
|
|
|
px->feconn, px->fe_counters.conn_max, px->maxconn, px->fe_counters.cum_sess,
|
|
|
|
|
px->fe_counters.bytes_in, px->fe_counters.bytes_out,
|
|
|
|
|
px->fe_counters.denied_req, px->fe_counters.denied_resp,
|
|
|
|
|
px->fe_counters.failed_req,
|
2011-07-25 02:11:52 -04:00
|
|
|
px->state == PR_STREADY ? "OPEN" :
|
|
|
|
|
px->state == PR_STFULL ? "FULL" : "STOP",
|
2009-03-05 12:43:00 -05:00
|
|
|
relative_pid, px->uuid, STATS_TYPE_FE,
|
2009-05-10 13:01:49 -04:00
|
|
|
read_freq_ctr(&px->fe_sess_per_sec),
|
2011-03-10 17:25:56 -05:00
|
|
|
px->fe_sps_lim, px->fe_counters.sps_max);
|
2009-10-24 09:36:15 -04:00
|
|
|
|
|
|
|
|
/* http response: 1xx, 2xx, 3xx, 4xx, 5xx, other */
|
|
|
|
|
if (px->mode == PR_MODE_HTTP) {
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i=1; i<6; i++)
|
2011-03-10 17:25:56 -05:00
|
|
|
chunk_printf(&msg, "%lld,", px->fe_counters.p.http.rsp[i]);
|
2009-10-24 09:36:15 -04:00
|
|
|
|
2011-03-10 17:25:56 -05:00
|
|
|
chunk_printf(&msg, "%lld,", px->fe_counters.p.http.rsp[0]);
|
2009-10-24 09:36:15 -04:00
|
|
|
} else {
|
|
|
|
|
chunk_printf(&msg, ",,,,,,");
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-15 16:31:24 -05:00
|
|
|
/* failed health analyses */
|
|
|
|
|
chunk_printf(&msg, ",");
|
|
|
|
|
|
2010-02-26 04:05:55 -05:00
|
|
|
/* requests : req_rate, req_rate_max, req_tot, */
|
|
|
|
|
chunk_printf(&msg, "%u,%u,%lld,",
|
|
|
|
|
read_freq_ctr(&px->fe_req_per_sec),
|
2011-03-10 17:25:56 -05:00
|
|
|
px->fe_counters.p.http.rps_max, px->fe_counters.p.http.cum_req);
|
2010-02-26 04:05:55 -05:00
|
|
|
|
2010-03-04 14:34:23 -05:00
|
|
|
/* errors: cli_aborts, srv_aborts */
|
|
|
|
|
chunk_printf(&msg, ",,");
|
|
|
|
|
|
2009-10-24 09:36:15 -04:00
|
|
|
/* finish with EOL */
|
|
|
|
|
chunk_printf(&msg, "\n");
|
2007-10-17 12:44:57 -04:00
|
|
|
}
|
2007-10-17 11:06:05 -04:00
|
|
|
|
2012-05-07 05:56:55 -04:00
|
|
|
if (bi_putchk(rep, &msg) == -1)
|
2007-10-17 11:06:05 -04:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.stats.l = px->listen; /* may be NULL */
|
|
|
|
|
si->applet.ctx.stats.px_st = STAT_PX_ST_LI;
|
2009-10-04 09:43:17 -04:00
|
|
|
/* fall through */
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
case STAT_PX_ST_LI:
|
2009-10-04 09:43:17 -04:00
|
|
|
/* stats.l has been initialized above */
|
2011-03-10 05:25:07 -05:00
|
|
|
for (; si->applet.ctx.stats.l != NULL; si->applet.ctx.stats.l = l->next) {
|
2012-07-02 11:01:20 -04:00
|
|
|
if (buffer_almost_full(&rep->buf))
|
2009-10-11 17:35:10 -04:00
|
|
|
return 0;
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
l = si->applet.ctx.stats.l;
|
2009-10-04 09:43:17 -04:00
|
|
|
if (!l->counters)
|
|
|
|
|
continue;
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
if (si->applet.ctx.stats.flags & STAT_BOUND) {
|
|
|
|
|
if (!(si->applet.ctx.stats.type & (1 << STATS_TYPE_SO)))
|
2009-10-04 09:43:17 -04:00
|
|
|
break;
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
if (si->applet.ctx.stats.sid != -1 && l->luid != si->applet.ctx.stats.sid)
|
2009-10-04 09:43:17 -04:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
if (!(si->applet.ctx.stats.flags & STAT_FMT_CSV)) {
|
2010-10-11 18:14:35 -04:00
|
|
|
chunk_printf(&msg, "<tr class=socket>");
|
2011-03-10 05:25:07 -05:00
|
|
|
if (px->cap & PR_CAP_BE && px->srv && (si->applet.ctx.stats.flags & STAT_ADMIN)) {
|
2010-10-11 18:14:35 -04:00
|
|
|
/* Column sub-heading for Enable or Disable server */
|
|
|
|
|
chunk_printf(&msg, "<td></td>");
|
|
|
|
|
}
|
|
|
|
|
chunk_printf(&msg, "<td class=ac");
|
2010-01-04 10:03:09 -05:00
|
|
|
|
|
|
|
|
if (uri->flags&ST_SHLGNDS) {
|
2011-09-04 18:36:48 -04:00
|
|
|
char str[INET6_ADDRSTRLEN];
|
2010-01-04 10:03:09 -05:00
|
|
|
int port;
|
|
|
|
|
|
2011-09-04 18:36:48 -04:00
|
|
|
chunk_printf(&msg, " title=\"");
|
|
|
|
|
|
|
|
|
|
port = get_host_port(&l->addr);
|
|
|
|
|
switch (addr_to_str(&l->addr, str, sizeof(str))) {
|
|
|
|
|
case AF_INET:
|
|
|
|
|
chunk_printf(&msg, "IPv4: %s:%d, ", str, port);
|
|
|
|
|
break;
|
|
|
|
|
case AF_INET6:
|
|
|
|
|
chunk_printf(&msg, "IPv6: [%s]:%d, ", str, port);
|
|
|
|
|
break;
|
|
|
|
|
case AF_UNIX:
|
|
|
|
|
chunk_printf(&msg, "unix, ");
|
|
|
|
|
break;
|
|
|
|
|
case -1:
|
|
|
|
|
chunk_printf(&msg, "(%s), ", strerror(errno));
|
|
|
|
|
break;
|
2010-01-04 10:03:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* id */
|
2011-09-04 18:36:48 -04:00
|
|
|
chunk_printf(&msg, "id: %d\"", l->luid);
|
2010-01-04 10:03:09 -05:00
|
|
|
}
|
|
|
|
|
|
2009-10-04 09:43:17 -04:00
|
|
|
chunk_printf(&msg,
|
|
|
|
|
/* name, queue */
|
2010-02-26 06:29:07 -05:00
|
|
|
">%s<a name=\"%s/+%s\"></a>"
|
|
|
|
|
"<a class=lfsb href=\"#%s/+%s\">%s</a></td><td colspan=3>%s</td>"
|
2009-10-04 09:43:17 -04:00
|
|
|
/* sessions rate: current, max, limit */
|
2009-10-12 17:09:08 -04:00
|
|
|
"<td colspan=3> </td>"
|
2009-10-04 09:43:17 -04:00
|
|
|
/* sessions: current, max, limit, total, lbtot */
|
2009-10-12 17:09:08 -04:00
|
|
|
"<td>%s</td><td>%s</td><td>%s</td>"
|
|
|
|
|
"<td>%s</td><td> </td>"
|
2009-10-04 09:43:17 -04:00
|
|
|
/* bytes: in, out */
|
2009-10-12 17:09:08 -04:00
|
|
|
"<td>%s</td><td>%s</td>"
|
2009-10-04 09:43:17 -04:00
|
|
|
"",
|
2010-02-26 06:29:07 -05:00
|
|
|
(uri->flags & ST_SHLGNDS)?"<u>":"",
|
2010-01-04 05:33:32 -05:00
|
|
|
px->id, l->name, px->id, l->name, l->name,
|
2010-02-26 06:29:07 -05:00
|
|
|
(uri->flags & ST_SHLGNDS)?"</u>":"",
|
2009-10-04 09:43:17 -04:00
|
|
|
U2H3(l->nbconn), U2H4(l->counters->conn_max), U2H5(l->maxconn),
|
|
|
|
|
U2H6(l->counters->cum_conn), U2H7(l->counters->bytes_in), U2H8(l->counters->bytes_out));
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg,
|
|
|
|
|
/* denied: req, resp */
|
2009-10-12 17:09:08 -04:00
|
|
|
"<td>%s</td><td>%s</td>"
|
2009-10-04 09:43:17 -04:00
|
|
|
/* errors: request, connect, response */
|
2009-10-12 17:09:08 -04:00
|
|
|
"<td>%s</td><td></td><td></td>"
|
2009-10-04 09:43:17 -04:00
|
|
|
/* warnings: retries, redispatches */
|
2009-10-12 17:09:08 -04:00
|
|
|
"<td></td><td></td>"
|
2009-10-04 09:43:17 -04:00
|
|
|
/* server status: reflect listener status */
|
2009-10-12 17:09:08 -04:00
|
|
|
"<td class=ac>%s</td>"
|
2009-10-04 09:43:17 -04:00
|
|
|
/* rest of server: nothing */
|
2009-10-12 17:09:08 -04:00
|
|
|
"<td class=ac colspan=8></td></tr>"
|
2009-10-04 09:43:17 -04:00
|
|
|
"",
|
|
|
|
|
U2H0(l->counters->denied_req), U2H1(l->counters->denied_resp),
|
|
|
|
|
U2H2(l->counters->failed_req),
|
2011-07-25 02:16:20 -04:00
|
|
|
(l->nbconn < l->maxconn) ? (l->state == LI_LIMITED) ? "WAITING" : "OPEN" : "FULL");
|
2009-10-04 09:43:17 -04:00
|
|
|
} else {
|
|
|
|
|
chunk_printf(&msg,
|
|
|
|
|
/* pxid, name, queue cur, queue max, */
|
|
|
|
|
"%s,%s,,,"
|
|
|
|
|
/* sessions: current, max, limit, total */
|
|
|
|
|
"%d,%d,%d,%lld,"
|
|
|
|
|
/* bytes: in, out */
|
|
|
|
|
"%lld,%lld,"
|
|
|
|
|
/* denied: req, resp */
|
|
|
|
|
"%lld,%lld,"
|
|
|
|
|
/* errors: request, connect, response */
|
|
|
|
|
"%lld,,,"
|
|
|
|
|
/* warnings: retries, redispatches */
|
|
|
|
|
",,"
|
|
|
|
|
/* server status: reflect listener status */
|
|
|
|
|
"%s,"
|
|
|
|
|
/* rest of server: nothing */
|
|
|
|
|
",,,,,,,,"
|
|
|
|
|
/* pid, iid, sid, throttle, lbtot, tracked, type */
|
|
|
|
|
"%d,%d,%d,,,,%d,"
|
|
|
|
|
/* rate, rate_lim, rate_max */
|
|
|
|
|
",,,"
|
|
|
|
|
/* check_status, check_code, check_duration */
|
|
|
|
|
",,,"
|
2009-10-13 15:14:09 -04:00
|
|
|
/* http response: 1xx, 2xx, 3xx, 4xx, 5xx, other */
|
|
|
|
|
",,,,,,"
|
2009-12-15 16:31:24 -05:00
|
|
|
/* failed health analyses */
|
|
|
|
|
","
|
2010-02-26 04:05:55 -05:00
|
|
|
/* requests : req_rate, req_rate_max, req_tot, */
|
|
|
|
|
",,,"
|
2010-03-04 14:34:23 -05:00
|
|
|
/* errors: cli_aborts, srv_aborts */
|
|
|
|
|
",,"
|
2009-10-04 09:43:17 -04:00
|
|
|
"\n",
|
|
|
|
|
px->id, l->name,
|
|
|
|
|
l->nbconn, l->counters->conn_max,
|
|
|
|
|
l->maxconn, l->counters->cum_conn,
|
|
|
|
|
l->counters->bytes_in, l->counters->bytes_out,
|
|
|
|
|
l->counters->denied_req, l->counters->denied_resp,
|
|
|
|
|
l->counters->failed_req,
|
|
|
|
|
(l->nbconn < l->maxconn) ? "OPEN" : "FULL",
|
|
|
|
|
relative_pid, px->uuid, l->luid, STATS_TYPE_SO);
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-07 05:56:55 -04:00
|
|
|
if (bi_putchk(rep, &msg) == -1)
|
2009-10-04 09:43:17 -04:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.stats.sv = px->srv; /* may be NULL */
|
|
|
|
|
si->applet.ctx.stats.px_st = STAT_PX_ST_SV;
|
2007-10-17 11:06:05 -04:00
|
|
|
/* fall through */
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
case STAT_PX_ST_SV:
|
2007-10-17 11:06:05 -04:00
|
|
|
/* stats.sv has been initialized above */
|
2011-03-10 05:25:07 -05:00
|
|
|
for (; si->applet.ctx.stats.sv != NULL; si->applet.ctx.stats.sv = sv->next) {
|
2007-11-30 06:04:38 -05:00
|
|
|
int sv_state; /* 0=DOWN, 1=going up, 2=going down, 3=UP, 4,5=NOLB, 6=unchecked */
|
2007-10-17 11:06:05 -04:00
|
|
|
|
2012-07-02 11:01:20 -04:00
|
|
|
if (buffer_almost_full(&rep->buf))
|
2009-10-11 17:35:10 -04:00
|
|
|
return 0;
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
sv = si->applet.ctx.stats.sv;
|
2007-10-17 11:06:05 -04:00
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
if (si->applet.ctx.stats.flags & STAT_BOUND) {
|
|
|
|
|
if (!(si->applet.ctx.stats.type & (1 << STATS_TYPE_SV)))
|
[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.
2008-03-01 20:42:14 -05:00
|
|
|
break;
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
if (si->applet.ctx.stats.sid != -1 && sv->puid != si->applet.ctx.stats.sid)
|
[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.
2008-03-01 20:42:14 -05:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-28 09:35:33 -04:00
|
|
|
if (sv->track)
|
|
|
|
|
svs = sv->track;
|
2008-02-17 19:26:35 -05:00
|
|
|
else
|
|
|
|
|
svs = sv;
|
|
|
|
|
|
2007-10-17 11:06:05 -04:00
|
|
|
/* FIXME: produce some small strings for "UP/DOWN x/y &#xxxx;" */
|
2008-02-17 19:26:35 -05:00
|
|
|
if (!(svs->state & SRV_CHECKED))
|
2007-11-30 06:04:38 -05:00
|
|
|
sv_state = 6;
|
2008-02-17 19:26:35 -05:00
|
|
|
else if (svs->state & SRV_RUNNING) {
|
|
|
|
|
if (svs->health == svs->rise + svs->fall - 1)
|
2007-10-17 11:06:05 -04:00
|
|
|
sv_state = 3; /* UP */
|
|
|
|
|
else
|
|
|
|
|
sv_state = 2; /* going down */
|
2007-11-30 06:04:38 -05:00
|
|
|
|
2008-02-17 19:26:35 -05:00
|
|
|
if (svs->state & SRV_GOINGDOWN)
|
2007-11-30 06:04:38 -05:00
|
|
|
sv_state += 2;
|
|
|
|
|
}
|
2007-10-17 11:06:05 -04:00
|
|
|
else
|
2008-02-17 19:26:35 -05:00
|
|
|
if (svs->health)
|
2007-10-17 11:06:05 -04:00
|
|
|
sv_state = 1; /* going up */
|
|
|
|
|
else
|
|
|
|
|
sv_state = 0; /* DOWN */
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
if (((sv_state == 0) || (sv->state & SRV_MAINTAIN)) && (si->applet.ctx.stats.flags & STAT_HIDE_DOWN)) {
|
2007-10-17 11:06:05 -04:00
|
|
|
/* do not report servers which are DOWN */
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.stats.sv = sv->next;
|
2007-10-17 11:06:05 -04:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
if (!(si->applet.ctx.stats.flags & STAT_FMT_CSV)) {
|
2007-11-30 06:04:38 -05:00
|
|
|
static char *srv_hlt_st[7] = { "DOWN", "DN %d/%d ↑",
|
|
|
|
|
"UP %d/%d ↓", "UP",
|
|
|
|
|
"NOLB %d/%d ↓", "NOLB",
|
|
|
|
|
"<i>no check</i>" };
|
2010-02-02 18:26:28 -05:00
|
|
|
if ((sv->state & SRV_MAINTAIN) || (svs->state & SRV_MAINTAIN)) {
|
2010-01-31 16:34:03 -05:00
|
|
|
chunk_printf(&msg,
|
|
|
|
|
/* name */
|
2010-10-11 18:14:35 -04:00
|
|
|
"<tr class=\"maintain\">"
|
2010-01-31 16:34:03 -05:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
chunk_printf(&msg,
|
|
|
|
|
/* name */
|
2010-10-11 18:14:35 -04:00
|
|
|
"<tr class=\"%s%d\">",
|
2010-01-31 16:34:03 -05:00
|
|
|
(sv->state & SRV_BACKUP) ? "backup" : "active", sv_state);
|
|
|
|
|
}
|
2010-01-04 10:03:09 -05:00
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
if (px->cap & PR_CAP_BE && px->srv && (si->applet.ctx.stats.flags & STAT_ADMIN)) {
|
2010-10-11 18:14:36 -04:00
|
|
|
chunk_printf(&msg,
|
|
|
|
|
"<td><input type=\"checkbox\" name=\"s\" value=\"%s\"></td>",
|
|
|
|
|
sv->id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg, "<td class=ac");
|
2010-10-11 18:14:35 -04:00
|
|
|
|
2010-01-04 10:03:09 -05:00
|
|
|
if (uri->flags&ST_SHLGNDS) {
|
|
|
|
|
char str[INET6_ADDRSTRLEN];
|
|
|
|
|
|
2011-09-04 18:36:48 -04:00
|
|
|
chunk_printf(&msg, " title=\"");
|
2010-01-04 10:03:09 -05:00
|
|
|
|
2011-09-04 18:36:48 -04:00
|
|
|
switch (addr_to_str(&sv->addr, str, sizeof(str))) {
|
2011-03-10 16:26:24 -05:00
|
|
|
case AF_INET:
|
2011-09-04 18:36:48 -04:00
|
|
|
chunk_printf(&msg, "IPv4: %s:%d, ", str, get_host_port(&sv->addr));
|
2011-03-10 16:26:24 -05:00
|
|
|
break;
|
|
|
|
|
case AF_INET6:
|
2011-09-04 18:36:48 -04:00
|
|
|
chunk_printf(&msg, "IPv6: [%s]:%d, ", str, get_host_port(&sv->addr));
|
|
|
|
|
break;
|
|
|
|
|
case AF_UNIX:
|
|
|
|
|
chunk_printf(&msg, "unix, ");
|
|
|
|
|
break;
|
|
|
|
|
case -1:
|
|
|
|
|
chunk_printf(&msg, "(%s), ", strerror(errno));
|
|
|
|
|
break;
|
|
|
|
|
default: /* address family not supported */
|
2011-03-10 16:26:24 -05:00
|
|
|
break;
|
|
|
|
|
}
|
2010-01-04 10:03:09 -05:00
|
|
|
|
|
|
|
|
/* id */
|
2011-09-04 18:36:48 -04:00
|
|
|
chunk_printf(&msg, "id: %d", sv->puid);
|
2010-01-04 10:03:09 -05:00
|
|
|
|
|
|
|
|
/* cookie */
|
|
|
|
|
if (sv->cookie) {
|
|
|
|
|
struct chunk src;
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg, ", cookie: '");
|
|
|
|
|
|
|
|
|
|
chunk_initlen(&src, sv->cookie, 0, strlen(sv->cookie));
|
|
|
|
|
chunk_htmlencode(&msg, &src);
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg, "'");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg, "\"");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg,
|
2010-02-26 06:29:07 -05:00
|
|
|
">%s<a name=\"%s/%s\"></a>"
|
|
|
|
|
"<a class=lfsb href=\"#%s/%s\">%s</a>%s</td>"
|
2007-10-25 14:15:38 -04:00
|
|
|
/* queue : current, max, limit */
|
2009-10-12 17:09:08 -04:00
|
|
|
"<td>%s</td><td>%s</td><td>%s</td>"
|
2009-05-10 13:19:41 -04:00
|
|
|
/* sessions rate : current, max, limit */
|
2009-10-12 17:09:08 -04:00
|
|
|
"<td>%s</td><td>%s</td><td></td>"
|
2009-10-13 15:14:09 -04:00
|
|
|
/* sessions: current, max, limit */
|
2009-10-12 17:09:08 -04:00
|
|
|
"<td>%s</td><td>%s</td><td>%s</td>"
|
2009-10-13 15:14:09 -04:00
|
|
|
"<td"
|
2009-03-29 08:46:01 -04:00
|
|
|
"",
|
2010-02-26 06:29:07 -05:00
|
|
|
(uri->flags & ST_SHLGNDS)?"<u>":"",
|
2010-01-04 10:03:09 -05:00
|
|
|
px->id, sv->id, px->id, sv->id, sv->id,
|
2010-02-26 06:29:07 -05:00
|
|
|
(uri->flags & ST_SHLGNDS)?"</u>":"",
|
2009-10-04 17:12:44 -04:00
|
|
|
U2H0(sv->nbpend), U2H1(sv->counters.nbpend_max), LIM2A2(sv->maxqueue, "-"),
|
|
|
|
|
U2H3(read_freq_ctr(&sv->sess_per_sec)), U2H4(sv->counters.sps_max),
|
2009-10-13 15:14:09 -04:00
|
|
|
U2H5(sv->cur_sess), U2H6(sv->counters.cur_sess_max), LIM2A7(sv->maxconn, "-"));
|
|
|
|
|
|
|
|
|
|
/* http response (via td title): 1xx, 2xx, 3xx, 4xx, 5xx, other */
|
|
|
|
|
if (px->mode == PR_MODE_HTTP) {
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg, " title=\"rsp codes:");
|
|
|
|
|
|
|
|
|
|
for (i = 1; i < 6; i++)
|
|
|
|
|
chunk_printf(&msg, " %dxx=%lld,", i, sv->counters.p.http.rsp[i]);
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg, " other=%lld\"", sv->counters.p.http.rsp[0]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg,
|
|
|
|
|
/* sessions: total, lbtot */
|
2010-02-26 06:29:07 -05:00
|
|
|
">%s%s%s</td><td>%s</td>",
|
|
|
|
|
(px->mode == PR_MODE_HTTP)?"<u>":"",
|
|
|
|
|
U2H0(sv->counters.cum_sess),
|
|
|
|
|
(px->mode == PR_MODE_HTTP)?"</u>":"",
|
|
|
|
|
U2H1(sv->counters.cum_lbconn));
|
2009-03-29 08:46:01 -04:00
|
|
|
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2007-10-17 11:06:05 -04:00
|
|
|
/* bytes : in, out */
|
2009-10-12 17:09:08 -04:00
|
|
|
"<td>%s</td><td>%s</td>"
|
2007-10-17 11:06:05 -04:00
|
|
|
/* denied: req, resp */
|
2009-10-12 17:09:08 -04:00
|
|
|
"<td></td><td>%s</td>"
|
2010-03-04 14:34:23 -05:00
|
|
|
/* errors : request, connect */
|
|
|
|
|
"<td></td><td>%s</td>"
|
|
|
|
|
/* errors : response */
|
2010-03-05 12:15:23 -05:00
|
|
|
"<td title=\"Connection resets during transfers: %lld client, %lld server\"><u>%s</u></td>"
|
2007-10-18 13:12:30 -04:00
|
|
|
/* warnings: retries, redispatches */
|
2009-10-12 17:09:08 -04:00
|
|
|
"<td>%lld</td><td>%lld</td>"
|
2007-10-17 11:06:05 -04:00
|
|
|
"",
|
2009-10-04 08:52:57 -04:00
|
|
|
U2H0(sv->counters.bytes_in), U2H1(sv->counters.bytes_out),
|
|
|
|
|
U2H2(sv->counters.failed_secu),
|
2010-03-04 14:34:23 -05:00
|
|
|
U2H3(sv->counters.failed_conns),
|
2010-03-05 12:15:23 -05:00
|
|
|
sv->counters.cli_aborts,
|
|
|
|
|
sv->counters.srv_aborts,
|
2010-03-04 14:34:23 -05:00
|
|
|
U2H6(sv->counters.failed_resp),
|
2009-10-04 08:52:57 -04:00
|
|
|
sv->counters.retries, sv->counters.redispatches);
|
2008-12-07 10:06:43 -05:00
|
|
|
|
2009-09-23 16:09:24 -04:00
|
|
|
/* status, lest check */
|
2009-10-12 17:09:08 -04:00
|
|
|
chunk_printf(&msg, "<td class=ac>");
|
[MEDIUM] stats: report server and backend cumulated downtime
Hello,
This patch implements new statistics for SLA calculation by adding new
field 'Dwntime' with total down time since restart (both HTTP/CSV) and
extending status field (HTTP) or inserting a new one (CSV) with time
showing how long each server/backend is in a current state. Additionaly,
down transations are also calculated and displayed for backends, so it is
possible to know how many times selected backend was down, generating "No
server is available to handle this request." error.
New information are presentetd in two different ways:
- for HTTP: a "human redable form", one of "100000d 23h", "23h 59m" or
"59m 59s"
- for CSV: seconds
I believe that seconds resolution is enough.
As there are more columns in the status page I decided to shrink some
names to make more space:
- Weight -> Wght
- Check -> Chk
- Down -> Dwn
Making described changes I also made some improvements and fixed some
small bugs:
- don't increment s->health above 's->rise + s->fall - 1'. Previously it
was incremented an then (re)set to 's->rise + s->fall - 1'.
- do not set server down if it is down already
- do not set server up if it is up already
- fix colspan in multiple places (mostly introduced by my previous patch)
- add missing "status" header to CSV
- fix order of retries/redispatches in server (CSV)
- s/Tthen/Then/
- s/server/backend/ in DATA_ST_PX_BE (dumpstats.c)
Changes from previous version:
- deal with negative time intervales
- don't relay on s->state (SRV_RUNNING)
- little reworked human_time + compacted format (no spaces). If needed it
can be used in the future for other purposes by optionally making "cnt"
as an argument
- leave set_server_down mostly unchanged
- only little reworked "process_chk: 9"
- additional fields in CSV are appended to the rigth
- fix "SEC" macro
- named arguments (human_time, be_downtime, srv_downtime)
Hope it is OK. If there are only cosmetic changes needed please fill free
to correct it, however if there are some bigger changes required I would
like to discuss it first or at last to know what exactly was changed
especially since I already put this patch into my production server. :)
Thank you,
Best regards,
Krzysztof Oledzki
2007-10-22 10:21:10 -04:00
|
|
|
|
2010-01-31 16:34:03 -05:00
|
|
|
if (sv->state & SRV_MAINTAIN) {
|
|
|
|
|
chunk_printf(&msg, "%s ",
|
|
|
|
|
human_time(now.tv_sec - sv->last_change, 1));
|
|
|
|
|
chunk_printf(&msg, "MAINT");
|
|
|
|
|
}
|
2010-02-02 18:26:28 -05:00
|
|
|
else if (svs != sv && svs->state & SRV_MAINTAIN) {
|
|
|
|
|
chunk_printf(&msg, "%s ",
|
|
|
|
|
human_time(now.tv_sec - svs->last_change, 1));
|
|
|
|
|
chunk_printf(&msg, "MAINT(via)");
|
|
|
|
|
}
|
2010-01-31 16:34:03 -05:00
|
|
|
else if (svs->state & SRV_CHECKED) {
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg, "%s ",
|
2010-02-02 18:26:28 -05:00
|
|
|
human_time(now.tv_sec - svs->last_change, 1));
|
[MEDIUM] stats: report server and backend cumulated downtime
Hello,
This patch implements new statistics for SLA calculation by adding new
field 'Dwntime' with total down time since restart (both HTTP/CSV) and
extending status field (HTTP) or inserting a new one (CSV) with time
showing how long each server/backend is in a current state. Additionaly,
down transations are also calculated and displayed for backends, so it is
possible to know how many times selected backend was down, generating "No
server is available to handle this request." error.
New information are presentetd in two different ways:
- for HTTP: a "human redable form", one of "100000d 23h", "23h 59m" or
"59m 59s"
- for CSV: seconds
I believe that seconds resolution is enough.
As there are more columns in the status page I decided to shrink some
names to make more space:
- Weight -> Wght
- Check -> Chk
- Down -> Dwn
Making described changes I also made some improvements and fixed some
small bugs:
- don't increment s->health above 's->rise + s->fall - 1'. Previously it
was incremented an then (re)set to 's->rise + s->fall - 1'.
- do not set server down if it is down already
- do not set server up if it is up already
- fix colspan in multiple places (mostly introduced by my previous patch)
- add missing "status" header to CSV
- fix order of retries/redispatches in server (CSV)
- s/Tthen/Then/
- s/server/backend/ in DATA_ST_PX_BE (dumpstats.c)
Changes from previous version:
- deal with negative time intervales
- don't relay on s->state (SRV_RUNNING)
- little reworked human_time + compacted format (no spaces). If needed it
can be used in the future for other purposes by optionally making "cnt"
as an argument
- leave set_server_down mostly unchanged
- only little reworked "process_chk: 9"
- additional fields in CSV are appended to the rigth
- fix "SEC" macro
- named arguments (human_time, be_downtime, srv_downtime)
Hope it is OK. If there are only cosmetic changes needed please fill free
to correct it, however if there are some bigger changes required I would
like to discuss it first or at last to know what exactly was changed
especially since I already put this patch into my production server. :)
Thank you,
Best regards,
Krzysztof Oledzki
2007-10-22 10:21:10 -04:00
|
|
|
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2009-09-23 16:09:24 -04:00
|
|
|
srv_hlt_st[sv_state],
|
|
|
|
|
(svs->state & SRV_RUNNING) ? (svs->health - svs->rise + 1) : (svs->health),
|
|
|
|
|
(svs->state & SRV_RUNNING) ? (svs->fall) : (svs->rise));
|
2010-01-05 12:44:44 -05:00
|
|
|
}
|
2009-10-10 15:06:49 -04:00
|
|
|
|
2010-01-05 12:44:44 -05:00
|
|
|
if (sv->state & SRV_CHECKED) {
|
2009-10-12 17:09:08 -04:00
|
|
|
chunk_printf(&msg, "</td><td class=ac title=\"%s",
|
2009-10-10 15:06:49 -04:00
|
|
|
get_check_status_description(sv->check_status));
|
|
|
|
|
|
|
|
|
|
if (*sv->check_desc) {
|
|
|
|
|
struct chunk src;
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg, ": ");
|
|
|
|
|
|
|
|
|
|
chunk_initlen(&src, sv->check_desc, 0, strlen(sv->check_desc));
|
|
|
|
|
chunk_htmlencode(&msg, &src);
|
|
|
|
|
}
|
2010-01-05 12:44:44 -05:00
|
|
|
|
2010-02-26 06:29:07 -05:00
|
|
|
chunk_printf(&msg, "\"><u> %s%s",
|
2009-09-23 16:09:24 -04:00
|
|
|
tv_iszero(&sv->check_start)?"":"* ",
|
|
|
|
|
get_check_status_info(sv->check_status));
|
|
|
|
|
|
|
|
|
|
if (sv->check_status >= HCHK_STATUS_L57DATA)
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg, "/%d", sv->check_code);
|
2009-09-23 16:09:24 -04:00
|
|
|
|
2009-12-15 16:31:24 -05:00
|
|
|
if (sv->check_status >= HCHK_STATUS_CHECKED && sv->check_duration >= 0)
|
2010-02-26 06:29:07 -05:00
|
|
|
chunk_printf(&msg, " in %lums</u>", sv->check_duration);
|
2010-01-05 12:44:44 -05:00
|
|
|
} else
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg, "</td><td>");
|
2007-10-17 11:06:05 -04:00
|
|
|
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2007-10-17 11:06:05 -04:00
|
|
|
/* weight */
|
2009-10-12 17:09:08 -04:00
|
|
|
"</td><td class=ac>%d</td>"
|
2007-10-17 11:06:05 -04:00
|
|
|
/* act, bck */
|
2009-10-12 17:09:08 -04:00
|
|
|
"<td class=ac>%s</td><td class=ac>%s</td>"
|
2007-10-17 11:06:05 -04:00
|
|
|
"",
|
2007-12-02 20:04:00 -05:00
|
|
|
(sv->eweight * px->lbprm.wmult + px->lbprm.wdiv - 1) / px->lbprm.wdiv,
|
2007-10-17 11:06:05 -04:00
|
|
|
(sv->state & SRV_BACKUP) ? "-" : "Y",
|
|
|
|
|
(sv->state & SRV_BACKUP) ? "Y" : "-");
|
|
|
|
|
|
[MEDIUM] stats: report server and backend cumulated downtime
Hello,
This patch implements new statistics for SLA calculation by adding new
field 'Dwntime' with total down time since restart (both HTTP/CSV) and
extending status field (HTTP) or inserting a new one (CSV) with time
showing how long each server/backend is in a current state. Additionaly,
down transations are also calculated and displayed for backends, so it is
possible to know how many times selected backend was down, generating "No
server is available to handle this request." error.
New information are presentetd in two different ways:
- for HTTP: a "human redable form", one of "100000d 23h", "23h 59m" or
"59m 59s"
- for CSV: seconds
I believe that seconds resolution is enough.
As there are more columns in the status page I decided to shrink some
names to make more space:
- Weight -> Wght
- Check -> Chk
- Down -> Dwn
Making described changes I also made some improvements and fixed some
small bugs:
- don't increment s->health above 's->rise + s->fall - 1'. Previously it
was incremented an then (re)set to 's->rise + s->fall - 1'.
- do not set server down if it is down already
- do not set server up if it is up already
- fix colspan in multiple places (mostly introduced by my previous patch)
- add missing "status" header to CSV
- fix order of retries/redispatches in server (CSV)
- s/Tthen/Then/
- s/server/backend/ in DATA_ST_PX_BE (dumpstats.c)
Changes from previous version:
- deal with negative time intervales
- don't relay on s->state (SRV_RUNNING)
- little reworked human_time + compacted format (no spaces). If needed it
can be used in the future for other purposes by optionally making "cnt"
as an argument
- leave set_server_down mostly unchanged
- only little reworked "process_chk: 9"
- additional fields in CSV are appended to the rigth
- fix "SEC" macro
- named arguments (human_time, be_downtime, srv_downtime)
Hope it is OK. If there are only cosmetic changes needed please fill free
to correct it, however if there are some bigger changes required I would
like to discuss it first or at last to know what exactly was changed
especially since I already put this patch into my production server. :)
Thank you,
Best regards,
Krzysztof Oledzki
2007-10-22 10:21:10 -04:00
|
|
|
/* check failures: unique, fatal, down time */
|
2010-01-03 18:48:43 -05:00
|
|
|
if (sv->state & SRV_CHECKED) {
|
2010-02-26 06:29:07 -05:00
|
|
|
chunk_printf(&msg, "<td title=\"Failed Health Checks%s\"><u>%lld",
|
2010-01-03 18:48:43 -05:00
|
|
|
svs->observe?"/Health Analyses":"", svs->counters.failed_checks);
|
|
|
|
|
|
|
|
|
|
if (svs->observe)
|
|
|
|
|
chunk_printf(&msg, "/%lld", svs->counters.failed_hana);
|
|
|
|
|
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2010-02-26 06:29:07 -05:00
|
|
|
"</u></td>"
|
2009-12-15 16:31:24 -05:00
|
|
|
"<td>%lld</td><td>%s</td>"
|
2007-11-30 12:16:29 -05:00
|
|
|
"",
|
2009-12-15 16:31:24 -05:00
|
|
|
svs->counters.down_trans, human_time(srv_downtime(sv), 1));
|
2010-01-03 18:48:43 -05:00
|
|
|
} else if (sv != svs)
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2010-01-05 12:33:01 -05:00
|
|
|
"<td class=ac colspan=3><a class=lfsb href=\"#%s/%s\">via %s/%s<a></td>",
|
|
|
|
|
svs->proxy->id, svs->id, svs->proxy->id, svs->id);
|
2007-10-17 12:44:57 -04:00
|
|
|
else
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2007-11-30 12:16:29 -05:00
|
|
|
"<td colspan=3></td>");
|
|
|
|
|
|
|
|
|
|
/* throttle */
|
|
|
|
|
if ((sv->state & SRV_WARMINGUP) &&
|
|
|
|
|
now.tv_sec < sv->last_change + sv->slowstart &&
|
|
|
|
|
now.tv_sec >= sv->last_change) {
|
|
|
|
|
unsigned int ratio;
|
|
|
|
|
ratio = MAX(1, 100 * (now.tv_sec - sv->last_change) / sv->slowstart);
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2009-10-12 17:09:08 -04:00
|
|
|
"<td class=ac>%d %%</td></tr>\n", ratio);
|
2007-11-30 12:16:29 -05:00
|
|
|
} else {
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2009-10-12 17:09:08 -04:00
|
|
|
"<td class=ac>-</td></tr>\n");
|
2007-11-30 12:16:29 -05:00
|
|
|
}
|
2007-10-17 12:44:57 -04:00
|
|
|
} else {
|
2007-11-30 06:04:38 -05:00
|
|
|
static char *srv_hlt_st[7] = { "DOWN,", "DOWN %d/%d,",
|
|
|
|
|
"UP %d/%d,", "UP,",
|
|
|
|
|
"NOLB %d/%d,", "NOLB,",
|
|
|
|
|
"no check," };
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2007-10-17 12:44:57 -04:00
|
|
|
/* pxid, name */
|
|
|
|
|
"%s,%s,"
|
|
|
|
|
/* queue : current, max */
|
|
|
|
|
"%d,%d,"
|
2007-12-05 04:34:49 -05:00
|
|
|
/* sessions : current, max, limit, total */
|
2009-04-11 14:44:08 -04:00
|
|
|
"%d,%d,%s,%lld,"
|
2007-10-17 12:44:57 -04:00
|
|
|
/* bytes : in, out */
|
|
|
|
|
"%lld,%lld,"
|
|
|
|
|
/* denied: req, resp */
|
2009-04-11 14:44:08 -04:00
|
|
|
",%lld,"
|
2007-10-17 12:44:57 -04:00
|
|
|
/* errors : request, connect, response */
|
2009-04-11 14:44:08 -04:00
|
|
|
",%lld,%lld,"
|
2007-10-18 13:12:30 -04:00
|
|
|
/* warnings: retries, redispatches */
|
2009-04-11 14:44:08 -04:00
|
|
|
"%lld,%lld,"
|
2007-10-17 12:44:57 -04:00
|
|
|
"",
|
|
|
|
|
px->id, sv->id,
|
2009-10-04 17:12:44 -04:00
|
|
|
sv->nbpend, sv->counters.nbpend_max,
|
|
|
|
|
sv->cur_sess, sv->counters.cur_sess_max, LIM2A0(sv->maxconn, ""), sv->counters.cum_sess,
|
2009-10-04 08:52:57 -04:00
|
|
|
sv->counters.bytes_in, sv->counters.bytes_out,
|
|
|
|
|
sv->counters.failed_secu,
|
|
|
|
|
sv->counters.failed_conns, sv->counters.failed_resp,
|
|
|
|
|
sv->counters.retries, sv->counters.redispatches);
|
2008-12-07 10:06:43 -05:00
|
|
|
|
2007-10-17 12:44:57 -04:00
|
|
|
/* status */
|
2010-01-31 16:34:03 -05:00
|
|
|
if (sv->state & SRV_MAINTAIN) {
|
|
|
|
|
chunk_printf(&msg, "MAINT,");
|
2010-02-02 18:26:28 -05:00
|
|
|
}
|
|
|
|
|
else if (svs != sv && svs->state & SRV_MAINTAIN) {
|
|
|
|
|
chunk_printf(&msg, "MAINT(via),");
|
|
|
|
|
}
|
|
|
|
|
else {
|
2010-01-31 16:34:03 -05:00
|
|
|
chunk_printf(&msg,
|
|
|
|
|
srv_hlt_st[sv_state],
|
|
|
|
|
(svs->state & SRV_RUNNING) ? (svs->health - svs->rise + 1) : (svs->health),
|
|
|
|
|
(svs->state & SRV_RUNNING) ? (svs->fall) : (svs->rise));
|
|
|
|
|
}
|
2007-10-17 12:44:57 -04:00
|
|
|
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2007-10-17 12:44:57 -04:00
|
|
|
/* weight, active, backup */
|
|
|
|
|
"%d,%d,%d,"
|
|
|
|
|
"",
|
2007-12-02 20:04:00 -05:00
|
|
|
(sv->eweight * px->lbprm.wmult + px->lbprm.wdiv - 1) / px->lbprm.wdiv,
|
2007-10-17 12:44:57 -04:00
|
|
|
(sv->state & SRV_BACKUP) ? 0 : 1,
|
|
|
|
|
(sv->state & SRV_BACKUP) ? 1 : 0);
|
2007-10-17 11:06:05 -04:00
|
|
|
|
[MEDIUM] stats: report server and backend cumulated downtime
Hello,
This patch implements new statistics for SLA calculation by adding new
field 'Dwntime' with total down time since restart (both HTTP/CSV) and
extending status field (HTTP) or inserting a new one (CSV) with time
showing how long each server/backend is in a current state. Additionaly,
down transations are also calculated and displayed for backends, so it is
possible to know how many times selected backend was down, generating "No
server is available to handle this request." error.
New information are presentetd in two different ways:
- for HTTP: a "human redable form", one of "100000d 23h", "23h 59m" or
"59m 59s"
- for CSV: seconds
I believe that seconds resolution is enough.
As there are more columns in the status page I decided to shrink some
names to make more space:
- Weight -> Wght
- Check -> Chk
- Down -> Dwn
Making described changes I also made some improvements and fixed some
small bugs:
- don't increment s->health above 's->rise + s->fall - 1'. Previously it
was incremented an then (re)set to 's->rise + s->fall - 1'.
- do not set server down if it is down already
- do not set server up if it is up already
- fix colspan in multiple places (mostly introduced by my previous patch)
- add missing "status" header to CSV
- fix order of retries/redispatches in server (CSV)
- s/Tthen/Then/
- s/server/backend/ in DATA_ST_PX_BE (dumpstats.c)
Changes from previous version:
- deal with negative time intervales
- don't relay on s->state (SRV_RUNNING)
- little reworked human_time + compacted format (no spaces). If needed it
can be used in the future for other purposes by optionally making "cnt"
as an argument
- leave set_server_down mostly unchanged
- only little reworked "process_chk: 9"
- additional fields in CSV are appended to the rigth
- fix "SEC" macro
- named arguments (human_time, be_downtime, srv_downtime)
Hope it is OK. If there are only cosmetic changes needed please fill free
to correct it, however if there are some bigger changes required I would
like to discuss it first or at last to know what exactly was changed
especially since I already put this patch into my production server. :)
Thank you,
Best regards,
Krzysztof Oledzki
2007-10-22 10:21:10 -04:00
|
|
|
/* check failures: unique, fatal; last change, total downtime */
|
2007-10-17 12:44:57 -04:00
|
|
|
if (sv->state & SRV_CHECKED)
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2009-04-11 14:44:08 -04:00
|
|
|
"%lld,%lld,%d,%d,",
|
2009-10-04 08:52:57 -04:00
|
|
|
sv->counters.failed_checks, sv->counters.down_trans,
|
2009-04-03 08:49:12 -04:00
|
|
|
(int)(now.tv_sec - sv->last_change), srv_downtime(sv));
|
2007-10-17 12:44:57 -04:00
|
|
|
else
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2007-10-25 14:15:38 -04:00
|
|
|
",,,,");
|
|
|
|
|
|
2007-11-30 12:16:29 -05:00
|
|
|
/* queue limit, pid, iid, sid, */
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2007-11-04 17:35:08 -05:00
|
|
|
"%s,"
|
2007-11-30 12:16:29 -05:00
|
|
|
"%d,%d,%d,",
|
2007-11-04 17:35:08 -05:00
|
|
|
LIM2A0(sv->maxqueue, ""),
|
|
|
|
|
relative_pid, px->uuid, sv->puid);
|
2007-11-30 12:16:29 -05:00
|
|
|
|
|
|
|
|
/* throttle */
|
|
|
|
|
if ((sv->state & SRV_WARMINGUP) &&
|
|
|
|
|
now.tv_sec < sv->last_change + sv->slowstart &&
|
|
|
|
|
now.tv_sec >= sv->last_change) {
|
|
|
|
|
unsigned int ratio;
|
|
|
|
|
ratio = MAX(1, 100 * (now.tv_sec - sv->last_change) / sv->slowstart);
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg, "%d", ratio);
|
2007-11-30 12:16:29 -05:00
|
|
|
}
|
|
|
|
|
|
2007-12-05 04:34:49 -05:00
|
|
|
/* sessions: lbtot */
|
2009-10-04 08:52:57 -04:00
|
|
|
chunk_printf(&msg, ",%lld,", sv->counters.cum_lbconn);
|
2008-02-17 19:26:35 -05:00
|
|
|
|
|
|
|
|
/* tracked */
|
2011-10-28 09:35:33 -04:00
|
|
|
if (sv->track)
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg, "%s/%s,",
|
2011-10-28 09:35:33 -04:00
|
|
|
sv->track->proxy->id, sv->track->id);
|
2008-02-17 19:26:35 -05:00
|
|
|
else
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg, ",");
|
2008-02-17 19:26:35 -05:00
|
|
|
|
2009-03-05 12:43:00 -05:00
|
|
|
/* type */
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg, "%d,", STATS_TYPE_SV);
|
2009-03-05 12:43:00 -05:00
|
|
|
|
|
|
|
|
/* rate */
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg, "%u,,%u,",
|
2009-05-10 13:01:49 -04:00
|
|
|
read_freq_ctr(&sv->sess_per_sec),
|
2009-10-04 17:12:44 -04:00
|
|
|
sv->counters.sps_max);
|
2009-03-05 12:43:00 -05:00
|
|
|
|
2009-09-23 16:09:24 -04:00
|
|
|
if (sv->state & SRV_CHECKED) {
|
|
|
|
|
/* check_status */
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg, "%s,", get_check_status_info(sv->check_status));
|
2009-09-23 16:09:24 -04:00
|
|
|
|
|
|
|
|
/* check_code */
|
|
|
|
|
if (sv->check_status >= HCHK_STATUS_L57DATA)
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg, "%u,", sv->check_code);
|
2009-09-23 16:09:24 -04:00
|
|
|
else
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg, ",");
|
2009-09-23 16:09:24 -04:00
|
|
|
|
|
|
|
|
/* check_duration */
|
2010-01-05 12:44:44 -05:00
|
|
|
if (sv->check_status >= HCHK_STATUS_CHECKED)
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg, "%lu,", sv->check_duration);
|
2009-09-23 16:09:24 -04:00
|
|
|
else
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg, ",");
|
2009-09-23 16:09:24 -04:00
|
|
|
|
|
|
|
|
} else {
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg, ",,,");
|
2009-09-23 16:09:24 -04:00
|
|
|
}
|
|
|
|
|
|
2009-10-13 15:14:09 -04:00
|
|
|
/* http response: 1xx, 2xx, 3xx, 4xx, 5xx, other */
|
|
|
|
|
if (px->mode == PR_MODE_HTTP) {
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i=1; i<6; i++)
|
|
|
|
|
chunk_printf(&msg, "%lld,", sv->counters.p.http.rsp[i]);
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg, "%lld,", sv->counters.p.http.rsp[0]);
|
|
|
|
|
} else {
|
|
|
|
|
chunk_printf(&msg, ",,,,,,");
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-15 16:31:24 -05:00
|
|
|
/* failed health analyses */
|
|
|
|
|
chunk_printf(&msg, "%lld,", sv->counters.failed_hana);
|
|
|
|
|
|
2010-02-26 04:05:55 -05:00
|
|
|
/* requests : req_rate, req_rate_max, req_tot, */
|
|
|
|
|
chunk_printf(&msg, ",,,");
|
|
|
|
|
|
2010-03-04 14:34:23 -05:00
|
|
|
/* errors: cli_aborts, srv_aborts */
|
|
|
|
|
chunk_printf(&msg, "%lld,%lld,",
|
|
|
|
|
sv->counters.cli_aborts, sv->counters.srv_aborts);
|
|
|
|
|
|
2009-03-05 12:43:00 -05:00
|
|
|
/* finish with EOL */
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg, "\n");
|
2007-10-17 12:44:57 -04:00
|
|
|
}
|
2012-05-07 05:56:55 -04:00
|
|
|
if (bi_putchk(rep, &msg) == -1)
|
2007-10-17 11:06:05 -04:00
|
|
|
return 0;
|
[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.
2008-03-01 20:42:14 -05:00
|
|
|
} /* for sv */
|
2007-10-17 11:06:05 -04:00
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.stats.px_st = STAT_PX_ST_BE;
|
2007-10-17 11:06:05 -04:00
|
|
|
/* fall through */
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
case STAT_PX_ST_BE:
|
2007-10-17 11:06:05 -04:00
|
|
|
/* print the backend */
|
[MEDIUM] fix stats socket limitation to 16 kB
Due to the way the stats socket work, it was not possible to
maintain the information related to the command entered, so
after filling a whole buffer, the request was lost and it was
considered that there was nothing to write anymore.
The major reason was that some flags were passed directly
during the first call to stats_dump_raw() instead of being
stored persistently in the session.
To definitely fix this problem, flags were added to the stats
member of the session structure.
A second problem appeared. When the stats were produced, a first
call to client_retnclose() was performed, then one or multiple
subsequent calls to buffer_write_chunks() were done. But once the
stats buffer was full and a reschedule operated, the buffer was
flushed, the write flag cleared from the buffer and nothing was
done to re-arm it.
For this reason, a check was added in the proto_uxst_stats()
function in order to re-call the client FSM when data were added
by stats_dump_raw(). Finally, the whole unix stats dump FSM was
rewritten to avoid all the magics it depended on. It is now
simpler and looks more like the HTTP one.
2008-03-17 16:38:24 -04:00
|
|
|
if ((px->cap & PR_CAP_BE) &&
|
2011-03-10 05:25:07 -05:00
|
|
|
(!(si->applet.ctx.stats.flags & STAT_BOUND) || (si->applet.ctx.stats.type & (1 << STATS_TYPE_BE)))) {
|
|
|
|
|
if (!(si->applet.ctx.stats.flags & STAT_FMT_CSV)) {
|
2010-10-11 18:14:35 -04:00
|
|
|
chunk_printf(&msg, "<tr class=\"backend\">");
|
2011-03-10 05:25:07 -05:00
|
|
|
if (px->cap & PR_CAP_BE && px->srv && (si->applet.ctx.stats.flags & STAT_ADMIN)) {
|
2010-10-11 18:14:35 -04:00
|
|
|
/* Column sub-heading for Enable or Disable server */
|
|
|
|
|
chunk_printf(&msg, "<td></td>");
|
|
|
|
|
}
|
|
|
|
|
chunk_printf(&msg, "<td class=ac");
|
2010-01-04 10:03:09 -05:00
|
|
|
|
|
|
|
|
if (uri->flags&ST_SHLGNDS) {
|
|
|
|
|
/* balancing */
|
2010-01-06 09:03:18 -05:00
|
|
|
chunk_printf(&msg, " title=\"balancing: %s",
|
2010-01-04 10:03:09 -05:00
|
|
|
backend_lb_algo_str(px->lbprm.algo & BE_LB_ALGO));
|
2010-01-06 09:03:18 -05:00
|
|
|
|
|
|
|
|
/* cookie */
|
|
|
|
|
if (px->cookie_name) {
|
|
|
|
|
struct chunk src;
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg, ", cookie: '");
|
|
|
|
|
|
|
|
|
|
chunk_initlen(&src, px->cookie_name, 0, strlen(px->cookie_name));
|
|
|
|
|
chunk_htmlencode(&msg, &src);
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg, "'");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg, "\"");
|
|
|
|
|
|
2010-01-04 10:03:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg,
|
2010-10-11 18:14:35 -04:00
|
|
|
/* name */
|
2010-02-26 06:29:07 -05:00
|
|
|
">%s<a name=\"%s/Backend\"></a>"
|
|
|
|
|
"<a class=lfsb href=\"#%s/Backend\">Backend</a>%s</td>"
|
2007-10-17 11:06:05 -04:00
|
|
|
/* queue : current, max */
|
2009-10-12 17:09:08 -04:00
|
|
|
"<td>%s</td><td>%s</td><td></td>"
|
2009-05-10 13:19:41 -04:00
|
|
|
/* sessions rate : current, max, limit */
|
2009-10-12 17:09:08 -04:00
|
|
|
"<td>%s</td><td>%s</td><td></td>"
|
2009-05-10 13:19:41 -04:00
|
|
|
"",
|
2010-02-26 06:29:07 -05:00
|
|
|
(uri->flags & ST_SHLGNDS)?"<u>":"",
|
2009-10-24 08:24:30 -04:00
|
|
|
px->id, px->id,
|
2010-02-26 06:29:07 -05:00
|
|
|
(uri->flags & ST_SHLGNDS)?"</u>":"",
|
2011-03-10 17:25:56 -05:00
|
|
|
U2H0(px->nbpend) /* or px->totpend ? */, U2H1(px->be_counters.nbpend_max),
|
|
|
|
|
U2H2(read_freq_ctr(&px->be_sess_per_sec)), U2H3(px->be_counters.sps_max));
|
2009-05-10 13:19:41 -04:00
|
|
|
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2009-10-13 15:14:09 -04:00
|
|
|
/* sessions: current, max, limit */
|
2009-10-12 17:09:08 -04:00
|
|
|
"<td>%s</td><td>%s</td><td>%s</td>"
|
2009-10-13 15:14:09 -04:00
|
|
|
"<td"
|
|
|
|
|
"",
|
2011-03-10 17:25:56 -05:00
|
|
|
U2H2(px->beconn), U2H3(px->be_counters.conn_max), U2H4(px->fullconn));
|
2009-10-13 15:14:09 -04:00
|
|
|
|
|
|
|
|
/* http response (via td title): 1xx, 2xx, 3xx, 4xx, 5xx, other */
|
|
|
|
|
if (px->mode == PR_MODE_HTTP) {
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg, " title=\"rsp codes:");
|
|
|
|
|
|
|
|
|
|
for (i = 1; i < 6; i++)
|
2011-03-10 17:25:56 -05:00
|
|
|
chunk_printf(&msg, " %dxx=%lld", i, px->be_counters.p.http.rsp[i]);
|
2009-10-13 15:14:09 -04:00
|
|
|
|
2011-03-10 17:25:56 -05:00
|
|
|
chunk_printf(&msg, " other=%lld\"", px->be_counters.p.http.rsp[0]);
|
2009-10-13 15:14:09 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg,
|
|
|
|
|
/* sessions: total, lbtot */
|
2010-02-26 06:29:07 -05:00
|
|
|
">%s%s%s</td><td>%s</td>"
|
2009-10-13 15:14:09 -04:00
|
|
|
/* bytes: in, out */
|
2009-10-12 17:09:08 -04:00
|
|
|
"<td>%s</td><td>%s</td>"
|
2009-03-29 08:46:01 -04:00
|
|
|
"",
|
2010-02-26 06:29:07 -05:00
|
|
|
(px->mode == PR_MODE_HTTP)?"<u>":"",
|
2011-03-10 17:25:56 -05:00
|
|
|
U2H6(px->be_counters.cum_conn),
|
2010-02-26 06:29:07 -05:00
|
|
|
(px->mode == PR_MODE_HTTP)?"</u>":"",
|
2011-03-10 17:25:56 -05:00
|
|
|
U2H7(px->be_counters.cum_lbconn),
|
|
|
|
|
U2H8(px->be_counters.bytes_in), U2H9(px->be_counters.bytes_out));
|
2009-03-29 08:46:01 -04:00
|
|
|
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2007-10-17 11:06:05 -04:00
|
|
|
/* denied: req, resp */
|
2009-10-12 17:09:08 -04:00
|
|
|
"<td>%s</td><td>%s</td>"
|
2010-03-04 14:34:23 -05:00
|
|
|
/* errors : request, connect */
|
|
|
|
|
"<td></td><td>%s</td>"
|
|
|
|
|
/* errors : response */
|
2010-03-05 12:15:23 -05:00
|
|
|
"<td title=\"Connection resets during transfers: %lld client, %lld server\"><u>%s</u></td>"
|
2007-10-18 13:12:30 -04:00
|
|
|
/* warnings: retries, redispatches */
|
2009-10-12 17:09:08 -04:00
|
|
|
"<td>%lld</td><td>%lld</td>"
|
[MEDIUM] stats: report server and backend cumulated downtime
Hello,
This patch implements new statistics for SLA calculation by adding new
field 'Dwntime' with total down time since restart (both HTTP/CSV) and
extending status field (HTTP) or inserting a new one (CSV) with time
showing how long each server/backend is in a current state. Additionaly,
down transations are also calculated and displayed for backends, so it is
possible to know how many times selected backend was down, generating "No
server is available to handle this request." error.
New information are presentetd in two different ways:
- for HTTP: a "human redable form", one of "100000d 23h", "23h 59m" or
"59m 59s"
- for CSV: seconds
I believe that seconds resolution is enough.
As there are more columns in the status page I decided to shrink some
names to make more space:
- Weight -> Wght
- Check -> Chk
- Down -> Dwn
Making described changes I also made some improvements and fixed some
small bugs:
- don't increment s->health above 's->rise + s->fall - 1'. Previously it
was incremented an then (re)set to 's->rise + s->fall - 1'.
- do not set server down if it is down already
- do not set server up if it is up already
- fix colspan in multiple places (mostly introduced by my previous patch)
- add missing "status" header to CSV
- fix order of retries/redispatches in server (CSV)
- s/Tthen/Then/
- s/server/backend/ in DATA_ST_PX_BE (dumpstats.c)
Changes from previous version:
- deal with negative time intervales
- don't relay on s->state (SRV_RUNNING)
- little reworked human_time + compacted format (no spaces). If needed it
can be used in the future for other purposes by optionally making "cnt"
as an argument
- leave set_server_down mostly unchanged
- only little reworked "process_chk: 9"
- additional fields in CSV are appended to the rigth
- fix "SEC" macro
- named arguments (human_time, be_downtime, srv_downtime)
Hope it is OK. If there are only cosmetic changes needed please fill free
to correct it, however if there are some bigger changes required I would
like to discuss it first or at last to know what exactly was changed
especially since I already put this patch into my production server. :)
Thank you,
Best regards,
Krzysztof Oledzki
2007-10-22 10:21:10 -04:00
|
|
|
/* backend status: reflect backend status (up/down): we display UP
|
2007-10-17 11:06:05 -04:00
|
|
|
* if the backend has known working servers or if it has no server at
|
[MEDIUM] stats: report server and backend cumulated downtime
Hello,
This patch implements new statistics for SLA calculation by adding new
field 'Dwntime' with total down time since restart (both HTTP/CSV) and
extending status field (HTTP) or inserting a new one (CSV) with time
showing how long each server/backend is in a current state. Additionaly,
down transations are also calculated and displayed for backends, so it is
possible to know how many times selected backend was down, generating "No
server is available to handle this request." error.
New information are presentetd in two different ways:
- for HTTP: a "human redable form", one of "100000d 23h", "23h 59m" or
"59m 59s"
- for CSV: seconds
I believe that seconds resolution is enough.
As there are more columns in the status page I decided to shrink some
names to make more space:
- Weight -> Wght
- Check -> Chk
- Down -> Dwn
Making described changes I also made some improvements and fixed some
small bugs:
- don't increment s->health above 's->rise + s->fall - 1'. Previously it
was incremented an then (re)set to 's->rise + s->fall - 1'.
- do not set server down if it is down already
- do not set server up if it is up already
- fix colspan in multiple places (mostly introduced by my previous patch)
- add missing "status" header to CSV
- fix order of retries/redispatches in server (CSV)
- s/Tthen/Then/
- s/server/backend/ in DATA_ST_PX_BE (dumpstats.c)
Changes from previous version:
- deal with negative time intervales
- don't relay on s->state (SRV_RUNNING)
- little reworked human_time + compacted format (no spaces). If needed it
can be used in the future for other purposes by optionally making "cnt"
as an argument
- leave set_server_down mostly unchanged
- only little reworked "process_chk: 9"
- additional fields in CSV are appended to the rigth
- fix "SEC" macro
- named arguments (human_time, be_downtime, srv_downtime)
Hope it is OK. If there are only cosmetic changes needed please fill free
to correct it, however if there are some bigger changes required I would
like to discuss it first or at last to know what exactly was changed
especially since I already put this patch into my production server. :)
Thank you,
Best regards,
Krzysztof Oledzki
2007-10-22 10:21:10 -04:00
|
|
|
* all (eg: for stats). Then we display the total weight, number of
|
2007-10-17 11:06:05 -04:00
|
|
|
* active and backups. */
|
2009-10-12 17:09:08 -04:00
|
|
|
"<td class=ac>%s %s</td><td class=ac> </td><td class=ac>%d</td>"
|
|
|
|
|
"<td class=ac>%d</td><td class=ac>%d</td>"
|
2009-03-29 08:46:01 -04:00
|
|
|
"",
|
2011-03-10 17:25:56 -05:00
|
|
|
U2H0(px->be_counters.denied_req), U2H1(px->be_counters.denied_resp),
|
|
|
|
|
U2H2(px->be_counters.failed_conns),
|
|
|
|
|
px->be_counters.cli_aborts,
|
|
|
|
|
px->be_counters.srv_aborts,
|
|
|
|
|
U2H5(px->be_counters.failed_resp),
|
|
|
|
|
px->be_counters.retries, px->be_counters.redispatches,
|
[MEDIUM] stats: report server and backend cumulated downtime
Hello,
This patch implements new statistics for SLA calculation by adding new
field 'Dwntime' with total down time since restart (both HTTP/CSV) and
extending status field (HTTP) or inserting a new one (CSV) with time
showing how long each server/backend is in a current state. Additionaly,
down transations are also calculated and displayed for backends, so it is
possible to know how many times selected backend was down, generating "No
server is available to handle this request." error.
New information are presentetd in two different ways:
- for HTTP: a "human redable form", one of "100000d 23h", "23h 59m" or
"59m 59s"
- for CSV: seconds
I believe that seconds resolution is enough.
As there are more columns in the status page I decided to shrink some
names to make more space:
- Weight -> Wght
- Check -> Chk
- Down -> Dwn
Making described changes I also made some improvements and fixed some
small bugs:
- don't increment s->health above 's->rise + s->fall - 1'. Previously it
was incremented an then (re)set to 's->rise + s->fall - 1'.
- do not set server down if it is down already
- do not set server up if it is up already
- fix colspan in multiple places (mostly introduced by my previous patch)
- add missing "status" header to CSV
- fix order of retries/redispatches in server (CSV)
- s/Tthen/Then/
- s/server/backend/ in DATA_ST_PX_BE (dumpstats.c)
Changes from previous version:
- deal with negative time intervales
- don't relay on s->state (SRV_RUNNING)
- little reworked human_time + compacted format (no spaces). If needed it
can be used in the future for other purposes by optionally making "cnt"
as an argument
- leave set_server_down mostly unchanged
- only little reworked "process_chk: 9"
- additional fields in CSV are appended to the rigth
- fix "SEC" macro
- named arguments (human_time, be_downtime, srv_downtime)
Hope it is OK. If there are only cosmetic changes needed please fill free
to correct it, however if there are some bigger changes required I would
like to discuss it first or at last to know what exactly was changed
especially since I already put this patch into my production server. :)
Thank you,
Best regards,
Krzysztof Oledzki
2007-10-22 10:21:10 -04:00
|
|
|
human_time(now.tv_sec - px->last_change, 1),
|
2007-11-30 06:04:38 -05:00
|
|
|
(px->lbprm.tot_weight > 0 || !px->srv) ? "UP" :
|
|
|
|
|
"<font color=\"red\"><b>DOWN</b></font>",
|
2007-12-02 20:04:00 -05:00
|
|
|
(px->lbprm.tot_weight * px->lbprm.wmult + px->lbprm.wdiv - 1) / px->lbprm.wdiv,
|
2007-11-15 17:26:18 -05:00
|
|
|
px->srv_act, px->srv_bck);
|
[MEDIUM] stats: report server and backend cumulated downtime
Hello,
This patch implements new statistics for SLA calculation by adding new
field 'Dwntime' with total down time since restart (both HTTP/CSV) and
extending status field (HTTP) or inserting a new one (CSV) with time
showing how long each server/backend is in a current state. Additionaly,
down transations are also calculated and displayed for backends, so it is
possible to know how many times selected backend was down, generating "No
server is available to handle this request." error.
New information are presentetd in two different ways:
- for HTTP: a "human redable form", one of "100000d 23h", "23h 59m" or
"59m 59s"
- for CSV: seconds
I believe that seconds resolution is enough.
As there are more columns in the status page I decided to shrink some
names to make more space:
- Weight -> Wght
- Check -> Chk
- Down -> Dwn
Making described changes I also made some improvements and fixed some
small bugs:
- don't increment s->health above 's->rise + s->fall - 1'. Previously it
was incremented an then (re)set to 's->rise + s->fall - 1'.
- do not set server down if it is down already
- do not set server up if it is up already
- fix colspan in multiple places (mostly introduced by my previous patch)
- add missing "status" header to CSV
- fix order of retries/redispatches in server (CSV)
- s/Tthen/Then/
- s/server/backend/ in DATA_ST_PX_BE (dumpstats.c)
Changes from previous version:
- deal with negative time intervales
- don't relay on s->state (SRV_RUNNING)
- little reworked human_time + compacted format (no spaces). If needed it
can be used in the future for other purposes by optionally making "cnt"
as an argument
- leave set_server_down mostly unchanged
- only little reworked "process_chk: 9"
- additional fields in CSV are appended to the rigth
- fix "SEC" macro
- named arguments (human_time, be_downtime, srv_downtime)
Hope it is OK. If there are only cosmetic changes needed please fill free
to correct it, however if there are some bigger changes required I would
like to discuss it first or at last to know what exactly was changed
especially since I already put this patch into my production server. :)
Thank you,
Best regards,
Krzysztof Oledzki
2007-10-22 10:21:10 -04:00
|
|
|
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2007-11-30 12:16:29 -05:00
|
|
|
/* rest of backend: nothing, down transitions, total downtime, throttle */
|
2009-10-12 17:09:08 -04:00
|
|
|
"<td class=ac> </td><td>%d</td>"
|
|
|
|
|
"<td>%s</td>"
|
2007-11-30 12:16:29 -05:00
|
|
|
"<td></td>"
|
[MEDIUM] stats: report server and backend cumulated downtime
Hello,
This patch implements new statistics for SLA calculation by adding new
field 'Dwntime' with total down time since restart (both HTTP/CSV) and
extending status field (HTTP) or inserting a new one (CSV) with time
showing how long each server/backend is in a current state. Additionaly,
down transations are also calculated and displayed for backends, so it is
possible to know how many times selected backend was down, generating "No
server is available to handle this request." error.
New information are presentetd in two different ways:
- for HTTP: a "human redable form", one of "100000d 23h", "23h 59m" or
"59m 59s"
- for CSV: seconds
I believe that seconds resolution is enough.
As there are more columns in the status page I decided to shrink some
names to make more space:
- Weight -> Wght
- Check -> Chk
- Down -> Dwn
Making described changes I also made some improvements and fixed some
small bugs:
- don't increment s->health above 's->rise + s->fall - 1'. Previously it
was incremented an then (re)set to 's->rise + s->fall - 1'.
- do not set server down if it is down already
- do not set server up if it is up already
- fix colspan in multiple places (mostly introduced by my previous patch)
- add missing "status" header to CSV
- fix order of retries/redispatches in server (CSV)
- s/Tthen/Then/
- s/server/backend/ in DATA_ST_PX_BE (dumpstats.c)
Changes from previous version:
- deal with negative time intervales
- don't relay on s->state (SRV_RUNNING)
- little reworked human_time + compacted format (no spaces). If needed it
can be used in the future for other purposes by optionally making "cnt"
as an argument
- leave set_server_down mostly unchanged
- only little reworked "process_chk: 9"
- additional fields in CSV are appended to the rigth
- fix "SEC" macro
- named arguments (human_time, be_downtime, srv_downtime)
Hope it is OK. If there are only cosmetic changes needed please fill free
to correct it, however if there are some bigger changes required I would
like to discuss it first or at last to know what exactly was changed
especially since I already put this patch into my production server. :)
Thank you,
Best regards,
Krzysztof Oledzki
2007-10-22 10:21:10 -04:00
|
|
|
"</tr>",
|
|
|
|
|
px->down_trans,
|
|
|
|
|
px->srv?human_time(be_downtime(px), 1):" ");
|
2007-10-17 12:44:57 -04:00
|
|
|
} else {
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2007-10-17 12:44:57 -04:00
|
|
|
/* pxid, name */
|
|
|
|
|
"%s,BACKEND,"
|
|
|
|
|
/* queue : current, max */
|
|
|
|
|
"%d,%d,"
|
2007-12-05 04:34:49 -05:00
|
|
|
/* sessions : current, max, limit, total */
|
2009-04-11 14:44:08 -04:00
|
|
|
"%d,%d,%d,%lld,"
|
2007-10-17 12:44:57 -04:00
|
|
|
/* bytes : in, out */
|
|
|
|
|
"%lld,%lld,"
|
|
|
|
|
/* denied: req, resp */
|
2009-04-11 14:44:08 -04:00
|
|
|
"%lld,%lld,"
|
2007-10-17 12:44:57 -04:00
|
|
|
/* errors : request, connect, response */
|
2009-04-11 14:44:08 -04:00
|
|
|
",%lld,%lld,"
|
2007-10-18 13:12:30 -04:00
|
|
|
/* warnings: retries, redispatches */
|
2009-04-11 14:44:08 -04:00
|
|
|
"%lld,%lld,"
|
[MEDIUM] stats: report server and backend cumulated downtime
Hello,
This patch implements new statistics for SLA calculation by adding new
field 'Dwntime' with total down time since restart (both HTTP/CSV) and
extending status field (HTTP) or inserting a new one (CSV) with time
showing how long each server/backend is in a current state. Additionaly,
down transations are also calculated and displayed for backends, so it is
possible to know how many times selected backend was down, generating "No
server is available to handle this request." error.
New information are presentetd in two different ways:
- for HTTP: a "human redable form", one of "100000d 23h", "23h 59m" or
"59m 59s"
- for CSV: seconds
I believe that seconds resolution is enough.
As there are more columns in the status page I decided to shrink some
names to make more space:
- Weight -> Wght
- Check -> Chk
- Down -> Dwn
Making described changes I also made some improvements and fixed some
small bugs:
- don't increment s->health above 's->rise + s->fall - 1'. Previously it
was incremented an then (re)set to 's->rise + s->fall - 1'.
- do not set server down if it is down already
- do not set server up if it is up already
- fix colspan in multiple places (mostly introduced by my previous patch)
- add missing "status" header to CSV
- fix order of retries/redispatches in server (CSV)
- s/Tthen/Then/
- s/server/backend/ in DATA_ST_PX_BE (dumpstats.c)
Changes from previous version:
- deal with negative time intervales
- don't relay on s->state (SRV_RUNNING)
- little reworked human_time + compacted format (no spaces). If needed it
can be used in the future for other purposes by optionally making "cnt"
as an argument
- leave set_server_down mostly unchanged
- only little reworked "process_chk: 9"
- additional fields in CSV are appended to the rigth
- fix "SEC" macro
- named arguments (human_time, be_downtime, srv_downtime)
Hope it is OK. If there are only cosmetic changes needed please fill free
to correct it, however if there are some bigger changes required I would
like to discuss it first or at last to know what exactly was changed
especially since I already put this patch into my production server. :)
Thank you,
Best regards,
Krzysztof Oledzki
2007-10-22 10:21:10 -04:00
|
|
|
/* backend status: reflect backend status (up/down): we display UP
|
2007-10-17 12:44:57 -04:00
|
|
|
* if the backend has known working servers or if it has no server at
|
[MEDIUM] stats: report server and backend cumulated downtime
Hello,
This patch implements new statistics for SLA calculation by adding new
field 'Dwntime' with total down time since restart (both HTTP/CSV) and
extending status field (HTTP) or inserting a new one (CSV) with time
showing how long each server/backend is in a current state. Additionaly,
down transations are also calculated and displayed for backends, so it is
possible to know how many times selected backend was down, generating "No
server is available to handle this request." error.
New information are presentetd in two different ways:
- for HTTP: a "human redable form", one of "100000d 23h", "23h 59m" or
"59m 59s"
- for CSV: seconds
I believe that seconds resolution is enough.
As there are more columns in the status page I decided to shrink some
names to make more space:
- Weight -> Wght
- Check -> Chk
- Down -> Dwn
Making described changes I also made some improvements and fixed some
small bugs:
- don't increment s->health above 's->rise + s->fall - 1'. Previously it
was incremented an then (re)set to 's->rise + s->fall - 1'.
- do not set server down if it is down already
- do not set server up if it is up already
- fix colspan in multiple places (mostly introduced by my previous patch)
- add missing "status" header to CSV
- fix order of retries/redispatches in server (CSV)
- s/Tthen/Then/
- s/server/backend/ in DATA_ST_PX_BE (dumpstats.c)
Changes from previous version:
- deal with negative time intervales
- don't relay on s->state (SRV_RUNNING)
- little reworked human_time + compacted format (no spaces). If needed it
can be used in the future for other purposes by optionally making "cnt"
as an argument
- leave set_server_down mostly unchanged
- only little reworked "process_chk: 9"
- additional fields in CSV are appended to the rigth
- fix "SEC" macro
- named arguments (human_time, be_downtime, srv_downtime)
Hope it is OK. If there are only cosmetic changes needed please fill free
to correct it, however if there are some bigger changes required I would
like to discuss it first or at last to know what exactly was changed
especially since I already put this patch into my production server. :)
Thank you,
Best regards,
Krzysztof Oledzki
2007-10-22 10:21:10 -04:00
|
|
|
* all (eg: for stats). Then we display the total weight, number of
|
2007-10-17 12:44:57 -04:00
|
|
|
* active and backups. */
|
|
|
|
|
"%s,"
|
|
|
|
|
"%d,%d,%d,"
|
2007-11-30 12:16:29 -05:00
|
|
|
/* rest of backend: nothing, down transitions, last change, total downtime */
|
2007-10-25 14:15:38 -04:00
|
|
|
",%d,%d,%d,,"
|
[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.
2008-03-01 20:42:14 -05:00
|
|
|
/* pid, iid, sid, throttle, lbtot, tracked, type */
|
2009-04-11 14:44:08 -04:00
|
|
|
"%d,%d,0,,%lld,,%d,"
|
2009-05-10 13:01:49 -04:00
|
|
|
/* rate, rate_lim, rate_max, */
|
|
|
|
|
"%u,,%u,"
|
2009-09-23 16:09:24 -04:00
|
|
|
/* check_status, check_code, check_duration */
|
2009-10-13 15:14:09 -04:00
|
|
|
",,,",
|
2007-10-17 12:44:57 -04:00
|
|
|
px->id,
|
2011-03-10 17:25:56 -05:00
|
|
|
px->nbpend /* or px->totpend ? */, px->be_counters.nbpend_max,
|
|
|
|
|
px->beconn, px->be_counters.conn_max, px->fullconn, px->be_counters.cum_conn,
|
|
|
|
|
px->be_counters.bytes_in, px->be_counters.bytes_out,
|
|
|
|
|
px->be_counters.denied_req, px->be_counters.denied_resp,
|
|
|
|
|
px->be_counters.failed_conns, px->be_counters.failed_resp,
|
|
|
|
|
px->be_counters.retries, px->be_counters.redispatches,
|
2007-11-15 17:26:18 -05:00
|
|
|
(px->lbprm.tot_weight > 0 || !px->srv) ? "UP" : "DOWN",
|
2007-12-02 20:04:00 -05:00
|
|
|
(px->lbprm.tot_weight * px->lbprm.wmult + px->lbprm.wdiv - 1) / px->lbprm.wdiv,
|
2007-11-15 17:26:18 -05:00
|
|
|
px->srv_act, px->srv_bck,
|
2009-04-03 08:49:12 -04:00
|
|
|
px->down_trans, (int)(now.tv_sec - px->last_change),
|
2007-11-15 17:26:18 -05:00
|
|
|
px->srv?be_downtime(px):0,
|
2007-12-05 04:34:49 -05:00
|
|
|
relative_pid, px->uuid,
|
2011-03-10 17:25:56 -05:00
|
|
|
px->be_counters.cum_lbconn, STATS_TYPE_BE,
|
2009-05-10 13:01:49 -04:00
|
|
|
read_freq_ctr(&px->be_sess_per_sec),
|
2011-03-10 17:25:56 -05:00
|
|
|
px->be_counters.sps_max);
|
2009-10-13 15:14:09 -04:00
|
|
|
|
|
|
|
|
/* http response: 1xx, 2xx, 3xx, 4xx, 5xx, other */
|
|
|
|
|
if (px->mode == PR_MODE_HTTP) {
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
for (i=1; i<6; i++)
|
2011-03-10 17:25:56 -05:00
|
|
|
chunk_printf(&msg, "%lld,", px->be_counters.p.http.rsp[i]);
|
2009-10-13 15:14:09 -04:00
|
|
|
|
2011-03-10 17:25:56 -05:00
|
|
|
chunk_printf(&msg, "%lld,", px->be_counters.p.http.rsp[0]);
|
2009-10-13 15:14:09 -04:00
|
|
|
} else {
|
|
|
|
|
chunk_printf(&msg, ",,,,,,");
|
|
|
|
|
}
|
|
|
|
|
|
2009-12-15 16:31:24 -05:00
|
|
|
/* failed health analyses */
|
|
|
|
|
chunk_printf(&msg, ",");
|
|
|
|
|
|
2010-02-26 04:05:55 -05:00
|
|
|
/* requests : req_rate, req_rate_max, req_tot, */
|
|
|
|
|
chunk_printf(&msg, ",,,");
|
|
|
|
|
|
2010-03-04 14:34:23 -05:00
|
|
|
/* errors: cli_aborts, srv_aborts */
|
|
|
|
|
chunk_printf(&msg, "%lld,%lld,",
|
2011-03-10 17:25:56 -05:00
|
|
|
px->be_counters.cli_aborts, px->be_counters.srv_aborts);
|
2010-03-04 14:34:23 -05:00
|
|
|
|
2009-10-13 15:14:09 -04:00
|
|
|
/* finish with EOL */
|
|
|
|
|
chunk_printf(&msg, "\n");
|
|
|
|
|
|
2007-10-17 12:44:57 -04:00
|
|
|
}
|
2012-05-07 05:56:55 -04:00
|
|
|
if (bi_putchk(rep, &msg) == -1)
|
2007-10-17 11:06:05 -04:00
|
|
|
return 0;
|
|
|
|
|
}
|
2008-12-07 10:06:43 -05:00
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.stats.px_st = STAT_PX_ST_END;
|
2007-10-17 11:06:05 -04:00
|
|
|
/* fall through */
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
case STAT_PX_ST_END:
|
|
|
|
|
if (!(si->applet.ctx.stats.flags & STAT_FMT_CSV)) {
|
2010-10-11 18:14:35 -04:00
|
|
|
chunk_printf(&msg, "</table>");
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
if (px->cap & PR_CAP_BE && px->srv && (si->applet.ctx.stats.flags & STAT_ADMIN)) {
|
2010-10-11 18:14:35 -04:00
|
|
|
/* close the form used to enable/disable this proxy servers */
|
|
|
|
|
chunk_printf(&msg,
|
|
|
|
|
"Choose the action to perform on the checked servers : "
|
|
|
|
|
"<select name=action>"
|
|
|
|
|
"<option value=\"\"></option>"
|
|
|
|
|
"<option value=\"disable\">Disable</option>"
|
|
|
|
|
"<option value=\"enable\">Enable</option>"
|
2012-06-03 18:22:44 -04:00
|
|
|
"<option value=\"stop\">Soft Stop</option>"
|
|
|
|
|
"<option value=\"start\">Soft Start</option>"
|
2012-06-03 18:26:23 -04:00
|
|
|
"<option value=\"shutdown\">Kill Sessions</option>"
|
2010-10-11 18:14:35 -04:00
|
|
|
"</select>"
|
2012-04-04 06:57:20 -04:00
|
|
|
"<input type=\"hidden\" name=\"b\" value=\"#%d\">"
|
2010-10-11 18:14:35 -04:00
|
|
|
" <input type=\"submit\" value=\"Apply\">"
|
|
|
|
|
"</form>",
|
2012-04-04 06:57:20 -04:00
|
|
|
px->uuid);
|
2010-10-11 18:14:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg, "<p>\n");
|
2007-10-17 11:06:05 -04:00
|
|
|
|
2012-05-07 05:56:55 -04:00
|
|
|
if (bi_putchk(rep, &msg) == -1)
|
2007-10-17 12:44:57 -04:00
|
|
|
return 0;
|
|
|
|
|
}
|
2007-10-17 11:06:05 -04:00
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.stats.px_st = STAT_PX_ST_FIN;
|
2007-10-17 11:06:05 -04:00
|
|
|
/* fall through */
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
case STAT_PX_ST_FIN:
|
2007-10-17 11:06:05 -04:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
/* unknown state, we should put an abort() here ! */
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-13 09:27:22 -05:00
|
|
|
/* This function dumps a complete session state onto the stream intreface's
|
|
|
|
|
* read buffer. The data_ctx must have been zeroed first, and the flags
|
|
|
|
|
* properly set. The session has to be set in data_ctx.sess.target. It returns
|
|
|
|
|
* 0 if the output buffer is full and it needs to be called again, otherwise
|
|
|
|
|
* non-zero. It is designed to be called from stats_dump_sess_to_buffer() below.
|
2010-03-05 11:53:32 -05:00
|
|
|
*/
|
2011-06-15 02:18:44 -04:00
|
|
|
static int stats_dump_full_sess_to_buffer(struct stream_interface *si)
|
2010-03-05 11:53:32 -05:00
|
|
|
{
|
|
|
|
|
struct tm tm;
|
|
|
|
|
struct chunk msg;
|
|
|
|
|
struct session *sess;
|
|
|
|
|
extern const char *monthname[12];
|
|
|
|
|
char pn[INET6_ADDRSTRLEN];
|
|
|
|
|
|
2012-05-16 08:16:48 -04:00
|
|
|
chunk_init(&msg, trash, trashlen);
|
2011-03-10 05:25:07 -05:00
|
|
|
sess = si->applet.ctx.sess.target;
|
2010-03-05 11:53:32 -05:00
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
if (si->applet.ctx.sess.section > 0 && si->applet.ctx.sess.uid != sess->uniq_id) {
|
2010-03-05 11:53:32 -05:00
|
|
|
/* session changed, no need to go any further */
|
|
|
|
|
chunk_printf(&msg, " *** session terminated while we were watching it ***\n");
|
2012-05-07 05:56:55 -04:00
|
|
|
if (bi_putchk(si->ib, &msg) == -1)
|
2010-03-05 11:53:32 -05:00
|
|
|
return 0;
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.sess.target = NULL;
|
|
|
|
|
si->applet.ctx.sess.uid = 0;
|
2010-03-05 11:53:32 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
switch (si->applet.ctx.sess.section) {
|
2010-03-05 11:53:32 -05:00
|
|
|
case 0: /* main status of the session */
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.sess.uid = sess->uniq_id;
|
|
|
|
|
si->applet.ctx.sess.section = 1;
|
2010-03-05 11:53:32 -05:00
|
|
|
/* fall through */
|
|
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
|
chunk_printf(&msg,
|
|
|
|
|
"%p: id=%u, proto=%s",
|
|
|
|
|
sess,
|
|
|
|
|
sess->uniq_id,
|
|
|
|
|
sess->listener->proto->name);
|
|
|
|
|
|
2011-09-23 04:54:59 -04:00
|
|
|
switch (addr_to_str(&sess->si[0].addr.from, pn, sizeof(pn))) {
|
2010-03-05 11:53:32 -05:00
|
|
|
case AF_INET:
|
|
|
|
|
case AF_INET6:
|
2011-09-04 18:36:48 -04:00
|
|
|
chunk_printf(&msg, " source=%s:%d\n",
|
2011-09-23 04:54:59 -04:00
|
|
|
pn, get_host_port(&sess->si[0].addr.from));
|
2010-03-05 11:53:32 -05:00
|
|
|
break;
|
|
|
|
|
case AF_UNIX:
|
2011-09-04 18:36:48 -04:00
|
|
|
chunk_printf(&msg, " source=unix:%d\n", sess->listener->luid);
|
2010-10-22 10:19:01 -04:00
|
|
|
break;
|
2010-03-05 11:53:32 -05:00
|
|
|
default:
|
|
|
|
|
/* no more information to print right now */
|
|
|
|
|
chunk_printf(&msg, "\n");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg,
|
|
|
|
|
" flags=0x%x, conn_retries=%d, srv_conn=%p, pend_pos=%p\n",
|
2010-06-01 03:51:00 -04:00
|
|
|
sess->flags, sess->si[1].conn_retries, sess->srv_conn, sess->pend_pos);
|
2010-03-05 11:53:32 -05:00
|
|
|
|
|
|
|
|
chunk_printf(&msg,
|
2012-03-23 13:53:36 -04:00
|
|
|
" frontend=%s (id=%u mode=%s), listener=%s (id=%u)",
|
2010-03-05 11:53:32 -05:00
|
|
|
sess->fe->id, sess->fe->uuid, sess->fe->mode ? "http" : "tcp",
|
|
|
|
|
sess->listener ? sess->listener->name ? sess->listener->name : "?" : "?",
|
|
|
|
|
sess->listener ? sess->listener->luid : 0);
|
|
|
|
|
|
2012-05-11 10:16:40 -04:00
|
|
|
si_get_to_addr(&sess->si[0]);
|
2012-03-23 13:53:36 -04:00
|
|
|
switch (addr_to_str(&sess->si[0].addr.to, pn, sizeof(pn))) {
|
|
|
|
|
case AF_INET:
|
|
|
|
|
case AF_INET6:
|
|
|
|
|
chunk_printf(&msg, " addr=%s:%d\n",
|
|
|
|
|
pn, get_host_port(&sess->si[0].addr.to));
|
|
|
|
|
break;
|
|
|
|
|
case AF_UNIX:
|
|
|
|
|
chunk_printf(&msg, " addr=unix:%d\n", sess->listener->luid);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
/* no more information to print right now */
|
|
|
|
|
chunk_printf(&msg, "\n");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2011-09-02 11:33:05 -04:00
|
|
|
if (sess->be->cap & PR_CAP_BE)
|
|
|
|
|
chunk_printf(&msg,
|
2012-03-23 13:53:36 -04:00
|
|
|
" backend=%s (id=%u mode=%s)",
|
2011-09-02 11:33:05 -04:00
|
|
|
sess->be->id,
|
2012-03-23 13:53:36 -04:00
|
|
|
sess->be->uuid, sess->be->mode ? "http" : "tcp");
|
|
|
|
|
else
|
|
|
|
|
chunk_printf(&msg, " backend=<NONE> (id=-1 mode=-)");
|
|
|
|
|
|
2012-05-11 10:16:40 -04:00
|
|
|
si_get_from_addr(&sess->si[1]);
|
2012-03-23 13:53:36 -04:00
|
|
|
switch (addr_to_str(&sess->si[1].addr.from, pn, sizeof(pn))) {
|
|
|
|
|
case AF_INET:
|
|
|
|
|
case AF_INET6:
|
|
|
|
|
chunk_printf(&msg, " addr=%s:%d\n",
|
|
|
|
|
pn, get_host_port(&sess->si[1].addr.from));
|
|
|
|
|
break;
|
|
|
|
|
case AF_UNIX:
|
|
|
|
|
chunk_printf(&msg, " addr=unix\n");
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
/* no more information to print right now */
|
|
|
|
|
chunk_printf(&msg, "\n");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sess->be->cap & PR_CAP_BE)
|
|
|
|
|
chunk_printf(&msg,
|
|
|
|
|
" server=%s (id=%u)",
|
2011-09-02 11:33:05 -04:00
|
|
|
target_srv(&sess->target) ? target_srv(&sess->target)->id : "<none>",
|
|
|
|
|
target_srv(&sess->target) ? target_srv(&sess->target)->puid : 0);
|
|
|
|
|
else
|
2012-03-23 13:53:36 -04:00
|
|
|
chunk_printf(&msg, " server=<NONE> (id=-1)");
|
|
|
|
|
|
2012-05-11 10:16:40 -04:00
|
|
|
si_get_to_addr(&sess->si[1]);
|
2012-03-23 13:53:36 -04:00
|
|
|
switch (addr_to_str(&sess->si[1].addr.to, pn, sizeof(pn))) {
|
|
|
|
|
case AF_INET:
|
|
|
|
|
case AF_INET6:
|
|
|
|
|
chunk_printf(&msg, " addr=%s:%d\n",
|
|
|
|
|
pn, get_host_port(&sess->si[1].addr.to));
|
|
|
|
|
break;
|
|
|
|
|
case AF_UNIX:
|
|
|
|
|
chunk_printf(&msg, " addr=unix\n");
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
/* no more information to print right now */
|
|
|
|
|
chunk_printf(&msg, "\n");
|
|
|
|
|
break;
|
|
|
|
|
}
|
2010-03-05 11:53:32 -05:00
|
|
|
|
|
|
|
|
chunk_printf(&msg,
|
|
|
|
|
" task=%p (state=0x%02x nice=%d calls=%d exp=%s%s)\n",
|
|
|
|
|
sess->task,
|
|
|
|
|
sess->task->state,
|
|
|
|
|
sess->task->nice, sess->task->calls,
|
|
|
|
|
sess->task->expire ?
|
|
|
|
|
tick_is_expired(sess->task->expire, now_ms) ? "<PAST>" :
|
|
|
|
|
human_time(TICKS_TO_MS(sess->task->expire - now_ms),
|
|
|
|
|
TICKS_TO_MS(1000)) : "<NEVER>",
|
|
|
|
|
task_in_rq(sess->task) ? ", running" : "");
|
|
|
|
|
|
|
|
|
|
get_localtime(sess->logs.accept_date.tv_sec, &tm);
|
|
|
|
|
chunk_printf(&msg,
|
|
|
|
|
" task created [%02d/%s/%04d:%02d:%02d:%02d.%06d] (age=%s)\n",
|
|
|
|
|
tm.tm_mday, monthname[tm.tm_mon], tm.tm_year+1900,
|
|
|
|
|
tm.tm_hour, tm.tm_min, tm.tm_sec, (int)(sess->logs.accept_date.tv_usec),
|
|
|
|
|
human_time(now.tv_sec - sess->logs.accept_date.tv_sec, 1));
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg,
|
|
|
|
|
" si[0]=%p (state=%d flags=0x%02x fd=%d exp=%s, et=0x%03x)\n",
|
|
|
|
|
&sess->si[0],
|
|
|
|
|
sess->si[0].state,
|
|
|
|
|
sess->si[0].flags,
|
2012-05-21 10:47:54 -04:00
|
|
|
si_fd(&sess->si[0]),
|
2010-03-05 11:53:32 -05:00
|
|
|
sess->si[0].exp ?
|
|
|
|
|
tick_is_expired(sess->si[0].exp, now_ms) ? "<PAST>" :
|
|
|
|
|
human_time(TICKS_TO_MS(sess->si[0].exp - now_ms),
|
|
|
|
|
TICKS_TO_MS(1000)) : "<NEVER>",
|
|
|
|
|
sess->si[0].err_type);
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg,
|
|
|
|
|
" si[1]=%p (state=%d flags=0x%02x fd=%d exp=%s, et=0x%03x)\n",
|
|
|
|
|
&sess->si[1],
|
|
|
|
|
sess->si[1].state,
|
|
|
|
|
sess->si[1].flags,
|
2012-05-21 10:47:54 -04:00
|
|
|
si_fd(&sess->si[1]),
|
2010-03-05 11:53:32 -05:00
|
|
|
sess->si[1].exp ?
|
|
|
|
|
tick_is_expired(sess->si[1].exp, now_ms) ? "<PAST>" :
|
|
|
|
|
human_time(TICKS_TO_MS(sess->si[1].exp - now_ms),
|
|
|
|
|
TICKS_TO_MS(1000)) : "<NEVER>",
|
|
|
|
|
sess->si[1].err_type);
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg,
|
|
|
|
|
" txn=%p (flags=0x%x meth=%d status=%d req.st=%d rsp.st=%d)\n",
|
|
|
|
|
&sess->txn, sess->txn.flags, sess->txn.meth, sess->txn.status,
|
|
|
|
|
sess->txn.req.msg_state, sess->txn.rsp.msg_state);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg,
|
2012-03-01 12:19:58 -05:00
|
|
|
" req=%p (f=0x%06x an=0x%x i=%d o=%d pipe=%d fwd=%d)\n"
|
2010-03-05 11:53:32 -05:00
|
|
|
" an_exp=%s",
|
|
|
|
|
sess->req,
|
|
|
|
|
sess->req->flags, sess->req->analysers,
|
2012-07-02 11:01:20 -04:00
|
|
|
sess->req->buf.i, sess->req->buf.o,
|
2010-03-05 11:53:32 -05:00
|
|
|
sess->req->pipe ? sess->req->pipe->data : 0,
|
|
|
|
|
sess->req->to_forward,
|
|
|
|
|
sess->req->analyse_exp ?
|
|
|
|
|
human_time(TICKS_TO_MS(sess->req->analyse_exp - now_ms),
|
|
|
|
|
TICKS_TO_MS(1000)) : "<NEVER>");
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg,
|
|
|
|
|
" rex=%s",
|
|
|
|
|
sess->req->rex ?
|
|
|
|
|
human_time(TICKS_TO_MS(sess->req->rex - now_ms),
|
|
|
|
|
TICKS_TO_MS(1000)) : "<NEVER>");
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg,
|
|
|
|
|
" wex=%s\n"
|
2012-03-05 05:17:50 -05:00
|
|
|
" data=%p p=%d next=%d total=%lld\n",
|
2010-03-05 11:53:32 -05:00
|
|
|
sess->req->wex ?
|
|
|
|
|
human_time(TICKS_TO_MS(sess->req->wex - now_ms),
|
|
|
|
|
TICKS_TO_MS(1000)) : "<NEVER>",
|
2012-07-02 11:01:20 -04:00
|
|
|
sess->req->buf.data,
|
|
|
|
|
(int)(sess->req->buf.p - sess->req->buf.data),
|
2012-03-05 05:17:50 -05:00
|
|
|
sess->txn.req.next,
|
2010-03-05 11:53:32 -05:00
|
|
|
sess->req->total);
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg,
|
2012-03-01 12:19:58 -05:00
|
|
|
" res=%p (f=0x%06x an=0x%x i=%d o=%d pipe=%d fwd=%d)\n"
|
2010-03-05 11:53:32 -05:00
|
|
|
" an_exp=%s",
|
|
|
|
|
sess->rep,
|
|
|
|
|
sess->rep->flags, sess->rep->analysers,
|
2012-07-02 11:01:20 -04:00
|
|
|
sess->rep->buf.i, sess->rep->buf.o,
|
2010-03-05 11:53:32 -05:00
|
|
|
sess->rep->pipe ? sess->rep->pipe->data : 0,
|
|
|
|
|
sess->rep->to_forward,
|
|
|
|
|
sess->rep->analyse_exp ?
|
|
|
|
|
human_time(TICKS_TO_MS(sess->rep->analyse_exp - now_ms),
|
|
|
|
|
TICKS_TO_MS(1000)) : "<NEVER>");
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg,
|
|
|
|
|
" rex=%s",
|
|
|
|
|
sess->rep->rex ?
|
|
|
|
|
human_time(TICKS_TO_MS(sess->rep->rex - now_ms),
|
|
|
|
|
TICKS_TO_MS(1000)) : "<NEVER>");
|
|
|
|
|
|
|
|
|
|
chunk_printf(&msg,
|
|
|
|
|
" wex=%s\n"
|
2012-03-05 05:17:50 -05:00
|
|
|
" data=%p p=%d next=%d total=%lld\n",
|
2010-03-05 11:53:32 -05:00
|
|
|
sess->rep->wex ?
|
|
|
|
|
human_time(TICKS_TO_MS(sess->rep->wex - now_ms),
|
|
|
|
|
TICKS_TO_MS(1000)) : "<NEVER>",
|
2012-07-02 11:01:20 -04:00
|
|
|
sess->rep->buf.data,
|
|
|
|
|
(int)(sess->rep->buf.p - sess->rep->buf.data),
|
2012-03-05 05:17:50 -05:00
|
|
|
sess->txn.rsp.next,
|
2010-03-05 11:53:32 -05:00
|
|
|
sess->rep->total);
|
|
|
|
|
|
2012-05-07 05:56:55 -04:00
|
|
|
if (bi_putchk(si->ib, &msg) == -1)
|
2010-03-05 11:53:32 -05:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
/* use other states to dump the contents */
|
|
|
|
|
}
|
|
|
|
|
/* end of dump */
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.sess.uid = 0;
|
2010-03-05 11:53:32 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
2008-12-07 16:29:48 -05:00
|
|
|
|
2011-02-13 09:27:22 -05:00
|
|
|
/* This function dumps all sessions' states onto the stream intreface's
|
|
|
|
|
* read buffer. The data_ctx must have been zeroed first, and the flags
|
|
|
|
|
* properly set. It returns 0 if the output buffer is full and it needs
|
|
|
|
|
* to be called again, otherwise non-zero. It is designed to be called
|
|
|
|
|
* from stats_dump_sess_to_buffer() below.
|
2008-12-07 16:29:48 -05:00
|
|
|
*/
|
2011-06-15 02:18:44 -04:00
|
|
|
static int stats_dump_sess_to_buffer(struct stream_interface *si)
|
2008-12-07 16:29:48 -05:00
|
|
|
{
|
|
|
|
|
struct chunk msg;
|
|
|
|
|
|
2011-02-13 09:27:22 -05:00
|
|
|
if (unlikely(si->ib->flags & (BF_WRITE_ERROR|BF_SHUTW))) {
|
2008-12-07 16:29:48 -05:00
|
|
|
/* If we're forced to shut down, we might have to remove our
|
|
|
|
|
* reference to the last session being dumped.
|
|
|
|
|
*/
|
2012-05-21 11:09:48 -04:00
|
|
|
if (si->conn.data_st == STAT_ST_LIST) {
|
2011-03-10 05:25:07 -05:00
|
|
|
if (!LIST_ISEMPTY(&si->applet.ctx.sess.bref.users)) {
|
|
|
|
|
LIST_DEL(&si->applet.ctx.sess.bref.users);
|
|
|
|
|
LIST_INIT(&si->applet.ctx.sess.bref.users);
|
2009-02-22 09:17:24 -05:00
|
|
|
}
|
2008-12-07 16:29:48 -05:00
|
|
|
}
|
2009-10-03 17:55:14 -04:00
|
|
|
return 1;
|
2008-12-07 16:29:48 -05:00
|
|
|
}
|
|
|
|
|
|
2012-05-16 08:16:48 -04:00
|
|
|
chunk_init(&msg, trash, trashlen);
|
2008-12-07 16:29:48 -05:00
|
|
|
|
2012-05-21 11:09:48 -04:00
|
|
|
switch (si->conn.data_st) {
|
2011-03-10 05:25:07 -05:00
|
|
|
case STAT_ST_INIT:
|
2008-12-07 16:29:48 -05:00
|
|
|
/* the function had not been called yet, let's prepare the
|
|
|
|
|
* buffer for a response. We initialize the current session
|
2009-02-22 09:17:24 -05:00
|
|
|
* pointer to the first in the global list. When a target
|
|
|
|
|
* session is being destroyed, it is responsible for updating
|
|
|
|
|
* this pointer. We know we have reached the end when this
|
|
|
|
|
* pointer points back to the head of the sessions list.
|
2008-12-07 16:29:48 -05:00
|
|
|
*/
|
2011-03-10 05:25:07 -05:00
|
|
|
LIST_INIT(&si->applet.ctx.sess.bref.users);
|
|
|
|
|
si->applet.ctx.sess.bref.ref = sessions.n;
|
2012-05-21 11:09:48 -04:00
|
|
|
si->conn.data_st = STAT_ST_LIST;
|
2008-12-07 16:29:48 -05:00
|
|
|
/* fall through */
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
case STAT_ST_LIST:
|
2009-02-22 09:17:24 -05:00
|
|
|
/* first, let's detach the back-ref from a possible previous session */
|
2011-03-10 05:25:07 -05:00
|
|
|
if (!LIST_ISEMPTY(&si->applet.ctx.sess.bref.users)) {
|
|
|
|
|
LIST_DEL(&si->applet.ctx.sess.bref.users);
|
|
|
|
|
LIST_INIT(&si->applet.ctx.sess.bref.users);
|
2009-02-22 09:17:24 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* and start from where we stopped */
|
2011-03-10 05:25:07 -05:00
|
|
|
while (si->applet.ctx.sess.bref.ref != &sessions) {
|
2010-11-01 14:26:02 -04:00
|
|
|
char pn[INET6_ADDRSTRLEN];
|
2008-12-07 16:29:48 -05:00
|
|
|
struct session *curr_sess;
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
curr_sess = LIST_ELEM(si->applet.ctx.sess.bref.ref, struct session *, list);
|
2008-12-07 16:29:48 -05:00
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
if (si->applet.ctx.sess.target) {
|
|
|
|
|
if (si->applet.ctx.sess.target != curr_sess)
|
2010-03-05 11:53:32 -05:00
|
|
|
goto next_sess;
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
LIST_ADDQ(&curr_sess->back_refs, &si->applet.ctx.sess.bref.users);
|
2010-03-05 11:53:32 -05:00
|
|
|
/* call the proper dump() function and return if we're missing space */
|
2011-02-13 09:27:22 -05:00
|
|
|
if (!stats_dump_full_sess_to_buffer(si))
|
2010-03-05 11:53:32 -05:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
/* session dump complete */
|
2011-03-10 05:25:07 -05:00
|
|
|
LIST_DEL(&si->applet.ctx.sess.bref.users);
|
|
|
|
|
LIST_INIT(&si->applet.ctx.sess.bref.users);
|
|
|
|
|
si->applet.ctx.sess.target = NULL;
|
2010-03-05 11:53:32 -05:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2008-12-07 16:29:48 -05:00
|
|
|
"%p: proto=%s",
|
|
|
|
|
curr_sess,
|
|
|
|
|
curr_sess->listener->proto->name);
|
|
|
|
|
|
|
|
|
|
|
2011-09-23 04:54:59 -04:00
|
|
|
switch (addr_to_str(&curr_sess->si[0].addr.from, pn, sizeof(pn))) {
|
2011-09-04 18:36:48 -04:00
|
|
|
case AF_INET:
|
2008-12-07 16:29:48 -05:00
|
|
|
case AF_INET6:
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2008-12-07 16:29:48 -05:00
|
|
|
" src=%s:%d fe=%s be=%s srv=%s",
|
|
|
|
|
pn,
|
2011-09-23 04:54:59 -04:00
|
|
|
get_host_port(&curr_sess->si[0].addr.from),
|
2008-12-07 16:29:48 -05:00
|
|
|
curr_sess->fe->id,
|
2011-09-02 11:33:05 -04:00
|
|
|
(curr_sess->be->cap & PR_CAP_BE) ? curr_sess->be->id : "<NONE>",
|
2011-03-10 10:55:02 -05:00
|
|
|
target_srv(&curr_sess->target) ? target_srv(&curr_sess->target)->id : "<none>"
|
2008-12-07 16:29:48 -05:00
|
|
|
);
|
|
|
|
|
break;
|
|
|
|
|
case AF_UNIX:
|
2010-10-22 10:19:01 -04:00
|
|
|
chunk_printf(&msg,
|
|
|
|
|
" src=unix:%d fe=%s be=%s srv=%s",
|
|
|
|
|
curr_sess->listener->luid,
|
|
|
|
|
curr_sess->fe->id,
|
2011-09-02 11:33:05 -04:00
|
|
|
(curr_sess->be->cap & PR_CAP_BE) ? curr_sess->be->id : "<NONE>",
|
2011-03-10 10:55:02 -05:00
|
|
|
target_srv(&curr_sess->target) ? target_srv(&curr_sess->target)->id : "<none>"
|
2010-10-22 10:19:01 -04:00
|
|
|
);
|
2008-12-07 16:29:48 -05:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2009-10-04 08:24:59 -04:00
|
|
|
" ts=%02x age=%s calls=%d",
|
|
|
|
|
curr_sess->task->state,
|
2009-03-28 12:54:35 -04:00
|
|
|
human_time(now.tv_sec - curr_sess->logs.tv_accept.tv_sec, 1),
|
|
|
|
|
curr_sess->task->calls);
|
2008-12-07 16:29:48 -05:00
|
|
|
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2012-03-01 12:19:58 -05:00
|
|
|
" rq[f=%06xh,i=%d,an=%02xh,rx=%s",
|
2009-03-28 19:18:14 -04:00
|
|
|
curr_sess->req->flags,
|
2012-07-02 11:01:20 -04:00
|
|
|
curr_sess->req->buf.i,
|
2009-03-28 19:18:14 -04:00
|
|
|
curr_sess->req->analysers,
|
|
|
|
|
curr_sess->req->rex ?
|
|
|
|
|
human_time(TICKS_TO_MS(curr_sess->req->rex - now_ms),
|
|
|
|
|
TICKS_TO_MS(1000)) : "");
|
|
|
|
|
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2009-03-28 19:18:14 -04:00
|
|
|
",wx=%s",
|
|
|
|
|
curr_sess->req->wex ?
|
|
|
|
|
human_time(TICKS_TO_MS(curr_sess->req->wex - now_ms),
|
|
|
|
|
TICKS_TO_MS(1000)) : "");
|
|
|
|
|
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2009-03-28 19:18:14 -04:00
|
|
|
",ax=%s]",
|
|
|
|
|
curr_sess->req->analyse_exp ?
|
|
|
|
|
human_time(TICKS_TO_MS(curr_sess->req->analyse_exp - now_ms),
|
|
|
|
|
TICKS_TO_MS(1000)) : "");
|
|
|
|
|
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2012-03-01 12:19:58 -05:00
|
|
|
" rp[f=%06xh,i=%d,an=%02xh,rx=%s",
|
2009-03-28 19:18:14 -04:00
|
|
|
curr_sess->rep->flags,
|
2012-07-02 11:01:20 -04:00
|
|
|
curr_sess->rep->buf.i,
|
2009-03-28 19:18:14 -04:00
|
|
|
curr_sess->rep->analysers,
|
|
|
|
|
curr_sess->rep->rex ?
|
|
|
|
|
human_time(TICKS_TO_MS(curr_sess->rep->rex - now_ms),
|
|
|
|
|
TICKS_TO_MS(1000)) : "");
|
|
|
|
|
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2009-03-28 19:18:14 -04:00
|
|
|
",wx=%s",
|
|
|
|
|
curr_sess->rep->wex ?
|
|
|
|
|
human_time(TICKS_TO_MS(curr_sess->rep->wex - now_ms),
|
|
|
|
|
TICKS_TO_MS(1000)) : "");
|
|
|
|
|
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2009-03-28 19:18:14 -04:00
|
|
|
",ax=%s]",
|
|
|
|
|
curr_sess->rep->analyse_exp ?
|
|
|
|
|
human_time(TICKS_TO_MS(curr_sess->rep->analyse_exp - now_ms),
|
|
|
|
|
TICKS_TO_MS(1000)) : "");
|
|
|
|
|
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2009-03-28 19:18:14 -04:00
|
|
|
" s0=[%d,%1xh,fd=%d,ex=%s]",
|
|
|
|
|
curr_sess->si[0].state,
|
|
|
|
|
curr_sess->si[0].flags,
|
2012-05-21 10:47:54 -04:00
|
|
|
si_fd(&curr_sess->si[0]),
|
2009-03-28 19:18:14 -04:00
|
|
|
curr_sess->si[0].exp ?
|
|
|
|
|
human_time(TICKS_TO_MS(curr_sess->si[0].exp - now_ms),
|
|
|
|
|
TICKS_TO_MS(1000)) : "");
|
|
|
|
|
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2009-03-28 19:18:14 -04:00
|
|
|
" s1=[%d,%1xh,fd=%d,ex=%s]",
|
|
|
|
|
curr_sess->si[1].state,
|
|
|
|
|
curr_sess->si[1].flags,
|
2012-05-21 10:47:54 -04:00
|
|
|
si_fd(&curr_sess->si[1]),
|
2009-03-28 19:18:14 -04:00
|
|
|
curr_sess->si[1].exp ?
|
|
|
|
|
human_time(TICKS_TO_MS(curr_sess->si[1].exp - now_ms),
|
|
|
|
|
TICKS_TO_MS(1000)) : "");
|
|
|
|
|
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2009-03-28 19:18:14 -04:00
|
|
|
" exp=%s",
|
|
|
|
|
curr_sess->task->expire ?
|
|
|
|
|
human_time(TICKS_TO_MS(curr_sess->task->expire - now_ms),
|
|
|
|
|
TICKS_TO_MS(1000)) : "");
|
2009-03-07 11:25:21 -05:00
|
|
|
if (task_in_rq(curr_sess->task))
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg, " run(nice=%d)", curr_sess->task->nice);
|
2009-03-28 19:18:14 -04:00
|
|
|
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg, "\n");
|
2008-12-07 16:29:48 -05:00
|
|
|
|
2012-05-07 05:56:55 -04:00
|
|
|
if (bi_putchk(si->ib, &msg) == -1) {
|
2009-02-22 09:17:24 -05:00
|
|
|
/* let's try again later from this session. We add ourselves into
|
|
|
|
|
* this session's users so that it can remove us upon termination.
|
|
|
|
|
*/
|
2011-03-10 05:25:07 -05:00
|
|
|
LIST_ADDQ(&curr_sess->back_refs, &si->applet.ctx.sess.bref.users);
|
2009-10-03 17:55:14 -04:00
|
|
|
return 0;
|
2008-12-07 16:29:48 -05:00
|
|
|
}
|
|
|
|
|
|
2010-03-05 11:53:32 -05:00
|
|
|
next_sess:
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.sess.bref.ref = curr_sess->list.n;
|
2008-12-07 16:29:48 -05:00
|
|
|
}
|
2010-03-05 11:53:32 -05:00
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
if (si->applet.ctx.sess.target) {
|
2010-03-05 11:53:32 -05:00
|
|
|
/* specified session not found */
|
2011-03-10 05:25:07 -05:00
|
|
|
if (si->applet.ctx.sess.section > 0)
|
2010-03-05 11:53:32 -05:00
|
|
|
chunk_printf(&msg, " *** session terminated while we were watching it ***\n");
|
|
|
|
|
else
|
|
|
|
|
chunk_printf(&msg, "Session not found.\n");
|
|
|
|
|
|
2012-05-07 05:56:55 -04:00
|
|
|
if (bi_putchk(si->ib, &msg) == -1)
|
2010-03-05 11:53:32 -05:00
|
|
|
return 0;
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.sess.target = NULL;
|
|
|
|
|
si->applet.ctx.sess.uid = 0;
|
2010-03-05 11:53:32 -05:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-21 11:09:48 -04:00
|
|
|
si->conn.data_st = STAT_ST_FIN;
|
2008-12-07 16:29:48 -05:00
|
|
|
/* fall through */
|
|
|
|
|
|
|
|
|
|
default:
|
2012-05-21 11:09:48 -04:00
|
|
|
si->conn.data_st = STAT_ST_FIN;
|
2009-10-03 17:55:14 -04:00
|
|
|
return 1;
|
2008-12-07 16:29:48 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-13 09:27:22 -05:00
|
|
|
/* This function dumps all tables' states onto the stream intreface's
|
|
|
|
|
* read buffer. The data_ctx must have been zeroed first, and the flags
|
|
|
|
|
* properly set. It returns 0 if the output buffer is full and it needs
|
|
|
|
|
* to be called again, otherwise non-zero.
|
2010-07-12 11:55:33 -04:00
|
|
|
*/
|
2011-06-15 02:18:49 -04:00
|
|
|
static int stats_table_request(struct stream_interface *si, bool show)
|
2010-07-12 11:55:33 -04:00
|
|
|
{
|
2012-05-21 11:09:48 -04:00
|
|
|
struct session *s = si->conn.data_ctx;
|
2010-07-12 11:55:33 -04:00
|
|
|
struct chunk msg;
|
|
|
|
|
struct ebmb_node *eb;
|
|
|
|
|
int dt;
|
2011-06-15 02:18:49 -04:00
|
|
|
bool skip_entry;
|
2010-07-12 11:55:33 -04:00
|
|
|
|
|
|
|
|
/*
|
2012-05-21 11:09:48 -04:00
|
|
|
* We have 3 possible states in si->conn.data_st :
|
2011-03-10 05:25:07 -05:00
|
|
|
* - STAT_ST_INIT : the first call
|
|
|
|
|
* - STAT_ST_INFO : the proxy pointer points to the next table to
|
2010-07-12 11:55:33 -04:00
|
|
|
* dump, the entry pointer is NULL ;
|
2011-03-10 05:25:07 -05:00
|
|
|
* - STAT_ST_LIST : the proxy pointer points to the current table
|
2010-07-12 11:55:33 -04:00
|
|
|
* and the entry pointer points to the next entry to be dumped,
|
|
|
|
|
* and the refcount on the next entry is held ;
|
2011-03-10 05:25:07 -05:00
|
|
|
* - STAT_ST_END : nothing left to dump, the buffer may contain some
|
2010-07-12 11:55:33 -04:00
|
|
|
* data though.
|
|
|
|
|
*/
|
|
|
|
|
|
2011-02-13 09:27:22 -05:00
|
|
|
if (unlikely(si->ib->flags & (BF_WRITE_ERROR|BF_SHUTW))) {
|
2010-07-12 11:55:33 -04:00
|
|
|
/* in case of abort, remove any refcount we might have set on an entry */
|
2012-05-21 11:09:48 -04:00
|
|
|
if (si->conn.data_st == STAT_ST_LIST) {
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.table.entry->ref_cnt--;
|
|
|
|
|
stksess_kill_if_expired(&si->applet.ctx.table.proxy->table, si->applet.ctx.table.entry);
|
2010-08-03 14:34:06 -04:00
|
|
|
}
|
2010-07-12 11:55:33 -04:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-16 08:16:48 -04:00
|
|
|
chunk_init(&msg, trash, trashlen);
|
2010-07-12 11:55:33 -04:00
|
|
|
|
2012-05-21 11:09:48 -04:00
|
|
|
while (si->conn.data_st != STAT_ST_FIN) {
|
|
|
|
|
switch (si->conn.data_st) {
|
2011-03-10 05:25:07 -05:00
|
|
|
case STAT_ST_INIT:
|
|
|
|
|
si->applet.ctx.table.proxy = si->applet.ctx.table.target;
|
|
|
|
|
if (!si->applet.ctx.table.proxy)
|
|
|
|
|
si->applet.ctx.table.proxy = proxy;
|
2010-07-12 11:55:33 -04:00
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.table.entry = NULL;
|
2012-05-21 11:09:48 -04:00
|
|
|
si->conn.data_st = STAT_ST_INFO;
|
2010-07-12 11:55:33 -04:00
|
|
|
break;
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
case STAT_ST_INFO:
|
|
|
|
|
if (!si->applet.ctx.table.proxy ||
|
|
|
|
|
(si->applet.ctx.table.target &&
|
|
|
|
|
si->applet.ctx.table.proxy != si->applet.ctx.table.target)) {
|
2012-05-21 11:09:48 -04:00
|
|
|
si->conn.data_st = STAT_ST_END;
|
2010-07-12 11:55:33 -04:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
if (si->applet.ctx.table.proxy->table.size) {
|
2011-06-15 02:18:49 -04:00
|
|
|
if (show && !stats_dump_table_head_to_buffer(&msg, si, si->applet.ctx.table.proxy,
|
|
|
|
|
si->applet.ctx.table.target))
|
2010-07-12 11:55:33 -04:00
|
|
|
return 0;
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
if (si->applet.ctx.table.target &&
|
2010-07-12 11:55:33 -04:00
|
|
|
s->listener->perm.ux.level >= ACCESS_LVL_OPER) {
|
|
|
|
|
/* dump entries only if table explicitly requested */
|
2011-03-10 05:25:07 -05:00
|
|
|
eb = ebmb_first(&si->applet.ctx.table.proxy->table.keys);
|
2010-07-12 11:55:33 -04:00
|
|
|
if (eb) {
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.table.entry = ebmb_entry(eb, struct stksess, key);
|
|
|
|
|
si->applet.ctx.table.entry->ref_cnt++;
|
2012-05-21 11:09:48 -04:00
|
|
|
si->conn.data_st = STAT_ST_LIST;
|
2010-07-12 11:55:33 -04:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.table.proxy = si->applet.ctx.table.proxy->next;
|
2010-07-12 11:55:33 -04:00
|
|
|
break;
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
case STAT_ST_LIST:
|
2011-06-15 02:18:49 -04:00
|
|
|
skip_entry = false;
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
if (si->applet.ctx.table.data_type >= 0) {
|
2010-07-18 05:46:20 -04:00
|
|
|
/* we're filtering on some data contents */
|
|
|
|
|
void *ptr;
|
|
|
|
|
long long data;
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
dt = si->applet.ctx.table.data_type;
|
|
|
|
|
ptr = stktable_data_ptr(&si->applet.ctx.table.proxy->table,
|
|
|
|
|
si->applet.ctx.table.entry,
|
2010-07-18 05:46:20 -04:00
|
|
|
dt);
|
|
|
|
|
|
|
|
|
|
data = 0;
|
|
|
|
|
switch (stktable_data_types[dt].std_type) {
|
|
|
|
|
case STD_T_SINT:
|
|
|
|
|
data = stktable_data_cast(ptr, std_t_sint);
|
|
|
|
|
break;
|
|
|
|
|
case STD_T_UINT:
|
|
|
|
|
data = stktable_data_cast(ptr, std_t_uint);
|
|
|
|
|
break;
|
|
|
|
|
case STD_T_ULL:
|
|
|
|
|
data = stktable_data_cast(ptr, std_t_ull);
|
|
|
|
|
break;
|
|
|
|
|
case STD_T_FRQP:
|
|
|
|
|
data = read_freq_ctr_period(&stktable_data_cast(ptr, std_t_frqp),
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.table.proxy->table.data_arg[dt].u);
|
2010-07-18 05:46:20 -04:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* skip the entry if the data does not match the test and the value */
|
2011-03-10 05:25:07 -05:00
|
|
|
if ((data < si->applet.ctx.table.value &&
|
|
|
|
|
(si->applet.ctx.table.data_op == STD_OP_EQ ||
|
|
|
|
|
si->applet.ctx.table.data_op == STD_OP_GT ||
|
|
|
|
|
si->applet.ctx.table.data_op == STD_OP_GE)) ||
|
|
|
|
|
(data == si->applet.ctx.table.value &&
|
|
|
|
|
(si->applet.ctx.table.data_op == STD_OP_NE ||
|
|
|
|
|
si->applet.ctx.table.data_op == STD_OP_GT ||
|
|
|
|
|
si->applet.ctx.table.data_op == STD_OP_LT)) ||
|
|
|
|
|
(data > si->applet.ctx.table.value &&
|
|
|
|
|
(si->applet.ctx.table.data_op == STD_OP_EQ ||
|
|
|
|
|
si->applet.ctx.table.data_op == STD_OP_LT ||
|
|
|
|
|
si->applet.ctx.table.data_op == STD_OP_LE)))
|
2011-06-15 02:18:49 -04:00
|
|
|
skip_entry = true;
|
2010-07-18 05:46:20 -04:00
|
|
|
}
|
|
|
|
|
|
2011-06-15 02:18:49 -04:00
|
|
|
if (show && !skip_entry &&
|
|
|
|
|
!stats_dump_table_entry_to_buffer(&msg, si, si->applet.ctx.table.proxy,
|
2011-06-15 02:18:45 -04:00
|
|
|
si->applet.ctx.table.entry))
|
|
|
|
|
return 0;
|
2010-07-12 11:55:33 -04:00
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.table.entry->ref_cnt--;
|
2010-07-12 11:55:33 -04:00
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
eb = ebmb_next(&si->applet.ctx.table.entry->key);
|
2010-07-12 11:55:33 -04:00
|
|
|
if (eb) {
|
2011-03-10 05:25:07 -05:00
|
|
|
struct stksess *old = si->applet.ctx.table.entry;
|
|
|
|
|
si->applet.ctx.table.entry = ebmb_entry(eb, struct stksess, key);
|
2012-01-09 05:50:03 -05:00
|
|
|
if (show)
|
|
|
|
|
stksess_kill_if_expired(&si->applet.ctx.table.proxy->table, old);
|
|
|
|
|
else
|
|
|
|
|
stksess_kill(&si->applet.ctx.table.proxy->table, old);
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.table.entry->ref_cnt++;
|
2010-07-12 11:55:33 -04:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-15 02:18:49 -04:00
|
|
|
|
|
|
|
|
if (show)
|
|
|
|
|
stksess_kill_if_expired(&si->applet.ctx.table.proxy->table, si->applet.ctx.table.entry);
|
|
|
|
|
else if (!skip_entry && !si->applet.ctx.table.entry->ref_cnt)
|
|
|
|
|
stksess_kill(&si->applet.ctx.table.proxy->table, si->applet.ctx.table.entry);
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.table.proxy = si->applet.ctx.table.proxy->next;
|
2012-05-21 11:09:48 -04:00
|
|
|
si->conn.data_st = STAT_ST_INFO;
|
2010-07-12 11:55:33 -04:00
|
|
|
break;
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
case STAT_ST_END:
|
2012-05-21 11:09:48 -04:00
|
|
|
si->conn.data_st = STAT_ST_FIN;
|
2010-07-12 11:55:33 -04:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2010-03-05 08:58:26 -05:00
|
|
|
/* print a line of text buffer (limited to 70 bytes) to <out>. The format is :
|
2009-03-04 09:53:18 -05:00
|
|
|
* <2 spaces> <offset=5 digits> <space or plus> <space> <70 chars max> <\n>
|
|
|
|
|
* which is 60 chars per line. Non-printable chars \t, \n, \r and \e are
|
|
|
|
|
* encoded in C format. Other non-printable chars are encoded "\xHH". Original
|
|
|
|
|
* lines are respected within the limit of 70 output chars. Lines that are
|
|
|
|
|
* continuation of a previous truncated line begin with "+" instead of " "
|
|
|
|
|
* after the offset. The new pointer is returned.
|
|
|
|
|
*/
|
2010-03-05 08:58:26 -05:00
|
|
|
static int dump_text_line(struct chunk *out, const char *buf, int bsize, int len,
|
|
|
|
|
int *line, int ptr)
|
2009-03-04 09:53:18 -05:00
|
|
|
{
|
|
|
|
|
int end;
|
|
|
|
|
unsigned char c;
|
|
|
|
|
|
|
|
|
|
end = out->len + 80;
|
2009-09-27 07:23:20 -04:00
|
|
|
if (end > out->size)
|
2009-03-04 09:53:18 -05:00
|
|
|
return ptr;
|
|
|
|
|
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(out, " %05d%c ", ptr, (ptr == *line) ? ' ' : '+');
|
2009-03-04 09:53:18 -05:00
|
|
|
|
2010-03-05 08:58:26 -05:00
|
|
|
while (ptr < len && ptr < bsize) {
|
|
|
|
|
c = buf[ptr];
|
2009-03-12 03:18:33 -04:00
|
|
|
if (isprint(c) && isascii(c) && c != '\\') {
|
2009-03-04 09:53:18 -05:00
|
|
|
if (out->len > end - 2)
|
|
|
|
|
break;
|
|
|
|
|
out->str[out->len++] = c;
|
2009-03-12 03:18:33 -04:00
|
|
|
} else if (c == '\t' || c == '\n' || c == '\r' || c == '\e' || c == '\\') {
|
2009-03-04 09:53:18 -05:00
|
|
|
if (out->len > end - 3)
|
|
|
|
|
break;
|
|
|
|
|
out->str[out->len++] = '\\';
|
|
|
|
|
switch (c) {
|
|
|
|
|
case '\t': c = 't'; break;
|
|
|
|
|
case '\n': c = 'n'; break;
|
|
|
|
|
case '\r': c = 'r'; break;
|
|
|
|
|
case '\e': c = 'e'; break;
|
2009-03-12 03:18:33 -04:00
|
|
|
case '\\': c = '\\'; break;
|
2009-03-04 09:53:18 -05:00
|
|
|
}
|
|
|
|
|
out->str[out->len++] = c;
|
|
|
|
|
} else {
|
|
|
|
|
if (out->len > end - 5)
|
|
|
|
|
break;
|
|
|
|
|
out->str[out->len++] = '\\';
|
|
|
|
|
out->str[out->len++] = 'x';
|
|
|
|
|
out->str[out->len++] = hextab[(c >> 4) & 0xF];
|
|
|
|
|
out->str[out->len++] = hextab[c & 0xF];
|
|
|
|
|
}
|
2010-03-05 08:58:26 -05:00
|
|
|
if (buf[ptr++] == '\n') {
|
2009-03-04 09:53:18 -05:00
|
|
|
/* we had a line break, let's return now */
|
|
|
|
|
out->str[out->len++] = '\n';
|
|
|
|
|
*line = ptr;
|
|
|
|
|
return ptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/* we have an incomplete line, we return it as-is */
|
|
|
|
|
out->str[out->len++] = '\n';
|
|
|
|
|
return ptr;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-13 09:27:22 -05:00
|
|
|
/* This function dumps all captured errors onto the stream intreface's
|
|
|
|
|
* read buffer. The data_ctx must have been zeroed first, and the flags
|
|
|
|
|
* properly set. It returns 0 if the output buffer is full and it needs
|
|
|
|
|
* to be called again, otherwise non-zero.
|
2009-03-04 09:53:18 -05:00
|
|
|
*/
|
2011-06-15 02:18:44 -04:00
|
|
|
static int stats_dump_errors_to_buffer(struct stream_interface *si)
|
2009-03-04 09:53:18 -05:00
|
|
|
{
|
|
|
|
|
extern const char *monthname[12];
|
|
|
|
|
struct chunk msg;
|
|
|
|
|
|
2011-02-13 09:27:22 -05:00
|
|
|
if (unlikely(si->ib->flags & (BF_WRITE_ERROR|BF_SHUTW)))
|
2009-10-03 17:49:35 -04:00
|
|
|
return 1;
|
2009-03-04 09:53:18 -05:00
|
|
|
|
2012-05-16 08:16:48 -04:00
|
|
|
chunk_init(&msg, trash, trashlen);
|
2009-03-04 09:53:18 -05:00
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
if (!si->applet.ctx.errors.px) {
|
2009-03-04 09:53:18 -05:00
|
|
|
/* the function had not been called yet, let's prepare the
|
|
|
|
|
* buffer for a response.
|
|
|
|
|
*/
|
2010-12-12 08:00:34 -05:00
|
|
|
struct tm tm;
|
|
|
|
|
|
|
|
|
|
get_localtime(date.tv_sec, &tm);
|
|
|
|
|
chunk_printf(&msg, "Total events captured on [%02d/%s/%04d:%02d:%02d:%02d.%03d] : %u\n",
|
|
|
|
|
tm.tm_mday, monthname[tm.tm_mon], tm.tm_year+1900,
|
|
|
|
|
tm.tm_hour, tm.tm_min, tm.tm_sec, (int)(date.tv_usec/1000),
|
|
|
|
|
error_snapshot_id);
|
|
|
|
|
|
2012-05-07 05:56:55 -04:00
|
|
|
if (bi_putchk(si->ib, &msg) == -1) {
|
2010-12-12 08:00:34 -05:00
|
|
|
/* Socket buffer full. Let's try again later from the same point */
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.errors.px = proxy;
|
|
|
|
|
si->applet.ctx.errors.buf = 0;
|
|
|
|
|
si->applet.ctx.errors.bol = 0;
|
|
|
|
|
si->applet.ctx.errors.ptr = -1;
|
2009-03-04 09:53:18 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* we have two inner loops here, one for the proxy, the other one for
|
|
|
|
|
* the buffer.
|
|
|
|
|
*/
|
2011-03-10 05:25:07 -05:00
|
|
|
while (si->applet.ctx.errors.px) {
|
2009-03-04 09:53:18 -05:00
|
|
|
struct error_snapshot *es;
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
if (si->applet.ctx.errors.buf == 0)
|
|
|
|
|
es = &si->applet.ctx.errors.px->invalid_req;
|
2009-03-04 09:53:18 -05:00
|
|
|
else
|
2011-03-10 05:25:07 -05:00
|
|
|
es = &si->applet.ctx.errors.px->invalid_rep;
|
2009-03-04 09:53:18 -05:00
|
|
|
|
|
|
|
|
if (!es->when.tv_sec)
|
|
|
|
|
goto next;
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
if (si->applet.ctx.errors.iid >= 0 &&
|
|
|
|
|
si->applet.ctx.errors.px->uuid != si->applet.ctx.errors.iid &&
|
|
|
|
|
es->oe->uuid != si->applet.ctx.errors.iid)
|
2009-03-04 09:53:18 -05:00
|
|
|
goto next;
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
if (si->applet.ctx.errors.ptr < 0) {
|
2009-03-04 09:53:18 -05:00
|
|
|
/* just print headers now */
|
|
|
|
|
|
|
|
|
|
char pn[INET6_ADDRSTRLEN];
|
|
|
|
|
struct tm tm;
|
MEDIUM: http: improve error capture reports
A number of important information were missing from the error captures, so
let's improve them. Now we also log source port, session flags, transaction
flags, message flags, pending output bytes, expected buffer wrapping position,
total bytes transferred, message chunk length, and message body length.
As such, the output format has slightly evolved and the source address moved
to the third line :
[08/May/2012:11:14:36.341] frontend echo (#1): invalid request
backend echo (#1), server <NONE> (#-1), event #1
src 127.0.0.1:40616, session #4, session flags 0x00000000
HTTP msg state 26, msg flags 0x00000000, tx flags 0x00000000
HTTP chunk len 0 bytes, HTTP body len 0 bytes
buffer flags 0x00909002, out 0 bytes, total 28 bytes
pending 28 bytes, wrapping at 8030, error at position 7:
00000 GET / /?t=20000 HTTP/1.1\r\n
00026 \r\n
[08/May/2012:11:13:13.426] backend echo (#1) : invalid response
frontend echo (#1), server local (#1), event #0
src 127.0.0.1:40615, session #1, session flags 0x0000044e
HTTP msg state 32, msg flags 0x0000000e, tx flags 0x08200000
HTTP chunk len 0 bytes, HTTP body len 20 bytes
buffer flags 0x00008002, out 81 bytes, total 92 bytes
pending 11 bytes, wrapping at 7949, error at position 9:
00000 Foo: bar\r\r\n
2012-05-08 05:03:10 -04:00
|
|
|
int port;
|
2009-03-04 09:53:18 -05:00
|
|
|
|
|
|
|
|
get_localtime(es->when.tv_sec, &tm);
|
2010-03-05 11:42:58 -05:00
|
|
|
chunk_printf(&msg, " \n[%02d/%s/%04d:%02d:%02d:%02d.%03d]",
|
2009-03-04 09:53:18 -05:00
|
|
|
tm.tm_mday, monthname[tm.tm_mon], tm.tm_year+1900,
|
2009-04-03 08:49:12 -04:00
|
|
|
tm.tm_hour, tm.tm_min, tm.tm_sec, (int)(es->when.tv_usec/1000));
|
2009-03-04 09:53:18 -05:00
|
|
|
|
MEDIUM: http: improve error capture reports
A number of important information were missing from the error captures, so
let's improve them. Now we also log source port, session flags, transaction
flags, message flags, pending output bytes, expected buffer wrapping position,
total bytes transferred, message chunk length, and message body length.
As such, the output format has slightly evolved and the source address moved
to the third line :
[08/May/2012:11:14:36.341] frontend echo (#1): invalid request
backend echo (#1), server <NONE> (#-1), event #1
src 127.0.0.1:40616, session #4, session flags 0x00000000
HTTP msg state 26, msg flags 0x00000000, tx flags 0x00000000
HTTP chunk len 0 bytes, HTTP body len 0 bytes
buffer flags 0x00909002, out 0 bytes, total 28 bytes
pending 28 bytes, wrapping at 8030, error at position 7:
00000 GET / /?t=20000 HTTP/1.1\r\n
00026 \r\n
[08/May/2012:11:13:13.426] backend echo (#1) : invalid response
frontend echo (#1), server local (#1), event #0
src 127.0.0.1:40615, session #1, session flags 0x0000044e
HTTP msg state 32, msg flags 0x0000000e, tx flags 0x08200000
HTTP chunk len 0 bytes, HTTP body len 20 bytes
buffer flags 0x00008002, out 81 bytes, total 92 bytes
pending 11 bytes, wrapping at 7949, error at position 9:
00000 Foo: bar\r\r\n
2012-05-08 05:03:10 -04:00
|
|
|
switch (addr_to_str(&es->src, pn, sizeof(pn))) {
|
|
|
|
|
case AF_INET:
|
|
|
|
|
case AF_INET6:
|
|
|
|
|
port = get_host_port(&es->src);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
port = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
switch (si->applet.ctx.errors.buf) {
|
2009-03-04 09:53:18 -05:00
|
|
|
case 0:
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2009-03-04 09:53:18 -05:00
|
|
|
" frontend %s (#%d): invalid request\n"
|
MEDIUM: http: improve error capture reports
A number of important information were missing from the error captures, so
let's improve them. Now we also log source port, session flags, transaction
flags, message flags, pending output bytes, expected buffer wrapping position,
total bytes transferred, message chunk length, and message body length.
As such, the output format has slightly evolved and the source address moved
to the third line :
[08/May/2012:11:14:36.341] frontend echo (#1): invalid request
backend echo (#1), server <NONE> (#-1), event #1
src 127.0.0.1:40616, session #4, session flags 0x00000000
HTTP msg state 26, msg flags 0x00000000, tx flags 0x00000000
HTTP chunk len 0 bytes, HTTP body len 0 bytes
buffer flags 0x00909002, out 0 bytes, total 28 bytes
pending 28 bytes, wrapping at 8030, error at position 7:
00000 GET / /?t=20000 HTTP/1.1\r\n
00026 \r\n
[08/May/2012:11:13:13.426] backend echo (#1) : invalid response
frontend echo (#1), server local (#1), event #0
src 127.0.0.1:40615, session #1, session flags 0x0000044e
HTTP msg state 32, msg flags 0x0000000e, tx flags 0x08200000
HTTP chunk len 0 bytes, HTTP body len 20 bytes
buffer flags 0x00008002, out 81 bytes, total 92 bytes
pending 11 bytes, wrapping at 7949, error at position 9:
00000 Foo: bar\r\r\n
2012-05-08 05:03:10 -04:00
|
|
|
" backend %s (#%d)",
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.errors.px->id, si->applet.ctx.errors.px->uuid,
|
MEDIUM: http: improve error capture reports
A number of important information were missing from the error captures, so
let's improve them. Now we also log source port, session flags, transaction
flags, message flags, pending output bytes, expected buffer wrapping position,
total bytes transferred, message chunk length, and message body length.
As such, the output format has slightly evolved and the source address moved
to the third line :
[08/May/2012:11:14:36.341] frontend echo (#1): invalid request
backend echo (#1), server <NONE> (#-1), event #1
src 127.0.0.1:40616, session #4, session flags 0x00000000
HTTP msg state 26, msg flags 0x00000000, tx flags 0x00000000
HTTP chunk len 0 bytes, HTTP body len 0 bytes
buffer flags 0x00909002, out 0 bytes, total 28 bytes
pending 28 bytes, wrapping at 8030, error at position 7:
00000 GET / /?t=20000 HTTP/1.1\r\n
00026 \r\n
[08/May/2012:11:13:13.426] backend echo (#1) : invalid response
frontend echo (#1), server local (#1), event #0
src 127.0.0.1:40615, session #1, session flags 0x0000044e
HTTP msg state 32, msg flags 0x0000000e, tx flags 0x08200000
HTTP chunk len 0 bytes, HTTP body len 20 bytes
buffer flags 0x00008002, out 81 bytes, total 92 bytes
pending 11 bytes, wrapping at 7949, error at position 9:
00000 Foo: bar\r\r\n
2012-05-08 05:03:10 -04:00
|
|
|
(es->oe->cap & PR_CAP_BE) ? es->oe->id : "<NONE>",
|
|
|
|
|
(es->oe->cap & PR_CAP_BE) ? es->oe->uuid : -1);
|
2009-03-04 09:53:18 -05:00
|
|
|
break;
|
|
|
|
|
case 1:
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2009-03-04 09:53:18 -05:00
|
|
|
" backend %s (#%d) : invalid response\n"
|
MEDIUM: http: improve error capture reports
A number of important information were missing from the error captures, so
let's improve them. Now we also log source port, session flags, transaction
flags, message flags, pending output bytes, expected buffer wrapping position,
total bytes transferred, message chunk length, and message body length.
As such, the output format has slightly evolved and the source address moved
to the third line :
[08/May/2012:11:14:36.341] frontend echo (#1): invalid request
backend echo (#1), server <NONE> (#-1), event #1
src 127.0.0.1:40616, session #4, session flags 0x00000000
HTTP msg state 26, msg flags 0x00000000, tx flags 0x00000000
HTTP chunk len 0 bytes, HTTP body len 0 bytes
buffer flags 0x00909002, out 0 bytes, total 28 bytes
pending 28 bytes, wrapping at 8030, error at position 7:
00000 GET / /?t=20000 HTTP/1.1\r\n
00026 \r\n
[08/May/2012:11:13:13.426] backend echo (#1) : invalid response
frontend echo (#1), server local (#1), event #0
src 127.0.0.1:40615, session #1, session flags 0x0000044e
HTTP msg state 32, msg flags 0x0000000e, tx flags 0x08200000
HTTP chunk len 0 bytes, HTTP body len 20 bytes
buffer flags 0x00008002, out 81 bytes, total 92 bytes
pending 11 bytes, wrapping at 7949, error at position 9:
00000 Foo: bar\r\r\n
2012-05-08 05:03:10 -04:00
|
|
|
" frontend %s (#%d)",
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.errors.px->id, si->applet.ctx.errors.px->uuid,
|
MEDIUM: http: improve error capture reports
A number of important information were missing from the error captures, so
let's improve them. Now we also log source port, session flags, transaction
flags, message flags, pending output bytes, expected buffer wrapping position,
total bytes transferred, message chunk length, and message body length.
As such, the output format has slightly evolved and the source address moved
to the third line :
[08/May/2012:11:14:36.341] frontend echo (#1): invalid request
backend echo (#1), server <NONE> (#-1), event #1
src 127.0.0.1:40616, session #4, session flags 0x00000000
HTTP msg state 26, msg flags 0x00000000, tx flags 0x00000000
HTTP chunk len 0 bytes, HTTP body len 0 bytes
buffer flags 0x00909002, out 0 bytes, total 28 bytes
pending 28 bytes, wrapping at 8030, error at position 7:
00000 GET / /?t=20000 HTTP/1.1\r\n
00026 \r\n
[08/May/2012:11:13:13.426] backend echo (#1) : invalid response
frontend echo (#1), server local (#1), event #0
src 127.0.0.1:40615, session #1, session flags 0x0000044e
HTTP msg state 32, msg flags 0x0000000e, tx flags 0x08200000
HTTP chunk len 0 bytes, HTTP body len 20 bytes
buffer flags 0x00008002, out 81 bytes, total 92 bytes
pending 11 bytes, wrapping at 7949, error at position 9:
00000 Foo: bar\r\r\n
2012-05-08 05:03:10 -04:00
|
|
|
es->oe->id, es->oe->uuid);
|
2009-03-04 09:53:18 -05:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
MEDIUM: http: improve error capture reports
A number of important information were missing from the error captures, so
let's improve them. Now we also log source port, session flags, transaction
flags, message flags, pending output bytes, expected buffer wrapping position,
total bytes transferred, message chunk length, and message body length.
As such, the output format has slightly evolved and the source address moved
to the third line :
[08/May/2012:11:14:36.341] frontend echo (#1): invalid request
backend echo (#1), server <NONE> (#-1), event #1
src 127.0.0.1:40616, session #4, session flags 0x00000000
HTTP msg state 26, msg flags 0x00000000, tx flags 0x00000000
HTTP chunk len 0 bytes, HTTP body len 0 bytes
buffer flags 0x00909002, out 0 bytes, total 28 bytes
pending 28 bytes, wrapping at 8030, error at position 7:
00000 GET / /?t=20000 HTTP/1.1\r\n
00026 \r\n
[08/May/2012:11:13:13.426] backend echo (#1) : invalid response
frontend echo (#1), server local (#1), event #0
src 127.0.0.1:40615, session #1, session flags 0x0000044e
HTTP msg state 32, msg flags 0x0000000e, tx flags 0x08200000
HTTP chunk len 0 bytes, HTTP body len 20 bytes
buffer flags 0x00008002, out 81 bytes, total 92 bytes
pending 11 bytes, wrapping at 7949, error at position 9:
00000 Foo: bar\r\r\n
2012-05-08 05:03:10 -04:00
|
|
|
chunk_printf(&msg,
|
|
|
|
|
", server %s (#%d), event #%u\n"
|
|
|
|
|
" src %s:%d, session #%d, session flags 0x%08x\n"
|
|
|
|
|
" HTTP msg state %d, msg flags 0x%08x, tx flags 0x%08x\n"
|
|
|
|
|
" HTTP chunk len %lld bytes, HTTP body len %lld bytes\n"
|
|
|
|
|
" buffer flags 0x%08x, out %d bytes, total %lld bytes\n"
|
|
|
|
|
" pending %d bytes, wrapping at %d, error at position %d:\n \n",
|
|
|
|
|
es->srv ? es->srv->id : "<NONE>", es->srv ? es->srv->puid : -1,
|
|
|
|
|
es->ev_id,
|
|
|
|
|
pn, port, es->sid, es->s_flags,
|
|
|
|
|
es->state, es->m_flags, es->t_flags,
|
|
|
|
|
es->m_clen, es->m_blen,
|
|
|
|
|
es->b_flags, es->b_out, es->b_tot,
|
|
|
|
|
es->len, es->b_wrap, es->pos);
|
|
|
|
|
|
2012-05-07 05:56:55 -04:00
|
|
|
if (bi_putchk(si->ib, &msg) == -1) {
|
2009-03-04 09:53:18 -05:00
|
|
|
/* Socket buffer full. Let's try again later from the same point */
|
2009-10-03 17:49:35 -04:00
|
|
|
return 0;
|
2009-03-04 09:53:18 -05:00
|
|
|
}
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.errors.ptr = 0;
|
|
|
|
|
si->applet.ctx.errors.sid = es->sid;
|
2009-03-04 09:53:18 -05:00
|
|
|
}
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
if (si->applet.ctx.errors.sid != es->sid) {
|
2009-03-04 09:53:18 -05:00
|
|
|
/* the snapshot changed while we were dumping it */
|
2009-09-27 07:23:20 -04:00
|
|
|
chunk_printf(&msg,
|
2009-03-04 09:53:18 -05:00
|
|
|
" WARNING! update detected on this snapshot, dump interrupted. Please re-check!\n");
|
2012-05-07 05:56:55 -04:00
|
|
|
if (bi_putchk(si->ib, &msg) == -1)
|
2009-10-03 17:49:35 -04:00
|
|
|
return 0;
|
2009-03-04 09:53:18 -05:00
|
|
|
goto next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* OK, ptr >= 0, so we have to dump the current line */
|
2011-03-10 05:25:07 -05:00
|
|
|
while (si->applet.ctx.errors.ptr < es->len && si->applet.ctx.errors.ptr < sizeof(es->buf)) {
|
2009-03-04 09:53:18 -05:00
|
|
|
int newptr;
|
|
|
|
|
int newline;
|
|
|
|
|
|
2011-03-10 05:25:07 -05:00
|
|
|
newline = si->applet.ctx.errors.bol;
|
|
|
|
|
newptr = dump_text_line(&msg, es->buf, sizeof(es->buf), es->len, &newline, si->applet.ctx.errors.ptr);
|
|
|
|
|
if (newptr == si->applet.ctx.errors.ptr)
|
2009-10-03 17:49:35 -04:00
|
|
|
return 0;
|
2009-03-04 09:53:18 -05:00
|
|
|
|
2012-05-07 05:56:55 -04:00
|
|
|
if (bi_putchk(si->ib, &msg) == -1) {
|
2009-03-04 09:53:18 -05:00
|
|
|
/* Socket buffer full. Let's try again later from the same point */
|
2009-10-03 17:49:35 -04:00
|
|
|
return 0;
|
2009-03-04 09:53:18 -05:00
|
|
|
}
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.errors.ptr = newptr;
|
|
|
|
|
si->applet.ctx.errors.bol = newline;
|
2009-03-04 09:53:18 -05:00
|
|
|
};
|
|
|
|
|
next:
|
2011-03-10 05:25:07 -05:00
|
|
|
si->applet.ctx.errors.bol = 0;
|
|
|
|
|
si->applet.ctx.errors.ptr = -1;
|
|
|
|
|
si->applet.ctx.errors.buf++;
|
|
|
|
|
if (si->applet.ctx.errors.buf > 1) {
|
|
|
|
|
si->applet.ctx.errors.buf = 0;
|
|
|
|
|
si->applet.ctx.errors.px = si->applet.ctx.errors.px->next;
|
2009-03-04 09:53:18 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* dump complete */
|
2009-10-03 17:49:35 -04:00
|
|
|
return 1;
|
2009-03-04 09:53:18 -05:00
|
|
|
}
|
|
|
|
|
|
2011-02-13 07:16:36 -05:00
|
|
|
struct si_applet http_stats_applet = {
|
|
|
|
|
.name = "<STATS>", /* used for logging */
|
|
|
|
|
.fct = http_stats_io_handler,
|
2012-04-02 21:57:53 -04:00
|
|
|
.release = NULL,
|
2011-02-13 07:16:36 -05:00
|
|
|
};
|
|
|
|
|
|
2011-06-15 02:18:44 -04:00
|
|
|
static struct si_applet cli_applet = {
|
2011-02-13 07:16:36 -05:00
|
|
|
.name = "<CLI>", /* used for logging */
|
|
|
|
|
.fct = cli_io_handler,
|
2012-04-02 21:57:53 -04:00
|
|
|
.release = NULL,
|
2011-02-13 07:16:36 -05:00
|
|
|
};
|
2008-12-07 16:29:48 -05:00
|
|
|
|
2008-07-09 14:12:41 -04:00
|
|
|
static struct cfg_kw_list cfg_kws = {{ },{
|
|
|
|
|
{ CFG_GLOBAL, "stats", stats_parse_global },
|
|
|
|
|
{ 0, NULL, NULL },
|
|
|
|
|
}};
|
|
|
|
|
|
|
|
|
|
__attribute__((constructor))
|
|
|
|
|
static void __dumpstats_module_init(void)
|
|
|
|
|
{
|
|
|
|
|
cfg_register_keywords(&cfg_kws);
|
|
|
|
|
}
|
|
|
|
|
|
2007-10-17 11:06:05 -04:00
|
|
|
/*
|
|
|
|
|
* Local variables:
|
|
|
|
|
* c-indent-level: 8
|
|
|
|
|
* c-basic-offset: 8
|
|
|
|
|
* End:
|
|
|
|
|
*/
|