[Libvir] PATCH: Create a logfile for each QEMU vm

Daniel P. Berrange berrange at redhat.com
Tue May 15 16:04:25 UTC 2007


Most of the error reporting the QEMU daemon is focused on sending errors
wrt to RPC ops to the client. There is no provision currently for getting
info about the QEMU vm itself when problems occur. The most common problem
is some mis-configurable in the XML causes qemu to fail to start up. This
results in the completely accurate & completely useless (mea-culpa) error
message  

libvirt.libvirtError: virDomainCreateLinux() failed internal error 
End-of-file while reading PTY startup output'

What this means is that qemu crashed/exited at startup. Now this patch
does not (yet) directly address that stupid error message, but what it
does do is provide a way to diagnose the real problem.

For every VM we start it will create a logfile

  /etc/libvirt/qemu/logs/[vmname].log

Or

  $HOME/.libvirt/qemu/logs/[vmname].log

And all output from QEMU's stderr/stdout will get written to this file.
So

# virsh --connect qemu:///system start wizz
libvir: QEMU error : internal error End-of-file while reading PTY startup output
error: Failed to start domain wizz

# cat /etc/libvirt/qemu/logs/wizz.log 
qemu: could not open hard disk image '/home/berrange/src/xen/virtinst--devel/demo'


Next up I'm going to work on 

  a) Improving the error message
  b) Adding validation that disk images actually exist before
     launching QEMU since that's the most common error we're seeing

Regards,
Dan.
-- 
|=- Red Hat, Engineering, Emerging Technologies, Boston.  +1 978 392 2496 -=|
|=-           Perl modules: http://search.cpan.org/~danberr/              -=|
|=-               Projects: http://freshmeat.net/~danielpb/               -=|
|=-  GnuPG: 7D3B9505   F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505  -=| 
-------------- next part --------------
diff -rup libvirt-0.2.2.orig/libvirt.spec.in libvirt-0.2.2.new/libvirt.spec.in
--- libvirt-0.2.2.orig/libvirt.spec.in	2007-04-17 05:33:16.000000000 -0400
+++ libvirt-0.2.2.new/libvirt.spec.in	2007-05-15 11:53:00.000000000 -0400
@@ -125,6 +125,7 @@ fi
 %{_libdir}/lib*.so.*
 %dir %attr(0700, root, root) %{_sysconfdir}/libvirt/
 %dir %attr(0700, root, root) %{_sysconfdir}/libvirt/qemu/
+%dir %attr(0700, root, root) %{_sysconfdir}/libvirt/qemu/logs
 %dir %attr(0700, root, root) %{_sysconfdir}/libvirt/qemu/networks/
 %dir %attr(0700, root, root) %{_sysconfdir}/libvirt/qemu/networks/autostart
 %{_sysconfdir}/rc.d/init.d/libvirtd
diff -rup libvirt-0.2.2.orig/qemud/internal.h libvirt-0.2.2.new/qemud/internal.h
--- libvirt-0.2.2.orig/qemud/internal.h	2007-05-15 10:52:00.000000000 -0400
+++ libvirt-0.2.2.new/qemud/internal.h	2007-05-15 10:55:08.000000000 -0400
@@ -63,7 +63,7 @@ typedef enum {
     QEMUD_DIR_AUTOSTART,
     QEMUD_DIR_NETWORK_CONFIG,
     QEMUD_DIR_NETWORK_AUTOSTART,
-
+    QEMUD_DIR_LOGS,
     QEMUD_N_CONFIG_DIRS
 } qemudConfigDirType;
 
@@ -213,6 +213,7 @@ struct qemud_vm {
     int stdout;
     int stderr;
     int monitor;
+    int logfile;
     int pid;
     int id;
     int state;
diff -rup libvirt-0.2.2.orig/qemud/Makefile.am libvirt-0.2.2.new/qemud/Makefile.am
--- libvirt-0.2.2.orig/qemud/Makefile.am	2007-04-06 07:12:29.000000000 -0400
+++ libvirt-0.2.2.new/qemud/Makefile.am	2007-05-15 11:52:46.000000000 -0400
@@ -24,6 +24,7 @@ libvirt_qemud_DEPENDENCIES =
 libvirt_qemud_LDADD =
 
 install-data-local:
+	mkdir -p $(DESTDIR)$(sysconfdir)/libvirt/qemu/logs
 	mkdir -p $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/autostart
 	$(INSTALL_DATA) $(srcdir)/default-network.xml $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/default.xml
 	sed -i -e "s,</name>,</name>\n  <uuid>$(UUID)</uuid>," $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/default.xml
@@ -36,6 +37,7 @@ uninstall-local:
 	rm -f $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/autostart/default.xml
 	rm -f $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/default.xml
 	rmdir $(DESTDIR)$(sysconfdir)/libvirt/qemu/networks/autostart || :
+	rmdir $(DESTDIR)$(sysconfdir)/libvirt/qemu/logs || :
 	rmdir $(DESTDIR)$(localstatedir)/run/libvirt || :
 	rmdir $(DESTDIR)$(localstatedir)/lib/libvirt || :
 
diff -rup libvirt-0.2.2.orig/qemud/qemud.c libvirt-0.2.2.new/qemud/qemud.c
--- libvirt-0.2.2.orig/qemud/qemud.c	2007-05-15 10:52:00.000000000 -0400
+++ libvirt-0.2.2.new/qemud/qemud.c	2007-05-15 11:46:02.000000000 -0400
@@ -415,6 +415,7 @@ static int qemudInitPaths(struct qemud_s
         "libvirt/qemu/autostart",          /* QEMUD_DIR_AUTO_DOMAINS */
         "libvirt/qemu/networks",           /* QEMUD_DIR_NETWORKS */
         "libvirt/qemu/networks/autostart", /* QEMUD_DIR_AUTO_NETWORKS */
+        "libvirt/qemu/logs",               /* QEMUD_DIR_LOGS */
     };
 
     uid_t uid;
@@ -785,6 +786,16 @@ qemudOpenMonitorPath(struct qemud_server
                      int fd ATTRIBUTE_UNUSED)
 {
     char monitor[PATH_MAX];
+    int len = strlen(output);
+
+ retry:
+    if (write(vm->logfile, output, len) < 0) {
+        /* Log, but ignore failures to write logfile for VM */
+        if (errno == EINTR)
+            goto retry;
+        qemudLog(QEMUD_WARN, "Unable to log VM console data: %s",
+                 strerror(errno));
+    }
 
     if (qemudExtractMonitorPath(output, monitor, sizeof(monitor)) < 0)
         return 1; /* keep reading */
@@ -841,6 +852,7 @@ int qemudStartVMDaemon(struct qemud_serv
                        struct qemud_vm *vm) {
     char **argv = NULL;
     int i, ret = -1;
+    char logfile[PATH_MAX];
 
     if (qemudIsActiveVM(vm)) {
         qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
@@ -859,6 +871,37 @@ int qemudStartVMDaemon(struct qemud_serv
     } else
         vm->def->vncActivePort = vm->def->vncPort;
 
+    if ((strlen(server->configDirs[QEMUD_DIR_LOGS]) + /* path */
+         1 + /* Separator */
+         strlen(vm->def->name) + /* basename */
+         4 + /* suffix .log */
+         1 /* NULL */) > PATH_MAX) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                         "config file path too long: %s/%s.log",
+                         server->configDirs[QEMUD_DIR_LOGS],
+                         vm->def->name);
+        return -1;
+    }
+    strcpy(logfile, server->configDirs[QEMUD_DIR_LOGS]);
+    strcat(logfile, "/");
+    strcat(logfile, vm->def->name);
+    strcat(logfile, ".log");
+
+    if (qemudEnsureDir(server->configDirs[QEMUD_DIR_LOGS]) < 0) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                         "cannot create log directory %s: %s",
+                         server->configDirs[QEMUD_DIR_LOGS], strerror(err));
+        return -1;
+    }
+
+    if ((vm->logfile = open(logfile, O_CREAT | O_TRUNC | O_WRONLY,
+                            S_IRUSR | S_IWUSR)) < 0) {
+        qemudReportError(server, VIR_ERR_INTERNAL_ERROR,
+                         "failed to create logfile %s: %s",
+                         logfile, strerror(errno));
+        return -1;
+    }
+
     if (qemudBuildCommandLine(server, vm, &argv) < 0)
         return -1;
 
@@ -1038,7 +1081,14 @@ static int qemudVMData(struct qemud_serv
         }
         buf[ret] = '\0';
 
-        qemudDebug("[%s]", buf);
+    retry:
+        if (write(vm->logfile, buf, ret) < 0) {
+            /* Log, but ignore failures to write logfile for VM */
+            if (errno == EINTR)
+                goto retry;
+            qemudLog(QEMUD_WARN, "Unable to log VM console data: %s",
+                     strerror(errno));
+        }
     }
 }
 
@@ -1053,10 +1103,12 @@ int qemudShutdownVMDaemon(struct qemud_s
 
     qemudVMData(server, vm, vm->stdout);
     qemudVMData(server, vm, vm->stderr);
+    close(vm->logfile);
     close(vm->stdout);
     close(vm->stderr);
     if (vm->monitor != -1)
         close(vm->monitor);
+    vm->logfile = -1;
     vm->stdout = -1;
     vm->stderr = -1;
     vm->monitor = -1;


More information about the libvir-list mailing list