All of lore.kernel.org
 help / color / mirror / Atom feed
From: Elizabeth Ashurov <eashurov@redhat.com>
To: qemu-devel@nongnu.org
Cc: berrange@redhat.com, kkostiuk@redhat.com, yvugenfi@redhat.com,
	Elizabeth Ashurov <eashurov@redhat.com>
Subject: [PATCH v2 2/2] qga: add --audit option for command logging control
Date: Wed, 18 Mar 2026 17:47:52 +0200	[thread overview]
Message-ID: <20260318154752.1880933-2-eashurov@redhat.com> (raw)
In-Reply-To: <20260318154752.1880933-1-eashurov@redhat.com>

Add -A/--audit=LIST option to control which guest agent commands
are logged at info level (visible with --verbose) and which at
debug level (visible only with --debug).

Patterns are comma-separated and checked in order; the first match
wins. Patterns starting with '!' log the command at debug level
instead of info.
For example: --audit=!guest-ping,* logs all commands
at info level except guest-ping.

Move command logging from individual handlers into process_event()
so all commands are logged in one place. Keep g_debug() calls in
handlers for useful details like file paths, handles, and PIDs.

The default pattern is '*', so all commands are logged at info
level unless configured otherwise.

Signed-off-by: Elizabeth Ashurov <eashurov@redhat.com>
---
 qga/commands-linux.c |  2 --
 qga/commands-posix.c | 11 +++----
 qga/commands-win32.c | 14 +++------
 qga/commands.c       |  6 ++--
 qga/main.c           | 73 ++++++++++++++++++++++++++++++++++++++++++--
 5 files changed, 81 insertions(+), 25 deletions(-)

diff --git a/qga/commands-linux.c b/qga/commands-linux.c
index a722de2e6a..8df83963fa 100644
--- a/qga/commands-linux.c
+++ b/qga/commands-linux.c
@@ -1158,8 +1158,6 @@ qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
     int fd;
     struct fstrim_range r;
 
-    g_info("guest-fstrim called");
-
     QTAILQ_INIT(&mounts);
     if (!build_fs_mount_list(&mounts, errp)) {
         return NULL;
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 96939a6f36..6a3e6c78e3 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -240,7 +240,7 @@ void qmp_guest_shutdown(const char *mode, Error **errp)
     const char *reboot_flag = "-r";
 #endif
 
-    g_info("guest-shutdown called, mode: %s", mode);
+    g_debug("guest-shutdown mode: %s", mode);
     if (!mode || strcmp(mode, "powerdown") == 0) {
         if (access(POWEROFF_CMD_PATH, X_OK) == 0) {
             shutdown_cmd = POWEROFF_CMD_PATH;
@@ -519,7 +519,7 @@ int64_t qmp_guest_file_open(const char *path, const char *mode,
     if (!mode) {
         mode = "r";
     }
-    g_info("guest-file-open called, filepath: %s, mode: %s", path, mode);
+    g_debug("guest-file-open filepath: %s, mode: %s", path, mode);
     fh = safe_open_or_create(path, mode, &local_err);
     if (local_err != NULL) {
         error_propagate(errp, local_err);
@@ -540,7 +540,7 @@ int64_t qmp_guest_file_open(const char *path, const char *mode,
         return -1;
     }
 
-    g_info("guest-file-open, handle: %" PRId64, handle);
+    g_debug("guest-file-open handle: %" PRId64, handle);
     return handle;
 }
 
@@ -549,7 +549,7 @@ void qmp_guest_file_close(int64_t handle, Error **errp)
     GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
     int ret;
 
-    g_info("guest-file-close called, handle: %" PRId64, handle);
+    g_debug("guest-file-close handle: %" PRId64, handle);
     if (!gfh) {
         return;
     }
@@ -793,8 +793,6 @@ int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints,
     FsMountList mounts;
     Error *local_err = NULL;
 
-    g_info("guest-fsfreeze called");
-
     execute_fsfreeze_hook(FSFREEZE_HOOK_FREEZE, &local_err);
     if (local_err) {
         error_propagate(errp, local_err);
@@ -833,7 +831,6 @@ int64_t qmp_guest_fsfreeze_thaw(Error **errp)
 
     if (ret >= 0) {
         ga_unset_frozen(ga_state);
-        g_info("guest-fsthaw called");
         execute_fsfreeze_hook(FSFREEZE_HOOK_THAW, errp);
     } else {
         ret = 0;
diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index d26b0041ce..e916d081f5 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -231,7 +231,7 @@ int64_t qmp_guest_file_open(const char *path, const char *mode, Error **errp)
     if (!mode) {
         mode = "r";
     }
-    g_info("guest-file-open called, filepath: %s, mode: %s", path, mode);
+    g_debug("guest-file-open filepath: %s, mode: %s", path, mode);
     guest_flags = find_open_flag(mode);
     if (guest_flags == NULL) {
         error_setg(errp, "invalid file open mode");
@@ -267,8 +267,7 @@ int64_t qmp_guest_file_open(const char *path, const char *mode, Error **errp)
         goto done;
     }
 
-    g_info("guest-file-open, handle: % " PRId64, fd);
-
+    g_debug("guest-file-open handle: %" PRId64, fd);
 done:
     g_free(w_path);
     return fd;
@@ -278,7 +277,7 @@ void qmp_guest_file_close(int64_t handle, Error **errp)
 {
     bool ret;
     GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
-    g_info("guest-file-close called, handle: %" PRId64, handle);
+    g_debug("guest-file-close handle: %" PRId64, handle);
     if (gfh == NULL) {
         return;
     }
@@ -337,8 +336,7 @@ void qmp_guest_shutdown(const char *mode, Error **errp)
     Error *local_err = NULL;
     UINT shutdown_flag = EWX_FORCE;
 
-    g_info("guest-shutdown called, mode: %s", mode);
-
+    g_debug("guest-shutdown mode: %s", mode);
     if (!mode || strcmp(mode, "powerdown") == 0) {
         shutdown_flag |= EWX_POWEROFF;
     } else if (strcmp(mode, "halt") == 0) {
@@ -1255,8 +1253,6 @@ int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints,
         return 0;
     }
 
-    g_info("guest-fsfreeze called");
-
     /* cannot risk guest agent blocking itself on a write in this state */
     ga_set_frozen(ga_state);
 
@@ -1294,8 +1290,6 @@ int64_t qmp_guest_fsfreeze_thaw(Error **errp)
 
     ga_unset_frozen(ga_state);
 
-    g_info("guest-fsthaw called");
-
     return i;
 }
 
diff --git a/qga/commands.c b/qga/commands.c
index 55edd9fd4c..4462922005 100644
--- a/qga/commands.c
+++ b/qga/commands.c
@@ -43,7 +43,6 @@ int64_t qmp_guest_sync(int64_t id, Error **errp)
 
 void qmp_guest_ping(Error **errp)
 {
-    g_info("guest-ping called");
 }
 
 static void qmp_command_info(const QmpCommand *cmd, void *opaque)
@@ -136,8 +135,7 @@ GuestExecStatus *qmp_guest_exec_status(int64_t pid, Error **errp)
     GuestExecInfo *gei;
     GuestExecStatus *ges;
 
-    g_info("guest-exec-status called, pid: %u", (uint32_t)pid);
-
+    g_debug("guest-exec-status pid: %u", (uint32_t)pid);
     gei = guest_exec_info_find(pid);
     if (gei == NULL) {
         error_setg(errp, "PID " PRId64 " does not exist");
@@ -238,7 +236,7 @@ static char **guest_exec_get_args(const strList *entry, bool log)
     args[i] = NULL;
 
     if (log) {
-        g_info("guest-exec called: \"%s\"", str);
+        g_debug("guest-exec called: \"%s\"", str);
     }
     g_free(str);
 
diff --git a/qga/main.c b/qga/main.c
index 04c772b680..5b289ae7f9 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -87,8 +87,10 @@ struct GAConfig {
 #endif
     gchar *bliststr; /* blockedrpcs may point to this string */
     gchar *aliststr; /* allowedrpcs may point to this string */
+    gchar *auditstr;
     GList *blockedrpcs;
     GList *allowedrpcs;
+    GList *audit_patterns;
     int daemonize;
     GLogLevelFlags log_level;
     int dumpconf;
@@ -116,6 +118,7 @@ struct GAState {
     bool frozen;
     GList *blockedrpcs;
     GList *allowedrpcs;
+    GList *audit_patterns;
     char *state_filepath_isfrozen;
     struct {
         const char *log_filepath;
@@ -288,6 +291,11 @@ QEMU_COPYRIGHT "\n"
 "                    only, default is %s)\n"
 "  -v, --verbose     enable verbose logging (warning/info and above)\n"
 "  -g, --debug       enable debug logging (all messages)\n"
+"  -A, --audit=LIST  comma-separated list of command patterns to log at\n"
+"                    info level (default: *, no spaces).\n"
+"                    Patterns prefixed with '!' are logged at debug level.\n"
+"                    Patterns are evaluated in order; the first match wins.\n"
+"                    Example: --audit=!guest-ping,*\n"
 "  -V, --version     print version information and exit\n"
 "  -d, --daemonize   become a daemon\n"
 #ifdef _WIN32
@@ -413,6 +421,29 @@ static void ga_log(const gchar *domain, GLogLevelFlags level,
     }
 }
 
+static void ga_audit_log(GAState *s, const char *command)
+{
+    GList *l;
+
+    for (l = s->audit_patterns; l; l = l->next) {
+        const char *pattern = l->data;
+
+        if (pattern[0] == '!') {
+            if (g_pattern_match_simple(pattern + 1, command)) {
+                g_debug("%s called", command);
+                return;
+            }
+        } else {
+            if (g_pattern_match_simple(pattern, command)) {
+                g_info("%s called", command);
+                return;
+            }
+        }
+    }
+
+    g_debug("%s called", command);
+}
+
 void ga_set_response_delimited(GAState *s)
 {
     s->delimit_response = true;
@@ -706,7 +737,22 @@ static void process_event(void *opaque, QObject *obj, Error *err)
     }
 
     g_debug("processing command");
-    rsp = qmp_dispatch(&ga_commands, obj, false, NULL);
+    {
+        QDict *dict = qobject_to(QDict, obj);
+        const char *command = dict ? qdict_get_try_str(dict, "execute") : NULL;
+        bool logging_before = ga_logging_enabled(s);
+        bool audit = command && qmp_find_command(&ga_commands, command);
+
+        if (audit) {
+            ga_audit_log(s, command);
+        }
+
+        rsp = qmp_dispatch(&ga_commands, obj, false, NULL);
+
+        if (!logging_before && audit) {
+            ga_audit_log(s, command);
+        }
+    }
 
 end:
     ret = send_response(s, rsp);
@@ -1158,6 +1204,14 @@ static void config_load(GAConfig *config, const char *confpath, bool required)
         config->retry_path =
             g_key_file_get_boolean(keyfile, "general", "retry-path", &gerr);
     }
+    if (g_key_file_has_key(keyfile, "general", "audit", NULL)) {
+        config->auditstr =
+            g_key_file_get_string(keyfile, "general", "audit", &gerr);
+        config->audit_patterns = g_list_concat(config->audit_patterns,
+                                               g_list_reverse(
+                                                   split_list(config->auditstr,
+                                                              ",")));
+    }
 
     if (g_key_file_has_key(keyfile, "general", "block-rpcs", NULL)) {
         config->bliststr =
@@ -1230,6 +1284,9 @@ static void config_dump(GAConfig *config)
                            config->log_level & G_LOG_LEVEL_DEBUG);
     g_key_file_set_boolean(keyfile, "general", "retry-path",
                            config->retry_path);
+    tmp = list_join(config->audit_patterns, ',');
+    g_key_file_set_string(keyfile, "general", "audit", tmp);
+    g_free(tmp);
     tmp = list_join(config->blockedrpcs, ',');
     g_key_file_set_string(keyfile, "general", "block-rpcs", tmp);
     g_free(tmp);
@@ -1251,7 +1308,7 @@ static void config_dump(GAConfig *config)
 
 static void config_parse(GAConfig *config, int argc, char **argv)
 {
-    const char *sopt = "hVvdgc:m:p:l:f:F::b:a:s:t:Dr";
+    const char *sopt = "hVvdgc:m:p:l:f:F::b:a:A:s:t:Dr";
     int opt_ind = 0, ch;
     const struct option lopt[] = {
         { "help", 0, NULL, 'h' },
@@ -1270,6 +1327,7 @@ static void config_parse(GAConfig *config, int argc, char **argv)
         { "daemonize", 0, NULL, 'd' },
         { "block-rpcs", 1, NULL, 'b' },
         { "allow-rpcs", 1, NULL, 'a' },
+        { "audit", 1, NULL, 'A' },
 #ifdef _WIN32
         { "service", 1, NULL, 's' },
 #endif
@@ -1363,6 +1421,10 @@ static void config_parse(GAConfig *config, int argc, char **argv)
                                                 split_list(optarg, ","));
             break;
         }
+        case 'A':
+            g_list_free_full(config->audit_patterns, g_free);
+            config->audit_patterns = g_list_reverse(split_list(optarg, ","));
+            break;
 #ifdef _WIN32
         case 's':
             config->service = optarg;
@@ -1417,6 +1479,8 @@ static void config_free(GAConfig *config)
 #endif
     g_list_free_full(config->blockedrpcs, g_free);
     g_list_free_full(config->allowedrpcs, g_free);
+    g_list_free_full(config->audit_patterns, g_free);
+    g_free(config->auditstr);
     g_free(config);
 }
 
@@ -1460,6 +1524,7 @@ static GAState *initialize_agent(GAConfig *config, int socket_activation)
     g_assert(ga_state == NULL);
 
     s->log_level = config->log_level;
+    s->audit_patterns = config->audit_patterns;
     s->log_file = stderr;
 #ifdef CONFIG_FSFREEZE
     s->fsfreeze_hook = config->fsfreeze_hook;
@@ -1698,6 +1763,10 @@ int main(int argc, char **argv)
     init_dfl_pathnames();
     config_parse(config, argc, argv);
 
+    if (config->audit_patterns == NULL) {
+        config->audit_patterns = g_list_append(NULL, g_strdup("*"));
+    }
+
     if (config->pid_filepath == NULL) {
         config->pid_filepath = g_strdup(dfl_pathnames.pidfile);
     }
-- 
2.51.0



  reply	other threads:[~2026-03-18 15:49 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-12 14:16 [PATCH v1] qga: rework slog to support multiple severity levels Elizabeth Ashurov
     [not found] ` <abLVj2eLZmKbPs9J@redhat.com>
     [not found]   ` <CAPMcbCq4i8DhwRqPkJxywt6H==NRW=3_7NA0ZQhe8cMFtVGRCA@mail.gmail.com>
2026-03-12 15:36     ` Daniel P. Berrangé
2026-03-18 16:13       ` Elizabeth Ashurov
2026-03-18 15:47 ` [PATCH v2 1/2] qga: replace slog() with standard GLib logging Elizabeth Ashurov
2026-03-18 15:47   ` Elizabeth Ashurov [this message]
2026-03-23 13:46     ` [PATCH v2 2/2] qga: add --audit option for command logging control Kostiantyn Kostiuk
2026-03-24 14:08       ` Elizabeth Ashurov
2026-03-24 14:18         ` Kostiantyn Kostiuk
2026-03-20 12:58   ` [PATCH v2 1/2] qga: replace slog() with standard GLib logging Daniel P. Berrangé
2026-03-24 14:15     ` Elizabeth Ashurov
2026-03-24 18:02   ` Daniel P. Berrangé

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260318154752.1880933-2-eashurov@redhat.com \
    --to=eashurov@redhat.com \
    --cc=berrange@redhat.com \
    --cc=kkostiuk@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=yvugenfi@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.