It is currently not possible to apply --log-level after a leftover.
This patch proposes a way to allow it and to deal with the ambiguity
that it poses.
In the simple case, we have:
babeltrace2 my-traces --log-level=TRACE
All source components auto-discovered from the `my-traces` leftover will
have the TRACE log level.
If we have more than one leftover, but _no_ cross-leftover grouping,
then it is also intuitive:
babeltrace2 my-traces-1 --log-level=TRACE my-traces-2 --log-level=DEBUG
... all source components discovered from `my-traces-1` will have log
level TRACE and all source components discovered from `my-traces-2` will
have log level DEBUG.
It becomes less obvious when components are given inputs coming from
multiple leftovers (because of the auto-discovery grouping feature):
which log level do they receive? For example, if the following line:
babeltrace2 my-traces-1 --log-level=TRACE my-traces-2 --log-level=DEBUG
leads to these components getting instantiated, with these inputs:
* Source component X with inputs `my-traces-1/x` and `my-traces-2/x`.
* Source component Y with input `my-traces-1/y`
In this case, each component receives (on the `run` command line) the
log level options of all leftovers that contributed to its inputs, in
the same order as they are provided on the command line. The resulting
`run` command line for the example above could therefore look like:
... --component x:src.my.comp --log-level=TRACE --log-level=DEBUG \
--component y:src.my.comp --log-level=TRACE
resulting in these effective log levels:
* Source component X: log level DEBUG
* Source component Y: log level TRACE
Change-Id: I5e1bf9e1b4dd139ff7900d81b302a1eda72fb37f
Signed-off-by: Simon Marchi <simon.marchi@efficios.com>
Reviewed-on: https://review.lttng.org/c/babeltrace/+/1810
Tested-by: jenkins <jenkins@lttng.org>
Reviewed-by: Philippe Proulx <eeppeliteloop@gmail.com>
int create_implicit_component_args_from_auto_discovered_sources(
const struct auto_source_discovery *auto_disc,
const bt_value *leftover_params,
+ const bt_value *leftover_loglevels,
GPtrArray *component_args)
{
gchar *cc_name = NULL;
}
/*
- * Append parameters of all the leftovers that contributed to
- * this component instance coming into existence.
+ * Append parameters and log levels of all the leftovers that
+ * contributed to this component instance coming into existence.
*/
orig_indices_count = bt_value_array_get_size(res->original_input_indices);
for (orig_indices_i = 0; orig_indices_i < orig_indices_count; orig_indices_i++) {
bt_value_array_borrow_element_by_index_const(
leftover_params, orig_idx);
uint64_t params_i, params_count;
+ const bt_value *loglevel_value;
params_count = bt_value_array_get_size(params_array);
for (params_i = 0; params_i < params_count; params_i++) {
goto error;
}
}
+
+ loglevel_value = bt_value_array_borrow_element_by_index_const(
+ leftover_loglevels, orig_idx);
+ if (bt_value_get_type(loglevel_value) == BT_VALUE_TYPE_STRING) {
+ const char *loglevel = bt_value_string_get(loglevel_value);
+ bt_value_array_append_element_status append_status;
+
+ append_status = bt_value_array_append_string_element(
+ comp->extra_params, "--log-level");
+ if (append_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) {
+ BT_CLI_LOGE_APPEND_CAUSE("Failed to append array element.");
+ goto error;
+ }
+
+ append_status = bt_value_array_append_string_element(
+ comp->extra_params, loglevel);
+ if (append_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) {
+ BT_CLI_LOGE_APPEND_CAUSE("Failed to append array element.");
+ goto error;
+ }
+ }
}
status = append_parameter_to_args(comp->extra_params, "inputs", res->inputs);
GList *sink_names = NULL;
bt_value *leftovers = NULL;
bt_value *leftover_params = NULL;
+ bt_value *leftover_loglevels = NULL;
struct implicit_component_args implicit_ctf_output_args = { 0 };
struct implicit_component_args implicit_lttng_live_args = { 0 };
struct implicit_component_args implicit_dummy_args = { 0 };
goto error;
}
+ leftover_loglevels = bt_value_array_create();
+ if (!leftover_loglevels) {
+ BT_CLI_LOGE_APPEND_CAUSE_OOM();
+ goto error;
+ }
+
if (auto_source_discovery_init(&auto_disc) != 0) {
goto error;
}
}
break;
case OPT_LOG_LEVEL:
- if (current_item_type != CONVERT_CURRENT_ITEM_TYPE_COMPONENT) {
- BT_CLI_LOGE_APPEND_CAUSE(
- "No current component (--component option) to assign a log level to:\n %s",
- arg);
- goto error;
- }
+ if (current_item_type == CONVERT_CURRENT_ITEM_TYPE_COMPONENT) {
+ if (bt_value_array_append_string_element(run_args, "--log-level")) {
+ BT_CLI_LOGE_APPEND_CAUSE_OOM();
+ goto error;
+ }
- if (bt_value_array_append_string_element(run_args, "--log-level")) {
- BT_CLI_LOGE_APPEND_CAUSE_OOM();
- goto error;
- }
+ if (bt_value_array_append_string_element(run_args, arg)) {
+ BT_CLI_LOGE_APPEND_CAUSE_OOM();
+ goto error;
+ }
+ } else if (current_item_type == CONVERT_CURRENT_ITEM_TYPE_LEFTOVER) {
+ uint64_t idx = bt_value_array_get_size(leftover_loglevels) - 1;
+ bt_value *log_level_str_value;
- if (bt_value_array_append_string_element(run_args, arg)) {
- BT_CLI_LOGE_APPEND_CAUSE_OOM();
+ log_level_str_value = bt_value_string_create_init(arg);
+ if (!log_level_str_value) {
+ BT_CLI_LOGE_APPEND_CAUSE_OOM();
+ goto error;
+ }
+
+ if (bt_value_array_set_element_by_index(leftover_loglevels, idx,
+ log_level_str_value)) {
+ bt_value_put_ref(log_level_str_value);
+ BT_CLI_LOGE_APPEND_CAUSE_OOM();
+ goto error;
+ }
+ } else {
+ BT_CLI_LOGE_APPEND_CAUSE(
+ "No current component (--component option) or non-option argument to assign a log level to:\n %s",
+ arg);
goto error;
}
BT_CLI_LOGE_APPEND_CAUSE_OOM();
goto error;
}
+
+ append_status = bt_value_array_append_element(leftover_loglevels, bt_value_null);
+ if (append_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) {
+ BT_CLI_LOGE_APPEND_CAUSE_OOM();
+ goto error;
+ }
} else {
abort();
}
}
status = create_implicit_component_args_from_auto_discovered_sources(
- &auto_disc, leftover_params, discovered_source_args);
+ &auto_disc, leftover_params, leftover_loglevels,
+ discovered_source_args);
if (status != 0) {
goto error;
}
--- /dev/null
+#!/bin/bash
+#
+# Copyright (C) 2019 Simon Marchi <simon.marchi@efficios.com>
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License, version 2 only, as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 51
+# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# Test log level options are applied to sources auto-discovered by the convert
+# command.
+
+if [ "x${BT_TESTS_SRCDIR:-}" != "x" ]; then
+ UTILSSH="$BT_TESTS_SRCDIR/utils/utils.sh"
+else
+ UTILSSH="$(dirname "$0")/../../utils/utils.sh"
+fi
+
+# shellcheck source=../../utils/utils.sh
+SH_TAP=1 source "$UTILSSH"
+
+NUM_TESTS=4
+
+plan_tests $NUM_TESTS
+
+data_dir="${BT_TESTS_DATADIR}/cli/convert/auto-source-discovery-params-log-level"
+plugin_dir="${data_dir}"
+dir_a="${data_dir}/dir-a"
+dir_b="${data_dir}/dir-b"
+dir_ab="${data_dir}/dir-ab"
+
+expected_file=$(mktemp -t expected.XXXXXX)
+stderr_expected=/dev/null
+
+print_log_level="--params print=\"log-level\""
+
+debug=2
+trace=1
+
+# Apply log level to two components from one leftover.
+cat > "$expected_file" <<END
+TestSourceA: ${debug}
+TestSourceB: ${debug}
+END
+
+bt_diff_cli_sorted "$expected_file" "$stderr_expected" \
+ convert --plugin-path "${plugin_dir}" \
+ "${dir_ab}" --log-level DEBUG ${print_log_level}
+ok "$?" "apply log level to two components from one leftover"
+
+# Apply log level to two components from two distinct leftovers.
+cat > "$expected_file" <<END
+TestSourceA: ${debug}
+TestSourceB: ${trace}
+END
+
+bt_diff_cli_sorted "$expected_file" "$stderr_expected" \
+ convert --plugin-path "${plugin_dir}" \
+ "${dir_a}" --log-level DEBUG ${print_log_level} "${dir_b}" --log-level TRACE ${print_log_level}
+ok "$?" "apply log level to two leftovers"
+
+# Apply log level to one component coming from one leftover and one component coming from two leftovers (1).
+cat > "$expected_file" <<END
+TestSourceA: ${trace}
+TestSourceB: ${trace}
+END
+
+bt_diff_cli_sorted "$expected_file" "$stderr_expected" \
+ convert --plugin-path "${plugin_dir}" \
+ "${dir_a}" --log-level DEBUG ${print_log_level} "${dir_ab}" --log-level TRACE ${print_log_level}
+ok "$?" "apply log level to one component coming from one leftover and one component coming from two leftovers (1)"
+
+# Apply log level to one component coming from one leftover and one component coming from two leftovers (2).
+cat > "$expected_file" <<END
+TestSourceA: ${trace}
+TestSourceB: ${debug}
+END
+
+bt_diff_cli_sorted "$expected_file" "$stderr_expected" \
+ convert --plugin-path "${plugin_dir}" \
+ "${dir_ab}" --log-level DEBUG ${print_log_level} "${dir_a}" --log-level TRACE ${print_log_level}
+ok "$?" "apply log level to one component coming from one leftover and one component coming from two leftovers (2)"
+
+rm -f "$expected_file"
plan_tests $NUM_TESTS
-data_dir="${BT_TESTS_DATADIR}/cli/convert/auto-source-discovery-params"
+data_dir="${BT_TESTS_DATADIR}/cli/convert/auto-source-discovery-params-log-level"
plugin_dir="${data_dir}"
dir_a="${data_dir}/dir-a"
dir_b="${data_dir}/dir-b"
expected_file=$(mktemp -t expected.XXXXXX)
stderr_expected=/dev/null
+print_test_params="--params print=\"test-params\""
+
# Apply params to two components from one leftover.
cat > "$expected_file" <<END
TestSourceA: ('test-allo', 'madame')
bt_diff_cli_sorted "$expected_file" "$stderr_expected" \
convert --plugin-path "${plugin_dir}" \
- "${dir_ab}" --params 'test-allo="madame"'
+ "${dir_ab}" --params 'test-allo="madame"' ${print_test_params}
ok "$?" "apply params to two components from one leftover"
# Apply params to two components from two distinct leftovers.
bt_diff_cli_sorted "$expected_file" "$stderr_expected" \
convert --plugin-path "${plugin_dir}" \
- "${dir_a}" --params 'test-allo="madame"' "${dir_b}" --params 'test-bonjour="monsieur"'
+ "${dir_a}" --params 'test-allo="madame"' ${print_test_params} "${dir_b}" --params 'test-bonjour="monsieur"' ${print_test_params}
ok "$?" "apply params to two leftovers"
# Apply params to one component coming from one leftover and one component coming from two leftovers (1).
bt_diff_cli_sorted "$expected_file" "$stderr_expected" \
convert --plugin-path "${plugin_dir}" \
- "${dir_a}" --params 'test-allo="madame"' "${dir_ab}" --params 'test-bonjour="monsieur"'
+ "${dir_a}" --params 'test-allo="madame"' ${print_test_params} "${dir_ab}" --params 'test-bonjour="monsieur"' ${print_test_params}
ok "$?" "apply params to one component coming from one leftover and one component coming from two leftovers (1)"
# Apply params to one component coming from one leftover and one component coming from two leftovers (2).
bt_diff_cli_sorted "$expected_file" "$stderr_expected" \
convert --plugin-path "${plugin_dir}" \
- "${dir_ab}" --params 'test-bonjour="madame",test-salut="les amis"' "${dir_a}" --params 'test-bonjour="monsieur"'
+ "${dir_ab}" --params 'test-bonjour="madame",test-salut="les amis"' ${print_test_params} "${dir_a}" --params 'test-bonjour="monsieur"' ${print_test_params}
ok "$?" "apply params to one component coming from one leftover and one component coming from two leftovers (2)"
rm -f "$expected_file"
output_path=$(cygpath -m "$output_path")
fi
-plan_tests 73
+plan_tests 71
test_bt_convert_run_args 'path leftover' "$path_to_trace" "--component auto-disc-source-ctf-fs:source.ctf.fs --params 'inputs=[\"$path_to_trace\"]' --component pretty:sink.text.pretty --component muxer:filter.utils.muxer --connect auto-disc-source-ctf-fs:muxer --connect muxer:pretty"
test_bt_convert_run_args 'path leftovers' "$path_to_trace $path_to_trace2" "--component auto-disc-source-ctf-fs:source.ctf.fs --params 'inputs=[\"$path_to_trace\", \"${path_to_trace2}\"]' --component pretty:sink.text.pretty --component muxer:filter.utils.muxer --connect auto-disc-source-ctf-fs:muxer --connect muxer:pretty"
test_bt_convert_fails '-o ctf without --output' 'my-trace -o ctf'
test_bt_convert_fails '-o ctf + --output with implicit sink.text.pretty' "my-trace -o ctf --output $output_path --no-delta"
test_bt_convert_fails '--stream-intersection' "$path_to_trace --stream-intersection"
-test_bt_convert_fails '--log-level after leftover' "--component src.ctf.fs $path_to_trace --log-level=W" 'No current component (--component option) to assign a log level to'
rm -f "${tmp_stderr}"
--- /dev/null
+import bt2
+import os
+
+# This file defines source component classes that can print (depending the on
+# the `print` param):
+#
+# - Parameter names and values, for parameter whose name starts with `test-`.
+# - Component log levels as integers
+
+
+class TestIter(bt2._UserMessageIterator):
+ pass
+
+
+class Base:
+ @classmethod
+ def _print_test_params(cls, params):
+ items = sorted([str(x) for x in params.items() if x[0].startswith('test-')])
+ print('{}: {}'.format(cls.__name__, ', '.join(items)))
+
+ def _print_log_level(self):
+ cls_name = self.__class__.__name__
+ log_level = self.logging_level
+ print('{}: {}'.format(cls_name, log_level))
+
+ def _print_info(self, params):
+ what = params['print']
+ if what == 'test-params':
+ self._print_test_params(params)
+ elif what == 'log-level':
+ self._print_log_level()
+ else:
+ assert False
+
+
+@bt2.plugin_component_class
+class TestSourceA(Base, bt2._UserSourceComponent, message_iterator_class=TestIter):
+ def __init__(self, params):
+ self._print_info(params)
+
+ @staticmethod
+ def _user_query(priv_query_exec, obj, params):
+ # Match files starting with 'aaa'.
+
+ if obj == 'babeltrace.support-info':
+ if params['type'] != 'file':
+ return 0
+
+ name = os.path.basename(str(params['input']))
+
+ if name.startswith('aaa'):
+ return {'weight': 1, 'group': 'aaa'}
+ else:
+ return 0
+ else:
+ raise bt2.UnknownObject
+
+
+@bt2.plugin_component_class
+class TestSourceB(Base, bt2._UserSourceComponent, message_iterator_class=TestIter):
+ def __init__(self, params):
+ self._print_info(params)
+
+ @staticmethod
+ def _user_query(priv_query_exec, obj, params):
+ # Match files starting with 'bbb'.
+
+ if obj == 'babeltrace.support-info':
+ if params['type'] != 'file':
+ return 0
+
+ name = os.path.basename(str(params['input']))
+
+ if name.startswith('bbb'):
+ return {'weight': 1, 'group': 'bbb'}
+ else:
+ return 0
+ else:
+ raise bt2.UnknownObject
+
+
+bt2.register_plugin(module_name=__name__, name="test")
+++ /dev/null
-import bt2
-import os
-
-# This file defines source component classes that print the parameters they
-# receive in their __init__ which start with 'test-'.
-
-
-class TestIter(bt2._UserMessageIterator):
- pass
-
-
-class Base:
- @classmethod
- def _print_test_params(cls, params):
- items = sorted([str(x) for x in params.items() if x[0].startswith('test-')])
- print('{}: {}'.format(cls.__name__, ', '.join(items)))
-
-
-@bt2.plugin_component_class
-class TestSourceA(Base, bt2._UserSourceComponent, message_iterator_class=TestIter):
- def __init__(self, params):
- self._print_test_params(params)
-
- @staticmethod
- def _user_query(priv_query_exec, obj, params):
- # Match files starting with 'aaa'.
-
- if obj == 'babeltrace.support-info':
- if params['type'] != 'file':
- return 0
-
- name = os.path.basename(str(params['input']))
-
- if name.startswith('aaa'):
- return {'weight': 1, 'group': 'aaa'}
- else:
- return 0
- else:
- raise bt2.UnknownObject
-
-
-@bt2.plugin_component_class
-class TestSourceB(Base, bt2._UserSourceComponent, message_iterator_class=TestIter):
- def __init__(self, params):
- self._print_test_params(params)
-
- @staticmethod
- def _user_query(priv_query_exec, obj, params):
- # Match files starting with 'bbb'.
-
- if obj == 'babeltrace.support-info':
- if params['type'] != 'file':
- return 0
-
- name = os.path.basename(str(params['input']))
-
- if name.startswith('bbb'):
- return {'weight': 1, 'group': 'bbb'}
- else:
- return 0
- else:
- raise bt2.UnknownObject
-
-
-bt2.register_plugin(module_name=__name__, name="test")