diff --git a/doc/configuration.txt b/doc/configuration.txt index 699796a99..ee601480b 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -52,6 +52,7 @@ Summary 3.1. Process management and security 3.2. Performance tuning 3.3. Debugging +3.3.1. Traces 3.4. Userlists 3.5. Peers 3.6. Mailers @@ -2903,25 +2904,6 @@ thread-hard-limit and a warning is emitted in so that the configuration anomaly can be fixed. By default there is no limit. See also "nbthread". -trace - This command configures one "trace" subsystem statement. Each of them can be - found in the management manual, and follow the exact same syntax. Only one - statement per line is permitted (i.e. if some long trace configurations using - semi-colons are to be imported, they must be placed one per line). Any output - that the "trace" command would produce will be emitted during the parsing - step of the section. Most of the time these will be errors and warnings, but - certain incomplete commands might list permissible choices. This command is - not meant for regular use, it will generally only be suggested by developers - along complex debugging sessions. For this reason it is internally marked as - experimental, meaning that "expose-experimental-directives" must appear on a - line before any "trace" statement. Note that these directives are parsed on - the fly, so referencing a ring buffer that is only declared further will not - work. For such use cases it is suggested to place another "global" section - with only the "trace" statements after the declaration of that ring. It is - important to keep in mind that depending on the trace level and details, - enabling traces can severely degrade the global performance. Please refer to - the management manual for the statements syntax. - uid Changes the process's user ID to . It is recommended that the user ID is dedicated to HAProxy or to a small set of similar daemons. HAProxy must @@ -4350,6 +4332,60 @@ zero-warning report errors in such a case. This option is equivalent to command line argument "-dW". +3.3.1. Traces +------------- + +For debugging purpose, it is possible to activate traces on an HAProxy's +subsystem. This will dump debug messages about a specific subsystem. It is a +very powerful tool to diagnose issues. Traces can be dynamically configured via +the CLI. It is also possible to predefined some settings in the configuration +file, in dedicated "traces" sections. More details about traces can be found in +the management guide. It remains a developper tools used during complex +debugging sessions. It is pretty verbose and have a cost, so use it with +caution. And because it is a developper tool, there is no warranty about the +backward compatibility of this section. + +traces + Starts a new traces section. One or multiple "traces" section may be + used. All direcitives are evaluated in the declararion order, the last ones + overriding previous ones. + +trace + Configures on "trace" subsystem. Each of them can be found in the management + manual, and follow the exact same syntax. Only one statement per line is + permitted (i.e. if some long trace configurations using semi-colons are to be + imported, they must be placed one per line). Any output that the "trace" + command would produce will be emitted during the parsing step of the + section. Most of the time these will be errors and warnings, but certain + incomplete commands might list permissible choices. This command is not meant + for regular use, it will generally only be suggested by developers along + complex debugging sessions. Note that these directives are parsed on the fly, + so referencing a ring buffer that is only declared further will not work. It + is important to keep in mind that depending on the trace level and details, + enabling traces can severely degrade the global performance. Please refer to + the management manual for the statements syntax. + + Example: + ring buf1 + size 10485760 # 10MB + format timed + backing-file /tmp/h1.traces + + ring buf2 + size 10485760 # 10MB + format timed + backing-file /tmp/h2.traces + + traces + trace h1 sink buf1 + trace h1 level developer + trace h1 verbosity complete + trace h1 start now + + trace h2 sink buf1 + trace h2 level developer + trace h2 verbosity complete + trace h2 start now 3.4. Userlists -------------- diff --git a/include/haproxy/cfgparse.h b/include/haproxy/cfgparse.h index 04c4ed94a..8b760cdae 100644 --- a/include/haproxy/cfgparse.h +++ b/include/haproxy/cfgparse.h @@ -37,6 +37,7 @@ struct acl_cond; #define CFG_PEERS 4 #define CFG_CRTLIST 5 #define CFG_CRTSTORE 6 +#define CFG_TRACES 7 /* various keyword modifiers */ enum kw_mod { @@ -110,6 +111,7 @@ extern struct proxy *curproxy; int cfg_parse_global(const char *file, int linenum, char **args, int inv); int cfg_parse_listen(const char *file, int linenum, char **args, int inv); +int cfg_parse_traces(const char *file, int linenum, char **args, int inv); int cfg_parse_track_sc_num(unsigned int *track_sc_num, const char *arg, const char *end, char **err); int parse_cfg(const struct cfgfile *cfg); diff --git a/src/cfgparse-global.c b/src/cfgparse-global.c index 4bff01b13..12cac06e3 100644 --- a/src/cfgparse-global.c +++ b/src/cfgparse-global.c @@ -897,7 +897,7 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm) } } } - + best = cfg_find_best_match(args[0], &cfg_keywords.list, CFG_GLOBAL, common_kw_list); if (best) ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section; did you mean '%s' maybe ?\n", file, linenum, args[0], cursection, best); diff --git a/src/cfgparse.c b/src/cfgparse.c index bd7c709b5..85b74f0d6 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -4937,6 +4937,7 @@ REGISTER_CONFIG_SECTION("userlist", cfg_parse_users, NULL); REGISTER_CONFIG_SECTION("peers", cfg_parse_peers, NULL); REGISTER_CONFIG_SECTION("mailers", cfg_parse_mailers, NULL); REGISTER_CONFIG_SECTION("namespace_list", cfg_parse_netns, NULL); +REGISTER_CONFIG_SECTION("traces", cfg_parse_traces, NULL); static struct cfg_kw_list cfg_kws = {{ },{ { CFG_GLOBAL, "default-path", cfg_parse_global_def_path }, diff --git a/src/trace.c b/src/trace.c index 852397ac7..ea0d65e27 100644 --- a/src/trace.c +++ b/src/trace.c @@ -1025,9 +1025,74 @@ static int cfg_parse_trace(char **args, int section_type, struct proxy *curpx, } ha_free(&msg); } + return 0; } +/* + * parse a line in a section. Returns the error code, 0 if OK, or + * any combination of : + * - ERR_ABORT: must abort ASAP + * - ERR_FATAL: we can continue parsing but not start the service + * - ERR_WARN: a warning has been emitted + * - ERR_ALERT: an alert has been emitted + * Only the two first ones can stop processing, the two others are just + * indicators. + */ +int cfg_parse_traces(const char *file, int linenum, char **args, int inv) +{ + int err_code = 0; + char *errmsg = NULL; + + if (strcmp(args[0], "traces") == 0) { /* new section */ + /* no option, nothing special to do */ + alertif_too_many_args(0, file, linenum, args, &err_code); + goto out; + } + else { + struct cfg_kw_list *kwl; + const char *best; + int index; + int rc; + + list_for_each_entry(kwl, &cfg_keywords.list, list) { + for (index = 0; kwl->kw[index].kw != NULL; index++) { + if (kwl->kw[index].section != CFG_TRACES) + continue; + if (strcmp(kwl->kw[index].kw, args[0]) == 0) { + if (check_kw_experimental(&kwl->kw[index], file, linenum, &errmsg)) { + ha_alert("%s\n", errmsg); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + + rc = kwl->kw[index].parse(args, CFG_TRACES, NULL, NULL, file, linenum, &errmsg); + if (rc < 0) { + ha_alert("parsing [%s:%d] : %s\n", file, linenum, errmsg); + err_code |= ERR_ALERT | ERR_FATAL; + } + else if (rc > 0) { + ha_warning("parsing [%s:%d] : %s\n", file, linenum, errmsg); + err_code |= ERR_WARN; + } + goto out; + } + } + } + + best = cfg_find_best_match(args[0], &cfg_keywords.list, CFG_TRACES, NULL); + if (best) + ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section; did you mean '%s' maybe ?\n", file, linenum, args[0], cursection, best); + else + ha_alert("parsing [%s:%d] : unknown keyword '%s' in '%s' section\n", file, linenum, args[0], "global"); + err_code |= ERR_ALERT | ERR_FATAL; + } + + out: + free(errmsg); + return err_code; +} + /* parse the command, returns 1 if a message is returned, otherwise zero */ static int cli_parse_trace(char **args, char *payload, struct appctx *appctx, void *private) { @@ -1108,7 +1173,7 @@ static struct cli_kw_list cli_kws = {{ },{ INITCALL1(STG_REGISTER, cli_register_kw, &cli_kws); static struct cfg_kw_list cfg_kws = {ILH, { - { CFG_GLOBAL, "trace", cfg_parse_trace, KWF_EXPERIMENTAL }, + { CFG_TRACES, "trace", cfg_parse_trace }, { /* END */ }, }};