@samitouri / QOSamiQemu / commits / f606321be8

tests/qtest: Individual verbose switches

Allow logging to be set for specific parts of QTest. Having a single QTEST_LOG knob creates an output stream that is almost useless due to spamming from some operations. Add a backward-compatible way of selecting which parts will be made verbose. Reuse the existing QTEST_LOG variable. The new options are: QTEST_LOG= fuzz - fuzz.c qga - unit/test-qga.c qmp - libqmp.c qtest - QTest device, i.e. -qtest-log option test - generic term for usage of all tests E.g.: QTEST_LOG=fuzz,qga,qmp,qtest,test equivalent to QTEST_LOG=1 QTEST_LOG=qmp,qtest enables logging of qmp operations from libqmp.c and logging of the qtest device. QTEST_LOG=test,qmp enable test output and libqmp.c output. QTEST_LOG=-qmp enable all output, except for libqmp.c Acked-by: Peter Xu <peterx@redhat.com> Link: https://lore.kernel.org/qemu-devel/20260429003130.15164-3-farosas@suse.de Signed-off-by: Fabiano Rosas <farosas@suse.de>

Fabiano Rosas committed Apr 28, 2026 at 21:31 UTC f606321be88c8af4a22b1105f4621bb4a790a6ba
10 files changed +82 -14
tests/qtest/fuzz/fuzz.c
+4 -3
@@ -105,7 +105,7 @@ static void usage(char *path)
105 "Set the environment variable FUZZ_SERIALIZE_QTEST=1 to serialize\n"
106 "QTest commands into an ASCII protocol. Useful for building crash\n"
107 "reproducers, but slows down execution.\n\n"
108 - "Set the environment variable QTEST_LOG=1 to log all qtest commands"
108 + "Set the environment variable QTEST_LOG=fuzz to log all qtest commands"
109 "\n");
110 exit(0);
111 }
@@ -168,6 +168,7 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp)
168 GString *cmd_line;
169 gchar *pretty_cmd_line;
170 bool serialize = false;
171 + bool verbose = qtest_verbose("fuzz");
172
173 /* Initialize qgraph and modules */
174 qos_graph_init();
@@ -211,14 +212,14 @@ int LLVMFuzzerInitialize(int *argc, char ***argv, char ***envp)
212 /* Run QEMU's system main with the fuzz-target dependent arguments */
213 cmd_line = fuzz_target->get_init_cmdline(fuzz_target);
214 g_string_append_printf(cmd_line, " %s -qtest /dev/null ",
214 - getenv("QTEST_LOG") ? "" : "-qtest-log none");
215 + verbose ? "" : "-qtest-log none");
216
217 /* Split the runcmd into an argv and argc */
218 wordexp_t result;
219 wordexp(cmd_line->str, &result, 0);
220 g_string_free(cmd_line, true);
221
221 - if (getenv("QTEST_LOG")) {
222 + if (verbose) {
223 pretty_cmd_line = g_strjoinv(" ", result.we_wordv + 1);
224 printf("Starting %s with Arguments: %s\n",
225 result.we_wordv[0], pretty_cmd_line);
tests/qtest/fuzz/generic_fuzz.c
+1 -1
@@ -776,7 +776,7 @@ static void generic_pre_fuzz(QTestState *s)
776 if (!getenv("QEMU_FUZZ_OBJECTS")) {
777 usage();
778 }
779 - if (getenv("QTEST_LOG")) {
779 + if (qtest_verbose("fuzz")) {
780 qtest_log_enabled = 1;
781 }
782 if (getenv("QEMU_AVOID_DOUBLE_FETCH")) {
tests/qtest/libqmp.c
+4 -3
@@ -17,6 +17,7 @@
17 #include "qemu/osdep.h"
18
19 #include "libqmp.h"
20 +#include "libqtest.h"
21
22 #ifndef _WIN32
23 #include <sys/socket.h>
@@ -62,7 +63,7 @@ static void qmp_response(void *opaque, QObject *obj, Error *err)
63 QDict *qmp_fd_receive(int fd)
64 {
65 QMPResponseParser qmp;
65 - bool log = getenv("QTEST_LOG") != NULL;
66 + bool log = qtest_verbose("qmp");
67
68 qmp.response = NULL;
69 json_message_parser_init(&qmp.parser, qmp_response, &qmp, NULL);
@@ -149,7 +150,7 @@ _qmp_fd_vsend_fds(int fd, int *fds, size_t fds_num,
150
151 /* No need to send anything for an empty QObject. */
152 if (qobj) {
152 - int log = getenv("QTEST_LOG") != NULL;
153 + bool log = qtest_verbose("qmp");
154 GString *str = qobject_to_json(qobj);
155
156 /*
@@ -220,7 +221,7 @@ void qmp_fd_send(int fd, const char *fmt, ...)
221
222 void qmp_fd_vsend_raw(int fd, const char *fmt, va_list ap)
223 {
223 - bool log = getenv("QTEST_LOG") != NULL;
224 + bool log = qtest_verbose("qmp");
225 char *str = g_strdup_vprintf(fmt, ap);
226
227 if (log) {
tests/qtest/libqtest.c
+55 -1
@@ -469,7 +469,7 @@ gchar *qtest_qemu_args(const char *extra_args)
469 "-accel qtest",
470
471 socket_path,
472 - getenv("QTEST_LOG") ? DEV_STDERR : DEV_NULL,
472 + qtest_verbose("qtest") ? DEV_STDERR : DEV_NULL,
473 qmp_socket_path,
474 can_exit_with_parent() ?
475 "-run-with exit-with-parent=on" : "",
@@ -2142,3 +2142,57 @@ bool mkimg(const char *file, const char *fmt, unsigned size_mb)
2142
2143 return ret && !err;
2144 }
2145 +
2146 +bool qtest_verbose(const char *domain)
2147 +{
2148 + const char *log = getenv("QTEST_LOG");
2149 + char *found;
2150 +
2151 + assert(domain);
2152 +
2153 + if (log) {
2154 + /*
2155 + * verbose=true for all domains if:
2156 + * QTEST_LOG=
2157 + * QTEST_LOG=1
2158 + * other one-character variations
2159 + */
2160 + if (log[0] == '\0' || log[1] == '\0') {
2161 + return true;
2162 + }
2163 +
2164 + /*
2165 + * verbose=true for specified domains if:
2166 + * QTEST_LOG=<domain>
2167 + * QTEST_LOG=<domain1>,<domain2>
2168 + * allows other separators, except - and +
2169 + *
2170 + * verbose=false for specified domains if:
2171 + * QTEST_LOG=-<domain>
2172 + * QTEST_LOG=<domain1>,-<domain2> (only false for domain2)
2173 + * allows other separators, except - and +
2174 + */
2175 + found = strstr(log, domain);
2176 +
2177 + if (found) {
2178 + /* reject options given twice */
2179 + assert(!strstr(found + strlen(domain), domain));
2180 +
2181 + if (found > log) {
2182 + ptrdiff_t i = found - log - 1;
2183 + if (log[i] == '-') {
2184 + return false;
2185 + }
2186 + }
2187 + return true;
2188 + } else {
2189 + /*
2190 + * If filtering out a specific domain, all others are
2191 + * enabled.
2192 + */
2193 + return !!strstr(log, "-");
2194 + }
2195 + }
2196 +
2197 + return false;
2198 +}
tests/qtest/libqtest.h
+11
@@ -1178,4 +1178,15 @@ bool have_qemu_img(void);
1178 */
1179 bool mkimg(const char *file, const char *fmt, unsigned size_mb);
1180
1181 +/**
1182 + * qtest_verbose:
1183 + * @domain: The logging domain
1184 + *
1185 + * Read the QTEST_LOG environment variable and return whether the
1186 + * specified domain is enabled for verbose logging. Enable specific
1187 + * logging domains with QTEST_LOG=<domain> or use QTEST_LOG=-<domain> to
1188 + * enable all domains except for the specific one.
1189 + */
1190 +bool qtest_verbose(const char *domain);
1191 +
1192 #endif
tests/qtest/migration/framework.c
+1 -1
@@ -365,7 +365,7 @@ int migrate_args(char **from, char **to, const char *uri, MigrateStart *args)
365 g_assert_not_reached();
366 }
367
368 - if (!getenv("QTEST_LOG") && args->hide_stderr) {
368 + if (!qtest_verbose("test") && args->hide_stderr) {
369 #ifndef _WIN32
370 ignore_stderr = "2>/dev/null";
371 #else
tests/qtest/migration/framework.h
+3 -2
@@ -118,8 +118,9 @@ typedef void (*TestMigrateEndHook)(QTestState *from,
118 */
119 typedef struct {
120 /*
121 - * QTEST_LOG=1 may override this. When QTEST_LOG=1, we always dump errors
122 - * unconditionally, because it means the user would like to be verbose.
121 + * QTEST_LOG=test may override this in which case we dump errors
122 + * unconditionally, because it means the user would like to be
123 + * verbose.
124 */
125 bool hide_stderr;
126 MemType mem_type;
tests/qtest/migration/precopy-tests.c
+1 -1
@@ -130,7 +130,7 @@ static bool mlock_check(void)
130 static int new_rdma_link(char *buffer, bool ipv6)
131 {
132 char cmd[256];
133 - bool verbose = g_getenv("QTEST_LOG");
133 + bool verbose = qtest_verbose("test");
134
135 snprintf(cmd, sizeof(cmd), "IP_FAMILY=%s %s detect %s",
136 ipv6 ? "ipv6" : "ipv4", RDMA_MIGRATION_HELPER,
tests/unit/meson.build
+1 -1
@@ -161,7 +161,7 @@ if have_system
161 endif
162
163 if have_ga and host_os == 'linux'
164 - tests += {'test-qga': ['../qtest/libqmp.c']}
164 + tests += {'test-qga': ['../qtest/libqmp.c', '../qtest/libqtest.c']}
165 test_deps += {'test-qga': qga}
166 endif
167
tests/unit/test-qga.c
+1 -1
@@ -68,7 +68,7 @@ fixture_setup(TestFixture *fixture, gconstpointer data, gchar **envp)
68 cmd = g_strdup_printf("%s%cqga%cqemu-ga -m unix-listen -t %s -p %s %s %s",
69 cwd, G_DIR_SEPARATOR, G_DIR_SEPARATOR,
70 fixture->test_dir, path,
71 - getenv("QTEST_LOG") ? "-v" : "",
71 + qtest_verbose("qga") ? "-v" : "",
72 extra_arg ?: "");
73 g_shell_parse_argv(cmd, NULL, &argv, &error);
74 g_assert_no_error(error);