Message ID | 20220326132534.543738-36-richard.henderson@linaro.org |
---|---|
State | Superseded |
Headers | show |
Series | Logging cleanup and per-thread logfiles | expand |
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
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 --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
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(-)