[MINOR] add "description", "node" and show-node"/"show-desc", remove "node-name", v2

This patch implements "description" (proxy and global) and "node" (global)
options, removes "node-name" and adds "show-node" & "show-desc" options
for "stats". It also changes the way the header lines (with proxy name) and
the statistics are displayed, so stats no longer look so clumsy with very
long names.

Instead of "node-name" it is possible to use show-node/show-desc with
an optional parameter that overrides a default node/description.

backend cust-0045
        # report specific values for this customer
        stats show-node Europe
        stats show-desc Master node for Europe, Asia, Africa

(cherry picked from commit 48cb2aed5a)
This commit is contained in:
Krzysztof Piotr Oledzki 2009-10-02 22:51:14 +02:00 committed by Willy Tarreau
parent 0a64b062e7
commit 4f9290afb3
8 changed files with 268 additions and 49 deletions

View File

@ -383,6 +383,8 @@ The following keywords are supported in the "global" section :
- ulimit-n
- user
- stats
- node
- description
* Performance tuning
- maxconn
@ -512,6 +514,21 @@ user <user name>
Similar to "uid" but uses the UID of user name <user name> from /etc/passwd.
See also "uid" and "group".
node <name>
Only letters, digits, hyphen and underscore are allowed, like in DNS names.
This statement is useful in HA configurations where two or more processes or
servers share the same IP address. By setting a different node-name on all
nodes, it becomes easy to immediately spot what server is handling the
traffic.
description <text>
Add a text that describes the instance.
Please note that it is required to escape certain characters (# for example)
and this text is inserted into a html page so you should avoid using
"<" and ">" characters.
3.2. Performance tuning
-----------------------
@ -670,6 +687,7 @@ clitimeout X X X - (deprecated)
contimeout X - X X (deprecated)
cookie X - X X
default_backend - X X -
description - X X X
disabled X X X X
dispatch - - X X
enabled X X X X
@ -3630,22 +3648,43 @@ stats enable
See also : "stats auth", "stats realm", "stats uri"
stats node-name [ <name> ]
stats show-node [ <name> ]
Enable reporting of a host name on the statistics page.
May be used in sections : defaults | frontend | listen | backend
yes | no | yes | yes
Arguments :
<name> is an optional name to be reported. If unspecified, the system's
hostname is automatically used instead.
Arguments:
<name> is an optional name to be reported. If unspecified, the
node name from global section is automatically used instead.
The node-name is read as a single word, so any spaces in it should be escaped
using a backslash ('\'). If it is left unspecified, the system's hostname is
used instead.
This statement is useful for users that offer shared services to their
customers, where node or description might be different on a stats page
provided for each customer.
This statement is useful in HA configurations where two or more processes or
servers share a same IP address. By setting a different node-name on all
nodes, it becomes easy to immediately spot what server is handling the
traffic.
Though this statement alone is enough to enable statistics reporting, it is
recommended to set all other settings in order to avoid relying on default
unobvious parameters.
Example:
# internal monitoring access (unlimited)
backend private_monitoring
stats enable
stats show-node Europe-1
stats uri /admin?stats
stats refresh 5s
See also: "show-desc", "stats enable", "stats uri", and "node" in global section.
stats show-desc [ <description> ]
Enable reporting of a description on the statistics page.
May be used in sections : defaults | frontend | listen | backend
yes | no | yes | yes
<name> is an optional description to be reported. If unspecified, the
description from global section is automatically used instead.
This statement is useful for users that offer shared services to their
customers, where node or description should be different for each customer.
Though this statement alone is enough to enable statistics reporting, it is
recommended to set all other settings in order to avoid relying on default
@ -3655,11 +3694,11 @@ stats node-name [ <name> ]
# internal monitoring access (unlimited)
backend private_monitoring
stats enable
stats node-name master
stats show-desc Master node for Europe, Asia, Africa
stats uri /admin?stats
stats refresh 5s
See also : "stats enable", "stats uri"
See also: "show-node", "stats enable", "stats uri" and "description" in global section.
stats realm <realm>

View File

@ -32,13 +32,15 @@ struct stat_scope {
};
#define ST_HIDEVER 0x00000001 /* do not report the version and reldate */
#define ST_SHNODE 0x00000002 /* show node name */
#define ST_SHDESC 0x00000004 /* show description */
/* later we may link them to support multiple URI matching */
struct uri_auth {
int uri_len; /* the prefix length */
char *uri_prefix; /* the prefix we want to match */
char *auth_realm; /* the realm reported to the client */
char *node_name; /* the node name reported to the client */
char *node, *desc; /* node name & description reported in this stats */
int refresh; /* refresh interval for the browser (in seconds) */
int flags; /* some flags describing the statistics page */
struct user_auth *users; /* linked list of valid user:passwd couples */
@ -75,7 +77,8 @@ struct uri_auth *stats_set_refresh(struct uri_auth **root, int interval);
struct uri_auth *stats_set_flag(struct uri_auth **root, int flag);
struct uri_auth *stats_add_auth(struct uri_auth **root, char *user);
struct uri_auth *stats_add_scope(struct uri_auth **root, char *scope);
struct uri_auth *stats_set_node_name(struct uri_auth **root, char *name);
struct uri_auth *stats_set_node(struct uri_auth **root, char *name);
struct uri_auth *stats_set_desc(struct uri_auth **root, char *desc);
#endif /* _COMMON_URI_AUTH_H */

View File

@ -70,6 +70,7 @@ struct global {
int spread_checks;
char *chroot;
char *pidfile;
char *node, *desc; /* node name & description */
int logfac1, logfac2;
int loglev1, loglev2;
int minlvl1, minlvl2;

View File

@ -223,7 +223,7 @@ struct proxy {
int httpreq; /* maximum time for complete HTTP request */
int check; /* maximum time for complete check */
} timeout;
char *id; /* proxy id */
char *id, *desc; /* proxy id (name) and description */
struct list pendconns; /* pending connections with no server assigned yet */
int nbpend, nbpend_max; /* number of pending connections with no server assigned yet */
int totpend; /* total number of pending connections on this instance (for stats) */

View File

@ -571,6 +571,52 @@ int cfg_parse_global(const char *file, int linenum, char **args, int inv)
}
global.chroot = strdup(args[1]);
}
else if (!strcmp(args[0], "description")) {
int i, len=0;
char *d;
if (!*args[1]) {
Alert("parsing [%s:%d]: '%s' expects a string argument.\n",
file, linenum, args[0]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
for(i=1; *args[i]; i++)
len += strlen(args[i])+1;
if (global.desc)
free(global.desc);
global.desc = d = (char *)calloc(1, len);
d += sprintf(d, "%s", args[1]);
for(i=2; *args[i]; i++)
d += sprintf(d, " %s", args[i]);
}
else if (!strcmp(args[0], "node")) {
int i;
char c;
for (i=0; args[1][i]; i++) {
c = args[1][i];
if (!isupper(c) && !islower(c) && !isdigit(c) && c != '_' && c != '-' && c != '.')
break;
}
if (!i || args[1][i]) {
Alert("parsing [%s:%d]: '%s' requires valid node name - non-empty string"
" with digits(0-9), letters(A-Z, a-z), dot(.), hyphen(-) or underscode(_).\n",
file, linenum, args[0]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
if (global.node)
free(global.node);
global.node = strdup(args[1]);
}
else if (!strcmp(args[0], "pidfile")) {
if (global.pidfile != NULL) {
Alert("parsing [%s:%d] : '%s' already specified. Continuing.\n", file, linenum, args[0]);
@ -696,6 +742,7 @@ int cfg_parse_global(const char *file, int linenum, char **args, int inv)
Alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global");
err_code |= ERR_ALERT | ERR_FATAL;
}
out:
return err_code;
}
@ -1109,6 +1156,27 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv)
goto out;
}
}
else if (!strcmp(args[0], "description")) {
int i, len=0;
char *d;
if (!*args[1]) {
Alert("parsing [%s:%d]: '%s' expects a string argument.\n",
file, linenum, args[0]);
return -1;
}
for(i=1; *args[i]; i++)
len += strlen(args[i])+1;
d = (char *)calloc(1, len);
curproxy->desc = d;
d += sprintf(d, "%s", args[1]);
for(i=2; *args[i]; i++)
d += sprintf(d, " %s", args[i]);
}
else if (!strcmp(args[0], "disabled")) { /* disables this proxy */
curproxy->state = PR_STSTOPPED;
}
@ -1624,7 +1692,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv)
curproxy->uri_auth = NULL; /* we must detach from the default config */
if (*(args[1]) == 0) {
Alert("parsing [%s:%d] : '%s' expects 'uri', 'realm', 'node-name', 'auth', 'scope' or 'enable'.\n", file, linenum, args[0]);
Alert("parsing [%s:%d] : '%s' expects 'uri', 'realm', 'auth', 'scope' or 'enable', 'hide-version', 'show-node', 'show-desc'.\n", file, linenum, args[0]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
} else if (!strcmp(args[1], "uri")) {
@ -1647,12 +1715,6 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv)
err_code |= ERR_ALERT | ERR_ABORT;
goto out;
}
} else if (!strcmp(args[1], "node-name")) {
if (!stats_set_node_name(&curproxy->uri_auth, *(args[2]) ? args[2] : hostname)) {
Alert("parsing [%s:%d] : out of memory.\n", file, linenum);
err_code |= ERR_ALERT | ERR_ABORT;
goto out;
}
} else if (!strcmp(args[1], "refresh")) {
unsigned interval;
@ -1699,6 +1761,61 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int inv)
err_code |= ERR_ALERT | ERR_ABORT;
goto out;
}
} else if (!strcmp(args[1], "show-node")) {
if (*args[2]) {
int i;
char c;
for (i=0; args[2][i]; i++) {
c = args[2][i];
if (!isupper(c) && !islower(c) && !isdigit(c) && c != '_' && c != '-' && c != '.')
break;
}
if (!i || args[2][i]) {
Alert("parsing [%s:%d]: '%s %s' invalid node name - should be a string"
"with digits(0-9), letters(A-Z, a-z), hyphen(-) or underscode(_).\n",
file, linenum, args[0], args[1]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
}
if (!stats_set_node(&curproxy->uri_auth, args[2])) {
Alert("parsing [%s:%d]: out of memory.\n", file, linenum);
err_code |= ERR_ALERT | ERR_ABORT;
goto out;
}
} else if (!strcmp(args[1], "show-desc")) {
char *desc = NULL;
if (*args[2]) {
int i, len=0;
char *d;
for(i=2; *args[i]; i++)
len += strlen(args[i])+1;
desc = d = (char *)calloc(1, len);
d += sprintf(d, "%s", args[2]);
for(i=3; *args[i]; i++)
d += sprintf(d, " %s", args[i]);
}
if (!*args[2] && !global.desc)
Warning("parsing [%s:%d]: '%s' requires a parameter or 'desc' to be set in the global section.\n",
file, linenum, args[1]);
else {
if (!stats_set_desc(&curproxy->uri_auth, desc)) {
free(desc);
Alert("parsing [%s:%d]: out of memory.\n", file, linenum);
err_code |= ERR_ALERT | ERR_ABORT;
goto out;
}
free(desc);
}
} else {
Alert("parsing [%s:%d] : unknown stats parameter '%s' (expects 'hide-version', 'uri', 'realm', 'auth' or 'enable').\n",
file, linenum, args[0]);

View File

@ -238,6 +238,8 @@ int stats_dump_raw(struct session *s, struct buffer *rep, struct uri_auth *uri)
"PipesFree: %d\n"
"Tasks: %d\n"
"Run_queue: %d\n"
"node: %s\n"
"description: %s\n"
"",
global.nbproc,
relative_pid,
@ -248,7 +250,8 @@ int stats_dump_raw(struct session *s, struct buffer *rep, struct uri_auth *uri)
global.rlimit_nofile,
global.maxsock, global.maxconn, global.maxpipes,
actconn, pipes_used, pipes_free,
nb_tasks_cur, run_queue_cur
nb_tasks_cur, run_queue_cur,
global.node, global.desc?global.desc:""
);
if (buffer_write_chunk(rep, &msg) >= 0)
return 0;
@ -415,8 +418,7 @@ int stats_dump_http(struct session *s, struct buffer *rep, struct uri_auth *uri)
" border-color: black;"
" border-bottom-style: solid;"
"}\n"
".pxname {background: #b00040;color: #ffff40;font-weight: bold;}\n"
".titre {background: #20D0D0;color: #000000;font-weight: bold;}\n"
".titre {background: #20D0D0;color: #000000; font-weight: bold;}\n"
".total {background: #20D0D0;color: #ffff80;}\n"
".frontend {background: #e8e8d0;}\n"
".backend {background: #e8e8d0;}\n"
@ -438,14 +440,16 @@ int stats_dump_http(struct session *s, struct buffer *rep, struct uri_auth *uri)
"table.tbl { border-collapse: collapse; border-style: none;}\n"
"table.tbl td { border-width: 1px 1px 1px 1px; border-style: solid solid solid solid; padding: 2px 3px; border-color: gray;}\n"
"table.tbl th { border-width: 1px; border-style: solid solid solid solid; border-color: gray;}\n"
"table.tbl th.pxname {background: #b00040; color: #ffff40; font-weight: bold; border-style: solid solid none solid; padding: 2px 3px; white-space: nowrap;}\n"
"table.tbl th.empty { border-style: none; empty-cells: hide; background: white;}\n"
"table.tbl th.desc { background: white; border-style: solid solid none solid; text-align: left; padding: 2px 3px;}\n"
"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"
"-->\n"
"</style></head>\n",
uri->node_name ? " on " : "",
uri->node_name ? uri->node_name : ""
(uri->flags&ST_SHNODE) ? " on " : "",
(uri->flags&ST_SHNODE) ? (uri->node ? uri->node : global.node) : ""
);
} else {
print_csv_header(&msg, sizeof(trash));
@ -467,16 +471,16 @@ int stats_dump_http(struct session *s, struct buffer *rep, struct uri_auth *uri)
chunk_printf(&msg, sizeof(trash),
"<body><h1><a href=\"" PRODUCT_URL "\" style=\"text-decoration: none;\">"
PRODUCT_NAME "%s</a></h1>\n"
"<h2>Statistics Report for pid %d%s%s</h2>\n"
"<h2>Statistics Report for pid %d%s%s%s%s</h2>\n"
"<hr width=\"100%%\" class=\"hr\">\n"
"<h3>&gt; General process information</h3>\n"
"<table border=0 cols=4><tr><td align=\"left\" nowrap width=\"1%%\">\n"
"<p><b>pid = </b> %d (process #%d, nbproc = %d)<br>\n"
"<b>uptime = </b> %dd %dh%02dm%02ds<br>\n"
"<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"
"current conns = %d ; current pipes = %d/%d<br>\n"
"Running tasks : %d/%d<br>\n"
"<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"
"current conns = %d; current pipes = %d/%d<br>\n"
"Running tasks: %d/%d<br>\n"
"</td><td align=\"center\" nowrap>\n"
"<table class=\"lgd\"><tr>\n"
"<td class=\"active3\">&nbsp;</td><td class=\"noborder\">active UP </td>"
@ -497,9 +501,9 @@ int stats_dump_http(struct session *s, struct buffer *rep, struct uri_auth *uri)
"<b>Display option:</b><ul style=\"margin-top: 0.25em;\">"
"",
(uri->flags&ST_HIDEVER)?"":(STATS_VERSION_STRING),
pid, uri->node_name ? " on " : "", uri->node_name ? uri->node_name : "",
pid,
relative_pid, global.nbproc,
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,
up / 86400, (up % 86400) / 3600,
(up % 3600) / 60, (up % 60),
global.rlimit_memmax ? ultoa(global.rlimit_memmax) : "unlimited",
@ -663,11 +667,13 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri)
if (!(s->data_ctx.stats.flags & STAT_FMT_CSV)) {
/* print a new table */
chunk_printf(&msg, sizeof(trash),
"<table cols=\"29\" class=\"tbl\" width=\"100%%\">\n"
"<table class=\"tbl\" width=\"100%%\">\n"
"<tr align=\"center\" class=\"titre\">"
"<th colspan=2 class=\"pxname\">%s</th>"
"<th colspan=27 class=\"empty\"></th>"
"<th class=\"pxname\" width=\"10%%\">%s</th>"
"<th class=\"%s\" width=\"90%%\">%s</th>"
"</tr>\n"
"</table>\n"
"<table cols=\"29\" class=\"tbl\" width=\"100%%\">\n"
"<tr align=\"center\" class=\"titre\">"
"<th rowspan=2></th>"
"<th colspan=3>Queue</th>"
@ -686,7 +692,8 @@ int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri)
"<th>Bck</th><th>Chk</th><th>Dwn</th><th>Dwntme</th>"
"<th>Thrtle</th>\n"
"</tr>",
px->id);
px->id,
px->desc ? "desc" : "empty", px->desc ? px->desc : "");
if (buffer_write_chunk(rep, &msg) >= 0)
return 0;

View File

@ -670,6 +670,9 @@ void init(int argc, char **argv)
printf("Using %s() as the polling mechanism.\n", cur_poller.name);
}
if (!global.node)
global.node = strdup(hostname);
}
void deinit(void)
@ -836,6 +839,8 @@ void deinit(void)
free(uap->uri_prefix);
free(uap->auth_realm);
free(uap->node);
free(uap->desc);
while (uap->users) {
user = uap->users;
@ -850,6 +855,8 @@ void deinit(void)
free(global.chroot); global.chroot = NULL;
free(global.pidfile); global.pidfile = NULL;
free(global.node); global.node = NULL;
free(global.desc); global.desc = NULL;
free(fdtab); fdtab = NULL;
free(oldpids); oldpids = NULL;

View File

@ -110,26 +110,71 @@ struct uri_auth *stats_set_realm(struct uri_auth **root, char *realm)
}
/*
* Returns a default uri_auth with <node-name> set as the node name.
* Returns a default uri_auth with ST_SHNODE flag enabled and
* <node> set as the name if it is not empty.
* Uses the pointer provided if not NULL and not initialized.
*/
struct uri_auth *stats_set_node_name(struct uri_auth **root, char *name)
struct uri_auth *stats_set_node(struct uri_auth **root, char *name)
{
struct uri_auth *u;
char *name_copy;
char *node_copy = NULL;
if ((name_copy = strdup(name)) == NULL)
goto out_realm;
if (name && *name) {
node_copy = strdup(name);
if (node_copy == NULL)
goto out_realm;
}
if ((u = stats_check_init_uri_auth(root)) == NULL)
goto out_u;
free(u->node_name);
u->node_name = name_copy;
if (!stats_set_flag(root, ST_SHNODE))
goto out_u;
if (node_copy) {
free(u->node);
u->node = node_copy;
}
return u;
out_u:
free(name_copy);
free(node_copy);
out_realm:
return NULL;
}
/*
* Returns a default uri_auth with ST_SHDESC flag enabled and
* <description> set as the desc if it is not empty.
* Uses the pointer provided if not NULL and not initialized.
*/
struct uri_auth *stats_set_desc(struct uri_auth **root, char *desc)
{
struct uri_auth *u;
char *desc_copy = NULL;
if (desc && *desc) {
desc_copy = strdup(desc);
if (desc_copy == NULL)
goto out_realm;
}
if ((u = stats_check_init_uri_auth(root)) == NULL)
goto out_u;
if (!stats_set_flag(root, ST_SHDESC))
goto out_u;
if (desc_copy) {
free(u->desc);
u->desc = desc_copy;
}
return u;
out_u:
free(desc_copy);
out_realm:
return NULL;
}