[MEDIUM] introduce the "stats" keyword in global section
Removed old unused MODE_LOG and MODE_STATS, and replaced the "stats" keyword in the global section. The new "stats" keyword in the global section is used to create a UNIX socket on which the statistics will be accessed. The client must issue a "show stat\n" command in order to get a CSV-formated output similar to the output on the HTTP socket in CSV mode.
This commit is contained in:
parent
3e76e728ce
commit
fbee71331d
@ -4,7 +4,7 @@
|
||||
----------------------
|
||||
version 1.3.13
|
||||
willy tarreau
|
||||
2007/10/15
|
||||
2007/10/18
|
||||
|
||||
|
||||
This document covers the configuration language as implemented in the version
|
||||
@ -39,6 +39,7 @@ The following keywords are supported in the "global" section :
|
||||
- uid
|
||||
- ulimit-n
|
||||
- user
|
||||
- stats
|
||||
|
||||
* Performance tuning
|
||||
- maxconn
|
||||
@ -52,7 +53,6 @@ The following keywords are supported in the "global" section :
|
||||
* Debugging
|
||||
- debug
|
||||
- quiet
|
||||
- stats
|
||||
|
||||
|
||||
1.1) Process management and security
|
||||
@ -111,6 +111,28 @@ pidfile <pidfile>
|
||||
the "-p" command line argument. The file must be accessible to the user
|
||||
starting the process. See also "daemon".
|
||||
|
||||
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. 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 group names after the "user" and
|
||||
"group" keywords. It is also possible to restrict permissions on the socket
|
||||
by passing an octal value after the "mode" keyword (same syntax as chmod).
|
||||
Depending on the platform, the permissions on the socket will be inherited
|
||||
from the directory which hosts it, or from the user the process is started
|
||||
with.
|
||||
|
||||
stats timeout <timeout, in milliseconds>
|
||||
The default timeout on the stats socket is set to 10 seconds. It is possible
|
||||
to change this value with "stats timeout". The value must be passed in
|
||||
milliseconds.
|
||||
|
||||
stats maxconn <connections>
|
||||
By default, the stats socket is limited to 10 concurrent connections. It is
|
||||
possible to change this value with "stats maxconn".
|
||||
|
||||
uid <number>
|
||||
Changes the process' user ID to <number>. It is recommended that the user ID
|
||||
is dedicated to HAProxy or to a small set of similar daemons. HAProxy must
|
||||
@ -186,10 +208,6 @@ quiet
|
||||
Do not display any message during startup. It is equivalent to the command-
|
||||
line argument "-q".
|
||||
|
||||
stats
|
||||
Dump internal statistics to stdout at regular interval. It is available for
|
||||
development purposes only and should never be set.
|
||||
|
||||
|
||||
2) Proxies
|
||||
----------
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
#define STAT_FMT_HTML 0x1
|
||||
|
||||
int stats_parse_global(const char **args, char *err, int errlen);
|
||||
int stats_dump_raw(struct session *s, struct uri_auth *uri, int flags);
|
||||
int stats_dump_http(struct session *s, struct uri_auth *uri, int flags);
|
||||
int stats_dump_proxy(struct session *s, struct proxy *px, struct uri_auth *uri, int flags);
|
||||
|
@ -29,15 +29,13 @@
|
||||
#include <types/task.h>
|
||||
|
||||
/* modes of operation (global.mode) */
|
||||
#define MODE_DEBUG 1
|
||||
#define MODE_STATS 2
|
||||
#define MODE_LOG 4
|
||||
#define MODE_DAEMON 8
|
||||
#define MODE_QUIET 16
|
||||
#define MODE_CHECK 32
|
||||
#define MODE_VERBOSE 64
|
||||
#define MODE_STARTING 128
|
||||
#define MODE_FOREGROUND 256
|
||||
#define MODE_DEBUG 0x01
|
||||
#define MODE_DAEMON 0x02
|
||||
#define MODE_QUIET 0x04
|
||||
#define MODE_CHECK 0x08
|
||||
#define MODE_VERBOSE 0x10
|
||||
#define MODE_STARTING 0x20
|
||||
#define MODE_FOREGROUND 0x40
|
||||
|
||||
/* list of last checks to perform, depending on config options */
|
||||
#define LSTCHK_CAP_BIND 0x00000001 /* check that we can bind to any port */
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include <proto/backend.h>
|
||||
#include <proto/buffers.h>
|
||||
#include <proto/checks.h>
|
||||
#include <proto/dumpstats.h>
|
||||
#include <proto/httperr.h>
|
||||
#include <proto/log.h>
|
||||
#include <proto/proxy.h>
|
||||
@ -279,7 +280,11 @@ int cfg_parse_global(const char *file, int linenum, char **args)
|
||||
global.mode |= MODE_QUIET;
|
||||
}
|
||||
else if (!strcmp(args[0], "stats")) {
|
||||
global.mode |= MODE_STATS;
|
||||
memcpy(trash, "error near 'stats'", 19);
|
||||
if (stats_parse_global((const char **)args + 1, trash, sizeof(trash)) < 0) {
|
||||
Alert("parsing [%s:%d] : %s\n", file, linenum, trash);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (!strcmp(args[0], "tune.maxpollevents")) {
|
||||
if (global.tune.maxpollevents != 0) {
|
||||
|
107
src/dumpstats.c
107
src/dumpstats.c
@ -17,6 +17,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
@ -42,9 +44,114 @@
|
||||
#include <proto/buffers.h>
|
||||
#include <proto/dumpstats.h>
|
||||
#include <proto/fd.h>
|
||||
#include <proto/proto_uxst.h>
|
||||
#include <proto/senddata.h>
|
||||
#include <proto/session.h>
|
||||
|
||||
/* 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
|
||||
* zero included. The trailing '\n' must not be written. The function must be
|
||||
* called with <args> pointing to the first word after "stats".
|
||||
*/
|
||||
int stats_parse_global(const char **args, char *err, int errlen)
|
||||
{
|
||||
if (!strcmp(args[0], "socket")) {
|
||||
struct sockaddr_un su;
|
||||
int cur_arg;
|
||||
|
||||
if (*args[1] == 0) {
|
||||
snprintf(err, errlen, "'stats socket' in global section expects a path to a UNIX socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (global.stats_sock.state != LI_NEW) {
|
||||
snprintf(err, errlen, "'stats socket' already specified in global section");
|
||||
return -1;
|
||||
}
|
||||
|
||||
su.sun_family = AF_UNIX;
|
||||
strncpy(su.sun_path, args[1], sizeof(su.sun_path));
|
||||
su.sun_path[sizeof(su.sun_path) - 1] = 0;
|
||||
memcpy(&global.stats_sock.addr, &su, sizeof(su)); // guaranteed to fit
|
||||
|
||||
global.stats_sock.state = LI_INIT;
|
||||
global.stats_sock.accept = uxst_event_accept;
|
||||
global.stats_sock.handler = process_uxst_stats;
|
||||
global.stats_sock.private = NULL;
|
||||
|
||||
cur_arg = 2;
|
||||
while (*args[cur_arg]) {
|
||||
if (!strcmp(args[cur_arg], "uid")) {
|
||||
global.stats_sock.perm.ux.uid = atol(args[cur_arg + 1]);
|
||||
cur_arg += 2;
|
||||
}
|
||||
else if (!strcmp(args[cur_arg], "gid")) {
|
||||
global.stats_sock.perm.ux.gid = atol(args[cur_arg + 1]);
|
||||
cur_arg += 2;
|
||||
}
|
||||
else if (!strcmp(args[cur_arg], "mode")) {
|
||||
global.stats_sock.perm.ux.mode = strtol(args[cur_arg + 1], NULL, 8);
|
||||
cur_arg += 2;
|
||||
}
|
||||
else if (!strcmp(args[cur_arg], "user")) {
|
||||
struct passwd *user;
|
||||
user = getpwnam(args[cur_arg + 1]);
|
||||
if (!user) {
|
||||
snprintf(err, errlen, "unknown user '%s' in 'global' section ('stats user')",
|
||||
args[cur_arg + 1]);
|
||||
return -1;
|
||||
}
|
||||
global.stats_sock.perm.ux.uid = user->pw_uid;
|
||||
cur_arg += 2;
|
||||
}
|
||||
else if (!strcmp(args[cur_arg], "group")) {
|
||||
struct group *group;
|
||||
group = getgrnam(args[cur_arg + 1]);
|
||||
if (!group) {
|
||||
snprintf(err, errlen, "unknown group '%s' in 'global' section ('stats group')",
|
||||
args[cur_arg + 1]);
|
||||
return -1;
|
||||
}
|
||||
global.stats_sock.perm.ux.gid = group->gr_gid;
|
||||
cur_arg += 2;
|
||||
}
|
||||
else {
|
||||
snprintf(err, errlen, "'stats socket' only supports 'user', 'uid', 'group', 'gid', and 'mode'");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
uxst_add_listener(&global.stats_sock);
|
||||
global.maxsock++;
|
||||
}
|
||||
else if (!strcmp(args[0], "timeout")) {
|
||||
int timeout = atol(args[1]);
|
||||
|
||||
if (timeout <= 0) {
|
||||
snprintf(err, errlen, "a positive value is expected for 'stats timeout' in 'global section'");
|
||||
return -1;
|
||||
}
|
||||
__tv_from_ms(&global.stats_timeout, timeout);
|
||||
}
|
||||
else if (!strcmp(args[0], "maxconn")) {
|
||||
int maxconn = atol(args[1]);
|
||||
|
||||
if (maxconn <= 0) {
|
||||
snprintf(err, errlen, "a positive value is expected for 'stats maxconn' in 'global section'");
|
||||
return -1;
|
||||
}
|
||||
global.maxsock -= global.stats_sock.maxconn;
|
||||
global.stats_sock.maxconn = maxconn;
|
||||
global.maxsock += global.stats_sock.maxconn;
|
||||
}
|
||||
else {
|
||||
snprintf(err, errlen, "'stats' only supports 'socket', 'maxconn' and 'timeout' in 'global' section");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Produces statistics data for the session <s>. Expects to be called with
|
||||
* s->cli_state == CL_STSHUTR. It *may* make use of informations from <uri>
|
||||
|
@ -116,6 +116,12 @@ struct global global = {
|
||||
logfac2 : -1,
|
||||
loglev1 : 7, /* max syslog level : debug */
|
||||
loglev2 : 7,
|
||||
.stats_timeout = { .tv_sec = 10, .tv_usec = 0 }, /* stats timeout = 10 seconds */
|
||||
.stats_sock.timeout = &global.stats_timeout,
|
||||
.stats_sock.maxconn = 10, /* 10 concurrent stats connections */
|
||||
.stats_sock.perm.ux.uid = -1,
|
||||
.stats_sock.perm.ux.gid = -1,
|
||||
.stats_sock.perm.ux.mode = 0,
|
||||
/* others NULL OK */
|
||||
};
|
||||
|
||||
@ -542,7 +548,7 @@ void init(int argc, char **argv)
|
||||
global.mode &= ~(MODE_DAEMON | MODE_QUIET);
|
||||
}
|
||||
global.mode |= (arg_mode & (MODE_DAEMON | MODE_FOREGROUND | MODE_QUIET |
|
||||
MODE_VERBOSE | MODE_DEBUG | MODE_STATS | MODE_LOG));
|
||||
MODE_VERBOSE | MODE_DEBUG ));
|
||||
|
||||
if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
|
||||
Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
|
||||
|
Loading…
x
Reference in New Issue
Block a user