]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: trace: change the detail_level to per-source verbosity
authorWilly Tarreau <w@1wt.eu>
Thu, 29 Aug 2019 06:24:16 +0000 (08:24 +0200)
committerWilly Tarreau <w@1wt.eu>
Thu, 29 Aug 2019 15:11:25 +0000 (17:11 +0200)
The detail level initially based on syslog levels is not used, while
something related is missing, trace verbosity, to indicate whether or
not we want to call the decoding callback and what level of decoding
we want (raw captures etc). Let's change the field to "verbosity" for
this. A verbosity of zero means that the decoding callback is not
called, and all other levels are handled by this callback and are
source-specific. The source is now prompted to list the levels that
are proposed to the user. When the source doesn't define anything,
"quiet" and "default" are available.

doc/management.txt
include/proto/trace.h
include/types/trace.h
src/trace.c

index a65eeca4f50fa34ead30c672f7782db4c5d1b445..6709cee310e5214ddcad9b5fd2aee1e1688375b0 100644 (file)
@@ -2752,6 +2752,25 @@ trace <source> sink [<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 <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
 ---------------
index 9c5c111282aae7ca375e4dd4bb548dede74f284d..4ef13078cf4c3df8df6be385b4bf20bbdab0455b 100644 (file)
@@ -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;
index 91a57f88cbe1202b52080813bbcf518e7d16fd0f..db7b1855062745fb48da5226da0ed4606933e978 100644 (file)
@@ -117,6 +117,12 @@ struct trace_event {
        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;
@@ -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 <module>" 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 <decoding> (0=no cb)
        struct sink *sink;       // where to send the trace
        /* trace state part below */
        enum trace_state state;
index 6729f06b0684ebd2de5df1187990deb423c23b76..97eec44ebd22f5006e3e4c87a0eed044ba9f822d 100644 (file)
@@ -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");