#if HAVE_SYSLOG_H
# include <syslog.h>
#endif
+#ifdef HAVE_EXECINFO_H
+# include <execinfo.h>
+#endif
#include "ignore-value.h"
#include "virterror_internal.h"
struct _virLogFilter {
const char *match;
int priority;
+ unsigned int flags;
};
typedef struct _virLogFilter virLogFilter;
typedef virLogFilter *virLogFilterPtr;
static int virLogResetOutputs(void);
static int virLogOutputToFd(const char *category, int priority,
const char *funcname, long long linenr,
- const char *timestamp, const char *str,
+ const char *timestamp,
+ unsigned int flags,
+ const char *str,
void *data);
/*
* virLogDefineFilter:
* @match: the pattern to match
* @priority: the priority to give to messages matching the pattern
- * @flags: extra flag, currently unused
+ * @flags: extra flags, see virLogFilterFlags enum
*
* Defines a pattern used for log filtering, it allow to select or
* reject messages independently of the default priority.
int i;
char *mdup = NULL;
- virCheckFlags(0, -1);
+ virCheckFlags(VIR_LOG_STACK_TRACE, -1);
if ((match == NULL) || (priority < VIR_LOG_DEBUG) ||
(priority > VIR_LOG_ERROR))
}
virLogFilters[i].match = mdup;
virLogFilters[i].priority = priority;
+ virLogFilters[i].flags = flags;
virLogNbFilters++;
cleanup:
virLogUnlock();
*
* Returns 0 if not matched or the new priority if found.
*/
-static int virLogFiltersCheck(const char *input) {
+static int virLogFiltersCheck(const char *input,
+ unsigned int *flags) {
int ret = 0;
int i;
for (i = 0;i < virLogNbFilters;i++) {
if (strstr(input, virLogFilters[i].match)) {
ret = virLogFilters[i].priority;
+ *flags = virLogFilters[i].flags;
break;
}
}
int saved_errno = errno;
int emit = 1;
va_list ap;
+ unsigned int filterflags = 0;
if (!virLogInitialized)
virLogStartup();
/*
* check against list of specific logging patterns
*/
- fprio = virLogFiltersCheck(category);
+ fprio = virLogFiltersCheck(category, &filterflags);
if (fprio == 0) {
if (priority < virLogDefaultPriority)
emit = 0;
if (virLogVersionString(&ver) >= 0)
virLogOutputs[i].f(category, VIR_LOG_INFO,
__func__, __LINE__,
- timestamp, ver,
+ timestamp, 0, ver,
virLogOutputs[i].data);
VIR_FREE(ver);
virLogOutputs[i].logVersion = false;
}
virLogOutputs[i].f(category, priority, funcname, linenr,
- timestamp, msg, virLogOutputs[i].data);
+ timestamp, filterflags,
+ msg, virLogOutputs[i].data);
}
}
if ((virLogNbOutputs == 0) && (flags != 1)) {
if (virLogVersionString(&ver) >= 0)
virLogOutputToFd(category, VIR_LOG_INFO,
__func__, __LINE__,
- timestamp, ver,
+ timestamp, 0, ver,
(void *) STDERR_FILENO);
VIR_FREE(ver);
logVersionStderr = false;
}
virLogOutputToFd(category, priority, funcname, linenr,
- timestamp, msg, (void *) STDERR_FILENO);
+ timestamp, filterflags,
+ msg, (void *) STDERR_FILENO);
}
virLogUnlock();
errno = saved_errno;
}
+
+static void virLogStackTraceToFd(int fd)
+{
+#ifdef HAVE_EXECINFO_H
+ void *array[100];
+ int size;
+
+# define STRIP_DEPTH 3
+
+ size = backtrace(array, ARRAY_CARDINALITY(array));
+ backtrace_symbols_fd(array + STRIP_DEPTH, size - STRIP_DEPTH, fd);
+ ignore_value(safewrite(fd, "\n", 1));
+#else
+ static bool doneWarning = false;
+ const char *msg = "Stack trace not available on this platform\n";
+ if (!doneWarning) {
+ ignore_value(safewrite(fd, msg, strlen(msg)));
+ doneWarning = true;
+ }
+#endif
+}
+
static int virLogOutputToFd(const char *category ATTRIBUTE_UNUSED,
int priority ATTRIBUTE_UNUSED,
const char *funcname ATTRIBUTE_UNUSED,
long long linenr ATTRIBUTE_UNUSED,
const char *timestamp,
+ unsigned int flags,
const char *str,
void *data)
{
ret = safewrite(fd, msg, strlen(msg));
VIR_FREE(msg);
+ if (flags & VIR_LOG_STACK_TRACE)
+ virLogStackTraceToFd(fd);
+
return ret;
}
const char *funcname ATTRIBUTE_UNUSED,
long long linenr ATTRIBUTE_UNUSED,
const char *timestamp ATTRIBUTE_UNUSED,
+ unsigned int flags,
const char *str,
void *data ATTRIBUTE_UNUSED)
{
int prio;
+ virCheckFlags(VIR_LOG_STACK_TRACE, -1);
+
switch (priority) {
case VIR_LOG_DEBUG:
prio = LOG_DEBUG;
virSkipSpaces(&cur);
while (*cur != 0) {
+ unsigned int flags = 0;
prio= virParseNumber(&cur);
if ((prio < VIR_LOG_DEBUG) || (prio > VIR_LOG_ERROR))
goto cleanup;
if (*cur != ':')
goto cleanup;
cur++;
+ if (*cur == '+') {
+ flags |= VIR_LOG_STACK_TRACE;
+ cur++;
+ }
str = cur;
while ((*cur != 0) && (!IS_SPACE(cur)))
cur++;
name = strndup(str, cur - str);
if (name == NULL)
goto cleanup;
- if (virLogDefineFilter(name, prio, 0) >= 0)
+ if (virLogDefineFilter(name, prio, flags) >= 0)
count++;
VIR_FREE(name);
virSkipSpaces(&cur);
virLogLock();
for (i = 0; i < virLogNbFilters; i++) {
- virBufferAsprintf(&filterbuf, "%d:%s ", virLogFilters[i].priority,
+ const char *sep = ":";
+ if (virLogFilters[i].flags & VIR_LOG_STACK_TRACE)
+ sep = ":+";
+ virBufferAsprintf(&filterbuf, "%d%s%s ",
+ virLogFilters[i].priority,
+ sep,
virLogFilters[i].match);
}
virLogUnlock();