On Wed, Dec 17, 2008 at 04:12:20PM +0100, Daniel Veillard wrote:
diff -u -r1.1 logging.h
--- src/logging.h 6 Nov 2008 16:36:07 -0000 1.1
+++ src/logging.h 17 Dec 2008 14:25:57 -0000
@@ -30,16 +30,87 @@
* defined at runtime of from the libvirt daemon configuration file
*/
#ifdef ENABLE_DEBUG
-extern int debugFlag;
#define VIR_DEBUG(category, fmt,...) \
- do { if (debugFlag) fprintf (stderr, "DEBUG: %s: %s (" fmt
")\n", category, __func__, __VA_ARGS__); } while (0)
+ virLogMessage(category, VIR_LOG_DEBUG, 0, fmt, __VA_ARGS__)
+#define VIR_INFO(category, fmt,...) \
+ virLogMessage(category, VIR_LOG_INFO, 0, fmt, __VA_ARGS__)
+#define VIR_WARN(category, fmt,...) \
+ virLogMessage(category, VIR_LOG_WARN, 0, fmt, __VA_ARGS__)
+#define VIR_ERROR(category, fmt,...) \
+ virLogMessage(category, VIR_LOG_ERROR, 0, fmt, __VA_ARGS__)
#else
#define VIR_DEBUG(category, fmt,...) \
do { } while (0)
+#define VIR_INFO(category, fmt,...) \
+ do { } while (0)
+#define VIR_WARN(category, fmt,...) \
+ do { } while (0)
+#define VIR_ERROR(category, fmt,...) \
+ do { } while (0)
#endif /* !ENABLE_DEBUG */
#define DEBUG(fmt,...) VIR_DEBUG(__FILE__, fmt, __VA_ARGS__)
#define DEBUG0(msg) VIR_DEBUG(__FILE__, "%s", msg)
+#define INFO(fmt,...) VIR_INFO(__FILE__, fmt, __VA_ARGS__)
+#define INFO0(msg) VIR_INFO(__FILE__, "%s", msg)
+#define WARN(fmt,...) VIR_WARN(__FILE__, fmt, __VA_ARGS__)
+#define WARN0(msg) VIR_WARN(__FILE__, "%s", msg)
+#define ERROR(fmt,...) VIR_ERROR(__FILE__, fmt, __VA_ARGS__)
+#define ERROR0(msg) VIR_ERROR(__FILE__, "%s", msg)
I think we should add a prefix to the filename to give a
little scope to the namespace. This would let people use
non-filename based namespaces without risk of clashing,
eg, perhaps
#define ERROR(fmt,...) VIR_ERROR("file." __FILE__, fmt, __VA_ARGS__)
thus turning into file.libvirt.c
+/**
+ * virLogOutputFunc:
+ * @data: extra output logging data
+ * @category: the category for the message
+ * @priority: the priority for the message
+ * @msg: the message to log, preformatted and zero terminated
+ * @len: the lenght of the message in bytes without the terminating zero
+ *
+ * Callback function used to output messages
+ *
+ * Returns the number of bytes written or -1 in case of error
+ */
+typedef int (*virLogOutputFunc) (void *data, const char *category,
+ int priority, const char *str, int len);
I have a preference for 'void *data' parameters to callbacks being
at end of the param list.
+extern int virLogStartup(void);
+extern int virLogReset(void);
+extern void virLogShutdown(void);
+extern int virLogParseFilters(const char *filters);
+extern int virLogParseOutputs(const char *output);
+extern void virLogMessage(const char *category, int priority, int flags,
+ const char *fmt, ...) ATTRIBUTE_FORMAT(printf, 4, 5);
I think it would be a good idea to have virLogMesage take a
function name, and line number too. Likewise for the
virLogOutputFunc() function.
The VIR_ERROR/WARN/INFO/DEBUG macros would automatically include
the __func__ and __line__ macros. eg
#define VIR_INFO(category, fmt,...) \
virLogMessage(category, __func__, __line__, VIR_LOG_INFO, 0, fmt,
__VA_ARGS__)
So when we process the 'char fmt,....' into an actual string we could
have some flag to turn on/off inclusion of the function & line data.
Cole did a similar thing for error reporting internal APIs when he
added this to virterror_internal.h:
void virReportErrorHelper(virConnectPtr conn, int domcode, int errcode,
const char *filename,
const char *funcname,
long long linenr,
const char *fmt, ...)
ATTRIBUTE_FORMAT(printf, 7, 8);
Though, the actual implementation currently ignores filename, funcname
and linenr.
+
+/*
+ * Macro used to format the message as a string in virLogMessage
+ * and borrowed from libxml2 (also used in virRaiseError)
+ */
+#define VIR_GET_VAR_STR(msg, str) { \
+ int size, prev_size = -1; \
+ int chars; \
+ char *larger; \
+ va_list ap; \
+ \
+ str = (char *) malloc(150); \
+ if (str != NULL) { \
+ \
+ size = 150; \
+ \
+ while (1) { \
+ va_start(ap, msg); \
+ chars = vsnprintf(str, size, msg, ap); \
+ va_end(ap); \
+ if ((chars > -1) && (chars < size)) { \
+ if (prev_size == chars) { \
+ break; \
+ } else { \
+ prev_size = chars; \
+ } \
+ } \
+ if (chars > -1) \
+ size += chars + 1; \
+ else \
+ size += 100; \
+ if ((larger = (char *) realloc(str, size)) == NULL) { \
+ break; \
+ } \
+ str = larger; \
+ }} \
+}
Wonder if we should make this use virBuffer instead of
char/malloc/realloc. Could then add this definition to
buf.h and share it between the logging & error routines.
+static const char *virLogPriorityString(virLogPriority lvl) {
+ switch (lvl) {
+ case VIR_LOG_DEBUG:
+ return("debug");
+ case VIR_LOG_INFO:
+ return("info");
+ case VIR_LOG_WARN:
+ return("warning");
+ case VIR_LOG_ERROR:
+ return("error");
+ }
+ return("unknown");
+}
+
+static int virLogInitialized = 0;
+
+/**
+ * virLogStartup:
+ *
+ * Initialize the logging module
+ *
+ * Returns 0 if successful, and -1 in case or error
+ */
+int virLogStartup(void) {
+ if (virLogInitialized)
+ return(-1);
+ virLogInitialized = 1;
Strictly speaking we should use pthread_once() for such
initializations, or an atomic test-and-set operation.
+ /*
+ * serialize the error message, add level and timestamp
+ */
+ VIR_GET_VAR_STR(fmt, str);
+ if (str == NULL)
+ return;
+ gettimeofday(&cur_time, NULL);
+ localtime_r(&cur_time.tv_sec, &time_info);
+
+ if (asprintf(&msg, "%02d:%02d:%02d.%03d: %s : %s\n",
+ time_info.tm_hour, time_info.tm_min,
+ time_info.tm_sec, (int) cur_time.tv_usec / 1000,
+ virLogPriorityString(priority), str) < 0) {
This would be the place where we'd add in (optional) inclusion of
the function name & line number data.
+
+#define IS_SPACE(cur) \
+ ((*cur == ' ') || (*cur == '\t') || (*cur == '\n') ||
\
+ (*cur == '\r') || (*cur == '\\'))
GNULIB already provides this with c_isspace() - unless we really
need the check for '\\' too ?
All basically looks good to me.
Regards,
Daniel
--
|: Red Hat, Engineering, London -o-
http://people.redhat.com/berrange/ :|
|:
http://libvirt.org -o-
http://virt-manager.org -o-
http://ovirt.org :|
|:
http://autobuild.org -o-
http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|