[libvirt] [PATCH] log: include hostname in initial log message

Daniel P. Berrange berrange at redhat.com
Fri Dec 4 17:38:43 UTC 2015


On the very first log message we send to any output, we include
the libvirt version number and package string. In some bug reports
we have been given libvirtd.log files that came from a different
host than the corresponding /var/log/libvirt/qemu log files. So
extend the initial log message to include the hostname too.

eg on first log message we would now see:

 $ libvirtd
 2015-12-04 17:35:36.610+0000: 20917: info : libvirt version: 1.3.0
 2015-12-04 17:35:36.610+0000: 20917: info : dhcp-1-180.lcy.redhat.com
 2015-12-04 17:35:36.610+0000: 20917: error : qemuMonitorIO:687 : internal error: End of file from monitor

Signed-off-by: Daniel P. Berrange <berrange at redhat.com>
---
 cfg.mk            |   2 +-
 src/util/virlog.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++--------
 2 files changed, 98 insertions(+), 18 deletions(-)

diff --git a/cfg.mk b/cfg.mk
index cf3f36c..2e3af1a 100644
--- a/cfg.mk
+++ b/cfg.mk
@@ -1160,7 +1160,7 @@ _src2=src/(util/vircommand|libvirt|lxc/lxc_controller|locking/lock_daemon|loggin
 exclude_file_name_regexp--sc_prohibit_fork_wrappers = \
   (^($(_src2)|tests/testutils|daemon/libvirtd)\.c$$)
 
-exclude_file_name_regexp--sc_prohibit_gethostname = ^src/util/virutil\.c$$
+exclude_file_name_regexp--sc_prohibit_gethostname = ^src/util/vir(log|util)\.c$$
 
 exclude_file_name_regexp--sc_prohibit_internal_functions = \
   ^src/(util/(viralloc|virutil|virfile)\.[hc]|esx/esx_vi\.c)$$
diff --git a/src/util/virlog.c b/src/util/virlog.c
index 627f4cb..34e7f2a 100644
--- a/src/util/virlog.c
+++ b/src/util/virlog.c
@@ -39,6 +39,7 @@
 #if HAVE_SYS_UN_H
 # include <sys/un.h>
 #endif
+#include <netdb.h>
 
 #include "virerror.h"
 #include "virlog.h"
@@ -94,7 +95,7 @@ static int virLogNbFilters;
  * after filtering, multiple output can be used simultaneously
  */
 struct _virLogOutput {
-    bool logVersion;
+    bool logInitMessage;
     void *data;
     virLogOutputFunc f;
     virLogCloseFunc c;
@@ -402,7 +403,7 @@ virLogDefineOutput(virLogOutputFunc f,
         goto cleanup;
     }
     ret = virLogNbOutputs++;
-    virLogOutputs[ret].logVersion = true;
+    virLogOutputs[ret].logInitMessage = true;
     virLogOutputs[ret].f = f;
     virLogOutputs[ret].c = c;
     virLogOutputs[ret].data = data;
@@ -452,6 +453,73 @@ virLogVersionString(const char **rawmsg,
     return virLogFormatString(msg, 0, NULL, VIR_LOG_INFO, VIR_LOG_VERSION_STRING);
 }
 
+/* Similar to virGetHostname() but avoids use of error
+ * reporting APIs or logging APIs, to prevent recursion
+ */
+static int
+virLogHostnameString(const char **rawmsg,
+                     char **msg)
+{
+    int r;
+    char hostname[HOST_NAME_MAX+1];
+    struct addrinfo hints, *info;
+    char *result = NULL;
+
+    *rawmsg = *msg = NULL;
+    r = gethostname(hostname, sizeof(hostname));
+    if (r == -1)
+        return -1;
+    NUL_TERMINATE(hostname);
+
+    if (STRPREFIX(hostname, "localhost") || strchr(hostname, '.')) {
+        /* in this case, gethostname returned localhost (meaning we can't
+         * do any further canonicalization), or it returned an FQDN (and
+         * we don't need to do any further canonicalization).  Return the
+         * string as-is; it's up to callers to check whether "localhost"
+         * is allowed.
+         */
+        ignore_value(VIR_STRDUP_QUIET(result, hostname));
+        goto cleanup;
+    }
+
+    /* otherwise, it's a shortened, non-localhost, hostname.  Attempt to
+     * canonicalize the hostname by running it through getaddrinfo
+     */
+
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_flags = AI_CANONNAME|AI_CANONIDN;
+    hints.ai_family = AF_UNSPEC;
+    r = getaddrinfo(hostname, NULL, &hints, &info);
+    if (r != 0) {
+        ignore_value(VIR_STRDUP_QUIET(result, hostname));
+        goto cleanup;
+    }
+
+    /* Tell static analyzers about getaddrinfo semantics.  */
+    sa_assert(info);
+
+    if (info->ai_canonname == NULL ||
+        STRPREFIX(info->ai_canonname, "localhost"))
+        /* in this case, we tried to canonicalize and we ended up back with
+         * localhost.  Ignore the canonicalized name and just return the
+         * original hostname
+         */
+        ignore_value(VIR_STRDUP_QUIET(result, hostname));
+    else
+        /* Caller frees this string. */
+        ignore_value(VIR_STRDUP_QUIET(result, info->ai_canonname));
+
+    freeaddrinfo(info);
+
+ cleanup:
+    if (virLogFormatString(msg, 0, NULL, VIR_LOG_INFO, result) < 0) {
+        VIR_FREE(result);
+        return -1;
+    }
+    *rawmsg = result;
+    return 0;
+}
+
 
 static void
 virLogSourceUpdate(virLogSourcePtr source)
@@ -533,7 +601,7 @@ virLogVMessage(virLogSourcePtr source,
                const char *fmt,
                va_list vargs)
 {
-    static bool logVersionStderr = true;
+    static bool logInitMessageStderr = true;
     char *str = NULL;
     char *msg = NULL;
     char timestamp[VIR_TIME_STRING_BUFLEN];
@@ -583,16 +651,22 @@ virLogVMessage(virLogSourcePtr source,
      */
     for (i = 0; i < virLogNbOutputs; i++) {
         if (priority >= virLogOutputs[i].priority) {
-            if (virLogOutputs[i].logVersion) {
-                const char *rawver;
-                char *ver = NULL;
-                if (virLogVersionString(&rawver, &ver) >= 0)
+            if (virLogOutputs[i].logInitMessage) {
+                const char *rawinitmsg;
+                char *initmsg = NULL;
+                if (virLogVersionString(&rawinitmsg, &initmsg) >= 0)
+                    virLogOutputs[i].f(&virLogSelf, VIR_LOG_INFO,
+                                       __FILE__, __LINE__, __func__,
+                                       timestamp, NULL, 0, rawinitmsg, initmsg,
+                                       virLogOutputs[i].data);
+                VIR_FREE(initmsg);
+                if (virLogHostnameString(&rawinitmsg, &initmsg) >= 0)
                     virLogOutputs[i].f(&virLogSelf, VIR_LOG_INFO,
                                        __FILE__, __LINE__, __func__,
-                                       timestamp, NULL, 0, rawver, ver,
+                                       timestamp, NULL, 0, rawinitmsg, initmsg,
                                        virLogOutputs[i].data);
-                VIR_FREE(ver);
-                virLogOutputs[i].logVersion = false;
+                VIR_FREE(initmsg);
+                virLogOutputs[i].logInitMessage = false;
             }
             virLogOutputs[i].f(source, priority,
                                filename, linenr, funcname,
@@ -601,16 +675,22 @@ virLogVMessage(virLogSourcePtr source,
         }
     }
     if (virLogNbOutputs == 0) {
-        if (logVersionStderr) {
-            const char *rawver;
-            char *ver = NULL;
-            if (virLogVersionString(&rawver, &ver) >= 0)
+        if (logInitMessageStderr) {
+            const char *rawinitmsg;
+            char *initmsg = NULL;
+            if (virLogVersionString(&rawinitmsg, &initmsg) >= 0)
+                virLogOutputToFd(&virLogSelf, VIR_LOG_INFO,
+                                 __FILE__, __LINE__, __func__,
+                                 timestamp, NULL, 0, rawinitmsg, initmsg,
+                                 (void *) STDERR_FILENO);
+            VIR_FREE(initmsg);
+            if (virLogHostnameString(&rawinitmsg, &initmsg) >= 0)
                 virLogOutputToFd(&virLogSelf, VIR_LOG_INFO,
                                  __FILE__, __LINE__, __func__,
-                                 timestamp, NULL, 0, rawver, ver,
+                                 timestamp, NULL, 0, rawinitmsg, initmsg,
                                  (void *) STDERR_FILENO);
-            VIR_FREE(ver);
-            logVersionStderr = false;
+            VIR_FREE(initmsg);
+            logInitMessageStderr = false;
         }
         virLogOutputToFd(source, priority,
                          filename, linenr, funcname,
-- 
2.5.0




More information about the libvir-list mailing list