[CLEANUP] move remaining stats sockets code to dumpstats

The remains of the stats socket code has nothing to do in proto_uxst
anymore and must move to dumpstats. The code is much cleaner and more
structured. It was also an opportunity to rename AN_REQ_UNIX_STATS
as AN_REQ_STATS_SOCK as the stats socket is no longer unix-specific
either.

The last item refering to stats in proto_uxst is the setting of the
task's nice value which should in fact come from the listener.
This commit is contained in:
Willy Tarreau 2009-08-16 19:06:42 +02:00
parent 8e13d7492d
commit 5ca791da8d
6 changed files with 164 additions and 164 deletions

View File

@ -64,8 +64,8 @@
// max # args on a configuration line
#define MAX_LINE_ARGS 64
// max # args on a uxts socket
#define MAX_UXST_ARGS 16
// max # args on a stats socket
#define MAX_STATS_ARGS 16
// max # of added headers per request
#define MAX_NEWHDR 10

View File

@ -44,6 +44,8 @@
#define STATS_ST_REP 2
#define STATS_ST_CLOSE 3
int stats_sock_parse_request(struct session *s, char *line);
int stats_sock_req_analyser(struct session *s, struct buffer *req, int an_bit);
int stats_dump_raw(struct session *s, struct buffer *rep, struct uri_auth *uri);
void stats_dump_raw_to_buffer(struct session *s, struct buffer *req);
int stats_dump_http(struct session *s, struct buffer *rep, struct uri_auth *uri);

View File

@ -113,7 +113,7 @@
#define AN_REQ_HTTP_INNER 0x00000020 /* inner processing of HTTP request */
#define AN_REQ_HTTP_TARPIT 0x00000040 /* wait for end of HTTP tarpit */
#define AN_REQ_HTTP_BODY 0x00000080 /* inspect HTTP request body */
#define AN_REQ_UNIX_STATS 0x00000100 /* process unix stats socket request */
#define AN_REQ_STATS_SOCK 0x00000100 /* process stats socket request */
#define AN_RTR_HTTP_HDR 0x00000200 /* inspect HTTP response headers */
#define AN_REQ_PRST_RDP_COOKIE 0x00000400 /* persistence on rdp cookie */

View File

@ -50,6 +50,19 @@
#include <proto/stream_interface.h>
#include <proto/task.h>
const char stats_sock_usage_msg[] =
"Unknown command. Please enter one of the following commands only :\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"
" show sess : report the list of current sessions\n"
"\n";
const struct chunk stats_sock_usage = {
.str = (char *)&stats_sock_usage_msg,
.len = sizeof(stats_sock_usage_msg)-1
};
/* This function parses a "stats" statement in the "global" section. It returns
* -1 if there is any error, otherwise zero. If it returns -1, it may write an
* error message into ther <err> buffer, for at most <errlen> bytes, trailing
@ -107,7 +120,7 @@ static int stats_parse_global(char **args, int section_type, struct proxy *curpx
global.stats_sock.options = LI_O_NONE;
global.stats_sock.accept = uxst_event_accept;
global.stats_sock.handler = process_session;
global.stats_sock.analysers = AN_REQ_UNIX_STATS;
global.stats_sock.analysers = AN_REQ_STATS_SOCK;
global.stats_sock.private = global.stats_fe; /* must point to the frontend */
global.stats_fe->timeout.client = MS_TO_TICKS(10000); /* default timeout of 10 seconds */
@ -211,6 +224,147 @@ int print_csv_header(struct chunk *msg, int size)
"\n");
}
/* Parses the request line in <cmd> and possibly starts dumping stats on
* s->rep with the hijack bit set. Returns 1 if OK, 0 in case of any error.
* The line is modified after parsing.
*/
int stats_sock_parse_request(struct session *s, char *line)
{
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;
if (strcmp(args[0], "show") == 0) {
if (strcmp(args[1], "stat") == 0) {
if (*args[2] && *args[3] && *args[4]) {
s->data_ctx.stats.flags |= STAT_BOUND;
s->data_ctx.stats.iid = atoi(args[2]);
s->data_ctx.stats.type = atoi(args[3]);
s->data_ctx.stats.sid = atoi(args[4]);
}
s->data_ctx.stats.flags |= STAT_SHOW_STAT;
s->data_ctx.stats.flags |= STAT_FMT_CSV;
s->ana_state = STATS_ST_REP;
buffer_install_hijacker(s, s->rep, stats_dump_raw_to_buffer);
}
else if (strcmp(args[1], "info") == 0) {
s->data_ctx.stats.flags |= STAT_SHOW_INFO;
s->data_ctx.stats.flags |= STAT_FMT_CSV;
s->ana_state = STATS_ST_REP;
buffer_install_hijacker(s, s->rep, stats_dump_raw_to_buffer);
}
else if (strcmp(args[1], "sess") == 0) {
s->ana_state = STATS_ST_REP;
buffer_install_hijacker(s, s->rep, stats_dump_sess_to_buffer);
}
else if (strcmp(args[1], "errors") == 0) {
if (*args[2])
s->data_ctx.errors.iid = atoi(args[2]);
else
s->data_ctx.errors.iid = -1;
s->data_ctx.errors.px = NULL;
s->ana_state = STATS_ST_REP;
buffer_install_hijacker(s, s->rep, stats_dump_errors_to_buffer);
}
else { /* neither "stat" nor "info" nor "sess" */
return 0;
}
}
else { /* not "show" */
return 0;
}
return 1;
}
/* Processes the stats interpreter on the statistics socket.
* In order to ease the transition, we simply simulate the server status
* for now. It only knows states STATS_ST_INIT, STATS_ST_REQ, STATS_ST_REP, and
* STATS_ST_CLOSE. It removes its analyser bit from req->analysers once done.
* It always returns 0.
*/
int stats_sock_req_analyser(struct session *s, struct buffer *req, int an_bit)
{
char *line, *p;
switch (s->ana_state) {
case STATS_ST_INIT:
/* Stats output not initialized yet */
memset(&s->data_ctx.stats, 0, sizeof(s->data_ctx.stats));
s->data_source = DATA_SRC_STATS;
s->ana_state = STATS_ST_REQ;
buffer_write_dis(s->req);
/* fall through */
case STATS_ST_REQ:
/* Now, stats are initialized, hijack is not set, and
* we are waiting for a complete request line.
*/
line = s->req->data;
p = memchr(line, '\n', s->req->l);
if (p) {
*p = '\0';
if (!stats_sock_parse_request(s, line)) {
/* invalid request */
stream_int_retnclose(s->req->prod, &stats_sock_usage);
s->ana_state = 0;
req->analysers = 0;
return 0;
}
}
/* processing a valid or incomplete request */
if ((req->flags & BF_FULL) || /* invalid request */
(req->flags & BF_READ_ERROR) || /* input error */
(req->flags & BF_READ_TIMEOUT) || /* read timeout */
tick_is_expired(req->analyse_exp, now_ms) || /* request timeout */
(req->flags & BF_SHUTR)) { /* input closed */
buffer_shutw_now(s->rep);
s->ana_state = 0;
req->analysers = 0;
return 0;
}
/* don't forward nor abort */
req->flags |= BF_READ_DONTWAIT; /* we plan to read small requests */
return 0;
case STATS_ST_REP:
/* do nothing while response is being processed */
return 0;
case STATS_ST_CLOSE:
/* end of dump */
s->req->analysers &= ~an_bit;
s->ana_state = 0;
break;
}
return 0;
}
/*
* Produces statistics data for the session <s>. Expects to be called with
* client socket shut down on input. It *may* make use of informations from

View File

@ -41,7 +41,6 @@
#include <proto/acl.h>
#include <proto/backend.h>
#include <proto/buffers.h>
#include <proto/dumpstats.h>
#include <proto/fd.h>
#include <proto/log.h>
#include <proto/protocols.h>
@ -78,19 +77,6 @@ static struct protocol proto_unix = {
.nb_listeners = 0,
};
const char unix_sock_usage_msg[] =
"Unknown command. Please enter one of the following commands only :\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"
" show sess : report the list of current sessions\n"
"\n";
const struct chunk unix_sock_usage = {
.str = (char *)&unix_sock_usage_msg,
.len = sizeof(unix_sock_usage_msg)-1
};
/********************************
* 1) low-level socket functions
********************************/
@ -572,148 +558,6 @@ int uxst_event_accept(int fd) {
return 0;
}
/* Parses the request line in <cmd> and possibly starts dumping stats on
* s->rep with the hijack bit set. Returns 1 if OK, 0 in case of any error.
* The line is modified after parsing.
*/
int unix_sock_parse_request(struct session *s, char *line)
{
char *args[MAX_UXST_ARGS + 1];
int arg;
while (isspace((unsigned char)*line))
line++;
arg = 0;
args[arg] = line;
while (*line && arg < MAX_UXST_ARGS) {
if (isspace((unsigned char)*line)) {
*line++ = '\0';
while (isspace((unsigned char)*line))
line++;
args[++arg] = line;
continue;
}
line++;
}
while (++arg <= MAX_UXST_ARGS)
args[arg] = line;
if (strcmp(args[0], "show") == 0) {
if (strcmp(args[1], "stat") == 0) {
if (*args[2] && *args[3] && *args[4]) {
s->data_ctx.stats.flags |= STAT_BOUND;
s->data_ctx.stats.iid = atoi(args[2]);
s->data_ctx.stats.type = atoi(args[3]);
s->data_ctx.stats.sid = atoi(args[4]);
}
s->data_ctx.stats.flags |= STAT_SHOW_STAT;
s->data_ctx.stats.flags |= STAT_FMT_CSV;
s->ana_state = STATS_ST_REP;
buffer_install_hijacker(s, s->rep, stats_dump_raw_to_buffer);
}
else if (strcmp(args[1], "info") == 0) {
s->data_ctx.stats.flags |= STAT_SHOW_INFO;
s->data_ctx.stats.flags |= STAT_FMT_CSV;
s->ana_state = STATS_ST_REP;
buffer_install_hijacker(s, s->rep, stats_dump_raw_to_buffer);
}
else if (strcmp(args[1], "sess") == 0) {
s->ana_state = STATS_ST_REP;
buffer_install_hijacker(s, s->rep, stats_dump_sess_to_buffer);
}
else if (strcmp(args[1], "errors") == 0) {
if (*args[2])
s->data_ctx.errors.iid = atoi(args[2]);
else
s->data_ctx.errors.iid = -1;
s->data_ctx.errors.px = NULL;
s->ana_state = STATS_ST_REP;
buffer_install_hijacker(s, s->rep, stats_dump_errors_to_buffer);
}
else { /* neither "stat" nor "info" nor "sess" */
return 0;
}
}
else { /* not "show" */
return 0;
}
return 1;
}
/* Processes the stats interpreter on the statistics socket.
* In order to ease the transition, we simply simulate the server status
* for now. It only knows states STATS_ST_INIT, STATS_ST_REQ, STATS_ST_REP, and
* STATS_ST_CLOSE. It removes the AN_REQ_UNIX_STATS bit from req->analysers
* once done. It always returns 0.
*/
int uxst_req_analyser_stats(struct session *s, struct buffer *req, int an_bit)
{
char *line, *p;
switch (s->ana_state) {
case STATS_ST_INIT:
/* Stats output not initialized yet */
memset(&s->data_ctx.stats, 0, sizeof(s->data_ctx.stats));
s->data_source = DATA_SRC_STATS;
s->ana_state = STATS_ST_REQ;
buffer_write_dis(s->req);
/* fall through */
case STATS_ST_REQ:
/* Now, stats are initialized, hijack is not set, and
* we are waiting for a complete request line.
*/
line = s->req->data;
p = memchr(line, '\n', s->req->l);
if (p) {
*p = '\0';
if (!unix_sock_parse_request(s, line)) {
/* invalid request */
stream_int_retnclose(s->req->prod, &unix_sock_usage);
s->ana_state = 0;
req->analysers = 0;
return 0;
}
}
/* processing a valid or incomplete request */
if ((req->flags & BF_FULL) || /* invalid request */
(req->flags & BF_READ_ERROR) || /* input error */
(req->flags & BF_READ_TIMEOUT) || /* read timeout */
tick_is_expired(req->analyse_exp, now_ms) || /* request timeout */
(req->flags & BF_SHUTR)) { /* input closed */
buffer_shutw_now(s->rep);
s->ana_state = 0;
req->analysers = 0;
return 0;
}
/* don't forward nor abort */
req->flags |= BF_READ_DONTWAIT; /* we plan to read small requests */
return 0;
case STATS_ST_REP:
/* do nothing while response is being processed */
return 0;
case STATS_ST_CLOSE:
/* end of dump */
s->req->analysers &= ~an_bit;
s->ana_state = 0;
break;
}
return 0;
}
__attribute__((constructor))
static void __uxst_protocol_init(void)
{

View File

@ -22,13 +22,13 @@
#include <proto/acl.h>
#include <proto/backend.h>
#include <proto/buffers.h>
#include <proto/dumpstats.h>
#include <proto/hdr_idx.h>
#include <proto/log.h>
#include <proto/session.h>
#include <proto/pipe.h>
#include <proto/proto_http.h>
#include <proto/proto_tcp.h>
#include <proto/proto_uxst.h>
#include <proto/proxy.h>
#include <proto/queue.h>
#include <proto/server.h>
@ -841,9 +841,9 @@ resync_stream_interface:
break;
}
if (s->req->analysers & AN_REQ_UNIX_STATS) {
last_ana |= AN_REQ_UNIX_STATS;
if (!uxst_req_analyser_stats(s, s->req, AN_REQ_UNIX_STATS))
if (s->req->analysers & AN_REQ_STATS_SOCK) {
last_ana |= AN_REQ_STATS_SOCK;
if (!stats_sock_req_analyser(s, s->req, AN_REQ_STATS_SOCK))
break;
}