[libvirt] [PATCH] Allow to dynamically set the size of the debug buffer

Daniel Veillard veillard at redhat.com
Tue Mar 8 10:44:56 UTC 2011


This is the part allowing to dynamically resize the debug log
buffer from it's default 64kB size. The buffer is now dynamically
allocated.
It adds a new API virLogSetBufferSize() which resizes the buffer
(possibly dynamically but in that case the existing content is lost -
the complexity wasn't looking like worth it).
If passed a zero size, the buffer is deallocated and we do the small
optimization of not formatting messages which are not output anymore.
On the daemon side, it just adds a new option log_buffer_size to
libvirtd.conf and call virLogSetBufferSize() if needed (minor
pbm of the GET_CONF_* macros is you can't guess if the value was set
or not)

Seems to work fine, I tried to keep the code as simple as needed,
this allowed me to find out that on a quiet daemon startup we emit
half a megabyte of debug log !

The next patch missing now is the update of the documentation for the
log buffer.

Daniel


-- 
Daniel Veillard      | libxml Gnome XML XSLT toolkit  http://xmlsoft.org/
daniel at veillard.com  | Rpmfind RPM search engine http://rpmfind.net/
http://veillard.com/ | virtualization library  http://libvirt.org/
-------------- next part --------------
commit 445d751a76f1046d13a31014d5eb4fb5b41ece9f
Author: Daniel Veillard <veillard at redhat.com>
Date:   Tue Mar 8 18:31:20 2011 +0800

    Allow to dynamically set the size of the debug buffer
    
    This is the part allowing to dynamically resize the debug log
    buffer from it's default 64kB size. The buffer is now dynamically
    allocated.
    It adds a new API virLogSetBufferSize() which resizes the buffer
    If passed a zero size, the buffer is deallocated and we do the small
    optimization of not formatting messages which are not output anymore.
    On the daemon side, it just adds a new option log_buffer_size to
    libvirtd.conf and call virLogSetBufferSize() if needed
    * src/util/logging.h src/util/logging.c src/libvirt_private.syms:
      make buffer dynamic and add virLogSetBufferSize() internal API
    * daemon/libvirtd.conf: document the new log_buffer_size option
    * daemon/libvirtd.c: read and use the new log_buffer_size option

diff --git a/daemon/libvirtd.c b/daemon/libvirtd.c
index 452566c..d3631ec 100644
--- a/daemon/libvirtd.c
+++ b/daemon/libvirtd.c
@@ -2720,11 +2720,16 @@ qemudSetLogging(struct qemud_server *server, virConfPtr conf,
                 const char *filename)
 {
     int log_level = 0;
+    int log_buffer_size = -2;
     char *log_filters = NULL;
     char *log_outputs = NULL;
     char *log_file = NULL;
     int ret = -1;
 
+    GET_CONF_INT (conf, filename, log_buffer_size);
+    if (log_buffer_size != -2)
+        virLogSetBufferSize(log_buffer_size);
+
     virLogReset();
 
     /*
diff --git a/daemon/libvirtd.conf b/daemon/libvirtd.conf
index 163a80f..71ef763 100644
--- a/daemon/libvirtd.conf
+++ b/daemon/libvirtd.conf
@@ -313,6 +313,12 @@
 # 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 set to 0 that buffer is deactivated
+#log_buffer_size = 64
+
 
 ##################################################################
 #
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index efcf3c5..7567c78 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -558,6 +558,7 @@ virLogParseDefaultPriority;
 virLogParseFilters;
 virLogParseOutputs;
 virLogReset;
+virLogSetBufferSize;
 virLogSetDefaultPriority;
 virLogSetFromEnv;
 virLogShutdown;
diff --git a/src/util/logging.c b/src/util/logging.c
index 6490376..d50595e 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;
@@ -192,6 +195,15 @@ 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.
+         */
+        virReportOOMError();
+        virLogSize = 0;
+    }
     virLogLen = 0;
     virLogStart = 0;
     virLogEnd = 0;
@@ -201,6 +213,51 @@ int virLogStartup(void) {
 }
 
 /**
+ * virLogSetBufferSize:
+ * @size: size of the buffer in kilobytes or 0 to deactivate
+ *
+ * Dynamically set the size or desactivate 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;
+
+    if (size < 0)
+        size = 0;
+
+    if ((virLogInitialized == 0) || (size * 1024 == virLogSize))
+        return ret;
+
+    virLogLock();
+
+    oldsize = virLogSize;
+    oldLogBuffer = virLogBuffer;
+
+    virLogSize = size * 1024;
+    if (VIR_ALLOC_N(virLogBuffer, virLogSize) < 0) {
+        virReportOOMError();
+        virLogBuffer = oldLogBuffer;
+        virLogSize = oldsize;
+        ret =-1;
+        goto error;
+    }
+    VIR_FREE(oldLogBuffer);
+    virLogLen = 0;
+    virLogStart = 0;
+    virLogEnd = 0;
+
+error:
+    virLogUnlock();
+    return ret;
+}
+
+/**
  * virLogReset:
  *
  * Reset the logging module to its default initial state
@@ -235,6 +292,7 @@ void virLogShutdown(void) {
     virLogLen = 0;
     virLogStart = 0;
     virLogEnd = 0;
+    VIR_FREE(virLogBuffer);
     virLogUnlock();
     virMutexDestroy(&virLogMutex);
     virLogInitialized = 0;
@@ -246,21 +304,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 +329,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 +408,28 @@ virLogEmergencyDumpAll(int signum) {
             virLogDumpAllFD( "Caught unexpected signal", -1);
             break;
     }
+    if ((virLogBuffer == NULL) || (virLogSize <= 0)) {
+        virLogDumpAllFD(" internal log buffer desactivated\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 +706,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 c168dff..0dba78c 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


More information about the libvir-list mailing list