mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-01-01 01:32:04 +00:00
[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:
parent
65671abd32
commit
b0c9bc4f95
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user