cli: print current thread's error causes, if any, before exiting
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Thu, 4 Jul 2019 06:00:18 +0000 (02:00 -0400)
committerPhilippe Proulx <eeppeliteloop@gmail.com>
Sat, 6 Jul 2019 03:47:50 +0000 (23:47 -0400)
This patch makes the CLI print the error causes of the current thread's
error object, if any, before it finally exits.

The causes are printed from the most recent to the least recent. In
other words, the root cause, or deepest cause, is printed at the end of
the list. This is similar to what Python does when it prints a
traceback.

The CLI prints error causes with colors if supported to highlight the
cause's module name, specific properties, file name, and line number.
The CLI prints the messages indented with two spaces and folded on the
terminal's current width if available, otherwise on 80 columns.

You can test the output with

    babeltrace2 $(uuidgen)

This prints something like:

    ERROR:    [Babeltrace CLI] (babeltrace2.c:2531)
      Cannot create components.
    CAUSED BY [Babeltrace CLI] (babeltrace2.c:2355)
      Cannot create component: plugin-name="ctf", comp-cls-name="fs",
      comp-cls-type=0, comp-name="source-ctf-fs"
    CAUSED BY [Babeltrace library] (graph.c:1336)
      Component initialization method failed: status=ERROR,
      comp-addr=0x5590750b8fa0, comp-name="source-ctf-fs",
      comp-log-level=BT_LOGGING_LEVEL_WARN,
      comp-class-type=BT_COMPONENT_CLASS_TYPE_SOURCE, comp-class-name="fs",
      comp-class-partial-descr="Read CTF traces from the file sy",
      comp-class-is-frozen=0, comp-class-so-handle-addr=0x5590750b2aa0,
      comp-class-so-handle-path="babeltrace2/plugins/babeltrace-plugin-ctf.so",
      comp-input-port-count=0, comp-output-port-count=0
    CAUSED BY [source-ctf-fs: 'source.ctf.fs'] (fs.c:1320)
      No CTF traces recursively found in
      `6419ec89-991d-4cf7-ab7f-b143a9901562`.

Signed-off-by: Philippe Proulx <eeppeliteloop@gmail.com>
Change-Id: Ib8101e097acf98db305775ac5b90f4eb006ce4ff
Reviewed-on: https://review.lttng.org/c/babeltrace/+/1622
Tested-by: jenkins <jenkins@lttng.org>
Reviewed-by: Francis Deslauriers <francis.deslauriers@efficios.com>
Reviewed-by: Simon Marchi <simon.marchi@efficios.com>
src/cli/babeltrace2.c

index 97ad6af9f85b6f68a16b041bda6a317dc51ae1ac..fa37cf18f8db30f932fd76d1ba3c383bbb2bff0a 100644 (file)
@@ -400,9 +400,11 @@ void print_plugin_comp_cls_opt(FILE *fh, const char *plugin_name,
        GString *shell_plugin_name = NULL;
        GString *shell_comp_cls_name = NULL;
 
-       shell_plugin_name = bt_common_shell_quote(plugin_name, false);
-       if (!shell_plugin_name) {
-               goto end;
+       if (plugin_name) {
+               shell_plugin_name = bt_common_shell_quote(plugin_name, false);
+               if (!shell_plugin_name) {
+                       goto end;
+               }
        }
 
        shell_comp_cls_name = bt_common_shell_quote(comp_cls_name, false);
@@ -410,14 +412,20 @@ void print_plugin_comp_cls_opt(FILE *fh, const char *plugin_name,
                goto end;
        }
 
-       fprintf(fh, "'%s%s%s%s.%s%s%s.%s%s%s'",
+       fprintf(fh, "'%s%s%s%s",
                bt_common_color_bold(),
                bt_common_color_fg_cyan(),
                component_type_str(type),
-               bt_common_color_fg_default(),
-               bt_common_color_fg_blue(),
-               shell_plugin_name->str,
-               bt_common_color_fg_default(),
+               bt_common_color_fg_default());
+
+       if (shell_plugin_name) {
+               fprintf(fh, ".%s%s%s",
+                       bt_common_color_fg_blue(),
+                       shell_plugin_name->str,
+                       bt_common_color_fg_default());
+       }
+
+       fprintf(fh, ".%s%s%s'",
                bt_common_color_fg_yellow(),
                shell_comp_cls_name->str,
                bt_common_color_reset());
@@ -2719,6 +2727,123 @@ void set_auto_log_levels(struct bt_config *cfg)
        }
 }
 
+static
+void print_error_causes(void)
+{
+       const bt_error *error = bt_current_thread_take_error();
+       int64_t i;
+       GString *folded = NULL;
+       unsigned int columns;
+
+       if (!error || bt_error_get_cause_count(error) == 0) {
+               fprintf(stderr, "%s%sUnknown command-line error.%s\n",
+                       bt_common_color_bold(), bt_common_color_fg_red(),
+                       bt_common_color_reset());
+               goto end;
+       }
+
+       /* Try to get terminal width to fold the error cause messages */
+       if (bt_common_get_term_size(&columns, NULL) < 0) {
+               /* Width not found: default to 80 */
+               columns = 80;
+       }
+
+       /*
+        * This helps visually separate the error causes from the last
+        * logging statement.
+        */
+       fprintf(stderr, "\n");
+
+       /* Reverse order: deepest (root) cause printed at the end */
+       for (i = bt_error_get_cause_count(error) - 1; i >= 0; i--) {
+               const bt_error_cause *cause =
+                       bt_error_borrow_cause_by_index(error, (uint64_t) i);
+               const char *prefix_fmt =
+                       i == bt_error_get_cause_count(error) - 1 ?
+                               "%s%sERROR%s:    " : "%s%sCAUSED BY%s ";
+
+               /* Print prefix */
+               fprintf(stderr, prefix_fmt,
+                       bt_common_color_bold(), bt_common_color_fg_red(),
+                       bt_common_color_reset());
+
+               /* Print actor name */
+               fprintf(stderr, "[");
+               switch (bt_error_cause_get_actor_type(cause)) {
+               case BT_ERROR_CAUSE_ACTOR_TYPE_UNKNOWN:
+                       fprintf(stderr, "%s%s%s",
+                               bt_common_color_bold(),
+                               bt_error_cause_get_module_name(cause),
+                               bt_common_color_reset());
+                       break;
+               case BT_ERROR_CAUSE_ACTOR_TYPE_COMPONENT:
+                       fprintf(stderr, "%s%s%s: ",
+                               bt_common_color_bold(),
+                               bt_error_cause_component_actor_get_component_name(cause),
+                               bt_common_color_reset());
+                       print_plugin_comp_cls_opt(stderr,
+                               bt_error_cause_component_actor_get_plugin_name(cause),
+                               bt_error_cause_component_actor_get_component_class_name(cause),
+                               bt_error_cause_component_actor_get_component_class_type(cause));
+                       break;
+               case BT_ERROR_CAUSE_ACTOR_TYPE_COMPONENT_CLASS:
+                       print_plugin_comp_cls_opt(stderr,
+                               bt_error_cause_component_class_actor_get_plugin_name(cause),
+                               bt_error_cause_component_class_actor_get_component_class_name(cause),
+                               bt_error_cause_component_class_actor_get_component_class_type(cause));
+                       break;
+               case BT_ERROR_CAUSE_ACTOR_TYPE_MESSAGE_ITERATOR:
+                       fprintf(stderr, "%s%s%s (%s%s%s): ",
+                               bt_common_color_bold(),
+                               bt_error_cause_message_iterator_actor_get_component_name(cause),
+                               bt_common_color_reset(),
+                               bt_common_color_bold(),
+                               bt_error_cause_message_iterator_actor_get_component_output_port_name(cause),
+                               bt_common_color_reset());
+                       print_plugin_comp_cls_opt(stderr,
+                               bt_error_cause_message_iterator_actor_get_plugin_name(cause),
+                               bt_error_cause_message_iterator_actor_get_component_class_name(cause),
+                               bt_error_cause_message_iterator_actor_get_component_class_type(cause));
+                       break;
+               default:
+                       abort();
+               }
+
+               /* Print file name and line number */
+               fprintf(stderr, "] (%s%s%s%s:%s%" PRIu64 "%s)\n",
+                       bt_common_color_bold(),
+                       bt_common_color_fg_magenta(),
+                       bt_error_cause_get_file_name(cause),
+                       bt_common_color_reset(),
+                       bt_common_color_fg_green(),
+                       bt_error_cause_get_line_number(cause),
+                       bt_common_color_reset());
+
+               /* Print message */
+               folded = bt_common_fold(bt_error_cause_get_message(cause),
+                       columns, 2);
+               if (!folded) {
+                       BT_LOGE_STR("Could not fold string.");
+                       fprintf(stderr, "%s\n",
+                               bt_error_cause_get_message(cause));
+                       continue;
+               }
+
+               fprintf(stderr, "%s\n", folded->str);
+               g_string_free(folded, TRUE);
+               folded = NULL;
+       }
+
+end:
+       if (folded) {
+               g_string_free(folded, TRUE);
+       }
+
+       if (error) {
+               bt_error_release(error);
+       }
+}
+
 int main(int argc, const char **argv)
 {
        int ret;
@@ -2799,6 +2924,10 @@ end:
        BT_OBJECT_PUT_REF_AND_RESET(cfg);
        fini_static_data();
 
+       if (retcode != 0) {
+               print_error_causes();
+       }
+
        /*
         * Clear current thread's error in case there is one to avoid a
         * memory leak.
This page took 0.027792 seconds and 4 git commands to generate.