[MEDIUM] stats: make HTTP stats use an I/O handler

Doing this, we can remove the last BF_HIJACK user and remove
produce_content(). s->data_source could also be removed but
it is currently used to detect if the stats or a server was
used.
This commit is contained in:
Willy Tarreau 2009-10-04 15:56:38 +02:00
parent 65671abd32
commit b0c9bc4f95
5 changed files with 86 additions and 78 deletions

View File

@ -59,6 +59,7 @@ int stats_dump_http(struct session *s, struct buffer *rep, struct uri_auth *uri)
int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri);
int stats_dump_sess_to_buffer(struct session *s, struct buffer *rep);
int stats_dump_errors_to_buffer(struct session *s, struct buffer *rep);
void http_stats_io_handler(struct stream_interface *si);
#endif /* _PROTO_DUMPSTATS_H */

View File

@ -1,23 +1,23 @@
/*
include/proto/proto_http.h
This file contains HTTP protocol definitions.
Copyright (C) 2000-2008 Willy Tarreau - w@1wt.eu
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation, version 2.1
exclusively.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
* include/proto/proto_http.h
* This file contains HTTP protocol definitions.
*
* Copyright (C) 2000-2009 Willy Tarreau - w@1wt.eu
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, version 2.1
* exclusively.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _PROTO_PROTO_HTTP_H
#define _PROTO_PROTO_HTTP_H
@ -68,9 +68,6 @@ int http_process_tarpit(struct session *s, struct buffer *req, int an_bit);
int http_process_request_body(struct session *s, struct buffer *req, int an_bit);
int process_response(struct session *t);
void produce_content(struct session *s, struct buffer *rep);
int produce_content_stats(struct session *s);
int produce_content_stats_proxy(struct session *s, struct proxy *px);
void debug_hdr(const char *dir, struct session *t, const char *start, const char *end);
void get_srv_from_appsession(struct session *t, const char *begin, int len);
int apply_filter_to_req_headers(struct session *t, struct buffer *req, struct hdr_exp *exp);

View File

@ -211,7 +211,7 @@ struct session {
int ptr; /* <0: headers, >=0 : text pointer to restart from */
int bol; /* pointer to beginning of current line */
} errors;
} data_ctx; /* used by produce_content to dump the stats right now */
} data_ctx; /* used by stats I/O handlers to dump the stats */
unsigned int uniq_id; /* unique ID used for the traces */
};

View File

@ -587,7 +587,6 @@ int stats_dump_raw_to_buffer(struct session *s, struct buffer *rep)
/* skip the disabled proxies and non-networked ones */
if (px->state != PR_STSTOPPED &&
(px->cap & (PR_CAP_FE | PR_CAP_BE))) {
rep->flags |= BF_READ_PARTIAL; /* remove this once stats_dump_proxy uses buffer_feed */
if (stats_dump_proxy(s, px, NULL) == 0)
return 0;
}
@ -616,6 +615,57 @@ int stats_dump_raw_to_buffer(struct session *s, struct buffer *rep)
}
/* 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.
* si->st0 becomes non-zero once the transfer is finished. The handler
* automatically unregisters itself once transfer is complete.
*/
void http_stats_io_handler(struct stream_interface *si)
{
struct session *s = si->private;
struct buffer *req = si->ob;
struct buffer *res = si->ib;
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))
si->st0 = 1;
if (!si->st0) {
if (stats_dump_http(s, res, s->be->uri_auth)) {
si->st0 = 1;
si->shutw(si);
} else {
/* buffer full */
si->flags |= SI_FL_WAIT_ROOM;
}
}
if ((res->flags & BF_SHUTR) && (si->state == SI_ST_EST))
si->shutw(si);
if ((req->flags & BF_SHUTW) && (si->state == SI_ST_EST) && si->st0) {
si->shutr(si);
res->flags |= BF_READ_NULL;
}
/* update all other flags and resync with the other side */
si->update(si);
/* 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);
}
}
/*
* Produces statistics data for the session <s>. Expects to be called with
* client socket shut down on input. It stops by itself by unsetting the
@ -650,11 +700,9 @@ int stats_dump_http(struct session *s, struct buffer *rep, struct uri_auth *uri)
chunk_printf(&msg, "\r\n");
s->txn.status = 200;
if (buffer_write_chunk(rep, &msg) >= 0)
if (buffer_feed_chunk(rep, &msg) >= 0)
return 0;
msg.len = 0;
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))
@ -663,7 +711,6 @@ int stats_dump_http(struct session *s, struct buffer *rep, struct uri_auth *uri)
if (s->txn.meth == HTTP_METH_HEAD) {
/* that's all we return in case of HEAD request */
s->data_state = DATA_ST_FIN;
buffer_stop_hijack(rep);
return 1;
}
@ -754,7 +801,7 @@ int stats_dump_http(struct session *s, struct buffer *rep, struct uri_auth *uri)
} else {
print_csv_header(&msg);
}
if (buffer_write_chunk(rep, &msg) >= 0)
if (buffer_feed_chunk(rep, &msg) >= 0)
return 0;
s->data_state = DATA_ST_INFO;
@ -866,7 +913,7 @@ int stats_dump_http(struct session *s, struct buffer *rep, struct uri_auth *uri)
""
);
if (buffer_write_chunk(rep, &msg) >= 0)
if (buffer_feed_chunk(rep, &msg) >= 0)
return 0;
}
@ -895,7 +942,7 @@ int stats_dump_http(struct session *s, struct buffer *rep, struct uri_auth *uri)
case DATA_ST_END:
if (!(s->data_ctx.stats.flags & STAT_FMT_CSV)) {
chunk_printf(&msg, "</body></html>\n");
if (buffer_write_chunk(rep, &msg) >= 0)
if (buffer_feed_chunk(rep, &msg) >= 0)
return 0;
}
@ -903,12 +950,11 @@ int stats_dump_http(struct session *s, struct buffer *rep, struct uri_auth *uri)
/* fall through */
case DATA_ST_FIN:
buffer_stop_hijack(rep);
return 1;
default:
/* unknown state ! */
buffer_stop_hijack(rep);
s->data_state = DATA_ST_FIN;
return -1;
}
}
@ -994,7 +1040,7 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri)
px->id,
px->desc ? "desc" : "empty", px->desc ? px->desc : "");
if (buffer_write_chunk(rep, &msg) >= 0)
if (buffer_feed_chunk(rep, &msg) >= 0)
return 0;
}
@ -1075,7 +1121,7 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri)
px->fe_sps_lim, px->fe_sps_max);
}
if (buffer_write_chunk(rep, &msg) >= 0)
if (buffer_feed_chunk(rep, &msg) >= 0)
return 0;
}
@ -1339,7 +1385,7 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri)
/* finish with EOL */
chunk_printf(&msg, "\n");
}
if (buffer_write_chunk(rep, &msg) >= 0)
if (buffer_feed_chunk(rep, &msg) >= 0)
return 0;
} /* for sv */
@ -1452,7 +1498,7 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri)
read_freq_ctr(&px->be_sess_per_sec),
px->be_sps_max);
}
if (buffer_write_chunk(rep, &msg) >= 0)
if (buffer_feed_chunk(rep, &msg) >= 0)
return 0;
}
@ -1463,7 +1509,7 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri)
if (!(s->data_ctx.stats.flags & STAT_FMT_CSV)) {
chunk_printf(&msg, "</table><p>\n");
if (buffer_write_chunk(rep, &msg) >= 0)
if (buffer_feed_chunk(rep, &msg) >= 0)
return 0;
}

View File

@ -3238,40 +3238,6 @@ int process_response(struct session *t)
return 0;
}
/*
* Produces data for the session <s> depending on its source. Expects to be
* called with client socket shut down on input. Right now, only statistics can
* be produced. It stops by itself by unsetting the BF_HIJACK flag from the
* buffer, which it uses to keep on being called when there is free space in
* the buffer, or simply by letting an empty buffer upon return.
*/
void produce_content(struct session *s, struct buffer *rep)
{
if (s->data_source == DATA_SRC_NONE) {
buffer_stop_hijack(rep);
return;
}
else if (s->data_source == DATA_SRC_STATS) {
/* dump server statistics */
int ret;
ret = stats_dump_http(s, rep, s->be->uri_auth);
if (ret >= 0)
return;
/* -1 indicates an error */
}
/* unknown data source or internal error */
s->txn.status = 500;
stream_int_retnclose(rep->cons, error_message(s, HTTP_ERR_500));
if (!(s->flags & SN_ERR_MASK))
s->flags |= SN_ERR_PRXCOND;
if (!(s->flags & SN_FINST_MASK))
s->flags |= SN_FINST_R;
buffer_stop_hijack(rep);
return;
}
/* Iterate the same filter through all request headers.
* Returns 1 if this filter can be stopped upon return, otherwise 0.
* Since it can manage the switch to another backend, it updates the per-proxy
@ -4508,7 +4474,7 @@ void get_srv_from_appsession(struct session *t, const char *begin, int len)
*
* It is assumed that the request is either a HEAD or GET and that the
* t->be->uri_auth field is valid. An HTTP/401 response may be sent, or
* produce_content() can be called to start sending data.
* the stats I/O handler will be registered to start sending data.
*
* Returns 1 if the session's state changes, otherwise 0.
*/
@ -4625,15 +4591,13 @@ int stats_check_uri_auth(struct session *t, struct proxy *backend)
/* The request is valid, the user is authenticated. Let's start sending
* data.
*/
buffer_dont_connect(t->req);
buffer_shutw_now(t->req);
buffer_shutr_now(t->rep);
stream_int_retnclose(t->rep->cons, NULL);
t->logs.tv_request = now;
t->data_source = DATA_SRC_STATS;
t->data_state = DATA_ST_INIT;
t->task->nice = -32; /* small boost for HTTP statistics */
buffer_install_hijacker(t, t->rep, produce_content);
stream_int_register_handler(t->rep->prod, http_stats_io_handler);
t->rep->prod->private = t;
t->rep->prod->st0 = t->rep->prod->st1 = 0;
return 1;
}