mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-01-03 18:52:04 +00:00
[MEDIUM] add support for "show sess" in unix stats socket
It is now possible to list all known sessions by issuing "show sess" on the unix stats socket. The format is not much evolved but it is very useful for debugging. The doc has been updated to reflect the new keyword.
This commit is contained in:
parent
62e4f1dedd
commit
3dfe6cd095
@ -151,8 +151,10 @@ stats socket <path> [{uid | user} <uid>] [{gid | group} <gid>] [mode <mode>]
|
||||
Creates a UNIX socket in stream mode at location <path>. Any previously
|
||||
existing socket will be backed up then replaced. Connections to this socket
|
||||
will get a CSV-formated output of the process statistics in response to the
|
||||
"show stat" command followed by a line feed, and more general process
|
||||
information in response to the "show info" command followed by a line feed.
|
||||
"show stat" command followed by a line feed, more general process information
|
||||
in response to the "show info" command followed by a line feed, and a
|
||||
complete list of all existing sessions in response to the "show sess" command
|
||||
followed by a line feed.
|
||||
|
||||
On platforms which support it, it is possible to restrict access to this
|
||||
socket by specifying numerical IDs after "uid" and "gid", or valid user and
|
||||
@ -4339,7 +4341,9 @@ Notes related to these keywords :
|
||||
|
||||
[to do]
|
||||
|
||||
|
||||
2.7) CSV format
|
||||
---------------
|
||||
|
||||
0. pxname: proxy name
|
||||
1. svname: service name (FRONTEND for frontend, BACKEND for backend, any name
|
||||
@ -4376,18 +4380,33 @@ Notes related to these keywords :
|
||||
31. tracked: id of proxy/server if tracking is enabled
|
||||
32. type (0=frontend, 1=backend, 2=server)
|
||||
|
||||
|
||||
2.8) Unix Socket commands
|
||||
-------------------------
|
||||
|
||||
- "show stat [<iid> <type> <sid>]": dump statistics in the cvs format. By
|
||||
passing id, type and sid it is possible to dump only selected items:
|
||||
- iid is a proxy id, -1 to dump everything
|
||||
- type selects type of dumpable objects: 1 for frontend, 2 for backend, 4 for
|
||||
server, -1 for everything. Values can be ORed, for example:
|
||||
1+2=3 -> frontend+backend.
|
||||
1+2+4=7 -> frontend+backend+server.
|
||||
- sid is a service id, -1 to dump everything from the selected proxy.
|
||||
The following commands are supported on the UNIX stats socket ; all of them
|
||||
must be terminated by a line feed. It is important to understand that when
|
||||
multiple haproxy processes are started on the same sockets, any process may
|
||||
pick up the request and will output its own stats.
|
||||
|
||||
show stat [<iid> <type> <sid>]
|
||||
Dump statistics in the CSV format. By passing <id>, <type> and <sid>, it is
|
||||
possible to dump only selected items :
|
||||
- <iid> is a proxy ID, -1 to dump everything
|
||||
- <type> selects the type of dumpable objects : 1 for frontends, 2 for
|
||||
backends, 4 for servers, -1 for everything. These values can be ORed,
|
||||
for example:
|
||||
1 + 2 = 3 -> frontend + backend.
|
||||
1 + 2 + 4 = 7 -> frontend + backend + server.
|
||||
- <sid> is a server ID, -1 to dump everything from the selected proxy.
|
||||
|
||||
show info
|
||||
Dump info about haproxy status on current process.
|
||||
|
||||
show sess
|
||||
Dump all known sessions. Avoid doing this on slow connections as this can
|
||||
be huge.
|
||||
|
||||
- "show info": dump info about current haproxy status.
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
|
@ -48,6 +48,7 @@ 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);
|
||||
int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri);
|
||||
void stats_dump_sess_to_buffer(struct session *s, struct buffer *rep);
|
||||
|
||||
|
||||
#endif /* _PROTO_DUMPSTATS_H */
|
||||
|
@ -201,6 +201,9 @@ struct session {
|
||||
unsigned int flags; /* STAT_* */
|
||||
int iid, type, sid; /* proxy id, type and service id if bounding of stats is enabled */
|
||||
} stats;
|
||||
struct {
|
||||
struct bref bref;
|
||||
} sess;
|
||||
} data_ctx; /* used by produce_content to dump the stats right now */
|
||||
unsigned int uniq_id; /* unique ID used for the traces */
|
||||
};
|
||||
|
126
src/dumpstats.c
126
src/dumpstats.c
@ -1081,6 +1081,132 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* This function is called to send output to the response buffer.
|
||||
* It dumps the sessions states onto the output buffer <rep>.
|
||||
* Expects to be called with client socket shut down on input.
|
||||
* s->data_ctx must have been zeroed first, and the flags properly set.
|
||||
* It automatically clears the HIJACK bit from the response buffer.
|
||||
*/
|
||||
void stats_dump_sess_to_buffer(struct session *s, struct buffer *rep)
|
||||
{
|
||||
struct chunk msg;
|
||||
|
||||
if (unlikely(rep->flags & (BF_WRITE_ERROR|BF_SHUTW))) {
|
||||
/* If we're forced to shut down, we might have to remove our
|
||||
* reference to the last session being dumped.
|
||||
*/
|
||||
if (s->data_state == DATA_ST_LIST) {
|
||||
if (!LIST_ISEMPTY(&s->data_ctx.sess.bref.users))
|
||||
LIST_DEL(&s->data_ctx.sess.bref.users);
|
||||
}
|
||||
s->data_state = DATA_ST_FIN;
|
||||
buffer_stop_hijack(rep);
|
||||
s->ana_state = STATS_ST_CLOSE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->ana_state != STATS_ST_REP)
|
||||
return;
|
||||
|
||||
msg.len = 0;
|
||||
msg.str = trash;
|
||||
|
||||
switch (s->data_state) {
|
||||
case DATA_ST_INIT:
|
||||
/* the function had not been called yet, let's prepare the
|
||||
* buffer for a response. We initialize the current session
|
||||
* pointer to the first in the global list.
|
||||
*/
|
||||
stream_int_retnclose(rep->cons, &msg);
|
||||
LIST_INIT(&s->data_ctx.sess.bref.users);
|
||||
s->data_ctx.sess.bref.ref = sessions.n;
|
||||
s->data_state = DATA_ST_LIST;
|
||||
/* fall through */
|
||||
|
||||
case DATA_ST_LIST:
|
||||
while (s->data_ctx.sess.bref.ref != &sessions) {
|
||||
char pn[INET6_ADDRSTRLEN + strlen(":65535")];
|
||||
struct session *curr_sess;
|
||||
|
||||
curr_sess = LIST_ELEM(s->data_ctx.sess.bref.ref, struct session *, list);
|
||||
|
||||
/* first, let's detach the back-ref from a possible previous session */
|
||||
if (!LIST_ISEMPTY(&s->data_ctx.sess.bref.users))
|
||||
LIST_DEL(&s->data_ctx.sess.bref.users);
|
||||
|
||||
chunk_printf(&msg, sizeof(trash),
|
||||
"%p: proto=%s",
|
||||
curr_sess,
|
||||
curr_sess->listener->proto->name);
|
||||
|
||||
switch (curr_sess->listener->proto->sock_family) {
|
||||
case AF_INET:
|
||||
inet_ntop(AF_INET,
|
||||
(const void *)&((struct sockaddr_in *)&curr_sess->cli_addr)->sin_addr,
|
||||
pn, sizeof(pn));
|
||||
|
||||
chunk_printf(&msg, sizeof(trash),
|
||||
" src=%s:%d fe=%s be=%s srv=%s",
|
||||
pn,
|
||||
ntohs(((struct sockaddr_in *)&curr_sess->cli_addr)->sin_port),
|
||||
curr_sess->fe->id,
|
||||
curr_sess->be->id,
|
||||
curr_sess->srv ? curr_sess->srv->id : "<none>"
|
||||
);
|
||||
break;
|
||||
case AF_INET6:
|
||||
inet_ntop(AF_INET6,
|
||||
(const void *)&((struct sockaddr_in6 *)(&curr_sess->cli_addr))->sin6_addr,
|
||||
pn, sizeof(pn));
|
||||
|
||||
chunk_printf(&msg, sizeof(trash),
|
||||
" src=%s:%d fe=%s be=%s srv=%s",
|
||||
pn,
|
||||
ntohs(((struct sockaddr_in6 *)&curr_sess->cli_addr)->sin6_port),
|
||||
curr_sess->fe->id,
|
||||
curr_sess->be->id,
|
||||
curr_sess->srv ? curr_sess->srv->id : "<none>"
|
||||
);
|
||||
|
||||
break;
|
||||
case AF_UNIX:
|
||||
/* no more information to print right now */
|
||||
break;
|
||||
}
|
||||
|
||||
chunk_printf(&msg, sizeof(trash),
|
||||
" si=(%d,%d) as=%d age=%s",
|
||||
curr_sess->si[0].state, curr_sess->si[1].state,
|
||||
curr_sess->ana_state,
|
||||
human_time(now.tv_sec - curr_sess->logs.tv_accept.tv_sec, 1));
|
||||
|
||||
chunk_printf(&msg, sizeof(trash),
|
||||
" exp=%s\n",
|
||||
curr_sess->task->expire ?
|
||||
human_time(TICKS_TO_MS(tick_remain(now_ms, curr_sess->task->expire)),
|
||||
TICKS_TO_MS(1000)) : "never");
|
||||
|
||||
if (buffer_write_chunk(rep, &msg) >= 0) {
|
||||
/* let's try again later */
|
||||
LIST_ADDQ(&curr_sess->back_refs, &s->data_ctx.sess.bref.users);
|
||||
return;
|
||||
}
|
||||
|
||||
s->data_ctx.sess.bref.ref = curr_sess->list.n;
|
||||
}
|
||||
s->data_state = DATA_ST_FIN;
|
||||
/* fall through */
|
||||
|
||||
default:
|
||||
s->data_state = DATA_ST_FIN;
|
||||
buffer_stop_hijack(rep);
|
||||
s->ana_state = STATS_ST_CLOSE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static struct cfg_kw_list cfg_kws = {{ },{
|
||||
{ CFG_GLOBAL, "stats", stats_parse_global },
|
||||
{ 0, NULL, NULL },
|
||||
|
@ -472,6 +472,8 @@ int uxst_event_accept(int fd) {
|
||||
memset(&s->logs, 0, sizeof(s->logs));
|
||||
memset(&s->txn, 0, sizeof(s->txn));
|
||||
|
||||
s->logs.tv_accept = now; /* corrected date for internal use */
|
||||
|
||||
s->data_state = DATA_ST_INIT;
|
||||
s->data_source = DATA_SRC_NONE;
|
||||
s->uniq_id = totalconn;
|
||||
@ -611,7 +613,11 @@ int unix_sock_parse_request(struct session *s, char *line)
|
||||
s->ana_state = STATS_ST_REP;
|
||||
buffer_install_hijacker(s, s->rep, stats_dump_raw_to_buffer);
|
||||
}
|
||||
else { /* neither "stat" nor "info" */
|
||||
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 { /* neither "stat" nor "info" nor "sess" */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user