diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index d2730f188b..7beebbf27b 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1891,6 +1891,7 @@ virLogFilterFree; virLogFilterListFree; virLogFilterNew; virLogFindOutput; +virLogGetDefaultOutput; virLogGetDefaultPriority; virLogGetFilters; virLogGetNbFilters; @@ -1909,6 +1910,7 @@ virLogParseOutputs; virLogPriorityFromSyslog; virLogProbablyLogMessage; virLogReset; +virLogSetDefaultOutput; virLogSetDefaultPriority; virLogSetFilters; virLogSetFromEnv; diff --git a/src/util/virlog.c b/src/util/virlog.c index 77bc6b3c22..a13b471a63 100644 --- a/src/util/virlog.c +++ b/src/util/virlog.c @@ -50,6 +50,7 @@ #include "virtime.h" #include "intprops.h" #include "virstring.h" +#include "configmake.h" /* Journald output is only supported on Linux new enough to expose * htole64. */ @@ -105,6 +106,7 @@ struct _virLogOutput { char *name; }; +static char *virLogDefaultOutput; static virLogOutputPtr *virLogOutputs; static size_t virLogNbOutputs; @@ -147,6 +149,96 @@ virLogUnlock(void) } +static int +virLogSetDefaultOutputToStderr(void) +{ + return virAsprintf(&virLogDefaultOutput, "%d:stderr", + virLogDefaultPriority); +} + + +static int +virLogSetDefaultOutputToJournald(void) +{ + virLogPriority priority = virLogDefaultPriority; + + /* By default we don't want to log too much stuff into journald as + * it may employ rate limiting and thus block libvirt execution. */ + if (priority == VIR_LOG_DEBUG) + priority = VIR_LOG_INFO; + + return virAsprintf(&virLogDefaultOutput, "%d:journald", priority); +} + + +static int +virLogSetDefaultOutputToFile(const char *filename, bool privileged) +{ + int ret = -1; + char *logdir = NULL; + mode_t old_umask; + + if (privileged) { + if (virAsprintf(&virLogDefaultOutput, + "%d:file:%s/log/libvirt/%s", virLogDefaultPriority, + LOCALSTATEDIR, filename) < 0) + goto cleanup; + } else { + if (!(logdir = virGetUserCacheDirectory())) + goto cleanup; + + old_umask = umask(077); + if (virFileMakePath(logdir) < 0) { + umask(old_umask); + goto cleanup; + } + umask(old_umask); + + if (virAsprintf(&virLogDefaultOutput, "%d:file:%s/%s", + virLogDefaultPriority, logdir, filename) < 0) + goto cleanup; + } + + ret = 0; + cleanup: + VIR_FREE(logdir); + return ret; +} + + +/* + * virLogSetDefaultOutput: + * @filename: the file that the output should be redirected to (only needed + * when @godaemon equals true + * @godaemon: whether we're running daemonized + * @privileged: whether we're running with root privileges or not (session) + * + * Decides on what the default output (journald, file, stderr) should be + * according to @filename, @godaemon, @privileged. This function should be run + * exactly once at daemon startup, so no locks are used. + * + * Returns 0 on success, -1 in case of a failure. + */ +int +virLogSetDefaultOutput(const char *filename, bool godaemon, bool privileged) +{ + if (!godaemon) + return virLogSetDefaultOutputToStderr(); + + if (access("/run/systemd/journal/socket", W_OK) >= 0) + return virLogSetDefaultOutputToJournald(); + + return virLogSetDefaultOutputToFile(filename, privileged); +} + + +char * +virLogGetDefaultOutput(void) +{ + return virLogDefaultOutput; +} + + static const char * virLogPriorityString(virLogPriority lvl) { diff --git a/src/util/virlog.h b/src/util/virlog.h index 3f2d4223bf..b4ffecafb2 100644 --- a/src/util/virlog.h +++ b/src/util/virlog.h @@ -189,6 +189,8 @@ void virLogFilterFree(virLogFilterPtr filter); void virLogFilterListFree(virLogFilterPtr *list, int count); int virLogSetOutputs(const char *outputs) ATTRIBUTE_NONNULL(1); int virLogSetFilters(const char *filters); +char *virLogGetDefaultOutput(void); +int virLogSetDefaultOutput(const char *fname, bool godaemon, bool privileged); /* * Internal logging API