[libvirt] [PATCH] Imprint all logs with version + package build information

The logging functions are enhanced so that immediately prior to the first log message being printed to any output channel, the libvirt package version will be printed. eg $ LIBVIRT_DEBUG=1 virsh 18:13:28.013: 17536: info : libvirt version: 0.8.7 18:13:28.013: 17536: debug : virInitialize:361 : register drivers ... The 'configure' script gains a '--with-package-string' argument to allow distros to append a custom string with package specific data. The RPM specfile is modified so that it appends the RPM version, the build host, the build date and the packager name. eg $ LIBVIRT_DEBUG=1 virsh 18:14:52.086: 17551: info : libvirt version: 0.8.7, package: 1.fc13 (Fedora Project, x86-01.phx2.fedoraproject.org, 01-27-2011-18:00:10) 18:14:52.086: 17551: debug : virInitialize:361 : register drivers Thus when distro packagers receive bug reports they can clearly see what version was in use, even if the bug reporter mistakenly or intentionally lies about version/builds * src/util/logging.c: Output version data prior to first log message * libvirt.spec.in: Include RPM release, date, hostname & packager * configure.ac: Add --with-package-string arg --- configure.ac | 10 ++++++ libvirt.spec.in | 7 ++++ src/util/logging.c | 86 +++++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 88 insertions(+), 15 deletions(-) diff --git a/configure.ac b/configure.ac index f310a5e..92d77e4 100644 --- a/configure.ac +++ b/configure.ac @@ -29,6 +29,16 @@ AC_SUBST([LIBVIRT_VERSION]) AC_SUBST([LIBVIRT_VERSION_INFO]) AC_SUBST([LIBVIRT_VERSION_NUMBER]) +AC_ARG_WITH([package-string], + [AS_HELP_STRING([--with-package-string], + [Extra package name/version string])], + [],[]) +if test "x$with_package_string" != "xno" +then + AC_DEFINE_UNQUOTED([PACKAGE_STRING], ["$with_package_string"], + [Extra package name/version string]) +fi + dnl Required minimum versions of all libs we depend on LIBXML_REQUIRED="2.6.0" GNUTLS_REQUIRED="1.0.25" diff --git a/libvirt.spec.in b/libvirt.spec.in index 0a2d10e..43c9067 100644 --- a/libvirt.spec.in +++ b/libvirt.spec.in @@ -592,6 +592,12 @@ of recent versions of Linux (and other OSes). %define _without_dtrace --without-dtrace %endif +%define when %(date +"%%m-%%d-%%Y-%%H:%%M:%%S") +%define where %(hostname) +%define who %{?packager}%{!?packager:Unknown} +%define with_package_string --with-package-string="%{release} (%{who}, %{when}, %{where})" + + %configure %{?_without_xen} \ %{?_without_qemu} \ %{?_without_openvz} \ @@ -626,6 +632,7 @@ of recent versions of Linux (and other OSes). %{?_without_macvtap} \ %{?_without_audit} \ %{?_without_dtrace} \ + %{with_package_string} \ --with-qemu-user=%{qemu_user} \ --with-qemu-group=%{qemu_group} \ --with-init-script=redhat \ diff --git a/src/util/logging.c b/src/util/logging.c index a80c3e3..5102e06 100644 --- a/src/util/logging.c +++ b/src/util/logging.c @@ -108,6 +108,7 @@ static int virLogNbFilters = 0; * after filtering, multiple output can be used simultaneously */ struct _virLogOutput { + bool logVersion; void *data; virLogOutputFunc f; virLogCloseFunc c; @@ -490,6 +491,7 @@ int virLogDefineOutput(virLogOutputFunc f, virLogCloseFunc c, void *data, goto cleanup; } ret = virLogNbOutputs++; + virLogOutputs[ret].logVersion = true; virLogOutputs[ret].f = f; virLogOutputs[ret].c = c; virLogOutputs[ret].data = data; @@ -501,6 +503,50 @@ cleanup: return ret; } +static int +virLogFormatString(char **msg, + const char *funcname, + long long linenr, + struct tm *time_info, + struct timeval *cur_time, + int priority, + const char *str) +{ + int ret; + if ((funcname != NULL)) { + ret = virAsprintf(msg, "%02d:%02d:%02d.%03d: %d: %s : %s:%lld : %s\n", + time_info->tm_hour, time_info->tm_min, + time_info->tm_sec, (int) cur_time->tv_usec / 1000, + virThreadSelfID(), + virLogPriorityString(priority), funcname, linenr, str); + } else { + ret = virAsprintf(msg, "%02d:%02d:%02d.%03d: %d: %s : %s\n", + time_info->tm_hour, time_info->tm_min, + time_info->tm_sec, (int) cur_time->tv_usec / 1000, + virThreadSelfID(), + virLogPriorityString(priority), str); + } + return ret; +} + +static int +virLogVersionString(char **msg, + struct tm *time_info, + struct timeval *cur_time) +{ +#ifdef PACKAGE_STRING +# define LOG_VERSION_STRING \ + "libvirt version: " VERSION ", package: " PACKAGE_STRING +#else +# define LOG_VERSION_STRING \ + "libvirt version: " VERSION +#endif + + return virLogFormatString(msg, NULL, 0, + time_info, cur_time, + VIR_LOG_INFO, LOG_VERSION_STRING); +} + /** * virLogMessage: * @category: where is that message coming from @@ -516,6 +562,7 @@ cleanup: */ void virLogMessage(const char *category, int priority, const char *funcname, long long linenr, int flags, const char *fmt, ...) { + static bool logVersionStderr = true; char *str = NULL; char *msg; struct timeval cur_time; @@ -547,19 +594,9 @@ void virLogMessage(const char *category, int priority, const char *funcname, gettimeofday(&cur_time, NULL); localtime_r(&cur_time.tv_sec, &time_info); - if ((funcname != NULL)) { - ret = virAsprintf(&msg, "%02d:%02d:%02d.%03d: %d: %s : %s:%lld : %s\n", - time_info.tm_hour, time_info.tm_min, - time_info.tm_sec, (int) cur_time.tv_usec / 1000, - virThreadSelfID(), - virLogPriorityString(priority), funcname, linenr, str); - } else { - ret = virAsprintf(&msg, "%02d:%02d:%02d.%03d: %d: %s : %s\n", - time_info.tm_hour, time_info.tm_min, - time_info.tm_sec, (int) cur_time.tv_usec / 1000, - virThreadSelfID(), - virLogPriorityString(priority), str); - } + ret = virLogFormatString(&msg, funcname, linenr, + &time_info, &cur_time, + priority, str); VIR_FREE(str); if (ret < 0) { /* apparently we're running out of memory */ @@ -578,12 +615,31 @@ void virLogMessage(const char *category, int priority, const char *funcname, virLogStr(msg, len); virLogLock(); for (i = 0; i < virLogNbOutputs;i++) { - if (priority >= virLogOutputs[i].priority) + if (priority >= virLogOutputs[i].priority) { + if (virLogOutputs[i].logVersion) { + char *ver = NULL; + if (virLogVersionString(&ver, &time_info, &cur_time) >= 0) + virLogOutputs[i].f(category, priority, __func__, __LINE__, + ver, strlen(ver), + virLogOutputs[i].data); + VIR_FREE(ver); + virLogOutputs[i].logVersion = false; + } virLogOutputs[i].f(category, priority, funcname, linenr, msg, len, virLogOutputs[i].data); + } } - if ((virLogNbOutputs == 0) && (flags != 1)) + if ((virLogNbOutputs == 0) && (flags != 1)) { + if (logVersionStderr) { + char *ver = NULL; + if (virLogVersionString(&ver, &time_info, &cur_time) >= 0) + ignore_value (safewrite(STDERR_FILENO, + ver, strlen(ver))); + VIR_FREE(ver); + logVersionStderr = false; + } ignore_value (safewrite(STDERR_FILENO, msg, len)); + } virLogUnlock(); VIR_FREE(msg); -- 1.7.3.4

[adding bug-gnulib] On 01/27/2011 11:21 AM, Daniel P. Berrange wrote:
The logging functions are enhanced so that immediately prior to the first log message being printed to any output channel, the libvirt package version will be printed.
eg
$ LIBVIRT_DEBUG=1 virsh 18:13:28.013: 17536: info : libvirt version: 0.8.7 18:13:28.013: 17536: debug : virInitialize:361 : register drivers
I like it.
* src/util/logging.c: Output version data prior to first log message * libvirt.spec.in: Include RPM release, date, hostname & packager * configure.ac: Add --with-package-string arg
Let's have some cross-project compatibility (to avoid confusion or subtle typos when using the same option already in use elsewhere). Many GNU projects already have the following configure options: --with-packager String identifying the packager of this software --with-packager-version Packager-specific version information --with-packager-bug-reports Packager info for bug reports (URL/e-mail/...) and in fact, they get that straight out of gnulib, via the version-etc module (unfortunately LGPLv3+ at the moment) - let me see if I can get that improved, so we can reap the benefits of shared code, before I review a slightly different implementation for libvirt. But part of the issue is that the current version-etc module, in addition to providing the nice .m4 file for defining additional PACKAGER variables in the source code, also provides the version_etc() function which is hardcoded to output a GPLv3+ version string (oops - why is the module LGPLv3+ if it outputs GPLv3+?). Gnulib already has version-etc-fsf separate from version-etc for easy exclusion of an FSF copyright holder, so what is still missing is an easy way to override the default license output when using version_etc(). Maybe by moving the default GPLv3+ out of version-etc.c and into version-etc-fsf.c. -- Eric Blake eblake@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org
participants (2)
-
Daniel P. Berrange
-
Eric Blake