MINOR: traces: enumerate the list of levels/verbosities when not found

It's quite frustrating, particularly on the command line, not to have
access to the list of available levels and verbosities when one does
not exist for a given source, because there's no easy way to find them
except by starting without and connecting to the CLI. Let's enumerate
the list of supported levels and verbosities when a name does not match.

For example:

  $ ./haproxy -db -f quic-repro.cfg -dt h2:help
  [NOTICE]   (9602) : haproxy version is 3.0-dev12-60496e-27
  [NOTICE]   (9602) : path to executable is ./haproxy
  [ALERT]    (9602) : -dt: no such trace level 'help', available levels are 'error', 'user', 'proto', 'state', 'data', and 'developer'.

  $ ./haproxy -db -f quic-repro.cfg -dt h2:user:help
  [NOTICE]   (9604) : haproxy version is 3.0-dev12-60496e-27
  [NOTICE]   (9604) : path to executable is ./haproxy
  [ALERT]    (9604) : -dt: no such trace verbosity 'help' for source 'h2', available verbosities for this source are: 'quiet', 'clean', 'minimal', 'simple', 'advanced', and 'complete'.

The same is done for the CLI where the existing help message is always
displayed when entering an invalid verbosity or level.
This commit is contained in:
Willy Tarreau 2024-05-22 11:12:32 +02:00
parent 60496e884e
commit 5b9503ed33
2 changed files with 32 additions and 25 deletions

View File

@ -414,8 +414,10 @@ list of options is :
detect protocol violations from clients or servers. An optional argument
can be used to specify a list of various trace configurations using ',' as
separator. Each element activates one or all trace sources. Additionally,
level and verbosity can be optionally specified on each element using ':' as
inner separator with trace name.
level and verbosity can be optionally specified on each element using ':'
as inner separator with trace name. When entering an invalid verbosity or
level name, the list of available keywords is presented. For example it can
be convenient to pass 'help' for each field to consult the list first.
-m <limit> : limit allocatable memory, which is used to keep process's data,
to <limit> megabytes. This may cause some connection refusals or some

View File

@ -566,10 +566,16 @@ static int trace_parse_statement(char **args, char **msg)
}
else if (strcmp(args[2], "level") == 0) {
const char *name = args[3];
int level;
int level = -1;
if (!*name) {
chunk_printf(&trash, "Supported trace levels for source %s:\n", src->name.ptr);
if (*name)
level = trace_parse_level(name);
if (level < 0) {
chunk_reset(&trash);
if (*name)
chunk_appendf(&trash, "No such trace level '%s'. ", name);
chunk_appendf(&trash, "Supported trace levels for source %s:\n", src->name.ptr);
chunk_appendf(&trash, " %c error : report errors\n",
src->level == TRACE_LEVEL_ERROR ? '*' : ' ');
chunk_appendf(&trash, " %c user : also information useful to the end user\n",
@ -584,13 +590,7 @@ static int trace_parse_statement(char **args, char **msg)
src->level == TRACE_LEVEL_DEVELOPER ? '*' : ' ');
trash.area[trash.data] = 0;
*msg = strdup(trash.area);
return LOG_WARNING;
}
level = trace_parse_level(name);
if (level < 0) {
memprintf(msg, "No such trace level '%s'", name);
return LOG_ERR;
return *name ? LOG_ERR : LOG_WARNING;
}
HA_ATOMIC_STORE(&src->level, level);
@ -734,10 +734,16 @@ static int trace_parse_statement(char **args, char **msg)
else if (strcmp(args[2], "verbosity") == 0) {
const char *name = args[3];
const struct name_desc *nd;
int verbosity;
int verbosity = -1;
if (!*name) {
chunk_printf(&trash, "Supported trace verbosities for source %s:\n", src->name.ptr);
if (*name)
verbosity = trace_source_parse_verbosity(src, name);
if (verbosity < 0) {
chunk_reset(&trash);
if (*name)
chunk_appendf(&trash, "No such verbosity level '%s'. ", name);
chunk_appendf(&trash, "Supported trace verbosities for source %s:\n", src->name.ptr);
chunk_appendf(&trash, " %c quiet : only report basic information with no decoding\n",
src->verbosity == 0 ? '*' : ' ');
if (!src->decoding || !src->decoding[0].name) {
@ -751,13 +757,7 @@ static int trace_parse_statement(char **args, char **msg)
}
trash.area[trash.data] = 0;
*msg = strdup(trash.area);
return LOG_WARNING;
}
verbosity = trace_source_parse_verbosity(src, name);
if (verbosity < 0) {
memprintf(msg, "No such verbosity level '%s'", name);
return LOG_ERR;
return *name ? LOG_ERR : LOG_WARNING;
}
HA_ATOMIC_STORE(&src->verbosity, verbosity);
@ -837,7 +837,7 @@ int trace_parse_cmd(char *arg, char **errmsg)
if (strlen(field)) {
level = trace_parse_level(field);
if (level < 0) {
memprintf(errmsg, "no such level '%s'", field);
memprintf(errmsg, "no such trace level '%s', available levels are 'error', 'user', 'proto', 'state', 'data', and 'developer'", field);
return 1;
}
}
@ -848,7 +848,7 @@ int trace_parse_cmd(char *arg, char **errmsg)
/* 3. verbosity */
field = str;
if (strchr(field, ':')) {
memprintf(errmsg, "too many double-colon separator");
memprintf(errmsg, "too many double-colon separators in trace definition");
return 1;
}
@ -859,7 +859,12 @@ int trace_parse_cmd(char *arg, char **errmsg)
verbosity = trace_source_parse_verbosity(src, field);
if (verbosity < 0) {
memprintf(errmsg, "no such verbosity '%s' for source '%s'", field, name);
const struct name_desc *nd;
memprintf(errmsg, "no such trace verbosity '%s' for source '%s', available verbosities for this source are: 'quiet'", field, name);
for (nd = src->decoding; nd->name && nd->desc; nd++)
memprintf(errmsg, "%s, %s'%s'", *errmsg, (nd + 1)->name ? "" : "and ", nd->name);
return 1;
}