2008-11-06 16:36:07 +00:00
|
|
|
/*
|
2012-12-12 17:59:27 +00:00
|
|
|
* virlog.c: internal logging and debugging
|
2008-11-06 16:36:07 +00:00
|
|
|
*
|
build: avoid non-portable cast of pthread_t
POSIX says pthread_t is opaque. We can't guarantee if it is scaler
or a pointer, nor what size it is; and BSD differs from Linux.
We've also had reports of gcc complaining on attempts to cast it,
if we use a cast to the wrong type (for example, pointers have to be
cast to void* or intptr_t before being narrowed; while casting a
function return of scalar pthread_t to void* triggers a different
warning).
Give up on casts, and use unions to get at decent bits instead. And
rather than futz around with figuring which 32 bits of a potentially
64-bit pointer are most likely to be unique, convert the rest of
the code base to use 64-bit values when using a debug id.
Based on a report by Guido Günther against kFreeBSD, but with a
fix that doesn't regress commit 4d970fd29 for FreeBSD.
* src/util/virthreadpthread.c (virThreadSelfID, virThreadID): Use
union to get at a decent bit representation of thread_t bits.
* src/util/virthread.h (virThreadSelfID, virThreadID): Alter
signature.
* src/util/virthreadwin32.c (virThreadSelfID, virThreadID):
Likewise.
* src/qemu/qemu_domain.h (qemuDomainJobObj): Alter type of owner.
* src/qemu/qemu_domain.c (qemuDomainObjTransferJob)
(qemuDomainObjSetJobPhase, qemuDomainObjReleaseAsyncJob)
(qemuDomainObjBeginNestedJob, qemuDomainObjBeginJobInternal): Fix
clients.
* src/util/virlog.c (virLogFormatString): Likewise.
* src/util/vireventpoll.c (virEventPollInterruptLocked):
Likewise.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-05-02 20:23:02 +00:00
|
|
|
* Copyright (C) 2008, 2010-2013 Red Hat, Inc.
|
2008-11-06 16:36:07 +00:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
2012-09-20 22:30:55 +00:00
|
|
|
* License along with this library. If not, see
|
2012-07-21 10:06:23 +00:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
2008-11-06 16:36:07 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
2008-12-22 10:36:54 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
2009-01-06 18:32:03 +00:00
|
|
|
#include <unistd.h>
|
2012-09-05 22:27:42 +00:00
|
|
|
#include <execinfo.h>
|
2013-03-04 20:46:32 +00:00
|
|
|
#include <regex.h>
|
2008-12-22 10:36:54 +00:00
|
|
|
#if HAVE_SYSLOG_H
|
2010-03-09 18:22:22 +00:00
|
|
|
# include <syslog.h>
|
2008-12-22 10:36:54 +00:00
|
|
|
#endif
|
2012-09-25 17:31:01 +00:00
|
|
|
#include <sys/socket.h>
|
|
|
|
#if HAVE_SYS_UN_H
|
|
|
|
# include <sys/un.h>
|
|
|
|
#endif
|
2008-12-22 10:36:54 +00:00
|
|
|
|
2012-12-13 18:21:53 +00:00
|
|
|
#include "virerror.h"
|
2012-12-12 17:59:27 +00:00
|
|
|
#include "virlog.h"
|
2012-12-12 18:06:53 +00:00
|
|
|
#include "viralloc.h"
|
2012-12-13 17:44:57 +00:00
|
|
|
#include "virutil.h"
|
2012-12-04 12:04:07 +00:00
|
|
|
#include "virbuffer.h"
|
2012-12-13 15:49:48 +00:00
|
|
|
#include "virthread.h"
|
2011-07-19 18:32:58 +00:00
|
|
|
#include "virfile.h"
|
2011-11-29 12:32:31 +00:00
|
|
|
#include "virtime.h"
|
2012-09-25 17:31:01 +00:00
|
|
|
#include "intprops.h"
|
2013-04-03 10:36:23 +00:00
|
|
|
#include "virstring.h"
|
2008-11-06 16:36:07 +00:00
|
|
|
|
2012-10-01 22:38:56 +00:00
|
|
|
/* Journald output is only supported on Linux new enough to expose
|
|
|
|
* htole64. */
|
|
|
|
#if HAVE_SYSLOG_H && defined(__linux__) && HAVE_DECL_HTOLE64
|
|
|
|
# define USE_JOURNALD 1
|
|
|
|
#endif
|
|
|
|
|
2011-03-08 10:31:20 +00:00
|
|
|
#define VIR_FROM_THIS VIR_FROM_NONE
|
|
|
|
|
2014-02-28 12:16:17 +00:00
|
|
|
VIR_LOG_INIT("util.log");
|
|
|
|
|
2013-03-04 20:46:32 +00:00
|
|
|
static regex_t *virLogRegex = NULL;
|
|
|
|
|
|
|
|
|
2013-04-22 16:33:01 +00:00
|
|
|
#define VIR_LOG_DATE_REGEX "[0-9]{4}-[0-9]{2}-[0-9]{2}"
|
|
|
|
#define VIR_LOG_TIME_REGEX "[0-9]{2}:[0-9]{2}:[0-9]{2}\\.[0-9]{3}\\+[0-9]{4}"
|
2013-03-04 20:46:32 +00:00
|
|
|
#define VIR_LOG_PID_REGEX "[0-9]+"
|
2013-10-11 16:07:54 +00:00
|
|
|
#define VIR_LOG_LEVEL_REGEX "(debug|info|warning|error)"
|
2013-03-04 20:46:32 +00:00
|
|
|
|
|
|
|
#define VIR_LOG_REGEX \
|
|
|
|
VIR_LOG_DATE_REGEX " " VIR_LOG_TIME_REGEX ": " \
|
|
|
|
VIR_LOG_PID_REGEX ": " VIR_LOG_LEVEL_REGEX " : "
|
2008-12-22 10:36:54 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Filters are used to refine the rules on what to keep or drop
|
|
|
|
* based on a matching pattern (currently a substring)
|
|
|
|
*/
|
|
|
|
struct _virLogFilter {
|
2013-09-03 11:36:22 +00:00
|
|
|
char *match;
|
2012-09-27 12:58:58 +00:00
|
|
|
virLogPriority priority;
|
2012-05-09 14:18:56 +00:00
|
|
|
unsigned int flags;
|
2008-12-22 10:36:54 +00:00
|
|
|
};
|
|
|
|
typedef struct _virLogFilter virLogFilter;
|
|
|
|
typedef virLogFilter *virLogFilterPtr;
|
|
|
|
|
Switch to filtering based on log source name instead of filename
Currently the log filter strings are used in a string comparison
against the source filename each time log message is emitted.
If no log filters at all are set, there's obviously no string
comparison to be done. If any single log filter is set though,
this imposes a compute burden on every logging call even if logs
from the file in question are disabled. This string comparison
must also be done while the logging mutex is held, which has
implications for concurrency when multiple threads are emitting
log messages.
This changes the log filtering to be done based on the virLogSource
object name. The virLogSource struct is extended to contain
'serial' and 'priority' fields. Any time the global log filter
rules are changed a global serial number is incremented. When a
log message is emitted, the serial in the virLogSource instance
is compared with the global serial number. If out of date, then
the 'priority' field in the virLogSource instance is updated based
on the new filter rules. The 'priority' field is checked to see
whether the log message should be sent to the log outputs.
The comparisons of the 'serial' and 'priority' fields are done
with no locks held. So in the common case each logging call has
an overhead of 2 integer comparisons, with no locks held. Only
if the decision is made to forward the message to the log output,
or if the 'serial' value is out of date do locks need to be
acquired.
Technically the comparisons of the 'serial' and 'priority' fields
should be done with locks held, or using atomic operations. Both
of these options have a notable performance impact, however, and
since all writes a protected by a global mutex, it is believed
that worst case behaviour where the fields are read concurrently
with being written would merely result in an mistaken emission
or dropping of the log message in question. This is an acceptable
tradeoff for the performance benefit of avoiding locking.
As a quick benchmark, a demo program that registers 500 file
descriptors with the event loop (eg equiv of 500 QEMU monitor
commands), creates pending read I/O on every FD, and then runs
virEventRunDefaultImpl() took 4.6 seconds to do 51200 iterations.
After this optimization it only takes 3.3 seconds, with the log
APIs no longer being a relevant factor in the running time.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2014-02-28 13:55:11 +00:00
|
|
|
static int virLogFiltersSerial = 1;
|
2008-12-22 10:36:54 +00:00
|
|
|
static virLogFilterPtr virLogFilters = NULL;
|
|
|
|
static int virLogNbFilters = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Outputs are used to emit the messages retained
|
|
|
|
* after filtering, multiple output can be used simultaneously
|
|
|
|
*/
|
|
|
|
struct _virLogOutput {
|
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 two new arguments which can be
used as
--with-packager="Fedora Project, x86-01.phx2.fedoraproject.org, 01-27-2011-18:00:10"
--with-packager-version="1.fc14"
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-packager & --with-packager-version args
2011-01-27 18:11:16 +00:00
|
|
|
bool logVersion;
|
2008-12-22 10:36:54 +00:00
|
|
|
void *data;
|
|
|
|
virLogOutputFunc f;
|
|
|
|
virLogCloseFunc c;
|
2012-09-27 12:58:58 +00:00
|
|
|
virLogPriority priority;
|
2009-10-08 15:05:01 +00:00
|
|
|
virLogDestination dest;
|
2013-09-03 11:36:22 +00:00
|
|
|
char *name;
|
2008-12-22 10:36:54 +00:00
|
|
|
};
|
|
|
|
typedef struct _virLogOutput virLogOutput;
|
|
|
|
typedef virLogOutput *virLogOutputPtr;
|
|
|
|
|
|
|
|
static virLogOutputPtr virLogOutputs = NULL;
|
|
|
|
static int virLogNbOutputs = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Default priorities
|
|
|
|
*/
|
2009-07-01 11:21:15 +00:00
|
|
|
static virLogPriority virLogDefaultPriority = VIR_LOG_DEFAULT;
|
2008-12-22 10:36:54 +00:00
|
|
|
|
|
|
|
static int virLogResetFilters(void);
|
|
|
|
static int virLogResetOutputs(void);
|
2014-02-27 17:44:53 +00:00
|
|
|
static void virLogOutputToFd(virLogSourcePtr src,
|
2012-09-27 13:14:01 +00:00
|
|
|
virLogPriority priority,
|
2012-09-27 13:28:44 +00:00
|
|
|
const char *filename,
|
2012-09-27 13:14:01 +00:00
|
|
|
int linenr,
|
2012-09-27 13:28:44 +00:00
|
|
|
const char *funcname,
|
2012-09-20 18:24:00 +00:00
|
|
|
const char *timestamp,
|
2012-10-17 18:17:15 +00:00
|
|
|
virLogMetadataPtr metadata,
|
2012-09-20 18:24:00 +00:00
|
|
|
unsigned int flags,
|
2012-09-27 13:14:01 +00:00
|
|
|
const char *rawstr,
|
|
|
|
const char *str,
|
2012-09-20 18:24:00 +00:00
|
|
|
void *data);
|
2008-12-22 10:36:54 +00:00
|
|
|
|
2014-02-27 17:44:53 +00:00
|
|
|
|
2008-12-22 10:36:54 +00:00
|
|
|
/*
|
|
|
|
* Logs accesses must be serialized though a mutex
|
|
|
|
*/
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutex virLogMutex;
|
2008-12-22 10:36:54 +00:00
|
|
|
|
2012-09-27 13:14:01 +00:00
|
|
|
void
|
|
|
|
virLogLock(void)
|
2008-12-22 10:36:54 +00:00
|
|
|
{
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexLock(&virLogMutex);
|
2008-12-22 10:36:54 +00:00
|
|
|
}
|
2012-09-27 13:14:01 +00:00
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
virLogUnlock(void)
|
2008-12-22 10:36:54 +00:00
|
|
|
{
|
2009-01-15 19:56:05 +00:00
|
|
|
virMutexUnlock(&virLogMutex);
|
2008-12-22 10:36:54 +00:00
|
|
|
}
|
|
|
|
|
2012-09-27 13:14:01 +00:00
|
|
|
|
|
|
|
static const char *
|
|
|
|
virLogOutputString(virLogDestination ldest)
|
|
|
|
{
|
2009-10-08 15:05:01 +00:00
|
|
|
switch (ldest) {
|
2011-01-21 16:30:17 +00:00
|
|
|
case VIR_LOG_TO_STDERR:
|
|
|
|
return "stderr";
|
|
|
|
case VIR_LOG_TO_SYSLOG:
|
|
|
|
return "syslog";
|
|
|
|
case VIR_LOG_TO_FILE:
|
|
|
|
return "file";
|
2012-09-25 17:31:01 +00:00
|
|
|
case VIR_LOG_TO_JOURNALD:
|
|
|
|
return "journald";
|
2009-10-08 15:05:01 +00:00
|
|
|
}
|
2011-01-21 16:30:17 +00:00
|
|
|
return "unknown";
|
2009-10-08 15:05:01 +00:00
|
|
|
}
|
2008-12-22 10:36:54 +00:00
|
|
|
|
2012-09-27 13:14:01 +00:00
|
|
|
|
|
|
|
static const char *
|
|
|
|
virLogPriorityString(virLogPriority lvl)
|
|
|
|
{
|
2008-12-22 10:36:54 +00:00
|
|
|
switch (lvl) {
|
2011-01-21 16:30:17 +00:00
|
|
|
case VIR_LOG_DEBUG:
|
|
|
|
return "debug";
|
|
|
|
case VIR_LOG_INFO:
|
|
|
|
return "info";
|
|
|
|
case VIR_LOG_WARN:
|
|
|
|
return "warning";
|
|
|
|
case VIR_LOG_ERROR:
|
|
|
|
return "error";
|
2008-12-22 10:36:54 +00:00
|
|
|
}
|
2011-01-21 16:30:17 +00:00
|
|
|
return "unknown";
|
2008-12-22 10:36:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-09-27 13:14:01 +00:00
|
|
|
static int
|
|
|
|
virLogOnceInit(void)
|
2012-07-11 13:35:42 +00:00
|
|
|
{
|
2009-01-15 19:56:05 +00:00
|
|
|
if (virMutexInit(&virLogMutex) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2008-12-22 10:36:54 +00:00
|
|
|
virLogLock();
|
2009-07-01 11:21:15 +00:00
|
|
|
virLogDefaultPriority = VIR_LOG_DEFAULT;
|
2013-03-04 20:46:32 +00:00
|
|
|
|
2013-06-07 08:37:25 +00:00
|
|
|
if (VIR_ALLOC_QUIET(virLogRegex) >= 0) {
|
2013-03-04 20:46:32 +00:00
|
|
|
if (regcomp(virLogRegex, VIR_LOG_REGEX, REG_EXTENDED) != 0)
|
|
|
|
VIR_FREE(virLogRegex);
|
|
|
|
}
|
|
|
|
|
2008-12-22 10:36:54 +00:00
|
|
|
virLogUnlock();
|
2011-01-21 16:30:17 +00:00
|
|
|
return 0;
|
2008-12-22 10:36:54 +00:00
|
|
|
}
|
|
|
|
|
2012-07-11 13:35:42 +00:00
|
|
|
VIR_ONCE_GLOBAL_INIT(virLog)
|
|
|
|
|
2012-09-27 13:14:01 +00:00
|
|
|
|
2008-12-22 10:36:54 +00:00
|
|
|
/**
|
|
|
|
* virLogReset:
|
|
|
|
*
|
|
|
|
* Reset the logging module to its default initial state
|
|
|
|
*
|
|
|
|
* Returns 0 if successful, and -1 in case or error
|
|
|
|
*/
|
2012-09-27 13:14:01 +00:00
|
|
|
int
|
|
|
|
virLogReset(void)
|
|
|
|
{
|
2012-07-11 13:35:42 +00:00
|
|
|
if (virLogInitialize() < 0)
|
|
|
|
return -1;
|
2008-12-22 10:36:54 +00:00
|
|
|
|
|
|
|
virLogLock();
|
|
|
|
virLogResetFilters();
|
|
|
|
virLogResetOutputs();
|
2009-07-01 11:21:15 +00:00
|
|
|
virLogDefaultPriority = VIR_LOG_DEFAULT;
|
2008-12-22 10:36:54 +00:00
|
|
|
virLogUnlock();
|
2011-01-21 16:30:17 +00:00
|
|
|
return 0;
|
2008-12-22 10:36:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virLogSetDefaultPriority:
|
|
|
|
* @priority: the default priority level
|
|
|
|
*
|
|
|
|
* Set the default priority level, i.e. any logged data of a priority
|
|
|
|
* equal or superior to this level will be logged, unless a specific rule
|
|
|
|
* was defined for the log category of the message.
|
|
|
|
*
|
|
|
|
* Returns 0 if successful, -1 in case of error.
|
|
|
|
*/
|
2012-09-27 13:14:01 +00:00
|
|
|
int
|
|
|
|
virLogSetDefaultPriority(virLogPriority priority)
|
|
|
|
{
|
2009-08-06 13:38:11 +00:00
|
|
|
if ((priority < VIR_LOG_DEBUG) || (priority > VIR_LOG_ERROR)) {
|
2011-05-09 09:24:09 +00:00
|
|
|
VIR_WARN("Ignoring invalid log level setting.");
|
2011-01-21 16:30:17 +00:00
|
|
|
return -1;
|
2009-08-06 13:38:11 +00:00
|
|
|
}
|
2012-07-11 13:35:42 +00:00
|
|
|
if (virLogInitialize() < 0)
|
|
|
|
return -1;
|
|
|
|
|
2008-12-22 10:36:54 +00:00
|
|
|
virLogDefaultPriority = priority;
|
2011-01-21 16:30:17 +00:00
|
|
|
return 0;
|
2008-12-22 10:36:54 +00:00
|
|
|
}
|
|
|
|
|
2012-09-27 13:14:01 +00:00
|
|
|
|
2008-12-22 10:36:54 +00:00
|
|
|
/**
|
|
|
|
* virLogResetFilters:
|
|
|
|
*
|
|
|
|
* Removes the set of logging filters defined.
|
|
|
|
*
|
|
|
|
* Returns the number of filters removed
|
|
|
|
*/
|
2012-09-27 13:14:01 +00:00
|
|
|
static int
|
|
|
|
virLogResetFilters(void)
|
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/util/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2008-12-22 10:36:54 +00:00
|
|
|
|
2013-05-24 16:58:25 +00:00
|
|
|
for (i = 0; i < virLogNbFilters; i++)
|
2008-12-22 10:36:54 +00:00
|
|
|
VIR_FREE(virLogFilters[i].match);
|
|
|
|
VIR_FREE(virLogFilters);
|
|
|
|
virLogNbFilters = 0;
|
Switch to filtering based on log source name instead of filename
Currently the log filter strings are used in a string comparison
against the source filename each time log message is emitted.
If no log filters at all are set, there's obviously no string
comparison to be done. If any single log filter is set though,
this imposes a compute burden on every logging call even if logs
from the file in question are disabled. This string comparison
must also be done while the logging mutex is held, which has
implications for concurrency when multiple threads are emitting
log messages.
This changes the log filtering to be done based on the virLogSource
object name. The virLogSource struct is extended to contain
'serial' and 'priority' fields. Any time the global log filter
rules are changed a global serial number is incremented. When a
log message is emitted, the serial in the virLogSource instance
is compared with the global serial number. If out of date, then
the 'priority' field in the virLogSource instance is updated based
on the new filter rules. The 'priority' field is checked to see
whether the log message should be sent to the log outputs.
The comparisons of the 'serial' and 'priority' fields are done
with no locks held. So in the common case each logging call has
an overhead of 2 integer comparisons, with no locks held. Only
if the decision is made to forward the message to the log output,
or if the 'serial' value is out of date do locks need to be
acquired.
Technically the comparisons of the 'serial' and 'priority' fields
should be done with locks held, or using atomic operations. Both
of these options have a notable performance impact, however, and
since all writes a protected by a global mutex, it is believed
that worst case behaviour where the fields are read concurrently
with being written would merely result in an mistaken emission
or dropping of the log message in question. This is an acceptable
tradeoff for the performance benefit of avoiding locking.
As a quick benchmark, a demo program that registers 500 file
descriptors with the event loop (eg equiv of 500 QEMU monitor
commands), creates pending read I/O on every FD, and then runs
virEventRunDefaultImpl() took 4.6 seconds to do 51200 iterations.
After this optimization it only takes 3.3 seconds, with the log
APIs no longer being a relevant factor in the running time.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2014-02-28 13:55:11 +00:00
|
|
|
virLogFiltersSerial++;
|
2011-01-21 16:30:17 +00:00
|
|
|
return i;
|
2008-12-22 10:36:54 +00:00
|
|
|
}
|
|
|
|
|
2012-09-27 13:14:01 +00:00
|
|
|
|
2008-12-22 10:36:54 +00:00
|
|
|
/**
|
|
|
|
* virLogDefineFilter:
|
|
|
|
* @match: the pattern to match
|
|
|
|
* @priority: the priority to give to messages matching the pattern
|
2012-05-09 14:18:56 +00:00
|
|
|
* @flags: extra flags, see virLogFilterFlags enum
|
2008-12-22 10:36:54 +00:00
|
|
|
*
|
|
|
|
* Defines a pattern used for log filtering, it allow to select or
|
|
|
|
* reject messages independently of the default priority.
|
|
|
|
* The filter defines a rules that will apply only to messages matching
|
|
|
|
* the pattern (currently if @match is a substring of the message category)
|
|
|
|
*
|
|
|
|
* Returns -1 in case of failure or the filter number if successful
|
|
|
|
*/
|
2012-09-27 13:14:01 +00:00
|
|
|
int
|
|
|
|
virLogDefineFilter(const char *match,
|
|
|
|
virLogPriority priority,
|
|
|
|
unsigned int flags)
|
2011-07-06 22:29:02 +00:00
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/util/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
|
|
|
int ret = -1;
|
2008-12-22 10:36:54 +00:00
|
|
|
char *mdup = NULL;
|
|
|
|
|
2012-05-09 14:18:56 +00:00
|
|
|
virCheckFlags(VIR_LOG_STACK_TRACE, -1);
|
2011-07-06 22:29:02 +00:00
|
|
|
|
2013-10-08 13:35:01 +00:00
|
|
|
if (virLogInitialize() < 0)
|
|
|
|
return -1;
|
|
|
|
|
2008-12-22 10:36:54 +00:00
|
|
|
if ((match == NULL) || (priority < VIR_LOG_DEBUG) ||
|
|
|
|
(priority > VIR_LOG_ERROR))
|
2011-01-21 16:30:17 +00:00
|
|
|
return -1;
|
2008-12-22 10:36:54 +00:00
|
|
|
|
|
|
|
virLogLock();
|
2013-05-24 16:58:25 +00:00
|
|
|
for (i = 0; i < virLogNbFilters; i++) {
|
2008-12-22 10:36:54 +00:00
|
|
|
if (STREQ(virLogFilters[i].match, match)) {
|
|
|
|
virLogFilters[i].priority = priority;
|
Convert 'int i' to 'size_t i' in src/util/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
ret = i;
|
2008-12-22 10:36:54 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Convert 'int i' to 'size_t i' in src/util/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
if (VIR_STRDUP_QUIET(mdup, match) < 0)
|
2008-12-22 10:36:54 +00:00
|
|
|
goto cleanup;
|
2013-06-07 08:37:25 +00:00
|
|
|
if (VIR_REALLOC_N_QUIET(virLogFilters, virLogNbFilters + 1)) {
|
2008-12-22 10:36:54 +00:00
|
|
|
VIR_FREE(mdup);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
Convert 'int i' to 'size_t i' in src/util/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
ret = virLogNbFilters;
|
2008-12-22 10:36:54 +00:00
|
|
|
virLogFilters[i].match = mdup;
|
|
|
|
virLogFilters[i].priority = priority;
|
2012-05-09 14:18:56 +00:00
|
|
|
virLogFilters[i].flags = flags;
|
2008-12-22 10:36:54 +00:00
|
|
|
virLogNbFilters++;
|
Switch to filtering based on log source name instead of filename
Currently the log filter strings are used in a string comparison
against the source filename each time log message is emitted.
If no log filters at all are set, there's obviously no string
comparison to be done. If any single log filter is set though,
this imposes a compute burden on every logging call even if logs
from the file in question are disabled. This string comparison
must also be done while the logging mutex is held, which has
implications for concurrency when multiple threads are emitting
log messages.
This changes the log filtering to be done based on the virLogSource
object name. The virLogSource struct is extended to contain
'serial' and 'priority' fields. Any time the global log filter
rules are changed a global serial number is incremented. When a
log message is emitted, the serial in the virLogSource instance
is compared with the global serial number. If out of date, then
the 'priority' field in the virLogSource instance is updated based
on the new filter rules. The 'priority' field is checked to see
whether the log message should be sent to the log outputs.
The comparisons of the 'serial' and 'priority' fields are done
with no locks held. So in the common case each logging call has
an overhead of 2 integer comparisons, with no locks held. Only
if the decision is made to forward the message to the log output,
or if the 'serial' value is out of date do locks need to be
acquired.
Technically the comparisons of the 'serial' and 'priority' fields
should be done with locks held, or using atomic operations. Both
of these options have a notable performance impact, however, and
since all writes a protected by a global mutex, it is believed
that worst case behaviour where the fields are read concurrently
with being written would merely result in an mistaken emission
or dropping of the log message in question. This is an acceptable
tradeoff for the performance benefit of avoiding locking.
As a quick benchmark, a demo program that registers 500 file
descriptors with the event loop (eg equiv of 500 QEMU monitor
commands), creates pending read I/O on every FD, and then runs
virEventRunDefaultImpl() took 4.6 seconds to do 51200 iterations.
After this optimization it only takes 3.3 seconds, with the log
APIs no longer being a relevant factor in the running time.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2014-02-28 13:55:11 +00:00
|
|
|
virLogFiltersSerial++;
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
2008-12-22 10:36:54 +00:00
|
|
|
virLogUnlock();
|
Convert 'int i' to 'size_t i' in src/util/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
if (ret < 0)
|
2013-05-24 07:19:51 +00:00
|
|
|
virReportOOMError();
|
Convert 'int i' to 'size_t i' in src/util/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
return ret;
|
2008-12-22 10:36:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* virLogResetOutputs:
|
|
|
|
*
|
|
|
|
* Removes the set of logging output defined.
|
|
|
|
*
|
|
|
|
* Returns the number of output removed
|
|
|
|
*/
|
2012-09-27 13:14:01 +00:00
|
|
|
static int
|
|
|
|
virLogResetOutputs(void)
|
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/util/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2008-12-22 10:36:54 +00:00
|
|
|
|
2013-05-24 16:58:25 +00:00
|
|
|
for (i = 0; i < virLogNbOutputs; i++) {
|
2008-12-22 10:36:54 +00:00
|
|
|
if (virLogOutputs[i].c != NULL)
|
|
|
|
virLogOutputs[i].c(virLogOutputs[i].data);
|
2009-10-08 15:05:01 +00:00
|
|
|
VIR_FREE(virLogOutputs[i].name);
|
2008-12-22 10:36:54 +00:00
|
|
|
}
|
|
|
|
VIR_FREE(virLogOutputs);
|
|
|
|
i = virLogNbOutputs;
|
|
|
|
virLogNbOutputs = 0;
|
2011-01-21 16:30:17 +00:00
|
|
|
return i;
|
2008-12-22 10:36:54 +00:00
|
|
|
}
|
|
|
|
|
2012-09-27 13:14:01 +00:00
|
|
|
|
2008-12-22 10:36:54 +00:00
|
|
|
/**
|
|
|
|
* virLogDefineOutput:
|
|
|
|
* @f: the function to call to output a message
|
2009-10-08 15:05:01 +00:00
|
|
|
* @c: the function to call to close the output (or NULL)
|
2008-12-22 10:36:54 +00:00
|
|
|
* @data: extra data passed as first arg to the function
|
|
|
|
* @priority: minimal priority for this filter, use 0 for none
|
2009-10-08 15:05:01 +00:00
|
|
|
* @dest: where to send output of this priority
|
|
|
|
* @name: optional name data associated with an output
|
2008-12-22 10:36:54 +00:00
|
|
|
* @flags: extra flag, currently unused
|
|
|
|
*
|
|
|
|
* Defines an output function for log messages. Each message once
|
|
|
|
* gone though filtering is emitted through each registered output.
|
|
|
|
*
|
|
|
|
* Returns -1 in case of failure or the output number if successful
|
|
|
|
*/
|
2012-09-27 13:14:01 +00:00
|
|
|
int
|
|
|
|
virLogDefineOutput(virLogOutputFunc f,
|
|
|
|
virLogCloseFunc c,
|
|
|
|
void *data,
|
|
|
|
virLogPriority priority,
|
|
|
|
virLogDestination dest,
|
|
|
|
const char *name,
|
|
|
|
unsigned int flags)
|
2011-07-06 22:29:02 +00:00
|
|
|
{
|
2008-12-22 10:36:54 +00:00
|
|
|
int ret = -1;
|
2009-10-08 15:05:01 +00:00
|
|
|
char *ndup = NULL;
|
2008-12-22 10:36:54 +00:00
|
|
|
|
2011-07-06 22:29:02 +00:00
|
|
|
virCheckFlags(0, -1);
|
|
|
|
|
2013-10-08 13:35:01 +00:00
|
|
|
if (virLogInitialize() < 0)
|
|
|
|
return -1;
|
|
|
|
|
2008-12-22 10:36:54 +00:00
|
|
|
if (f == NULL)
|
2011-01-21 16:30:17 +00:00
|
|
|
return -1;
|
2008-12-22 10:36:54 +00:00
|
|
|
|
2009-10-08 15:05:01 +00:00
|
|
|
if (dest == VIR_LOG_TO_SYSLOG || dest == VIR_LOG_TO_FILE) {
|
2013-05-24 07:19:51 +00:00
|
|
|
if (!name) {
|
|
|
|
virReportOOMError();
|
2011-01-21 16:30:17 +00:00
|
|
|
return -1;
|
2013-05-24 07:19:51 +00:00
|
|
|
}
|
|
|
|
if (VIR_STRDUP(ndup, name) < 0)
|
2011-01-21 16:30:17 +00:00
|
|
|
return -1;
|
2009-10-08 15:05:01 +00:00
|
|
|
}
|
|
|
|
|
2008-12-22 10:36:54 +00:00
|
|
|
virLogLock();
|
2013-06-07 08:37:25 +00:00
|
|
|
if (VIR_REALLOC_N_QUIET(virLogOutputs, virLogNbOutputs + 1)) {
|
2009-11-10 11:56:11 +00:00
|
|
|
VIR_FREE(ndup);
|
2008-12-22 10:36:54 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
ret = virLogNbOutputs++;
|
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 two new arguments which can be
used as
--with-packager="Fedora Project, x86-01.phx2.fedoraproject.org, 01-27-2011-18:00:10"
--with-packager-version="1.fc14"
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-packager & --with-packager-version args
2011-01-27 18:11:16 +00:00
|
|
|
virLogOutputs[ret].logVersion = true;
|
2008-12-22 10:36:54 +00:00
|
|
|
virLogOutputs[ret].f = f;
|
|
|
|
virLogOutputs[ret].c = c;
|
|
|
|
virLogOutputs[ret].data = data;
|
|
|
|
virLogOutputs[ret].priority = priority;
|
2009-10-08 15:05:01 +00:00
|
|
|
virLogOutputs[ret].dest = dest;
|
|
|
|
virLogOutputs[ret].name = ndup;
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
2008-12-22 10:36:54 +00:00
|
|
|
virLogUnlock();
|
2011-01-21 16:30:17 +00:00
|
|
|
return ret;
|
2008-12-22 10:36:54 +00:00
|
|
|
}
|
|
|
|
|
2011-09-28 13:20:07 +00:00
|
|
|
|
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 two new arguments which can be
used as
--with-packager="Fedora Project, x86-01.phx2.fedoraproject.org, 01-27-2011-18:00:10"
--with-packager-version="1.fc14"
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-packager & --with-packager-version args
2011-01-27 18:11:16 +00:00
|
|
|
static int
|
|
|
|
virLogFormatString(char **msg,
|
2012-09-27 13:00:21 +00:00
|
|
|
int linenr,
|
2012-09-27 13:28:44 +00:00
|
|
|
const char *funcname,
|
2012-09-27 12:58:58 +00:00
|
|
|
virLogPriority priority,
|
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 two new arguments which can be
used as
--with-packager="Fedora Project, x86-01.phx2.fedoraproject.org, 01-27-2011-18:00:10"
--with-packager-version="1.fc14"
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-packager & --with-packager-version args
2011-01-27 18:11:16 +00:00
|
|
|
const char *str)
|
|
|
|
{
|
|
|
|
int ret;
|
2011-03-30 11:57:27 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Be careful when changing the following log message formatting, we rely
|
|
|
|
* on it when stripping libvirt debug messages from qemu log files. So when
|
|
|
|
* changing this, you might also need to change the code there.
|
|
|
|
* virLogFormatString() function name is mentioned there so it's sufficient
|
|
|
|
* to just grep for it to find the right place.
|
|
|
|
*/
|
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 two new arguments which can be
used as
--with-packager="Fedora Project, x86-01.phx2.fedoraproject.org, 01-27-2011-18:00:10"
--with-packager-version="1.fc14"
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-packager & --with-packager-version args
2011-01-27 18:11:16 +00:00
|
|
|
if ((funcname != NULL)) {
|
2013-06-07 15:10:28 +00:00
|
|
|
ret = virAsprintfQuiet(msg, "%llu: %s : %s:%d : %s\n",
|
|
|
|
virThreadSelfID(), virLogPriorityString(priority),
|
|
|
|
funcname, linenr, str);
|
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 two new arguments which can be
used as
--with-packager="Fedora Project, x86-01.phx2.fedoraproject.org, 01-27-2011-18:00:10"
--with-packager-version="1.fc14"
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-packager & --with-packager-version args
2011-01-27 18:11:16 +00:00
|
|
|
} else {
|
2013-06-07 15:10:28 +00:00
|
|
|
ret = virAsprintfQuiet(msg, "%llu: %s : %s\n",
|
|
|
|
virThreadSelfID(), virLogPriorityString(priority),
|
|
|
|
str);
|
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 two new arguments which can be
used as
--with-packager="Fedora Project, x86-01.phx2.fedoraproject.org, 01-27-2011-18:00:10"
--with-packager-version="1.fc14"
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-packager & --with-packager-version args
2011-01-27 18:11:16 +00:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-09-27 13:14:01 +00:00
|
|
|
|
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 two new arguments which can be
used as
--with-packager="Fedora Project, x86-01.phx2.fedoraproject.org, 01-27-2011-18:00:10"
--with-packager-version="1.fc14"
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-packager & --with-packager-version args
2011-01-27 18:11:16 +00:00
|
|
|
static int
|
2012-09-27 13:14:01 +00:00
|
|
|
virLogVersionString(const char **rawmsg,
|
|
|
|
char **msg)
|
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 two new arguments which can be
used as
--with-packager="Fedora Project, x86-01.phx2.fedoraproject.org, 01-27-2011-18:00:10"
--with-packager-version="1.fc14"
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-packager & --with-packager-version args
2011-01-27 18:11:16 +00:00
|
|
|
{
|
|
|
|
#ifdef PACKAGER_VERSION
|
|
|
|
# ifdef PACKAGER
|
|
|
|
# define LOG_VERSION_STRING \
|
|
|
|
"libvirt version: " VERSION ", package: " PACKAGER_VERSION " (" PACKAGER ")"
|
|
|
|
# else
|
|
|
|
# define LOG_VERSION_STRING \
|
|
|
|
"libvirt version: " VERSION ", package: " PACKAGER_VERSION
|
|
|
|
# endif
|
|
|
|
#else
|
|
|
|
# define LOG_VERSION_STRING \
|
|
|
|
"libvirt version: " VERSION
|
|
|
|
#endif
|
|
|
|
|
2012-09-27 11:45:33 +00:00
|
|
|
*rawmsg = LOG_VERSION_STRING;
|
2012-09-27 13:28:44 +00:00
|
|
|
return virLogFormatString(msg, 0, NULL, VIR_LOG_INFO, LOG_VERSION_STRING);
|
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 two new arguments which can be
used as
--with-packager="Fedora Project, x86-01.phx2.fedoraproject.org, 01-27-2011-18:00:10"
--with-packager-version="1.fc14"
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-packager & --with-packager-version args
2011-01-27 18:11:16 +00:00
|
|
|
}
|
|
|
|
|
2012-09-27 13:14:01 +00:00
|
|
|
|
Switch to filtering based on log source name instead of filename
Currently the log filter strings are used in a string comparison
against the source filename each time log message is emitted.
If no log filters at all are set, there's obviously no string
comparison to be done. If any single log filter is set though,
this imposes a compute burden on every logging call even if logs
from the file in question are disabled. This string comparison
must also be done while the logging mutex is held, which has
implications for concurrency when multiple threads are emitting
log messages.
This changes the log filtering to be done based on the virLogSource
object name. The virLogSource struct is extended to contain
'serial' and 'priority' fields. Any time the global log filter
rules are changed a global serial number is incremented. When a
log message is emitted, the serial in the virLogSource instance
is compared with the global serial number. If out of date, then
the 'priority' field in the virLogSource instance is updated based
on the new filter rules. The 'priority' field is checked to see
whether the log message should be sent to the log outputs.
The comparisons of the 'serial' and 'priority' fields are done
with no locks held. So in the common case each logging call has
an overhead of 2 integer comparisons, with no locks held. Only
if the decision is made to forward the message to the log output,
or if the 'serial' value is out of date do locks need to be
acquired.
Technically the comparisons of the 'serial' and 'priority' fields
should be done with locks held, or using atomic operations. Both
of these options have a notable performance impact, however, and
since all writes a protected by a global mutex, it is believed
that worst case behaviour where the fields are read concurrently
with being written would merely result in an mistaken emission
or dropping of the log message in question. This is an acceptable
tradeoff for the performance benefit of avoiding locking.
As a quick benchmark, a demo program that registers 500 file
descriptors with the event loop (eg equiv of 500 QEMU monitor
commands), creates pending read I/O on every FD, and then runs
virEventRunDefaultImpl() took 4.6 seconds to do 51200 iterations.
After this optimization it only takes 3.3 seconds, with the log
APIs no longer being a relevant factor in the running time.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2014-02-28 13:55:11 +00:00
|
|
|
static void
|
|
|
|
virLogSourceUpdate(virLogSourcePtr source)
|
|
|
|
{
|
|
|
|
virLogLock();
|
|
|
|
if (source->serial < virLogFiltersSerial) {
|
|
|
|
unsigned int priority = virLogDefaultPriority;
|
|
|
|
unsigned int flags = 0;
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < virLogNbFilters; i++) {
|
|
|
|
if (strstr(source->name, virLogFilters[i].match)) {
|
|
|
|
priority = virLogFilters[i].priority;
|
|
|
|
flags = virLogFilters[i].flags;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
source->priority = priority;
|
|
|
|
source->flags = flags;
|
|
|
|
source->serial = virLogFiltersSerial;
|
|
|
|
}
|
|
|
|
virLogUnlock();
|
|
|
|
}
|
|
|
|
|
2008-12-22 10:36:54 +00:00
|
|
|
/**
|
|
|
|
* virLogMessage:
|
2012-09-27 13:44:22 +00:00
|
|
|
* @source: where is that message coming from
|
2008-12-22 10:36:54 +00:00
|
|
|
* @priority: the priority level
|
2012-09-27 13:44:22 +00:00
|
|
|
* @filename: file where the message was emitted
|
2008-12-22 10:44:10 +00:00
|
|
|
* @linenr: line where the message was emitted
|
2012-09-27 13:44:22 +00:00
|
|
|
* @funcname: the function emitting the (debug) message
|
Add a metadata parameter to virLog{, V}Message
... and update all users. No change in functionality, the parameter
will be used later.
The metadata representation is as minimal as possible, but requires
the caller to allocate an array on stack explicitly.
The alternative of using varargs in the virLogMessage() callers:
* Would not allow the caller to optionally omit some metadata elements,
except by having two calls to virLogMessage.
* Would not be as type-safe (e.g. using int vs. size_t), and the compiler
wouldn't be able to do type checking
* Depending on parameter order:
a) virLogMessage(..., message format, message params...,
metadata..., NULL)
can not be portably implemented (parse_printf_format() is a glibc
function)
b) virLogMessage(..., metadata..., NULL,
message format, message params...)
would prevent usage of ATTRIBUTE_FMT_PRINTF and the associated
compiler checking.
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2012-10-17 18:17:14 +00:00
|
|
|
* @metadata: NULL or metadata array, terminated by an item with NULL key
|
2008-12-22 10:36:54 +00:00
|
|
|
* @fmt: the string format
|
|
|
|
* @...: the arguments
|
|
|
|
*
|
2011-12-01 23:08:34 +00:00
|
|
|
* Call the libvirt logger with some information. Based on the configuration
|
2008-12-22 10:36:54 +00:00
|
|
|
* the message may be stored, sent to output or just discarded
|
|
|
|
*/
|
2012-09-27 13:14:01 +00:00
|
|
|
void
|
2014-02-27 17:44:53 +00:00
|
|
|
virLogMessage(virLogSourcePtr source,
|
2012-09-27 13:14:01 +00:00
|
|
|
virLogPriority priority,
|
2012-09-27 13:28:44 +00:00
|
|
|
const char *filename,
|
2012-09-27 13:14:01 +00:00
|
|
|
int linenr,
|
2012-09-27 13:28:44 +00:00
|
|
|
const char *funcname,
|
Add a metadata parameter to virLog{, V}Message
... and update all users. No change in functionality, the parameter
will be used later.
The metadata representation is as minimal as possible, but requires
the caller to allocate an array on stack explicitly.
The alternative of using varargs in the virLogMessage() callers:
* Would not allow the caller to optionally omit some metadata elements,
except by having two calls to virLogMessage.
* Would not be as type-safe (e.g. using int vs. size_t), and the compiler
wouldn't be able to do type checking
* Depending on parameter order:
a) virLogMessage(..., message format, message params...,
metadata..., NULL)
can not be portably implemented (parse_printf_format() is a glibc
function)
b) virLogMessage(..., metadata..., NULL,
message format, message params...)
would prevent usage of ATTRIBUTE_FMT_PRINTF and the associated
compiler checking.
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2012-10-17 18:17:14 +00:00
|
|
|
virLogMetadataPtr metadata,
|
2012-09-27 13:14:01 +00:00
|
|
|
const char *fmt, ...)
|
2012-01-23 14:57:16 +00:00
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
2012-09-27 13:44:22 +00:00
|
|
|
virLogVMessage(source, priority,
|
2012-09-27 13:28:44 +00:00
|
|
|
filename, linenr, funcname,
|
Add a metadata parameter to virLog{, V}Message
... and update all users. No change in functionality, the parameter
will be used later.
The metadata representation is as minimal as possible, but requires
the caller to allocate an array on stack explicitly.
The alternative of using varargs in the virLogMessage() callers:
* Would not allow the caller to optionally omit some metadata elements,
except by having two calls to virLogMessage.
* Would not be as type-safe (e.g. using int vs. size_t), and the compiler
wouldn't be able to do type checking
* Depending on parameter order:
a) virLogMessage(..., message format, message params...,
metadata..., NULL)
can not be portably implemented (parse_printf_format() is a glibc
function)
b) virLogMessage(..., metadata..., NULL,
message format, message params...)
would prevent usage of ATTRIBUTE_FMT_PRINTF and the associated
compiler checking.
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2012-10-17 18:17:14 +00:00
|
|
|
metadata, fmt, ap);
|
2012-01-23 14:57:16 +00:00
|
|
|
va_end(ap);
|
|
|
|
}
|
|
|
|
|
2012-09-27 13:14:01 +00:00
|
|
|
|
2012-01-23 14:57:16 +00:00
|
|
|
/**
|
|
|
|
* virLogVMessage:
|
2012-09-27 13:44:22 +00:00
|
|
|
* @source: where is that message coming from
|
2012-01-23 14:57:16 +00:00
|
|
|
* @priority: the priority level
|
2012-09-27 13:44:22 +00:00
|
|
|
* @filename: file where the message was emitted
|
2012-01-23 14:57:16 +00:00
|
|
|
* @linenr: line where the message was emitted
|
2012-09-27 13:44:22 +00:00
|
|
|
* @funcname: the function emitting the (debug) message
|
Add a metadata parameter to virLog{, V}Message
... and update all users. No change in functionality, the parameter
will be used later.
The metadata representation is as minimal as possible, but requires
the caller to allocate an array on stack explicitly.
The alternative of using varargs in the virLogMessage() callers:
* Would not allow the caller to optionally omit some metadata elements,
except by having two calls to virLogMessage.
* Would not be as type-safe (e.g. using int vs. size_t), and the compiler
wouldn't be able to do type checking
* Depending on parameter order:
a) virLogMessage(..., message format, message params...,
metadata..., NULL)
can not be portably implemented (parse_printf_format() is a glibc
function)
b) virLogMessage(..., metadata..., NULL,
message format, message params...)
would prevent usage of ATTRIBUTE_FMT_PRINTF and the associated
compiler checking.
Signed-off-by: Miloslav Trmač <mitr@redhat.com>
2012-10-17 18:17:14 +00:00
|
|
|
* @metadata: NULL or metadata array, terminated by an item with NULL key
|
2012-01-23 14:57:16 +00:00
|
|
|
* @fmt: the string format
|
|
|
|
* @vargs: format args
|
|
|
|
*
|
|
|
|
* Call the libvirt logger with some information. Based on the configuration
|
|
|
|
* the message may be stored, sent to output or just discarded
|
|
|
|
*/
|
2012-09-27 13:14:01 +00:00
|
|
|
void
|
2014-02-27 17:44:53 +00:00
|
|
|
virLogVMessage(virLogSourcePtr source,
|
2012-09-27 13:14:01 +00:00
|
|
|
virLogPriority priority,
|
2012-09-27 13:28:44 +00:00
|
|
|
const char *filename,
|
2012-09-27 13:14:01 +00:00
|
|
|
int linenr,
|
2012-09-27 13:28:44 +00:00
|
|
|
const char *funcname,
|
2012-10-17 18:17:15 +00:00
|
|
|
virLogMetadataPtr metadata,
|
2012-09-27 13:14:01 +00:00
|
|
|
const char *fmt,
|
|
|
|
va_list vargs)
|
2011-07-06 22:29:02 +00:00
|
|
|
{
|
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 two new arguments which can be
used as
--with-packager="Fedora Project, x86-01.phx2.fedoraproject.org, 01-27-2011-18:00:10"
--with-packager-version="1.fc14"
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-packager & --with-packager-version args
2011-01-27 18:11:16 +00:00
|
|
|
static bool logVersionStderr = true;
|
2008-12-22 10:36:54 +00:00
|
|
|
char *str = NULL;
|
2011-03-02 12:26:02 +00:00
|
|
|
char *msg = NULL;
|
2011-11-29 12:32:31 +00:00
|
|
|
char timestamp[VIR_TIME_STRING_BUFLEN];
|
Switch to filtering based on log source name instead of filename
Currently the log filter strings are used in a string comparison
against the source filename each time log message is emitted.
If no log filters at all are set, there's obviously no string
comparison to be done. If any single log filter is set though,
this imposes a compute burden on every logging call even if logs
from the file in question are disabled. This string comparison
must also be done while the logging mutex is held, which has
implications for concurrency when multiple threads are emitting
log messages.
This changes the log filtering to be done based on the virLogSource
object name. The virLogSource struct is extended to contain
'serial' and 'priority' fields. Any time the global log filter
rules are changed a global serial number is incremented. When a
log message is emitted, the serial in the virLogSource instance
is compared with the global serial number. If out of date, then
the 'priority' field in the virLogSource instance is updated based
on the new filter rules. The 'priority' field is checked to see
whether the log message should be sent to the log outputs.
The comparisons of the 'serial' and 'priority' fields are done
with no locks held. So in the common case each logging call has
an overhead of 2 integer comparisons, with no locks held. Only
if the decision is made to forward the message to the log output,
or if the 'serial' value is out of date do locks need to be
acquired.
Technically the comparisons of the 'serial' and 'priority' fields
should be done with locks held, or using atomic operations. Both
of these options have a notable performance impact, however, and
since all writes a protected by a global mutex, it is believed
that worst case behaviour where the fields are read concurrently
with being written would merely result in an mistaken emission
or dropping of the log message in question. This is an acceptable
tradeoff for the performance benefit of avoiding locking.
As a quick benchmark, a demo program that registers 500 file
descriptors with the event loop (eg equiv of 500 QEMU monitor
commands), creates pending read I/O on every FD, and then runs
virEventRunDefaultImpl() took 4.6 seconds to do 51200 iterations.
After this optimization it only takes 3.3 seconds, with the log
APIs no longer being a relevant factor in the running time.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2014-02-28 13:55:11 +00:00
|
|
|
int ret;
|
Convert 'int i' to 'size_t i' in src/util/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2011-02-16 23:49:15 +00:00
|
|
|
int saved_errno = errno;
|
2012-05-09 14:18:56 +00:00
|
|
|
unsigned int filterflags = 0;
|
2008-12-22 10:36:54 +00:00
|
|
|
|
2012-07-11 13:35:42 +00:00
|
|
|
if (virLogInitialize() < 0)
|
|
|
|
return;
|
2008-12-22 10:36:54 +00:00
|
|
|
|
|
|
|
if (fmt == NULL)
|
Switch to filtering based on log source name instead of filename
Currently the log filter strings are used in a string comparison
against the source filename each time log message is emitted.
If no log filters at all are set, there's obviously no string
comparison to be done. If any single log filter is set though,
this imposes a compute burden on every logging call even if logs
from the file in question are disabled. This string comparison
must also be done while the logging mutex is held, which has
implications for concurrency when multiple threads are emitting
log messages.
This changes the log filtering to be done based on the virLogSource
object name. The virLogSource struct is extended to contain
'serial' and 'priority' fields. Any time the global log filter
rules are changed a global serial number is incremented. When a
log message is emitted, the serial in the virLogSource instance
is compared with the global serial number. If out of date, then
the 'priority' field in the virLogSource instance is updated based
on the new filter rules. The 'priority' field is checked to see
whether the log message should be sent to the log outputs.
The comparisons of the 'serial' and 'priority' fields are done
with no locks held. So in the common case each logging call has
an overhead of 2 integer comparisons, with no locks held. Only
if the decision is made to forward the message to the log output,
or if the 'serial' value is out of date do locks need to be
acquired.
Technically the comparisons of the 'serial' and 'priority' fields
should be done with locks held, or using atomic operations. Both
of these options have a notable performance impact, however, and
since all writes a protected by a global mutex, it is believed
that worst case behaviour where the fields are read concurrently
with being written would merely result in an mistaken emission
or dropping of the log message in question. This is an acceptable
tradeoff for the performance benefit of avoiding locking.
As a quick benchmark, a demo program that registers 500 file
descriptors with the event loop (eg equiv of 500 QEMU monitor
commands), creates pending read I/O on every FD, and then runs
virEventRunDefaultImpl() took 4.6 seconds to do 51200 iterations.
After this optimization it only takes 3.3 seconds, with the log
APIs no longer being a relevant factor in the running time.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2014-02-28 13:55:11 +00:00
|
|
|
return;
|
2008-12-22 10:36:54 +00:00
|
|
|
|
|
|
|
/*
|
Switch to filtering based on log source name instead of filename
Currently the log filter strings are used in a string comparison
against the source filename each time log message is emitted.
If no log filters at all are set, there's obviously no string
comparison to be done. If any single log filter is set though,
this imposes a compute burden on every logging call even if logs
from the file in question are disabled. This string comparison
must also be done while the logging mutex is held, which has
implications for concurrency when multiple threads are emitting
log messages.
This changes the log filtering to be done based on the virLogSource
object name. The virLogSource struct is extended to contain
'serial' and 'priority' fields. Any time the global log filter
rules are changed a global serial number is incremented. When a
log message is emitted, the serial in the virLogSource instance
is compared with the global serial number. If out of date, then
the 'priority' field in the virLogSource instance is updated based
on the new filter rules. The 'priority' field is checked to see
whether the log message should be sent to the log outputs.
The comparisons of the 'serial' and 'priority' fields are done
with no locks held. So in the common case each logging call has
an overhead of 2 integer comparisons, with no locks held. Only
if the decision is made to forward the message to the log output,
or if the 'serial' value is out of date do locks need to be
acquired.
Technically the comparisons of the 'serial' and 'priority' fields
should be done with locks held, or using atomic operations. Both
of these options have a notable performance impact, however, and
since all writes a protected by a global mutex, it is believed
that worst case behaviour where the fields are read concurrently
with being written would merely result in an mistaken emission
or dropping of the log message in question. This is an acceptable
tradeoff for the performance benefit of avoiding locking.
As a quick benchmark, a demo program that registers 500 file
descriptors with the event loop (eg equiv of 500 QEMU monitor
commands), creates pending read I/O on every FD, and then runs
virEventRunDefaultImpl() took 4.6 seconds to do 51200 iterations.
After this optimization it only takes 3.3 seconds, with the log
APIs no longer being a relevant factor in the running time.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2014-02-28 13:55:11 +00:00
|
|
|
* 3 intentionally non-thread safe variable reads.
|
|
|
|
* Since writes to the variable are serialized on
|
|
|
|
* virLogLock, worst case result is a log message
|
|
|
|
* is accidentally dropped or emitted, if another
|
|
|
|
* thread is updating log filter list concurrently
|
|
|
|
* with a log message emission.
|
2008-12-22 10:36:54 +00:00
|
|
|
*/
|
Switch to filtering based on log source name instead of filename
Currently the log filter strings are used in a string comparison
against the source filename each time log message is emitted.
If no log filters at all are set, there's obviously no string
comparison to be done. If any single log filter is set though,
this imposes a compute burden on every logging call even if logs
from the file in question are disabled. This string comparison
must also be done while the logging mutex is held, which has
implications for concurrency when multiple threads are emitting
log messages.
This changes the log filtering to be done based on the virLogSource
object name. The virLogSource struct is extended to contain
'serial' and 'priority' fields. Any time the global log filter
rules are changed a global serial number is incremented. When a
log message is emitted, the serial in the virLogSource instance
is compared with the global serial number. If out of date, then
the 'priority' field in the virLogSource instance is updated based
on the new filter rules. The 'priority' field is checked to see
whether the log message should be sent to the log outputs.
The comparisons of the 'serial' and 'priority' fields are done
with no locks held. So in the common case each logging call has
an overhead of 2 integer comparisons, with no locks held. Only
if the decision is made to forward the message to the log output,
or if the 'serial' value is out of date do locks need to be
acquired.
Technically the comparisons of the 'serial' and 'priority' fields
should be done with locks held, or using atomic operations. Both
of these options have a notable performance impact, however, and
since all writes a protected by a global mutex, it is believed
that worst case behaviour where the fields are read concurrently
with being written would merely result in an mistaken emission
or dropping of the log message in question. This is an acceptable
tradeoff for the performance benefit of avoiding locking.
As a quick benchmark, a demo program that registers 500 file
descriptors with the event loop (eg equiv of 500 QEMU monitor
commands), creates pending read I/O on every FD, and then runs
virEventRunDefaultImpl() took 4.6 seconds to do 51200 iterations.
After this optimization it only takes 3.3 seconds, with the log
APIs no longer being a relevant factor in the running time.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2014-02-28 13:55:11 +00:00
|
|
|
if (source->serial < virLogFiltersSerial)
|
|
|
|
virLogSourceUpdate(source);
|
|
|
|
if (priority < source->priority)
|
2011-03-08 10:31:20 +00:00
|
|
|
goto cleanup;
|
Switch to filtering based on log source name instead of filename
Currently the log filter strings are used in a string comparison
against the source filename each time log message is emitted.
If no log filters at all are set, there's obviously no string
comparison to be done. If any single log filter is set though,
this imposes a compute burden on every logging call even if logs
from the file in question are disabled. This string comparison
must also be done while the logging mutex is held, which has
implications for concurrency when multiple threads are emitting
log messages.
This changes the log filtering to be done based on the virLogSource
object name. The virLogSource struct is extended to contain
'serial' and 'priority' fields. Any time the global log filter
rules are changed a global serial number is incremented. When a
log message is emitted, the serial in the virLogSource instance
is compared with the global serial number. If out of date, then
the 'priority' field in the virLogSource instance is updated based
on the new filter rules. The 'priority' field is checked to see
whether the log message should be sent to the log outputs.
The comparisons of the 'serial' and 'priority' fields are done
with no locks held. So in the common case each logging call has
an overhead of 2 integer comparisons, with no locks held. Only
if the decision is made to forward the message to the log output,
or if the 'serial' value is out of date do locks need to be
acquired.
Technically the comparisons of the 'serial' and 'priority' fields
should be done with locks held, or using atomic operations. Both
of these options have a notable performance impact, however, and
since all writes a protected by a global mutex, it is believed
that worst case behaviour where the fields are read concurrently
with being written would merely result in an mistaken emission
or dropping of the log message in question. This is an acceptable
tradeoff for the performance benefit of avoiding locking.
As a quick benchmark, a demo program that registers 500 file
descriptors with the event loop (eg equiv of 500 QEMU monitor
commands), creates pending read I/O on every FD, and then runs
virEventRunDefaultImpl() took 4.6 seconds to do 51200 iterations.
After this optimization it only takes 3.3 seconds, with the log
APIs no longer being a relevant factor in the running time.
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2014-02-28 13:55:11 +00:00
|
|
|
filterflags = source->flags;
|
2011-03-08 10:31:20 +00:00
|
|
|
|
2008-12-22 10:36:54 +00:00
|
|
|
/*
|
|
|
|
* serialize the error message, add level and timestamp
|
|
|
|
*/
|
2013-06-07 15:10:28 +00:00
|
|
|
if (virVasprintfQuiet(&str, fmt, vargs) < 0) {
|
2011-02-16 23:49:15 +00:00
|
|
|
goto cleanup;
|
2011-05-24 17:20:19 +00:00
|
|
|
}
|
2008-12-22 10:36:54 +00:00
|
|
|
|
2012-09-27 13:28:44 +00:00
|
|
|
ret = virLogFormatString(&msg, linenr, funcname, priority, str);
|
2011-02-16 23:49:15 +00:00
|
|
|
if (ret < 0)
|
|
|
|
goto cleanup;
|
2008-12-22 10:36:54 +00:00
|
|
|
|
2011-11-29 12:32:31 +00:00
|
|
|
if (virTimeStringNowRaw(timestamp) < 0)
|
|
|
|
timestamp[0] = '\0';
|
2011-09-28 13:20:07 +00:00
|
|
|
|
2014-03-03 14:54:33 +00:00
|
|
|
virLogLock();
|
|
|
|
|
2008-12-22 10:36:54 +00:00
|
|
|
/*
|
2014-03-03 14:54:33 +00:00
|
|
|
* Push the message to the outputs defined, if none exist then
|
2008-12-22 10:36:54 +00:00
|
|
|
* use stderr.
|
|
|
|
*/
|
2011-09-28 13:20:07 +00:00
|
|
|
for (i = 0; i < virLogNbOutputs; i++) {
|
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 two new arguments which can be
used as
--with-packager="Fedora Project, x86-01.phx2.fedoraproject.org, 01-27-2011-18:00:10"
--with-packager-version="1.fc14"
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-packager & --with-packager-version args
2011-01-27 18:11:16 +00:00
|
|
|
if (priority >= virLogOutputs[i].priority) {
|
|
|
|
if (virLogOutputs[i].logVersion) {
|
2012-09-27 11:45:33 +00:00
|
|
|
const char *rawver;
|
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 two new arguments which can be
used as
--with-packager="Fedora Project, x86-01.phx2.fedoraproject.org, 01-27-2011-18:00:10"
--with-packager-version="1.fc14"
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-packager & --with-packager-version args
2011-01-27 18:11:16 +00:00
|
|
|
char *ver = NULL;
|
2012-09-27 11:45:33 +00:00
|
|
|
if (virLogVersionString(&rawver, &ver) >= 0)
|
2014-02-27 17:44:53 +00:00
|
|
|
virLogOutputs[i].f(&virLogSelf, VIR_LOG_INFO,
|
2012-09-27 13:28:44 +00:00
|
|
|
__FILE__, __LINE__, __func__,
|
2012-10-17 18:17:15 +00:00
|
|
|
timestamp, NULL, 0, rawver, ver,
|
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 two new arguments which can be
used as
--with-packager="Fedora Project, x86-01.phx2.fedoraproject.org, 01-27-2011-18:00:10"
--with-packager-version="1.fc14"
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-packager & --with-packager-version args
2011-01-27 18:11:16 +00:00
|
|
|
virLogOutputs[i].data);
|
|
|
|
VIR_FREE(ver);
|
|
|
|
virLogOutputs[i].logVersion = false;
|
|
|
|
}
|
2012-09-27 13:44:22 +00:00
|
|
|
virLogOutputs[i].f(source, priority,
|
2012-09-27 13:28:44 +00:00
|
|
|
filename, linenr, funcname,
|
2012-10-17 18:17:15 +00:00
|
|
|
timestamp, metadata, filterflags,
|
2012-09-27 11:45:33 +00:00
|
|
|
str, msg, virLogOutputs[i].data);
|
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 two new arguments which can be
used as
--with-packager="Fedora Project, x86-01.phx2.fedoraproject.org, 01-27-2011-18:00:10"
--with-packager-version="1.fc14"
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-packager & --with-packager-version args
2011-01-27 18:11:16 +00:00
|
|
|
}
|
2008-12-22 10:36:54 +00:00
|
|
|
}
|
2014-03-03 18:29:33 +00:00
|
|
|
if (virLogNbOutputs == 0) {
|
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 two new arguments which can be
used as
--with-packager="Fedora Project, x86-01.phx2.fedoraproject.org, 01-27-2011-18:00:10"
--with-packager-version="1.fc14"
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-packager & --with-packager-version args
2011-01-27 18:11:16 +00:00
|
|
|
if (logVersionStderr) {
|
2012-09-27 11:45:33 +00:00
|
|
|
const char *rawver;
|
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 two new arguments which can be
used as
--with-packager="Fedora Project, x86-01.phx2.fedoraproject.org, 01-27-2011-18:00:10"
--with-packager-version="1.fc14"
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-packager & --with-packager-version args
2011-01-27 18:11:16 +00:00
|
|
|
char *ver = NULL;
|
2012-09-27 11:45:33 +00:00
|
|
|
if (virLogVersionString(&rawver, &ver) >= 0)
|
2014-02-27 17:44:53 +00:00
|
|
|
virLogOutputToFd(&virLogSelf, VIR_LOG_INFO,
|
2012-09-27 13:28:44 +00:00
|
|
|
__FILE__, __LINE__, __func__,
|
2012-10-17 18:17:15 +00:00
|
|
|
timestamp, NULL, 0, rawver, ver,
|
2011-09-28 13:20:07 +00:00
|
|
|
(void *) STDERR_FILENO);
|
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 two new arguments which can be
used as
--with-packager="Fedora Project, x86-01.phx2.fedoraproject.org, 01-27-2011-18:00:10"
--with-packager-version="1.fc14"
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-packager & --with-packager-version args
2011-01-27 18:11:16 +00:00
|
|
|
VIR_FREE(ver);
|
|
|
|
logVersionStderr = false;
|
|
|
|
}
|
2012-09-27 13:44:22 +00:00
|
|
|
virLogOutputToFd(source, priority,
|
2012-09-27 13:28:44 +00:00
|
|
|
filename, linenr, funcname,
|
2012-10-17 18:17:15 +00:00
|
|
|
timestamp, metadata, filterflags,
|
2012-09-27 11:45:33 +00:00
|
|
|
str, msg, (void *) STDERR_FILENO);
|
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 two new arguments which can be
used as
--with-packager="Fedora Project, x86-01.phx2.fedoraproject.org, 01-27-2011-18:00:10"
--with-packager-version="1.fc14"
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-packager & --with-packager-version args
2011-01-27 18:11:16 +00:00
|
|
|
}
|
2008-12-22 10:36:54 +00:00
|
|
|
virLogUnlock();
|
|
|
|
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
2012-09-27 11:45:33 +00:00
|
|
|
VIR_FREE(str);
|
2011-03-02 12:26:02 +00:00
|
|
|
VIR_FREE(msg);
|
2011-02-16 23:49:15 +00:00
|
|
|
errno = saved_errno;
|
2008-12-22 10:36:54 +00:00
|
|
|
}
|
|
|
|
|
2012-05-09 14:18:56 +00:00
|
|
|
|
2012-09-27 13:14:01 +00:00
|
|
|
static void
|
|
|
|
virLogStackTraceToFd(int fd)
|
2012-05-09 14:18:56 +00:00
|
|
|
{
|
|
|
|
void *array[100];
|
|
|
|
int size;
|
|
|
|
static bool doneWarning = false;
|
|
|
|
const char *msg = "Stack trace not available on this platform\n";
|
2012-09-05 22:27:42 +00:00
|
|
|
|
|
|
|
#define STRIP_DEPTH 3
|
|
|
|
size = backtrace(array, ARRAY_CARDINALITY(array));
|
|
|
|
if (size) {
|
|
|
|
backtrace_symbols_fd(array + STRIP_DEPTH, size - STRIP_DEPTH, fd);
|
|
|
|
ignore_value(safewrite(fd, "\n", 1));
|
|
|
|
} else if (!doneWarning) {
|
2012-05-09 14:18:56 +00:00
|
|
|
ignore_value(safewrite(fd, msg, strlen(msg)));
|
|
|
|
doneWarning = true;
|
|
|
|
}
|
2012-09-05 22:27:42 +00:00
|
|
|
#undef STRIP_DEPTH
|
2012-05-09 14:18:56 +00:00
|
|
|
}
|
|
|
|
|
2012-09-27 13:14:01 +00:00
|
|
|
static void
|
2014-02-27 17:44:53 +00:00
|
|
|
virLogOutputToFd(virLogSourcePtr source ATTRIBUTE_UNUSED,
|
2012-09-27 13:14:01 +00:00
|
|
|
virLogPriority priority ATTRIBUTE_UNUSED,
|
2012-09-27 13:28:44 +00:00
|
|
|
const char *filename ATTRIBUTE_UNUSED,
|
2012-09-27 13:14:01 +00:00
|
|
|
int linenr ATTRIBUTE_UNUSED,
|
2012-09-27 13:28:44 +00:00
|
|
|
const char *funcname ATTRIBUTE_UNUSED,
|
2012-09-27 13:14:01 +00:00
|
|
|
const char *timestamp,
|
2012-10-17 18:17:15 +00:00
|
|
|
virLogMetadataPtr metadata ATTRIBUTE_UNUSED,
|
2012-09-27 13:14:01 +00:00
|
|
|
unsigned int flags,
|
|
|
|
const char *rawstr ATTRIBUTE_UNUSED,
|
|
|
|
const char *str,
|
|
|
|
void *data)
|
2011-09-28 13:20:07 +00:00
|
|
|
{
|
2012-01-25 20:13:25 +00:00
|
|
|
int fd = (intptr_t) data;
|
2011-09-28 13:20:07 +00:00
|
|
|
char *msg;
|
2008-12-22 10:36:54 +00:00
|
|
|
|
|
|
|
if (fd < 0)
|
2012-09-20 18:24:00 +00:00
|
|
|
return;
|
2011-09-28 13:20:07 +00:00
|
|
|
|
2013-06-07 15:10:28 +00:00
|
|
|
if (virAsprintfQuiet(&msg, "%s: %s", timestamp, str) < 0)
|
2012-09-20 18:24:00 +00:00
|
|
|
return;
|
2011-09-28 13:20:07 +00:00
|
|
|
|
2012-09-20 18:24:00 +00:00
|
|
|
ignore_value(safewrite(fd, msg, strlen(msg)));
|
2011-09-28 13:20:07 +00:00
|
|
|
VIR_FREE(msg);
|
|
|
|
|
2012-05-09 14:18:56 +00:00
|
|
|
if (flags & VIR_LOG_STACK_TRACE)
|
|
|
|
virLogStackTraceToFd(fd);
|
2008-12-22 10:36:54 +00:00
|
|
|
}
|
|
|
|
|
2012-09-27 13:14:01 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
virLogCloseFd(void *data)
|
2012-06-07 13:16:50 +00:00
|
|
|
{
|
2012-01-25 20:13:25 +00:00
|
|
|
int fd = (intptr_t) data;
|
2008-12-22 10:36:54 +00:00
|
|
|
|
2012-06-07 13:16:50 +00:00
|
|
|
VIR_LOG_CLOSE(fd);
|
2008-12-22 10:36:54 +00:00
|
|
|
}
|
|
|
|
|
2012-09-27 13:14:01 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
virLogAddOutputToStderr(virLogPriority priority)
|
|
|
|
{
|
2009-10-08 15:05:01 +00:00
|
|
|
if (virLogDefineOutput(virLogOutputToFd, NULL, (void *)2L, priority,
|
|
|
|
VIR_LOG_TO_STDERR, NULL, 0) < 0)
|
2011-01-21 16:30:17 +00:00
|
|
|
return -1;
|
|
|
|
return 0;
|
2008-12-22 10:36:54 +00:00
|
|
|
}
|
|
|
|
|
2012-09-27 13:14:01 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
virLogAddOutputToFile(virLogPriority priority,
|
|
|
|
const char *file)
|
|
|
|
{
|
2008-12-22 10:36:54 +00:00
|
|
|
int fd;
|
|
|
|
|
2009-10-08 15:05:01 +00:00
|
|
|
fd = open(file, O_CREAT | O_APPEND | O_WRONLY, S_IRUSR | S_IWUSR);
|
2008-12-22 10:36:54 +00:00
|
|
|
if (fd < 0)
|
2011-01-21 16:30:17 +00:00
|
|
|
return -1;
|
2012-01-25 20:13:25 +00:00
|
|
|
if (virLogDefineOutput(virLogOutputToFd, virLogCloseFd,
|
|
|
|
(void *)(intptr_t)fd,
|
2009-10-08 15:05:01 +00:00
|
|
|
priority, VIR_LOG_TO_FILE, file, 0) < 0) {
|
2010-11-09 20:48:48 +00:00
|
|
|
VIR_FORCE_CLOSE(fd);
|
2011-01-21 16:30:17 +00:00
|
|
|
return -1;
|
2008-12-22 10:36:54 +00:00
|
|
|
}
|
2011-01-21 16:30:17 +00:00
|
|
|
return 0;
|
2008-12-22 10:36:54 +00:00
|
|
|
}
|
|
|
|
|
2012-09-27 13:14:01 +00:00
|
|
|
|
2014-02-24 16:21:55 +00:00
|
|
|
#if HAVE_SYSLOG_H || USE_JOURNALD
|
|
|
|
|
|
|
|
/* Compat in case we build with journald, but no syslog */
|
|
|
|
# ifndef LOG_DEBUG
|
|
|
|
# define LOG_DEBUG 7
|
|
|
|
# endif
|
|
|
|
# ifndef LOG_INFO
|
|
|
|
# define LOG_INFO 6
|
|
|
|
# endif
|
|
|
|
# ifndef LOG_WARNING
|
|
|
|
# define LOG_WARNING 4
|
|
|
|
# endif
|
|
|
|
# ifndef LOG_ERR
|
|
|
|
# define LOG_ERR 3
|
|
|
|
# endif
|
|
|
|
|
2012-09-27 13:14:01 +00:00
|
|
|
static int
|
|
|
|
virLogPrioritySyslog(virLogPriority priority)
|
2012-09-27 11:34:04 +00:00
|
|
|
{
|
|
|
|
switch (priority) {
|
|
|
|
case VIR_LOG_DEBUG:
|
|
|
|
return LOG_DEBUG;
|
|
|
|
case VIR_LOG_INFO:
|
|
|
|
return LOG_INFO;
|
|
|
|
case VIR_LOG_WARN:
|
|
|
|
return LOG_WARNING;
|
|
|
|
case VIR_LOG_ERROR:
|
|
|
|
return LOG_ERR;
|
|
|
|
default:
|
|
|
|
return LOG_ERR;
|
|
|
|
}
|
|
|
|
}
|
2014-02-24 16:21:55 +00:00
|
|
|
#endif /* HAVE_SYSLOG_H || USE_JOURNALD */
|
2012-09-27 11:34:04 +00:00
|
|
|
|
2012-09-27 13:14:01 +00:00
|
|
|
|
2014-02-24 16:21:55 +00:00
|
|
|
#if HAVE_SYSLOG_H
|
2012-09-27 13:14:01 +00:00
|
|
|
static void
|
2014-02-27 17:44:53 +00:00
|
|
|
virLogOutputToSyslog(virLogSourcePtr source ATTRIBUTE_UNUSED,
|
2012-09-27 13:14:01 +00:00
|
|
|
virLogPriority priority,
|
2012-09-27 13:28:44 +00:00
|
|
|
const char *filename ATTRIBUTE_UNUSED,
|
2012-09-27 13:14:01 +00:00
|
|
|
int linenr ATTRIBUTE_UNUSED,
|
2012-09-27 13:28:44 +00:00
|
|
|
const char *funcname ATTRIBUTE_UNUSED,
|
2012-09-27 13:14:01 +00:00
|
|
|
const char *timestamp ATTRIBUTE_UNUSED,
|
2012-10-17 18:17:15 +00:00
|
|
|
virLogMetadataPtr metadata ATTRIBUTE_UNUSED,
|
2012-09-27 13:14:01 +00:00
|
|
|
unsigned int flags,
|
|
|
|
const char *rawstr ATTRIBUTE_UNUSED,
|
|
|
|
const char *str,
|
|
|
|
void *data ATTRIBUTE_UNUSED)
|
2011-09-28 13:20:07 +00:00
|
|
|
{
|
2012-09-20 18:24:00 +00:00
|
|
|
virCheckFlags(VIR_LOG_STACK_TRACE,);
|
2012-05-09 14:18:56 +00:00
|
|
|
|
2012-09-27 11:34:04 +00:00
|
|
|
syslog(virLogPrioritySyslog(priority), "%s", str);
|
2008-12-22 10:36:54 +00:00
|
|
|
}
|
|
|
|
|
2009-01-20 21:34:44 +00:00
|
|
|
static char *current_ident = NULL;
|
|
|
|
|
2012-09-27 13:14:01 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
virLogCloseSyslog(void *data ATTRIBUTE_UNUSED)
|
|
|
|
{
|
2008-12-22 10:36:54 +00:00
|
|
|
closelog();
|
2009-01-20 21:34:44 +00:00
|
|
|
VIR_FREE(current_ident);
|
2008-12-22 10:36:54 +00:00
|
|
|
}
|
|
|
|
|
2012-09-27 13:14:01 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
virLogAddOutputToSyslog(virLogPriority priority,
|
|
|
|
const char *ident)
|
|
|
|
{
|
2009-01-20 21:34:44 +00:00
|
|
|
/*
|
|
|
|
* ident needs to be kept around on Solaris
|
|
|
|
*/
|
|
|
|
VIR_FREE(current_ident);
|
2013-05-24 07:19:51 +00:00
|
|
|
if (VIR_STRDUP(current_ident, ident) < 0)
|
2011-01-21 16:30:17 +00:00
|
|
|
return -1;
|
2009-01-20 21:34:44 +00:00
|
|
|
|
|
|
|
openlog(current_ident, 0, 0);
|
2008-12-22 10:36:54 +00:00
|
|
|
if (virLogDefineOutput(virLogOutputToSyslog, virLogCloseSyslog, NULL,
|
2009-10-08 15:05:01 +00:00
|
|
|
priority, VIR_LOG_TO_SYSLOG, ident, 0) < 0) {
|
2008-12-22 10:36:54 +00:00
|
|
|
closelog();
|
2009-01-20 21:34:44 +00:00
|
|
|
VIR_FREE(current_ident);
|
2011-01-21 16:30:17 +00:00
|
|
|
return -1;
|
2008-12-22 10:36:54 +00:00
|
|
|
}
|
2011-01-21 16:30:17 +00:00
|
|
|
return 0;
|
2008-12-22 10:36:54 +00:00
|
|
|
}
|
2012-09-25 17:31:01 +00:00
|
|
|
|
|
|
|
|
2012-10-01 22:38:56 +00:00
|
|
|
# if USE_JOURNALD
|
2012-10-17 18:17:16 +00:00
|
|
|
# define IOVEC_SET(iov, data, size) \
|
|
|
|
do { \
|
|
|
|
struct iovec *_i = &(iov); \
|
|
|
|
_i->iov_base = (void*)(data); \
|
|
|
|
_i->iov_len = (size); \
|
2012-09-25 17:31:01 +00:00
|
|
|
} while (0)
|
|
|
|
|
2012-10-17 18:17:16 +00:00
|
|
|
# define IOVEC_SET_STRING(iov, str) IOVEC_SET(iov, str, strlen(str))
|
|
|
|
|
|
|
|
/* Used for conversion of numbers to strings, and for length of binary data */
|
|
|
|
# define JOURNAL_BUF_SIZE (MAX(INT_BUFSIZE_BOUND(int), sizeof(uint64_t)))
|
|
|
|
|
|
|
|
struct journalState
|
|
|
|
{
|
|
|
|
struct iovec *iov, *iov_end;
|
|
|
|
char (*bufs)[JOURNAL_BUF_SIZE], (*bufs_end)[JOURNAL_BUF_SIZE];
|
|
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
|
|
journalAddString(struct journalState *state, const char *field,
|
|
|
|
const char *value)
|
|
|
|
{
|
|
|
|
static const char newline = '\n', equals = '=';
|
|
|
|
|
|
|
|
if (strchr(value, '\n') != NULL) {
|
|
|
|
uint64_t nstr;
|
|
|
|
|
|
|
|
/* If 'str' contains a newline, then we must
|
|
|
|
* encode the string length, since we can't
|
|
|
|
* rely on the newline for the field separator
|
|
|
|
*/
|
|
|
|
if (state->iov_end - state->iov < 5 || state->bufs == state->bufs_end)
|
|
|
|
return; /* Silently drop */
|
|
|
|
nstr = htole64(strlen(value));
|
|
|
|
memcpy(state->bufs[0], &nstr, sizeof(nstr));
|
|
|
|
|
|
|
|
IOVEC_SET_STRING(state->iov[0], field);
|
|
|
|
IOVEC_SET(state->iov[1], &newline, sizeof(newline));
|
|
|
|
IOVEC_SET(state->iov[2], state->bufs[0], sizeof(nstr));
|
|
|
|
state->bufs++;
|
|
|
|
state->iov += 3;
|
|
|
|
} else {
|
|
|
|
if (state->iov_end - state->iov < 4)
|
|
|
|
return; /* Silently drop */
|
|
|
|
IOVEC_SET_STRING(state->iov[0], field);
|
|
|
|
IOVEC_SET(state->iov[1], (void *)&equals, sizeof(equals));
|
|
|
|
state->iov += 2;
|
|
|
|
}
|
|
|
|
IOVEC_SET_STRING(state->iov[0], value);
|
|
|
|
IOVEC_SET(state->iov[1], (void *)&newline, sizeof(newline));
|
|
|
|
state->iov += 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
journalAddInt(struct journalState *state, const char *field, int value)
|
|
|
|
{
|
|
|
|
static const char newline = '\n', equals = '=';
|
|
|
|
|
|
|
|
char *num;
|
|
|
|
|
|
|
|
if (state->iov_end - state->iov < 4 || state->bufs == state->bufs_end)
|
|
|
|
return; /* Silently drop */
|
|
|
|
|
|
|
|
num = virFormatIntDecimal(state->bufs[0], sizeof(state->bufs[0]), value);
|
|
|
|
|
|
|
|
IOVEC_SET_STRING(state->iov[0], field);
|
|
|
|
IOVEC_SET(state->iov[1], (void *)&equals, sizeof(equals));
|
|
|
|
IOVEC_SET_STRING(state->iov[2], num);
|
|
|
|
IOVEC_SET(state->iov[3], (void *)&newline, sizeof(newline));
|
|
|
|
state->bufs++;
|
|
|
|
state->iov += 4;
|
|
|
|
}
|
2012-09-25 17:31:01 +00:00
|
|
|
|
|
|
|
static int journalfd = -1;
|
|
|
|
|
|
|
|
static void
|
2014-02-27 17:44:53 +00:00
|
|
|
virLogOutputToJournald(virLogSourcePtr source,
|
2012-09-25 17:31:01 +00:00
|
|
|
virLogPriority priority,
|
|
|
|
const char *filename,
|
|
|
|
int linenr,
|
|
|
|
const char *funcname,
|
|
|
|
const char *timestamp ATTRIBUTE_UNUSED,
|
2014-02-21 17:21:55 +00:00
|
|
|
virLogMetadataPtr metadata,
|
2012-09-25 17:31:01 +00:00
|
|
|
unsigned int flags,
|
|
|
|
const char *rawstr,
|
|
|
|
const char *str ATTRIBUTE_UNUSED,
|
|
|
|
void *data ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
virCheckFlags(VIR_LOG_STACK_TRACE,);
|
|
|
|
int buffd = -1;
|
|
|
|
struct msghdr mh;
|
|
|
|
struct sockaddr_un sa;
|
|
|
|
union {
|
|
|
|
struct cmsghdr cmsghdr;
|
|
|
|
uint8_t buf[CMSG_SPACE(sizeof(int))];
|
|
|
|
} control;
|
|
|
|
struct cmsghdr *cmsg;
|
|
|
|
/* We use /dev/shm instead of /tmp here, since we want this to
|
|
|
|
* be a tmpfs, and one that is available from early boot on
|
|
|
|
* and where unprivileged users can create files. */
|
|
|
|
char path[] = "/dev/shm/journal.XXXXXX";
|
2014-02-21 17:21:55 +00:00
|
|
|
size_t nmetadata = 0;
|
2012-09-25 17:31:01 +00:00
|
|
|
|
2014-02-21 17:21:55 +00:00
|
|
|
# define NUM_FIELDS_CORE 6
|
|
|
|
# define NUM_FIELDS_META 5
|
|
|
|
# define NUM_FIELDS (NUM_FIELDS_CORE + NUM_FIELDS_META)
|
2012-10-17 18:17:16 +00:00
|
|
|
struct iovec iov[NUM_FIELDS * 5];
|
|
|
|
char iov_bufs[NUM_FIELDS][JOURNAL_BUF_SIZE];
|
|
|
|
struct journalState state;
|
2012-09-25 17:31:01 +00:00
|
|
|
|
2012-10-17 18:17:16 +00:00
|
|
|
state.iov = iov;
|
|
|
|
state.iov_end = iov + ARRAY_CARDINALITY(iov);
|
|
|
|
state.bufs = iov_bufs;
|
|
|
|
state.bufs_end = iov_bufs + ARRAY_CARDINALITY(iov_bufs);
|
2012-09-25 17:31:01 +00:00
|
|
|
|
2013-11-19 23:00:32 +00:00
|
|
|
journalAddString(&state, "MESSAGE", rawstr);
|
2014-02-24 16:21:55 +00:00
|
|
|
journalAddInt(&state, "PRIORITY",
|
|
|
|
virLogPrioritySyslog(priority));
|
2014-02-27 17:44:53 +00:00
|
|
|
journalAddString(&state, "LIBVIRT_SOURCE", source->name);
|
2013-08-02 11:15:57 +00:00
|
|
|
if (filename)
|
|
|
|
journalAddString(&state, "CODE_FILE", filename);
|
2012-10-17 18:17:16 +00:00
|
|
|
journalAddInt(&state, "CODE_LINE", linenr);
|
2013-08-02 11:15:57 +00:00
|
|
|
if (funcname)
|
|
|
|
journalAddString(&state, "CODE_FUNC", funcname);
|
2014-02-21 17:21:55 +00:00
|
|
|
if (metadata != NULL) {
|
|
|
|
while (metadata->key != NULL &&
|
|
|
|
nmetadata < NUM_FIELDS_META) {
|
|
|
|
if (metadata->s != NULL)
|
|
|
|
journalAddString(&state, metadata->key, metadata->s);
|
|
|
|
else
|
|
|
|
journalAddInt(&state, metadata->key, metadata->iv);
|
|
|
|
metadata++;
|
|
|
|
nmetadata++;
|
|
|
|
}
|
|
|
|
}
|
2012-09-25 17:31:01 +00:00
|
|
|
|
|
|
|
memset(&sa, 0, sizeof(sa));
|
|
|
|
sa.sun_family = AF_UNIX;
|
|
|
|
if (!virStrcpy(sa.sun_path, "/run/systemd/journal/socket", sizeof(sa.sun_path)))
|
|
|
|
return;
|
|
|
|
|
|
|
|
memset(&mh, 0, sizeof(mh));
|
|
|
|
mh.msg_name = &sa;
|
|
|
|
mh.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path);
|
|
|
|
mh.msg_iov = iov;
|
2012-10-17 18:17:16 +00:00
|
|
|
mh.msg_iovlen = state.iov - iov;
|
2012-09-25 17:31:01 +00:00
|
|
|
|
|
|
|
if (sendmsg(journalfd, &mh, MSG_NOSIGNAL) >= 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (errno != EMSGSIZE && errno != ENOBUFS)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Message was too large, so dump to temporary file
|
|
|
|
* and pass an FD to the journal
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* NB: mkostemp is not declared async signal safe by
|
|
|
|
* POSIX, but this is Linux only code and the GLibc
|
|
|
|
* impl is safe enough, only using open() and inline
|
|
|
|
* asm to read a timestamp (falling back to gettimeofday
|
|
|
|
* on some arches
|
|
|
|
*/
|
|
|
|
if ((buffd = mkostemp(path, O_CLOEXEC|O_RDWR)) < 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (unlink(path) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2012-10-17 18:17:16 +00:00
|
|
|
if (writev(buffd, iov, state.iov - iov) < 0)
|
2012-09-25 17:31:01 +00:00
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
mh.msg_iov = NULL;
|
|
|
|
mh.msg_iovlen = 0;
|
|
|
|
|
|
|
|
memset(&control, 0, sizeof(control));
|
|
|
|
mh.msg_control = &control;
|
|
|
|
mh.msg_controllen = sizeof(control);
|
|
|
|
|
|
|
|
cmsg = CMSG_FIRSTHDR(&mh);
|
|
|
|
cmsg->cmsg_level = SOL_SOCKET;
|
|
|
|
cmsg->cmsg_type = SCM_RIGHTS;
|
|
|
|
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
|
|
|
|
memcpy(CMSG_DATA(cmsg), &buffd, sizeof(int));
|
|
|
|
|
|
|
|
mh.msg_controllen = cmsg->cmsg_len;
|
|
|
|
|
2014-03-25 16:57:58 +00:00
|
|
|
ignore_value(sendmsg(journalfd, &mh, MSG_NOSIGNAL));
|
2012-09-25 17:31:01 +00:00
|
|
|
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
2012-09-25 17:31:01 +00:00
|
|
|
VIR_LOG_CLOSE(buffd);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void virLogCloseJournald(void *data ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
VIR_LOG_CLOSE(journalfd);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int virLogAddOutputToJournald(int priority)
|
|
|
|
{
|
|
|
|
if ((journalfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
|
|
|
|
return -1;
|
|
|
|
if (virSetInherit(journalfd, false) < 0) {
|
|
|
|
VIR_LOG_CLOSE(journalfd);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (virLogDefineOutput(virLogOutputToJournald, virLogCloseJournald, NULL,
|
|
|
|
priority, VIR_LOG_TO_JOURNALD, NULL, 0) < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2012-10-01 22:38:56 +00:00
|
|
|
# endif /* USE_JOURNALD */
|
2013-06-07 09:55:27 +00:00
|
|
|
|
|
|
|
int virLogPriorityFromSyslog(int priority)
|
|
|
|
{
|
|
|
|
switch (priority) {
|
|
|
|
case LOG_EMERG:
|
|
|
|
case LOG_ALERT:
|
|
|
|
case LOG_CRIT:
|
|
|
|
case LOG_ERR:
|
|
|
|
return VIR_LOG_ERROR;
|
|
|
|
case LOG_WARNING:
|
|
|
|
case LOG_NOTICE:
|
|
|
|
return VIR_LOG_WARN;
|
|
|
|
case LOG_INFO:
|
|
|
|
return VIR_LOG_INFO;
|
|
|
|
case LOG_DEBUG:
|
|
|
|
return VIR_LOG_DEBUG;
|
|
|
|
}
|
|
|
|
return VIR_LOG_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else /* HAVE_SYSLOG_H */
|
|
|
|
int virLogPriorityFromSyslog(int priority ATTRIBUTE_UNUSED)
|
|
|
|
{
|
|
|
|
return VIR_LOG_ERROR;
|
|
|
|
}
|
2008-12-22 10:36:54 +00:00
|
|
|
#endif /* HAVE_SYSLOG_H */
|
|
|
|
|
|
|
|
#define IS_SPACE(cur) \
|
|
|
|
((*cur == ' ') || (*cur == '\t') || (*cur == '\n') || \
|
|
|
|
(*cur == '\r') || (*cur == '\\'))
|
|
|
|
|
2012-09-27 13:14:01 +00:00
|
|
|
|
2008-12-22 10:36:54 +00:00
|
|
|
/**
|
|
|
|
* virLogParseOutputs:
|
|
|
|
* @outputs: string defining a (set of) output(s)
|
|
|
|
*
|
|
|
|
* The format for an output can be:
|
|
|
|
* x:stderr
|
|
|
|
* output goes to stderr
|
|
|
|
* x:syslog:name
|
|
|
|
* use syslog for the output and use the given name as the ident
|
|
|
|
* x:file:file_path
|
|
|
|
* output to a file, with the given filepath
|
|
|
|
* In all case the x prefix is the minimal level, acting as a filter
|
|
|
|
* 1: DEBUG
|
|
|
|
* 2: INFO
|
|
|
|
* 3: WARNING
|
|
|
|
* 4: ERROR
|
|
|
|
*
|
|
|
|
* Multiple output can be defined in a single @output, they just need to be
|
|
|
|
* separated by spaces.
|
|
|
|
*
|
2013-10-09 09:59:36 +00:00
|
|
|
* If running in setuid mode, then only the 'stderr' output will
|
|
|
|
* be allowed
|
|
|
|
*
|
2008-12-22 10:36:54 +00:00
|
|
|
* Returns the number of output parsed and installed or -1 in case of error
|
|
|
|
*/
|
2012-09-27 13:14:01 +00:00
|
|
|
int
|
|
|
|
virLogParseOutputs(const char *outputs)
|
|
|
|
{
|
2008-12-22 10:36:54 +00:00
|
|
|
const char *cur = outputs, *str;
|
|
|
|
char *name;
|
2009-10-08 15:05:01 +00:00
|
|
|
char *abspath;
|
2012-09-27 12:58:58 +00:00
|
|
|
virLogPriority prio;
|
2009-08-06 13:38:11 +00:00
|
|
|
int ret = -1;
|
|
|
|
int count = 0;
|
2013-10-09 09:59:36 +00:00
|
|
|
bool isSUID = virIsSUID();
|
2008-12-22 10:36:54 +00:00
|
|
|
|
|
|
|
if (cur == NULL)
|
2011-01-21 16:30:17 +00:00
|
|
|
return -1;
|
2008-12-22 10:36:54 +00:00
|
|
|
|
2012-10-24 20:51:44 +00:00
|
|
|
VIR_DEBUG("outputs=%s", outputs);
|
|
|
|
|
2008-12-22 10:36:54 +00:00
|
|
|
virSkipSpaces(&cur);
|
|
|
|
while (*cur != 0) {
|
2014-01-20 11:27:29 +00:00
|
|
|
prio = virParseNumber(&cur);
|
2009-07-01 11:21:15 +00:00
|
|
|
if ((prio < VIR_LOG_DEBUG) || (prio > VIR_LOG_ERROR))
|
2009-08-06 13:38:11 +00:00
|
|
|
goto cleanup;
|
2008-12-22 10:36:54 +00:00
|
|
|
if (*cur != ':')
|
2009-08-06 13:38:11 +00:00
|
|
|
goto cleanup;
|
2008-12-22 10:36:54 +00:00
|
|
|
cur++;
|
|
|
|
if (STREQLEN(cur, "stderr", 6)) {
|
|
|
|
cur += 6;
|
|
|
|
if (virLogAddOutputToStderr(prio) == 0)
|
2009-08-06 13:38:11 +00:00
|
|
|
count++;
|
2008-12-22 10:36:54 +00:00
|
|
|
} else if (STREQLEN(cur, "syslog", 6)) {
|
2013-10-09 09:59:36 +00:00
|
|
|
if (isSUID)
|
|
|
|
goto cleanup;
|
2008-12-22 10:36:54 +00:00
|
|
|
cur += 6;
|
|
|
|
if (*cur != ':')
|
2009-08-06 13:38:11 +00:00
|
|
|
goto cleanup;
|
2008-12-22 10:36:54 +00:00
|
|
|
cur++;
|
|
|
|
str = cur;
|
|
|
|
while ((*cur != 0) && (!IS_SPACE(cur)))
|
|
|
|
cur++;
|
|
|
|
if (str == cur)
|
2009-08-06 13:38:11 +00:00
|
|
|
goto cleanup;
|
2008-12-22 10:36:54 +00:00
|
|
|
#if HAVE_SYSLOG_H
|
2013-05-24 07:19:51 +00:00
|
|
|
if (VIR_STRNDUP(name, str, cur - str) < 0)
|
2009-08-06 13:38:11 +00:00
|
|
|
goto cleanup;
|
2008-12-22 10:36:54 +00:00
|
|
|
if (virLogAddOutputToSyslog(prio, name) == 0)
|
2009-08-06 13:38:11 +00:00
|
|
|
count++;
|
2008-12-22 10:36:54 +00:00
|
|
|
VIR_FREE(name);
|
|
|
|
#endif /* HAVE_SYSLOG_H */
|
|
|
|
} else if (STREQLEN(cur, "file", 4)) {
|
2013-10-09 09:59:36 +00:00
|
|
|
if (isSUID)
|
|
|
|
goto cleanup;
|
2008-12-22 10:36:54 +00:00
|
|
|
cur += 4;
|
|
|
|
if (*cur != ':')
|
2009-08-06 13:38:11 +00:00
|
|
|
goto cleanup;
|
2008-12-22 10:36:54 +00:00
|
|
|
cur++;
|
|
|
|
str = cur;
|
|
|
|
while ((*cur != 0) && (!IS_SPACE(cur)))
|
|
|
|
cur++;
|
|
|
|
if (str == cur)
|
2009-08-06 13:38:11 +00:00
|
|
|
goto cleanup;
|
2013-05-24 07:19:51 +00:00
|
|
|
if (VIR_STRNDUP(name, str, cur - str) < 0)
|
2009-08-06 13:38:11 +00:00
|
|
|
goto cleanup;
|
2009-10-08 15:05:01 +00:00
|
|
|
if (virFileAbsPath(name, &abspath) < 0) {
|
|
|
|
VIR_FREE(name);
|
|
|
|
return -1; /* skip warning here because setting was fine */
|
|
|
|
}
|
|
|
|
if (virLogAddOutputToFile(prio, abspath) == 0)
|
2009-08-06 13:38:11 +00:00
|
|
|
count++;
|
2008-12-22 10:36:54 +00:00
|
|
|
VIR_FREE(name);
|
2009-10-08 15:05:01 +00:00
|
|
|
VIR_FREE(abspath);
|
2012-09-25 17:31:01 +00:00
|
|
|
} else if (STREQLEN(cur, "journald", 8)) {
|
2013-10-09 09:59:36 +00:00
|
|
|
if (isSUID)
|
|
|
|
goto cleanup;
|
2012-09-25 17:31:01 +00:00
|
|
|
cur += 8;
|
2012-10-01 22:38:56 +00:00
|
|
|
#if USE_JOURNALD
|
2012-09-25 17:31:01 +00:00
|
|
|
if (virLogAddOutputToJournald(prio) == 0)
|
|
|
|
count++;
|
2012-10-01 22:38:56 +00:00
|
|
|
#endif /* USE_JOURNALD */
|
2008-12-22 10:36:54 +00:00
|
|
|
} else {
|
2009-08-06 13:38:11 +00:00
|
|
|
goto cleanup;
|
2008-12-22 10:36:54 +00:00
|
|
|
}
|
|
|
|
virSkipSpaces(&cur);
|
|
|
|
}
|
2009-08-06 13:38:11 +00:00
|
|
|
ret = count;
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
2009-08-06 13:38:11 +00:00
|
|
|
if (ret == -1)
|
2011-05-09 09:24:09 +00:00
|
|
|
VIR_WARN("Ignoring invalid log output setting.");
|
2011-01-21 16:30:17 +00:00
|
|
|
return ret;
|
2008-12-22 10:36:54 +00:00
|
|
|
}
|
|
|
|
|
2012-09-27 13:14:01 +00:00
|
|
|
|
2008-12-22 10:36:54 +00:00
|
|
|
/**
|
|
|
|
* virLogParseFilters:
|
|
|
|
* @filters: string defining a (set of) filter(s)
|
|
|
|
*
|
|
|
|
* The format for a filter is:
|
|
|
|
* x:name
|
|
|
|
* where name is a match string
|
|
|
|
* the x prefix is the minimal level where the messages should be logged
|
|
|
|
* 1: DEBUG
|
|
|
|
* 2: INFO
|
|
|
|
* 3: WARNING
|
|
|
|
* 4: ERROR
|
|
|
|
*
|
|
|
|
* Multiple filter can be defined in a single @filters, they just need to be
|
|
|
|
* separated by spaces.
|
|
|
|
*
|
|
|
|
* Returns the number of filter parsed and installed or -1 in case of error
|
|
|
|
*/
|
2012-09-27 13:14:01 +00:00
|
|
|
int
|
|
|
|
virLogParseFilters(const char *filters)
|
|
|
|
{
|
2008-12-22 10:36:54 +00:00
|
|
|
const char *cur = filters, *str;
|
|
|
|
char *name;
|
2012-09-27 12:58:58 +00:00
|
|
|
virLogPriority prio;
|
2009-08-06 13:38:11 +00:00
|
|
|
int ret = -1;
|
|
|
|
int count = 0;
|
2008-12-22 10:36:54 +00:00
|
|
|
|
|
|
|
if (cur == NULL)
|
2011-01-21 16:30:17 +00:00
|
|
|
return -1;
|
2008-12-22 10:36:54 +00:00
|
|
|
|
|
|
|
virSkipSpaces(&cur);
|
|
|
|
while (*cur != 0) {
|
2012-05-09 14:18:56 +00:00
|
|
|
unsigned int flags = 0;
|
2014-01-20 11:27:29 +00:00
|
|
|
prio = virParseNumber(&cur);
|
2009-07-01 11:21:15 +00:00
|
|
|
if ((prio < VIR_LOG_DEBUG) || (prio > VIR_LOG_ERROR))
|
2009-08-06 13:38:11 +00:00
|
|
|
goto cleanup;
|
2008-12-22 10:36:54 +00:00
|
|
|
if (*cur != ':')
|
2009-08-06 13:38:11 +00:00
|
|
|
goto cleanup;
|
2008-12-22 10:36:54 +00:00
|
|
|
cur++;
|
2012-05-09 14:18:56 +00:00
|
|
|
if (*cur == '+') {
|
|
|
|
flags |= VIR_LOG_STACK_TRACE;
|
|
|
|
cur++;
|
|
|
|
}
|
2008-12-22 10:36:54 +00:00
|
|
|
str = cur;
|
|
|
|
while ((*cur != 0) && (!IS_SPACE(cur)))
|
|
|
|
cur++;
|
|
|
|
if (str == cur)
|
2009-08-06 13:38:11 +00:00
|
|
|
goto cleanup;
|
2013-05-24 07:19:51 +00:00
|
|
|
if (VIR_STRNDUP(name, str, cur - str) < 0)
|
2009-08-06 13:38:11 +00:00
|
|
|
goto cleanup;
|
2012-05-09 14:18:56 +00:00
|
|
|
if (virLogDefineFilter(name, prio, flags) >= 0)
|
2009-08-06 13:38:11 +00:00
|
|
|
count++;
|
2008-12-22 10:36:54 +00:00
|
|
|
VIR_FREE(name);
|
|
|
|
virSkipSpaces(&cur);
|
|
|
|
}
|
2009-08-06 13:38:11 +00:00
|
|
|
ret = count;
|
2014-03-25 06:53:22 +00:00
|
|
|
cleanup:
|
2009-08-06 13:38:11 +00:00
|
|
|
if (ret == -1)
|
2011-05-09 09:24:09 +00:00
|
|
|
VIR_WARN("Ignoring invalid log filter setting.");
|
2011-01-21 16:30:17 +00:00
|
|
|
return ret;
|
2008-12-22 10:36:54 +00:00
|
|
|
}
|
2009-08-06 13:45:50 +00:00
|
|
|
|
2012-09-27 13:14:01 +00:00
|
|
|
|
2009-08-06 13:45:50 +00:00
|
|
|
/**
|
|
|
|
* virLogGetDefaultPriority:
|
|
|
|
*
|
|
|
|
* Returns the current logging priority level.
|
|
|
|
*/
|
2012-09-27 13:14:01 +00:00
|
|
|
virLogPriority
|
|
|
|
virLogGetDefaultPriority(void)
|
|
|
|
{
|
2011-01-21 16:30:17 +00:00
|
|
|
return virLogDefaultPriority;
|
2009-08-06 13:45:50 +00:00
|
|
|
}
|
|
|
|
|
2012-09-27 13:14:01 +00:00
|
|
|
|
2009-10-08 15:05:01 +00:00
|
|
|
/**
|
|
|
|
* virLogGetFilters:
|
|
|
|
*
|
|
|
|
* Returns a string listing the current filters, in the format originally
|
|
|
|
* specified in the config file or environment. Caller must free the
|
|
|
|
* result.
|
|
|
|
*/
|
2012-09-27 13:14:01 +00:00
|
|
|
char *
|
|
|
|
virLogGetFilters(void)
|
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/util/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2009-10-08 15:05:01 +00:00
|
|
|
virBuffer filterbuf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
|
|
|
virLogLock();
|
|
|
|
for (i = 0; i < virLogNbFilters; i++) {
|
2012-05-09 14:18:56 +00:00
|
|
|
const char *sep = ":";
|
|
|
|
if (virLogFilters[i].flags & VIR_LOG_STACK_TRACE)
|
|
|
|
sep = ":+";
|
|
|
|
virBufferAsprintf(&filterbuf, "%d%s%s ",
|
|
|
|
virLogFilters[i].priority,
|
|
|
|
sep,
|
2009-10-08 15:05:01 +00:00
|
|
|
virLogFilters[i].match);
|
|
|
|
}
|
|
|
|
virLogUnlock();
|
|
|
|
|
2009-12-09 23:00:50 +00:00
|
|
|
if (virBufferError(&filterbuf)) {
|
|
|
|
virBufferFreeAndReset(&filterbuf);
|
2009-10-08 15:05:01 +00:00
|
|
|
return NULL;
|
2009-12-09 23:00:50 +00:00
|
|
|
}
|
2009-10-08 15:05:01 +00:00
|
|
|
|
|
|
|
return virBufferContentAndReset(&filterbuf);
|
|
|
|
}
|
|
|
|
|
2012-09-27 13:14:01 +00:00
|
|
|
|
2009-10-08 15:05:01 +00:00
|
|
|
/**
|
|
|
|
* virLogGetOutputs:
|
|
|
|
*
|
|
|
|
* Returns a string listing the current outputs, in the format originally
|
|
|
|
* specified in the config file or environment. Caller must free the
|
|
|
|
* result.
|
|
|
|
*/
|
2012-09-27 13:14:01 +00:00
|
|
|
char *
|
|
|
|
virLogGetOutputs(void)
|
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/util/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2009-10-08 15:05:01 +00:00
|
|
|
virBuffer outputbuf = VIR_BUFFER_INITIALIZER;
|
|
|
|
|
|
|
|
virLogLock();
|
|
|
|
for (i = 0; i < virLogNbOutputs; i++) {
|
2012-09-27 13:04:21 +00:00
|
|
|
virLogDestination dest = virLogOutputs[i].dest;
|
2009-10-08 15:05:01 +00:00
|
|
|
if (i)
|
2013-05-07 10:28:50 +00:00
|
|
|
virBufferAddChar(&outputbuf, ' ');
|
2009-10-08 15:05:01 +00:00
|
|
|
switch (dest) {
|
|
|
|
case VIR_LOG_TO_SYSLOG:
|
|
|
|
case VIR_LOG_TO_FILE:
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&outputbuf, "%d:%s:%s",
|
2009-10-08 15:05:01 +00:00
|
|
|
virLogOutputs[i].priority,
|
|
|
|
virLogOutputString(dest),
|
|
|
|
virLogOutputs[i].name);
|
|
|
|
break;
|
|
|
|
default:
|
2011-04-30 16:34:49 +00:00
|
|
|
virBufferAsprintf(&outputbuf, "%d:%s",
|
2009-10-08 15:05:01 +00:00
|
|
|
virLogOutputs[i].priority,
|
|
|
|
virLogOutputString(dest));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
virLogUnlock();
|
|
|
|
|
2009-12-09 23:00:50 +00:00
|
|
|
if (virBufferError(&outputbuf)) {
|
|
|
|
virBufferFreeAndReset(&outputbuf);
|
2009-10-08 15:05:01 +00:00
|
|
|
return NULL;
|
2009-12-09 23:00:50 +00:00
|
|
|
}
|
2009-10-08 15:05:01 +00:00
|
|
|
|
|
|
|
return virBufferContentAndReset(&outputbuf);
|
|
|
|
}
|
|
|
|
|
2012-09-27 13:14:01 +00:00
|
|
|
|
2009-08-06 13:45:50 +00:00
|
|
|
/**
|
|
|
|
* virLogGetNbFilters:
|
|
|
|
*
|
|
|
|
* Returns the current number of defined log filters.
|
|
|
|
*/
|
2012-09-27 13:14:01 +00:00
|
|
|
int
|
|
|
|
virLogGetNbFilters(void)
|
|
|
|
{
|
2011-01-21 16:30:17 +00:00
|
|
|
return virLogNbFilters;
|
2009-08-06 13:45:50 +00:00
|
|
|
}
|
|
|
|
|
2012-09-27 13:14:01 +00:00
|
|
|
|
2009-08-06 13:45:50 +00:00
|
|
|
/**
|
|
|
|
* virLogGetNbOutputs:
|
|
|
|
*
|
|
|
|
* Returns the current number of defined log outputs.
|
|
|
|
*/
|
2012-09-27 13:14:01 +00:00
|
|
|
int
|
|
|
|
virLogGetNbOutputs(void)
|
|
|
|
{
|
2011-01-21 16:30:17 +00:00
|
|
|
return virLogNbOutputs;
|
2009-08-06 13:45:50 +00:00
|
|
|
}
|
2009-08-06 13:55:07 +00:00
|
|
|
|
2012-09-27 13:14:01 +00:00
|
|
|
|
2009-08-06 13:55:07 +00:00
|
|
|
/**
|
|
|
|
* virLogParseDefaultPriority:
|
|
|
|
* @priority: string defining the desired logging level
|
|
|
|
*
|
|
|
|
* Parses and sets the default log priority level. It can take a string or
|
|
|
|
* number corresponding to the following levels:
|
|
|
|
* 1: DEBUG
|
|
|
|
* 2: INFO
|
|
|
|
* 3: WARNING
|
|
|
|
* 4: ERROR
|
|
|
|
*
|
2014-03-21 06:52:40 +00:00
|
|
|
* Returns 0 if successful, -1 in case of error.
|
2009-08-06 13:55:07 +00:00
|
|
|
*/
|
2012-09-27 13:14:01 +00:00
|
|
|
int
|
|
|
|
virLogParseDefaultPriority(const char *priority)
|
|
|
|
{
|
2009-08-06 13:55:07 +00:00
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (STREQ(priority, "1") || STREQ(priority, "debug"))
|
|
|
|
ret = virLogSetDefaultPriority(VIR_LOG_DEBUG);
|
|
|
|
else if (STREQ(priority, "2") || STREQ(priority, "info"))
|
|
|
|
ret = virLogSetDefaultPriority(VIR_LOG_INFO);
|
|
|
|
else if (STREQ(priority, "3") || STREQ(priority, "warning"))
|
|
|
|
ret = virLogSetDefaultPriority(VIR_LOG_WARN);
|
|
|
|
else if (STREQ(priority, "4") || STREQ(priority, "error"))
|
|
|
|
ret = virLogSetDefaultPriority(VIR_LOG_ERROR);
|
|
|
|
else
|
2011-05-09 09:24:09 +00:00
|
|
|
VIR_WARN("Ignoring invalid log level setting");
|
2009-08-06 13:55:07 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-09-27 13:14:01 +00:00
|
|
|
|
2009-08-06 13:55:07 +00:00
|
|
|
/**
|
|
|
|
* virLogSetFromEnv:
|
|
|
|
*
|
|
|
|
* Sets virLogDefaultPriority, virLogFilters and virLogOutputs based on
|
|
|
|
* environment variables.
|
|
|
|
*/
|
2012-09-27 13:14:01 +00:00
|
|
|
void
|
|
|
|
virLogSetFromEnv(void)
|
|
|
|
{
|
2013-10-09 10:18:15 +00:00
|
|
|
const char *debugEnv;
|
2009-08-06 13:55:07 +00:00
|
|
|
|
2013-10-11 16:07:54 +00:00
|
|
|
if (virLogInitialize() < 0)
|
|
|
|
return;
|
|
|
|
|
2013-10-09 10:18:15 +00:00
|
|
|
debugEnv = virGetEnvAllowSUID("LIBVIRT_DEBUG");
|
2009-08-06 13:55:07 +00:00
|
|
|
if (debugEnv && *debugEnv)
|
|
|
|
virLogParseDefaultPriority(debugEnv);
|
2013-10-09 10:18:15 +00:00
|
|
|
debugEnv = virGetEnvAllowSUID("LIBVIRT_LOG_FILTERS");
|
2009-08-06 13:55:07 +00:00
|
|
|
if (debugEnv && *debugEnv)
|
2010-12-01 16:42:17 +00:00
|
|
|
virLogParseFilters(debugEnv);
|
2013-10-09 10:18:15 +00:00
|
|
|
debugEnv = virGetEnvAllowSUID("LIBVIRT_LOG_OUTPUTS");
|
2009-08-06 13:55:07 +00:00
|
|
|
if (debugEnv && *debugEnv)
|
2010-12-01 16:42:17 +00:00
|
|
|
virLogParseOutputs(debugEnv);
|
2009-08-06 13:55:07 +00:00
|
|
|
}
|
2013-03-04 20:46:32 +00:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Returns a true value if the first line in @str is
|
|
|
|
* probably a log message generated by the libvirt
|
|
|
|
* logging layer
|
|
|
|
*/
|
|
|
|
bool virLogProbablyLogMessage(const char *str)
|
|
|
|
{
|
|
|
|
bool ret = false;
|
|
|
|
if (!virLogRegex)
|
|
|
|
return false;
|
|
|
|
if (regexec(virLogRegex, str, 0, NULL, 0) == 0)
|
|
|
|
ret = true;
|
|
|
|
return ret;
|
|
|
|
}
|