util/log: Introduce qemu_set_log_filename_flags

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>
Message-Id: <20220417183019.755276-28-richard.henderson@linaro.org>
This commit is contained in:
Richard Henderson 2022-04-17 11:30:07 -07:00
parent 6391c772d7
commit 144539d360
2 changed files with 77 additions and 46 deletions

View file

@ -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);

View file

@ -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