diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c index 1e41feb1db0e87d08fe7c64a36f7e5dcf23e860d..dc6fab4a51fa5c8417a8bba70ea6d6f6c5f68685 100644 --- a/daemon/libvirtd.c +++ b/daemon/libvirtd.c @@ -2714,18 +2714,22 @@ remoteReadSaslAllowedUsernameList (virConfPtr conf ATTRIBUTE_UNUSED, * Set up the logging environment * By default if daemonized all errors go to the logfile libvirtd.log, * but if verbose or error debugging is asked for then also output - * informations or debug. + * informational and debug messages. Default size if 64 kB. */ static int qemudSetLogging(struct qemud_server *server, virConfPtr conf, const char *filename) { int log_level = 0; + int log_buffer_size = 64; char *log_filters = NULL; char *log_outputs = NULL; char *log_file = NULL; int ret = -1; + GET_CONF_INT (conf, filename, log_buffer_size); + virLogSetBufferSize(log_buffer_size); + virLogReset(); /* diff --git a/daemon/libvirtd.conf b/daemon/libvirtd.conf index 163a80fb03dc932f85e19e4b7dc230382ea8894e..3a071b0fce9879b156e4f011430b83f6da1a1b5b 100644 --- a/daemon/libvirtd.conf +++ b/daemon/libvirtd.conf @@ -313,6 +313,13 @@ # log_outputs="3:syslog:libvirtd" # to log all warnings and errors to syslog under the libvirtd ident +# Log debug buffer size: default 64 +# The daemon keeps an internal debug log buffer which will be dumped in case +# of crash or upon receiving a SIGUSR2 signal. This setting allows to override +# the default buffer size in kilobytes. +# If value is 0 or less the debug log buffer is deactivated +#log_buffer_size = 64 + ################################################################## # diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index c0da78ec5a4e9ade0cf710c277f71bcfeffeffd9..09eb03a356a21a9de06f49e97935f8c6274a33d4 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -559,6 +559,7 @@ virLogParseDefaultPriority; virLogParseFilters; virLogParseOutputs; virLogReset; +virLogSetBufferSize; virLogSetDefaultPriority; virLogSetFromEnv; virLogShutdown; diff --git a/src/util/logging.c b/src/util/logging.c index 64903765f6b2622f3acf5640758350ff25a21a3d..4479938fa48d68fcd41f51453a40fd22787aff41 100644 --- a/src/util/logging.c +++ b/src/util/logging.c @@ -36,6 +36,7 @@ #endif #include "ignore-value.h" +#include "virterror_internal.h" #include "logging.h" #include "memory.h" #include "util.h" @@ -43,6 +44,8 @@ #include "threads.h" #include "files.h" +#define VIR_FROM_THIS VIR_FROM_NONE + /* * Macro used to format the message as a string in virLogMessage * and borrowed from libxml2 (also used in virRaiseError) @@ -83,9 +86,9 @@ /* * A logging buffer to keep some history over logs */ -#define LOG_BUFFER_SIZE 64000 -static char virLogBuffer[LOG_BUFFER_SIZE + 1]; +static int virLogSize = 64 * 1024; +static char *virLogBuffer = NULL; static int virLogLen = 0; static int virLogStart = 0; static int virLogEnd = 0; @@ -184,6 +187,8 @@ static int virLogInitialized = 0; * Returns 0 if successful, and -1 in case or error */ int virLogStartup(void) { + const char *pbm = NULL; + if (virLogInitialized) return -1; @@ -192,14 +197,84 @@ int virLogStartup(void) { virLogInitialized = 1; virLogLock(); + if (VIR_ALLOC_N(virLogBuffer, virLogSize) < 0) { + /* + * The debug buffer is not a critical component, allow startup + * even in case of failure to allocate it in case of a + * configuration mistake. + */ + virLogSize = 64 * 1024; + if (VIR_ALLOC_N(virLogBuffer, virLogSize) < 0) { + pbm = "Failed to allocate debug buffer: deactivating debug log\n"; + virLogSize = 0; + } else { + pbm = "Failed to allocate debug buffer: reduced to 64 kB\n"; + } + } virLogLen = 0; virLogStart = 0; virLogEnd = 0; virLogDefaultPriority = VIR_LOG_DEFAULT; virLogUnlock(); + if (pbm) + VIR_WARN0(pbm); return 0; } +/** + * virLogSetBufferSize: + * @size: size of the buffer in kilobytes or <= 0 to deactivate + * + * Dynamically set the size or deactivate the logging buffer used to keep + * a trace of all recent debug output. Note that the content of the buffer + * is lost if it gets reallocated. + * + * Return -1 in case of failure or 0 in case of success + */ +extern int +virLogSetBufferSize(int size) { + int ret = 0; + int oldsize; + char *oldLogBuffer; + const char *pbm = NULL; + + if (size < 0) + size = 0; + + if ((virLogInitialized == 0) || (size * 1024 == virLogSize)) + return ret; + + virLogLock(); + + oldsize = virLogSize; + oldLogBuffer = virLogBuffer; + + if (INT_MAX / 1024 < size) { + pbm = "Requested log size of %d kB too large\n"; + ret = -1; + goto error; + } + + virLogSize = size * 1024; + if (VIR_ALLOC_N(virLogBuffer, virLogSize) < 0) { + pbm = "Failed to allocate debug buffer of %d kB\n"; + virLogBuffer = oldLogBuffer; + virLogSize = oldsize; + ret = -1; + goto error; + } + VIR_FREE(oldLogBuffer); + virLogLen = 0; + virLogStart = 0; + virLogEnd = 0; + +error: + virLogUnlock(); + if (pbm) + VIR_ERROR(pbm, size); + return ret; +} + /** * virLogReset: * @@ -235,6 +310,7 @@ void virLogShutdown(void) { virLogLen = 0; virLogStart = 0; virLogEnd = 0; + VIR_FREE(virLogBuffer); virLogUnlock(); virMutexDestroy(&virLogMutex); virLogInitialized = 0; @@ -246,21 +322,21 @@ void virLogShutdown(void) { static void virLogStr(const char *str, int len) { int tmp; - if (str == NULL) + if ((str == NULL) || (virLogBuffer == NULL) || (virLogSize <= 0)) return; if (len <= 0) len = strlen(str); - if (len > LOG_BUFFER_SIZE) + if (len > virLogSize) return; virLogLock(); /* * copy the data and reset the end, we cycle over the end of the buffer */ - if (virLogEnd + len >= LOG_BUFFER_SIZE) { - tmp = LOG_BUFFER_SIZE - virLogEnd; + if (virLogEnd + len >= virLogSize) { + tmp = virLogSize - virLogEnd; memcpy(&virLogBuffer[virLogEnd], str, tmp); - virLogBuffer[LOG_BUFFER_SIZE] = 0; + virLogBuffer[virLogSize] = 0; memcpy(&virLogBuffer[0], &str[tmp], len - tmp); virLogEnd = len - tmp; } else { @@ -271,12 +347,12 @@ static void virLogStr(const char *str, int len) { * Update the log length, and if full move the start index */ virLogLen += len; - if (virLogLen > LOG_BUFFER_SIZE) { - tmp = virLogLen - LOG_BUFFER_SIZE; - virLogLen = LOG_BUFFER_SIZE; + if (virLogLen > virLogSize) { + tmp = virLogLen - virLogSize; + virLogLen = virLogSize; virLogStart += tmp; - if (virLogStart >= LOG_BUFFER_SIZE) - virLogStart -= LOG_BUFFER_SIZE; + if (virLogStart >= virLogSize) + virLogStart -= virLogSize; } virLogUnlock(); } @@ -350,23 +426,28 @@ virLogEmergencyDumpAll(int signum) { virLogDumpAllFD( "Caught unexpected signal", -1); break; } + if ((virLogBuffer == NULL) || (virLogSize <= 0)) { + virLogDumpAllFD(" internal log buffer deactivated\n", -1); + goto done; + } virLogDumpAllFD(" dumping internal log buffer:\n", -1); virLogDumpAllFD("\n\n ====== start of log =====\n\n", -1); while (virLogLen > 0) { - if (virLogStart + virLogLen < LOG_BUFFER_SIZE) { + if (virLogStart + virLogLen < virLogSize) { virLogBuffer[virLogStart + virLogLen] = 0; virLogDumpAllFD(&virLogBuffer[virLogStart], virLogLen); virLogStart += virLogLen; virLogLen = 0; } else { - len = LOG_BUFFER_SIZE - virLogStart; - virLogBuffer[LOG_BUFFER_SIZE] = 0; + len = virLogSize - virLogStart; + virLogBuffer[virLogSize] = 0; virLogDumpAllFD(&virLogBuffer[virLogStart], len); virLogLen -= len; virLogStart = 0; } } virLogDumpAllFD("\n\n ====== end of log =====\n\n", -1); +done: virLogUnlock(); } @@ -643,6 +724,9 @@ void virLogMessage(const char *category, int priority, const char *funcname, emit = 0; } + if ((emit == 0) && ((virLogBuffer == NULL) || (virLogSize <= 0))) + goto cleanup; + /* * serialize the error message, add level and timestamp */ diff --git a/src/util/logging.h b/src/util/logging.h index c168dff5c8c6b09efb91befbb0cc27d132cb4732..0dba78cda764b9aae718d906c458f8d19472b16d 100644 --- a/src/util/logging.h +++ b/src/util/logging.h @@ -133,5 +133,6 @@ extern int virLogParseOutputs(const char *output); extern void virLogMessage(const char *category, int priority, const char *funcname, long long linenr, int flags, const char *fmt, ...) ATTRIBUTE_FMT_PRINTF(6, 7); +extern int virLogSetBufferSize(int size); extern void virLogEmergencyDumpAll(int signum); #endif