From 3efa30527e93de6e2374c47ed9dfb633508e123b Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Wed, 14 Jun 2017 01:17:23 -0400 Subject: [PATCH] cli: add global --log-level option MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This new global option (applies before the command name) sets the default log level of all the known (project's) loggers. This default log level can still be overridden by a specific environment variable, for example: BABELTRACE_PLUGIN_CTF_METADATA_LOG_LEVEL=D babeltrace --log-level=I ... In this example, all the log levels are set to INFO, but BABELTRACE_PLUGIN_CTF_METADATA_LOG_LEVEL overrides the `ctf` plugin's metadata module's log level to DEBUG. When you don't specify --log-level, it defaults to W (WARN), the current behaviour. --verbose is now the equivalent of --log-level=I, and --debug is the equivalent of --log-level=V. --verbose and --debug do the same thing, for the `convert` command, whether they are global or specific to the command. --verbose and --debug can still be specified together, and whatever the order, the lowest log level always wins: VERBOSE. The --log-level option can override previous --verbose, --debug, or --log-level options because it didn't exist in Babeltrace 1 anyway so there's no way to break backward compatibility: babeltrace --log-level=W --verbose --log-level=E ... In this case, the final log level is ERROR. Other example with implicit `convert` command: babeltrace --log-level=E /path/to/trace -v In this case, the command's --verbose option sets the log level to INFO because it's lower than ERROR (set by --log-level=E). One of the main use cases of the new --log-level option is to completely disable logging: babeltrace --log-level=N ... Signed-off-by: Philippe Proulx Signed-off-by: Jérémie Galarneau --- cli/babeltrace-cfg-cli-args.c | 160 +++++++++++++++++++++++----------- cli/babeltrace-cfg.h | 1 + cli/babeltrace.c | 57 +++++++++++- 3 files changed, 163 insertions(+), 55 deletions(-) diff --git a/cli/babeltrace-cfg-cli-args.c b/cli/babeltrace-cfg-cli-args.c index e2608748..394e9e65 100644 --- a/cli/babeltrace-cfg-cli-args.c +++ b/cli/babeltrace-cfg-cli-args.c @@ -1775,7 +1775,7 @@ void print_help_usage(FILE *fp) fprintf(fp, " --omit-system-plugin-path Omit system plugins from plugin search path\n"); fprintf(fp, " --plugin-path=PATH[:PATH]... Add PATH to the list of paths from which\n"); fprintf(fp, " dynamic plugins can be loaded\n"); - fprintf(fp, " -h --help Show this help and quit\n"); + fprintf(fp, " -h, --help Show this help and quit\n"); fprintf(fp, "\n"); fprintf(fp, "See `babeltrace --help` for the list of general options.\n"); fprintf(fp, "\n"); @@ -1964,7 +1964,7 @@ void print_query_usage(FILE *fp) fprintf(fp, " (see the expected format of PARAMS below)\n"); fprintf(fp, " --plugin-path=PATH[:PATH]... Add PATH to the list of paths from which\n"); fprintf(fp, " dynamic plugins can be loaded\n"); - fprintf(fp, " -h --help Show this help and quit\n"); + fprintf(fp, " -h, --help Show this help and quit\n"); fprintf(fp, "\n\n"); print_expected_params_format(fp); } @@ -2160,7 +2160,7 @@ void print_list_plugins_usage(FILE *fp) fprintf(fp, " --omit-system-plugin-path Omit system plugins from plugin search path\n"); fprintf(fp, " --plugin-path=PATH[:PATH]... Add PATH to the list of paths from which\n"); fprintf(fp, " dynamic plugins can be loaded\n"); - fprintf(fp, " -h --help Show this help and quit\n"); + fprintf(fp, " -h, --help Show this help and quit\n"); fprintf(fp, "\n"); fprintf(fp, "See `babeltrace --help` for the list of general options.\n"); fprintf(fp, "\n"); @@ -2326,7 +2326,7 @@ void print_run_usage(FILE *fp) fprintf(fp, " the current component with a name given by\n"); fprintf(fp, " the last argument of the --key option and a\n"); fprintf(fp, " value set to VAL\n"); - fprintf(fp, " -h --help Show this help and quit\n"); + fprintf(fp, " -h, --help Show this help and quit\n"); fprintf(fp, "\n"); fprintf(fp, "See `babeltrace --help` for the list of general options.\n"); fprintf(fp, "\n\n"); @@ -2793,7 +2793,7 @@ void print_convert_usage(FILE *fp) fprintf(fp, " formatted for `xargs -0`, and quit\n"); fprintf(fp, " -u, --url=URL Set the `url` string parameter of the\n"); fprintf(fp, " current component to URL\n"); - fprintf(fp, " -h --help Show this help and quit\n"); + fprintf(fp, " -h, --help Show this help and quit\n"); fprintf(fp, "\n"); fprintf(fp, "Implicit `source.ctf.fs` component options:\n"); fprintf(fp, "\n"); @@ -3584,7 +3584,7 @@ static struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], int *retcode, bool force_omit_system_plugin_path, bool force_omit_home_plugin_path, bool force_no_debug_info, - struct bt_value *initial_plugin_paths) + struct bt_value *initial_plugin_paths, char *log_level) { poptContext pc = NULL; char *arg = NULL; @@ -3592,8 +3592,6 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], BT_CONFIG_COMPONENT_DEST_UNKNOWN; int opt, ret = 0; struct bt_config *cfg = NULL; - bool got_verbose_opt = false; - bool got_debug_opt = false; bool got_input_format_opt = false; bool got_output_format_opt = false; bool trimmer_has_begin = false; @@ -4273,18 +4271,12 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], base_implicit_ctf_input_args.exists = true; break; case OPT_VERBOSE: - if (got_verbose_opt) { - printf_err("Duplicate -v/--verbose option\n"); - goto error; + if (*log_level != 'V' && *log_level != 'D') { + *log_level = 'I'; } - - append_implicit_component_param(&implicit_text_args, - "verbose", "yes"); - implicit_text_args.exists = true; - got_verbose_opt = true; break; case OPT_DEBUG: - got_debug_opt = true; + *log_level = 'V'; break; } @@ -4299,6 +4291,16 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], goto error; } + /* + * Legacy behaviour: --verbose used to make the `text` output + * format print more information. --verbose is now equivalent to + * the INFO log level, which is why we compare to 'I' here. + */ + if (*log_level == 'I') { + append_implicit_component_param(&implicit_text_args, + "verbose", "yes"); + } + /* * Append home and system plugin paths now that we possibly got * --plugin-path. @@ -4345,8 +4347,6 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], goto error; } - cfg->debug = got_debug_opt; - cfg->verbose = got_verbose_opt; gs_leftover = leftovers->data; g_string_assign(cfg->cmd_data.print_ctf_metadata.path, gs_leftover->str); @@ -4435,8 +4435,6 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], goto error; } - cfg->debug = got_debug_opt; - cfg->verbose = got_verbose_opt; g_string_assign(cfg->cmd_data.print_lttng_live_sessions.url, gs_leftover->str); goto end; @@ -4706,8 +4704,6 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[], goto error; } - cfg->debug = got_debug_opt; - cfg->verbose = got_verbose_opt; goto end; error: @@ -4763,10 +4759,12 @@ void print_gen_usage(FILE *fp) fprintf(fp, "\n"); fprintf(fp, "General options:\n"); fprintf(fp, "\n"); - fprintf(fp, " -d, --debug Turn on debug mode\n"); - fprintf(fp, " -h --help Show this help and quit\n"); - fprintf(fp, " -v, --verbose Turn on verbose mode\n"); - fprintf(fp, " -V, --version Show version and quit\n"); + fprintf(fp, " -d, --debug Enable debug mode (same as --log-level=V)\n"); + fprintf(fp, " -h, --help Show this help and quit\n"); + fprintf(fp, " --log-level=LVL Set all log levels to LVL (`N`, `V`, `D`,\n"); + fprintf(fp, " `I`, `W` (default), `E`, or `F`)\n"); + fprintf(fp, " -v, --verbose Enable verbose mode (same as --log-level=I)\n"); + fprintf(fp, " -V, --version Show version and quit\n"); fprintf(fp, "\n"); fprintf(fp, "Available commands:\n"); fprintf(fp, "\n"); @@ -4779,18 +4777,49 @@ void print_gen_usage(FILE *fp) fprintf(fp, "Use `babeltrace COMMAND --help` to show the help of COMMAND.\n"); } +static +char log_level_from_arg(const char *arg) +{ + char level = 'U'; + + if (strcmp(arg, "VERBOSE") == 0 || + strcmp(arg, "V") == 0) { + level = 'V'; + } else if (strcmp(arg, "DEBUG") == 0 || + strcmp(arg, "D") == 0) { + level = 'D'; + } else if (strcmp(arg, "INFO") == 0 || + strcmp(arg, "I") == 0) { + level = 'I'; + } else if (strcmp(arg, "WARN") == 0 || + strcmp(arg, "WARNING") == 0 || + strcmp(arg, "W") == 0) { + level = 'W'; + } else if (strcmp(arg, "ERROR") == 0 || + strcmp(arg, "E") == 0) { + level = 'E'; + } else if (strcmp(arg, "FATAL") == 0 || + strcmp(arg, "F") == 0) { + level = 'F'; + } else if (strcmp(arg, "NONE") == 0 || + strcmp(arg, "N") == 0) { + level = 'N'; + } + + return level; +} + struct bt_config *bt_config_cli_args_create(int argc, const char *argv[], int *retcode, bool force_omit_system_plugin_path, bool force_omit_home_plugin_path, bool force_no_debug_info, struct bt_value *initial_plugin_paths) { struct bt_config *config = NULL; - bool verbose = false; - bool debug = false; int i; const char **command_argv = NULL; int command_argc = -1; const char *command_name = NULL; + char log_level = 'U'; enum command_type { COMMAND_TYPE_NONE = -1, @@ -4820,13 +4849,49 @@ struct bt_config *bt_config_cli_args_create(int argc, const char *argv[], for (i = 1; i < argc; i++) { const char *cur_arg = argv[i]; + const char *next_arg = i == (argc - 1) ? NULL : argv[i + 1]; if (strcmp(cur_arg, "-d") == 0 || strcmp(cur_arg, "--debug") == 0) { - debug = true; + log_level = 'V'; } else if (strcmp(cur_arg, "-v") == 0 || strcmp(cur_arg, "--verbose") == 0) { - verbose = true; + if (log_level != 'V' && log_level != 'D') { + /* + * Legacy: do not override a previous + * --debug because --verbose and --debug + * can be specified together (in this + * case we want the lowest log level to + * apply, VERBOSE). + */ + log_level = 'I'; + } + } else if (strcmp(cur_arg, "--log-level") == 0) { + if (!next_arg) { + printf_err("Missing log level value for --log-level option\n"); + *retcode = 1; + goto end; + } + + log_level = log_level_from_arg(next_arg); + if (log_level == 'U') { + printf_err("Invalid argument for --log-level option:\n %s\n", + next_arg); + *retcode = 1; + goto end; + } + + i++; + } else if (strncmp(cur_arg, "--log-level=", 12) == 0) { + const char *arg = &cur_arg[12]; + + log_level = log_level_from_arg(arg); + if (log_level == 'U') { + printf_err("Invalid argument for --log-level option:\n %s\n", + arg); + *retcode = 1; + goto end; + } } else if (strcmp(cur_arg, "-V") == 0 || strcmp(cur_arg, "--version") == 0) { print_version(); @@ -4836,12 +4901,13 @@ struct bt_config *bt_config_cli_args_create(int argc, const char *argv[], print_gen_usage(stdout); goto end; } else { - bool has_command = true; - /* * First unknown argument: is it a known command * name? */ + command_argv = &argv[i]; + command_argc = argc - i; + if (strcmp(cur_arg, "convert") == 0) { command_type = COMMAND_TYPE_CONVERT; } else if (strcmp(cur_arg, "list-plugins") == 0) { @@ -4855,20 +4921,13 @@ struct bt_config *bt_config_cli_args_create(int argc, const char *argv[], } else { /* * Unknown argument, but not a known - * command name: assume the whole - * arguments are for the default convert - * command. + * command name: assume the default + * `convert` command. */ command_type = COMMAND_TYPE_CONVERT; - command_argv = argv; - command_argc = argc; - has_command = false; - } - - if (has_command) { - command_argv = &argv[i]; - command_argc = argc - i; - command_name = cur_arg; + command_name = "convert"; + command_argv = &argv[i - 1]; + command_argc = argc - i + 1; } break; } @@ -4898,7 +4957,7 @@ struct bt_config *bt_config_cli_args_create(int argc, const char *argv[], config = bt_config_convert_from_args(command_argc, command_argv, retcode, force_omit_system_plugin_path, force_omit_home_plugin_path, force_no_debug_info, - initial_plugin_paths); + initial_plugin_paths, &log_level); break; case COMMAND_TYPE_LIST_PLUGINS: config = bt_config_list_plugins_from_args(command_argc, @@ -4920,14 +4979,11 @@ struct bt_config *bt_config_cli_args_create(int argc, const char *argv[], } if (config) { - if (verbose) { - config->verbose = true; - } - - if (debug) { - config->debug = true; + if (log_level == 'U') { + log_level = 'W'; } + config->log_level = log_level; config->command_name = command_name; } diff --git a/cli/babeltrace-cfg.h b/cli/babeltrace-cfg.h index 87231295..b9a4b5ed 100644 --- a/cli/babeltrace-cfg.h +++ b/cli/babeltrace-cfg.h @@ -70,6 +70,7 @@ struct bt_config { bool omit_home_plugin_path; bool command_needs_plugins; const char *command_name; + char log_level; enum bt_config_command command; union { /* BT_CONFIG_COMMAND_RUN */ diff --git a/cli/babeltrace.c b/cli/babeltrace.c index d7eeec61..668491e7 100644 --- a/cli/babeltrace.c +++ b/cli/babeltrace.c @@ -1938,7 +1938,31 @@ void set_auto_log_levels(struct bt_config *cfg) * Set library's default log level if not * explicitly specified. */ - bt_logging_set_global_level(BT_LOGGING_LEVEL_WARN); + switch (cfg->log_level) { + case 'N': + bt_logging_set_global_level(BT_LOGGING_LEVEL_NONE); + break; + case 'V': + bt_logging_set_global_level(BT_LOGGING_LEVEL_VERBOSE); + break; + case 'D': + bt_logging_set_global_level(BT_LOGGING_LEVEL_DEBUG); + break; + case 'I': + bt_logging_set_global_level(BT_LOGGING_LEVEL_INFO); + break; + case 'W': + bt_logging_set_global_level(BT_LOGGING_LEVEL_WARN); + break; + case 'E': + bt_logging_set_global_level(BT_LOGGING_LEVEL_ERROR); + break; + case 'F': + bt_logging_set_global_level(BT_LOGGING_LEVEL_FATAL); + break; + default: + abort(); + } } } @@ -1952,7 +1976,31 @@ void set_auto_log_levels(struct bt_config *cfg) * Set CLI's default log level if not explicitly * specified. */ - bt_cli_log_level = BT_LOG_WARN; + switch (cfg->log_level) { + case 'N': + bt_cli_log_level = BT_LOG_NONE; + break; + case 'V': + bt_cli_log_level = BT_LOG_VERBOSE; + break; + case 'D': + bt_cli_log_level = BT_LOG_DEBUG; + break; + case 'I': + bt_cli_log_level = BT_LOG_INFO; + break; + case 'W': + bt_cli_log_level = BT_LOG_WARN; + break; + case 'E': + bt_cli_log_level = BT_LOG_ERROR; + break; + case 'F': + bt_cli_log_level = BT_LOG_FATAL; + break; + default: + abort(); + } } } @@ -1965,11 +2013,14 @@ void set_auto_log_levels(struct bt_config *cfg) } else if (cfg->debug) { setenv(*env_var_name, "V", 1); } else { + char val[2] = { 0 }; + /* * Set module's default log level if not * explicitly specified. */ - setenv(*env_var_name, "W", 1); + val[0] = cfg->log_level; + setenv(*env_var_name, val, 1); } } -- 2.34.1