diff --git a/doc/management.txt b/doc/management.txt index a65eeca4f..6709cee31 100644 --- a/doc/management.txt +++ b/doc/management.txt @@ -2752,6 +2752,25 @@ trace sink [] sink change. In the worst case some may be lost if an invalid sink is used (or "none"), but operations do continue to a different destination. +trace verbosity [] + Without argument, this will list all verbosity levels for this source, and the + current one will be indicated by a star ('*') prepended in front of it. With + an argument, this will change the verbosity level to the specified one. + + Verbosity levels indicate how far the trace decoder should go to provide + detailed information. It depends on the trace source, since some sources will + not even provide a specific decoder. Level "quiet" is always available and + disables any decoding. It can be useful when trying to figure what's + happening before trying to understand the details, since it will have a very + low impact on performance and trace size. When no verbosity levels are + declared by a source, level "default" is available and will cause a decoder + to be called when specified in the traces. It is an opportunistic decoding. + When the source declares some verbosity levels, these ones are listed with + a description of what they correspond to. In this case the trace decoder + provided by the source will be as accurate as possible based on the + information available at the trace point. The first level above "quiet" is + set by default. + 9.4. Master CLI --------------- diff --git a/include/proto/trace.h b/include/proto/trace.h index 9c5c11128..4ef13078c 100644 --- a/include/proto/trace.h +++ b/include/proto/trace.h @@ -110,7 +110,7 @@ static inline void trace_register_source(struct trace_source *source) { source->lockon = TRACE_LOCKON_NOTHING; source->level = TRACE_LEVEL_USER; - source->detail_level = LOG_NOTICE; + source->verbosity = 1; source->sink = NULL; source->state = TRACE_STATE_STOPPED; source->lockon_ptr = NULL; diff --git a/include/types/trace.h b/include/types/trace.h index 91a57f88c..db7b18550 100644 --- a/include/types/trace.h +++ b/include/types/trace.h @@ -117,6 +117,12 @@ struct trace_event { const char *desc; }; +/* Regarding the verbosity, if is not NULL, it must point to a NULL- + * terminated array of name:description, which will define verbosity levels + * implemented by the decoding callback. The verbosity value will default to + * 1. When verbosity levels are defined, levels 1 and above are described by + * these levels. At level zero, the callback is never called. + */ struct trace_source { /* source definition */ const struct ist name; @@ -129,6 +135,7 @@ struct trace_source { const void *a1, const void *a2, const void *a3, const void *a4); uint32_t arg_def; // argument definitions (sum of TRC_ARG{1..4}_*) const struct name_desc *lockon_args; // must be 4 entries if not NULL + const struct name_desc *decoding; // null-terminated if not NULL /* trace configuration, adjusted by "trace " on CLI */ enum trace_lockon lockon; uint64_t start_events; // what will start the trace. default: 0=nothing @@ -136,7 +143,7 @@ struct trace_source { uint64_t stop_events; // what will stop the trace. default: 0=nothing uint64_t report_events; // mask of which events need to be reported. enum trace_level level; // report traces up to this level of info - int detail_level; // report events with this level of detail (LOG_*) + unsigned int verbosity; // decoder's level of detail among (0=no cb) struct sink *sink; // where to send the trace /* trace state part below */ enum trace_state state; diff --git a/src/trace.c b/src/trace.c index 6729f06b0..97eec44eb 100644 --- a/src/trace.c +++ b/src/trace.c @@ -207,7 +207,7 @@ void __trace(enum trace_level level, uint64_t mask, struct trace_source *src, if (!cb) cb = src->default_cb; - if (cb) { + if (cb && src->verbosity) { /* decode function passed, we want to pre-fill the * buffer with the message and let the decode function * do its job, possibly even overwriting it. @@ -219,8 +219,14 @@ void __trace(enum trace_level level, uint64_t mask, struct trace_source *src, line[words].len = trace_buf.data; words++; } - else + else { + /* Note that here we could decide to print some args whose type + * is known, when verbosity is above the quiet level, and even + * to print the name and values of those which are declared for + * lock-on. + */ line[words++] = msg; + } if (src->sink) sink_write(src->sink, line, words); @@ -293,14 +299,15 @@ static int cli_parse_trace(char **args, char *payload, struct appctx *appctx, vo if (!*args[2]) { return cli_msg(appctx, LOG_WARNING, "Supported commands:\n" - " event : list/enable/disable source-specific event reporting\n" - //" filter : list/enable/disable generic filters\n" - " level : list/set trace reporting level\n" - " lock : automatic lock on thread/connection/stream/...\n" - " pause : pause and automatically restart after a specific event\n" - " sink : list/set event sinks\n" - " start : start immediately or after a specific event\n" - " stop : stop immediately or after a specific event\n" + " event : list/enable/disable source-specific event reporting\n" + //" filter : list/enable/disable generic filters\n" + " level : list/set trace reporting level\n" + " lock : automatic lock on thread/connection/stream/...\n" + " pause : pause and automatically restart after a specific event\n" + " sink : list/set event sinks\n" + " start : start immediately or after a specific event\n" + " stop : stop immediately or after a specific event\n" + " verbosity : list/set trace output verbosity\n" ); } else if ((strcmp(args[2], "event") == 0 && (ev_ptr = &src->report_events)) || @@ -544,6 +551,45 @@ static int cli_parse_trace(char **args, char *payload, struct appctx *appctx, vo else return cli_err(appctx, "Unsupported lock-on criterion"); } + else if (strcmp(args[2], "verbosity") == 0) { + const char *name = args[3]; + const struct name_desc *nd; + + if (!*name) { + chunk_printf(&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) { + chunk_appendf(&trash, " %c default : report extra information when available\n", + src->verbosity > 0 ? '*' : ' '); + } else { + for (nd = src->decoding; nd->name && nd->desc; nd++) + chunk_appendf(&trash, " %c %-10s : %s\n", + nd == (src->decoding + src->verbosity - 1) ? '*' : ' ', + nd->name, nd->desc); + } + trash.area[trash.data] = 0; + return cli_msg(appctx, LOG_WARNING, trash.area); + } + + if (strcmp(name, "quiet") == 0) + HA_ATOMIC_STORE(&src->verbosity, 0); + else if (!src->decoding || !src->decoding[0].name) { + if (strcmp(name, "default") == 0) + HA_ATOMIC_STORE(&src->verbosity, 1); + else + return cli_err(appctx, "No such verbosity level"); + } else { + for (nd = src->decoding; nd->name && nd->desc; nd++) + if (strcmp(name, nd->name) == 0) + break; + + if (!nd->name || !nd->desc) + return cli_err(appctx, "No such verbosity level"); + + HA_ATOMIC_STORE(&src->verbosity, (nd - src->decoding) + 1); + } + } else return cli_err(appctx, "Unknown trace keyword");