diff mbox series

[v2,27/39] util/log: Introduce qemu_set_log_filename_flags

Message ID 20220326132534.543738-36-richard.henderson@linaro.org
State Superseded
Headers show
Series Logging cleanup and per-thread logfiles | expand

Commit Message

Richard Henderson March 26, 2022, 1:25 p.m. UTC
Provide a function to set both filename and flags at
the same time.  This is the common case at startup.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
v2: Return bool, per recommendations in qapi/error.h (phil).
---
 include/qemu/log.h |   1 +
 util/log.c         | 122 ++++++++++++++++++++++++++++-----------------
 2 files changed, 77 insertions(+), 46 deletions(-)

Comments

Alex Bennée April 14, 2022, 2:56 p.m. UTC | #1
Richard Henderson <richard.henderson@linaro.org> writes:

> Provide a function to set both filename and flags at
> the same time.  This is the common case at startup.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
> v2: Return bool, per recommendations in qapi/error.h (phil).
> ---
>  include/qemu/log.h |   1 +
>  util/log.c         | 122 ++++++++++++++++++++++++++++-----------------
>  2 files changed, 77 insertions(+), 46 deletions(-)
>
> diff --git a/include/qemu/log.h b/include/qemu/log.h
> index 42d545f77a..b6c73376b5 100644
> --- a/include/qemu/log.h
> +++ b/include/qemu/log.h
> @@ -82,6 +82,7 @@ extern const QEMULogItem qemu_log_items[];
>  
>  bool qemu_set_log(int log_flags, Error **errp);
>  bool qemu_set_log_filename(const char *filename, Error **errp);
> +bool qemu_set_log_filename_flags(const char *name, int flags, Error **errp);
>  void qemu_set_dfilter_ranges(const char *ranges, Error **errp);
>  bool qemu_log_in_addr_range(uint64_t addr);
>  int qemu_str_to_log_mask(const char *str);
> diff --git a/util/log.c b/util/log.c
> index 8b8b6a5d83..2152d5591e 100644
> --- a/util/log.c
> +++ b/util/log.c
> @@ -117,15 +117,58 @@ static void qemu_logfile_free(QemuLogFile *logfile)
>  }
>  
>  /* enable or disable low levels log */
> -bool qemu_set_log(int log_flags, Error **errp)
> +static bool qemu_set_log_internal(const char *filename, bool changed_name,
> +                                  int log_flags, Error **errp)
>  {
> -    bool need_to_open_file = false;
> +    bool need_to_open_file;
>      QemuLogFile *logfile;
>  
> -    qemu_loglevel = log_flags;
> +    QEMU_LOCK_GUARD(&qemu_logfile_mutex);
> +    logfile = qemu_logfile;
> +
> +    if (changed_name) {
> +        char *newname = NULL;
> +
> +        /*
> +         * Allow the user to include %d in their logfile which will be
> +         * substituted with the current PID. This is useful for debugging many
> +         * nested linux-user tasks but will result in lots of logs.
> +         *
> +         * filename may be NULL. In that case, log output is sent to stderr
> +         */
> +        if (filename) {
> +            char *pidstr = strstr(filename, "%");
> +
> +            if (pidstr) {
> +                /* We only accept one %d, no other format strings */
> +                if (pidstr[1] != 'd' || strchr(pidstr + 2, '%')) {
> +                    error_setg(errp, "Bad logfile format: %s", filename);
> +                    return false;
> +                }
> +                newname = g_strdup_printf(filename, getpid());
> +            } else {
> +                newname = g_strdup(filename);
> +            }
> +        }
> +
> +        g_free(logfilename);
> +        logfilename = newname;
> +        filename = newname;
> +
> +        if (logfile) {
> +            qatomic_rcu_set(&qemu_logfile, NULL);
> +            call_rcu(logfile, qemu_logfile_free, rcu);
> +            logfile = NULL;
> +        }
> +    } else {
> +        filename = logfilename;
> +    }
> +
>  #ifdef CONFIG_TRACE_LOG
> -    qemu_loglevel |= LOG_TRACE;
> +    log_flags |= LOG_TRACE;
>  #endif
> +    qemu_loglevel = log_flags;
> +

This looked weird - so should we consider a qatomic_set here to avoid an
inconsistent set of flags being read non-atomically elsewhere?

>      /*
>       * In all cases we only log if qemu_loglevel is set.
>       * Also:
> @@ -134,71 +177,58 @@ bool qemu_set_log(int log_flags, Error **errp)
>       *   If we are daemonized,
>       *     we will only log if there is a logfilename.
>       */
> -    if (qemu_loglevel && (!is_daemonized() || logfilename)) {
> -        need_to_open_file = true;
> -    }
> -    QEMU_LOCK_GUARD(&qemu_logfile_mutex);
> -    if (qemu_logfile && !need_to_open_file) {
> -        logfile = qemu_logfile;
> +    need_to_open_file = log_flags && (!is_daemonized() || filename);
> +
> +    if (logfile && !need_to_open_file) {
>          qatomic_rcu_set(&qemu_logfile, NULL);
>          call_rcu(logfile, qemu_logfile_free, rcu);
> -    } else if (!qemu_logfile && need_to_open_file) {
> -        logfile = g_new0(QemuLogFile, 1);
> -        if (logfilename) {
> -            logfile->fd = fopen(logfilename, log_append ? "a" : "w");
> -            if (!logfile->fd) {
> +        return true;
> +    }
> +    if (!logfile && need_to_open_file) {
> +        FILE *fd;
> +
> +        if (filename) {
> +            fd = fopen(filename, log_append ? "a" : "w");
> +            if (!fd) {
>                  error_setg_errno(errp, errno, "Error opening logfile %s",
> -                                 logfilename);
> +                                 filename);
>                  return false;
>              }
>              /* In case we are a daemon redirect stderr to logfile */
>              if (is_daemonized()) {
> -                dup2(fileno(logfile->fd), STDERR_FILENO);
> -                fclose(logfile->fd);
> +                dup2(fileno(fd), STDERR_FILENO);
> +                fclose(fd);
>                  /* This will skip closing logfile in qemu_log_close() */
> -                logfile->fd = stderr;
> +                fd = stderr;
>              }
>          } else {
>              /* Default to stderr if no log file specified */
>              assert(!is_daemonized());
> -            logfile->fd = stderr;
> +            fd = stderr;
>          }
>  
>          log_append = 1;
> +
> +        logfile = g_new0(QemuLogFile, 1);
> +        logfile->fd = fd;
>          qatomic_rcu_set(&qemu_logfile, logfile);

I was also pondering if flags should be part of the QemuLogFile
structure so it's consistent with each opened file. However I see it
gets repurposed just for clean-up later...

>      }
>      return true;
>  }
>  
> -/*
> - * Allow the user to include %d in their logfile which will be
> - * substituted with the current PID. This is useful for debugging many
> - * nested linux-user tasks but will result in lots of logs.
> - *
> - * filename may be NULL. In that case, log output is sent to stderr
> - */
> +bool qemu_set_log(int log_flags, Error **errp)
> +{
> +    return qemu_set_log_internal(NULL, false, log_flags, errp);
> +}
> +
>  bool qemu_set_log_filename(const char *filename, Error **errp)
>  {
> -    g_free(logfilename);
> -    logfilename = NULL;
> +    return qemu_set_log_internal(filename, true, qemu_loglevel, errp);
> +}
>  
> -    if (filename) {
> -            char *pidstr = strstr(filename, "%");
> -            if (pidstr) {
> -                /* We only accept one %d, no other format strings */
> -                if (pidstr[1] != 'd' || strchr(pidstr + 2, '%')) {
> -                    error_setg(errp, "Bad logfile format: %s", filename);
> -                    return false;
> -                } else {
> -                    logfilename = g_strdup_printf(filename, getpid());
> -                }
> -            } else {
> -                logfilename = g_strdup(filename);
> -            }
> -    }
> -
> -    qemu_log_close();
> -    return qemu_set_log(qemu_loglevel, errp);
> +bool qemu_set_log_filename_flags(const char *name, int flags, Error **errp)
> +{
> +    return qemu_set_log_internal(name, true, flags, errp);
>  }
>  
>  /* Returns true if addr is in our debug filter or no filter defined
Richard Henderson April 14, 2022, 5:32 p.m. UTC | #2
On 4/14/22 07:56, Alex Bennée wrote:
>>   #ifdef CONFIG_TRACE_LOG
>> -    qemu_loglevel |= LOG_TRACE;
>> +    log_flags |= LOG_TRACE;
>>   #endif
>> +    qemu_loglevel = log_flags;
>> +
> 
> This looked weird - so should we consider a qatomic_set here to avoid an
> inconsistent set of flags being read non-atomically elsewhere?

I suppose we could do, as a separate change, since this has not been considered before. 
But I don't believe in tears to aligned 'int' on any qemu host.

>> +        logfile = g_new0(QemuLogFile, 1);
>> +        logfile->fd = fd;
>>           qatomic_rcu_set(&qemu_logfile, logfile);
> 
> I was also pondering if flags should be part of the QemuLogFile
> structure so it's consistent with each opened file. However I see it
> gets repurposed just for clean-up later...

I actually had this at one point in development.  But yes, there's no point in it for just 
the release.


r~
diff mbox series

Patch

diff --git a/include/qemu/log.h b/include/qemu/log.h
index 42d545f77a..b6c73376b5 100644
--- a/include/qemu/log.h
+++ b/include/qemu/log.h
@@ -82,6 +82,7 @@  extern const QEMULogItem qemu_log_items[];
 
 bool qemu_set_log(int log_flags, Error **errp);
 bool qemu_set_log_filename(const char *filename, Error **errp);
+bool qemu_set_log_filename_flags(const char *name, int flags, Error **errp);
 void qemu_set_dfilter_ranges(const char *ranges, Error **errp);
 bool qemu_log_in_addr_range(uint64_t addr);
 int qemu_str_to_log_mask(const char *str);
diff --git a/util/log.c b/util/log.c
index 8b8b6a5d83..2152d5591e 100644
--- a/util/log.c
+++ b/util/log.c
@@ -117,15 +117,58 @@  static void qemu_logfile_free(QemuLogFile *logfile)
 }
 
 /* enable or disable low levels log */
-bool qemu_set_log(int log_flags, Error **errp)
+static bool qemu_set_log_internal(const char *filename, bool changed_name,
+                                  int log_flags, Error **errp)
 {
-    bool need_to_open_file = false;
+    bool need_to_open_file;
     QemuLogFile *logfile;
 
-    qemu_loglevel = log_flags;
+    QEMU_LOCK_GUARD(&qemu_logfile_mutex);
+    logfile = qemu_logfile;
+
+    if (changed_name) {
+        char *newname = NULL;
+
+        /*
+         * Allow the user to include %d in their logfile which will be
+         * substituted with the current PID. This is useful for debugging many
+         * nested linux-user tasks but will result in lots of logs.
+         *
+         * filename may be NULL. In that case, log output is sent to stderr
+         */
+        if (filename) {
+            char *pidstr = strstr(filename, "%");
+
+            if (pidstr) {
+                /* We only accept one %d, no other format strings */
+                if (pidstr[1] != 'd' || strchr(pidstr + 2, '%')) {
+                    error_setg(errp, "Bad logfile format: %s", filename);
+                    return false;
+                }
+                newname = g_strdup_printf(filename, getpid());
+            } else {
+                newname = g_strdup(filename);
+            }
+        }
+
+        g_free(logfilename);
+        logfilename = newname;
+        filename = newname;
+
+        if (logfile) {
+            qatomic_rcu_set(&qemu_logfile, NULL);
+            call_rcu(logfile, qemu_logfile_free, rcu);
+            logfile = NULL;
+        }
+    } else {
+        filename = logfilename;
+    }
+
 #ifdef CONFIG_TRACE_LOG
-    qemu_loglevel |= LOG_TRACE;
+    log_flags |= LOG_TRACE;
 #endif
+    qemu_loglevel = log_flags;
+
     /*
      * In all cases we only log if qemu_loglevel is set.
      * Also:
@@ -134,71 +177,58 @@  bool qemu_set_log(int log_flags, Error **errp)
      *   If we are daemonized,
      *     we will only log if there is a logfilename.
      */
-    if (qemu_loglevel && (!is_daemonized() || logfilename)) {
-        need_to_open_file = true;
-    }
-    QEMU_LOCK_GUARD(&qemu_logfile_mutex);
-    if (qemu_logfile && !need_to_open_file) {
-        logfile = qemu_logfile;
+    need_to_open_file = log_flags && (!is_daemonized() || filename);
+
+    if (logfile && !need_to_open_file) {
         qatomic_rcu_set(&qemu_logfile, NULL);
         call_rcu(logfile, qemu_logfile_free, rcu);
-    } else if (!qemu_logfile && need_to_open_file) {
-        logfile = g_new0(QemuLogFile, 1);
-        if (logfilename) {
-            logfile->fd = fopen(logfilename, log_append ? "a" : "w");
-            if (!logfile->fd) {
+        return true;
+    }
+    if (!logfile && need_to_open_file) {
+        FILE *fd;
+
+        if (filename) {
+            fd = fopen(filename, log_append ? "a" : "w");
+            if (!fd) {
                 error_setg_errno(errp, errno, "Error opening logfile %s",
-                                 logfilename);
+                                 filename);
                 return false;
             }
             /* In case we are a daemon redirect stderr to logfile */
             if (is_daemonized()) {
-                dup2(fileno(logfile->fd), STDERR_FILENO);
-                fclose(logfile->fd);
+                dup2(fileno(fd), STDERR_FILENO);
+                fclose(fd);
                 /* This will skip closing logfile in qemu_log_close() */
-                logfile->fd = stderr;
+                fd = stderr;
             }
         } else {
             /* Default to stderr if no log file specified */
             assert(!is_daemonized());
-            logfile->fd = stderr;
+            fd = stderr;
         }
 
         log_append = 1;
+
+        logfile = g_new0(QemuLogFile, 1);
+        logfile->fd = fd;
         qatomic_rcu_set(&qemu_logfile, logfile);
     }
     return true;
 }
 
-/*
- * Allow the user to include %d in their logfile which will be
- * substituted with the current PID. This is useful for debugging many
- * nested linux-user tasks but will result in lots of logs.
- *
- * filename may be NULL. In that case, log output is sent to stderr
- */
+bool qemu_set_log(int log_flags, Error **errp)
+{
+    return qemu_set_log_internal(NULL, false, log_flags, errp);
+}
+
 bool qemu_set_log_filename(const char *filename, Error **errp)
 {
-    g_free(logfilename);
-    logfilename = NULL;
+    return qemu_set_log_internal(filename, true, qemu_loglevel, errp);
+}
 
-    if (filename) {
-            char *pidstr = strstr(filename, "%");
-            if (pidstr) {
-                /* We only accept one %d, no other format strings */
-                if (pidstr[1] != 'd' || strchr(pidstr + 2, '%')) {
-                    error_setg(errp, "Bad logfile format: %s", filename);
-                    return false;
-                } else {
-                    logfilename = g_strdup_printf(filename, getpid());
-                }
-            } else {
-                logfilename = g_strdup(filename);
-            }
-    }
-
-    qemu_log_close();
-    return qemu_set_log(qemu_loglevel, errp);
+bool qemu_set_log_filename_flags(const char *name, int flags, Error **errp)
+{
+    return qemu_set_log_internal(name, true, flags, errp);
 }
 
 /* Returns true if addr is in our debug filter or no filter defined