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 <source> verbosity [<level>]
+ 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
---------------
const char *desc;
};
+/* Regarding the verbosity, if <decoding> 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;
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 <module>" on CLI */
enum trace_lockon lockon;
uint64_t start_events; // what will start the trace. default: 0=nothing
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 <decoding> (0=no cb)
struct sink *sink; // where to send the trace
/* trace state part below */
enum trace_state state;
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.
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);
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)) ||
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");