xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
From: Ian Jackson <ian.jackson@eu.citrix.com>
To: xen-devel@lists.xensource.com
Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Subject: [PATCH] xtl: New xentoollog mini-library.
Date: Thu, 27 May 2010 16:55:13 +0100	[thread overview]
Message-ID: <1274975721-3777-7-git-send-email-ian.jackson@eu.citrix.com> (raw)
In-Reply-To: <1274975721-3777-6-git-send-email-ian.jackson@eu.citrix.com>

We provide a new header file "xentoollog.h" which defines an interface
that libraries and applications can use for logging.  This avoids
having to wrap each library's log callbacks up, massage arguments to
log callbacks, and so on.

The library's .o files are within libxc to avoid having to create a
separate lib*.a, but callers do not need to #include xenctrl.h and it
should be regarded as a separate API.

Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
---
 tools/libxc/Makefile           |    4 +-
 tools/libxc/xentoollog.h       |  114 +++++++++++++++++++++++++++++++++++++
 tools/libxc/xtl_core.c         |   69 ++++++++++++++++++++++
 tools/libxc/xtl_logger_stdio.c |  122 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 308 insertions(+), 1 deletions(-)
 create mode 100644 tools/libxc/xentoollog.h
 create mode 100644 tools/libxc/xtl_core.c
 create mode 100644 tools/libxc/xtl_logger_stdio.c

diff --git a/tools/libxc/Makefile b/tools/libxc/Makefile
index 948be66..98cc88e 100644
--- a/tools/libxc/Makefile
+++ b/tools/libxc/Makefile
@@ -27,6 +27,8 @@ CTRL_SRCS-y       += xc_tmem.c
 CTRL_SRCS-y       += xc_mem_event.c
 CTRL_SRCS-y       += xc_mem_paging.c
 CTRL_SRCS-y       += xc_memshr.c
+CTRL_SRCS-y       += xtl_core.c
+CTRL_SRCS-y       += xtl_logger_stdio.c
 CTRL_SRCS-$(CONFIG_X86) += xc_pagetab.c
 CTRL_SRCS-$(CONFIG_Linux) += xc_linux.c
 CTRL_SRCS-$(CONFIG_SunOS) += xc_solaris.c
@@ -105,7 +107,7 @@ install: build
 	$(INSTALL_DATA) libxenctrl.a $(DESTDIR)$(LIBDIR)
 	ln -sf libxenctrl.so.$(MAJOR).$(MINOR) $(DESTDIR)$(LIBDIR)/libxenctrl.so.$(MAJOR)
 	ln -sf libxenctrl.so.$(MAJOR) $(DESTDIR)$(LIBDIR)/libxenctrl.so
-	$(INSTALL_DATA) xenctrl.h $(DESTDIR)$(INCLUDEDIR)
+	$(INSTALL_DATA) xenctrl.h xentoollog.h $(DESTDIR)$(INCLUDEDIR)
 
 	$(INSTALL_PROG) libxenguest.so.$(MAJOR).$(MINOR) $(DESTDIR)$(LIBDIR)
 	$(INSTALL_DATA) libxenguest.a $(DESTDIR)$(LIBDIR)
diff --git a/tools/libxc/xentoollog.h b/tools/libxc/xentoollog.h
new file mode 100644
index 0000000..d467168
--- /dev/null
+++ b/tools/libxc/xentoollog.h
@@ -0,0 +1,114 @@
+/*
+ * xentoollog.h
+ *
+ * Copyright (c) 2010 Citrix
+ * Part of a generic logging interface used by various dom0 userland libraries.
+ */
+
+#ifndef XENTOOLLOG_H
+#define XENTOOLLOG_H
+
+#include <stdio.h>
+#include <stdarg.h>
+
+
+/*---------- common declarations and types ----------*/
+
+typedef enum xentoollog_level {
+    XTL_NONE, /* sentinel etc, never used for logging */
+    XTL_DEBUG,
+    XTL_VERBOSE,
+    XTL_DETAIL,
+    XTL_PROGRESS, /* also used for "progress" messages */
+    XTL_INFO,
+    XTL_NOTICE,
+    XTL_WARN,
+    XTL_ERROR,
+    XTL_CRITICAL,
+    XTL_NUM_LEVELS
+} xentoollog_level;
+
+typedef struct xentoollog_logger xentoollog_logger;
+struct xentoollog_logger {
+    void (*vmessage)(struct xentoollog_logger *logger,
+                     xentoollog_level level,
+                     int errnoval /* or -1 */,
+                     const char *context /* eg "xc", "xl", may be 0 */,
+                     const char *format /* without level, context, \n */,
+                     va_list al)
+         __attribute__((format(printf,5,0)));
+    void (*progress)(struct xentoollog_logger *logger,
+                     const char *context /* see above */,
+                     const char *doing_what /* no \r,\n */,
+                     int percent, unsigned long done, unsigned long total)
+         /* null function pointer is ok.
+          * will always be called with done==0 for each new
+          * context/doing_what */;
+    void (*destroy)(struct xentoollog_logger *logger);
+    /* each logger can put its necessary data here */
+};
+
+
+/*---------- facilities for consuming log messages ----------*/
+
+#define XTL_STDIOSTREAM_SHOW_PID  01u
+#define XTL_STDIOSTREAM_SHOW_DATE 02u
+
+typedef struct xentoollog_logger_stdiostream  xentoollog_logger_stdiostream;
+
+xentoollog_logger_stdiostream *xtl_createlogger_stdiostream
+        (FILE *f, xentoollog_level min_level, unsigned flags);
+    /* may return 0 if malloc fails, in which case error was logged */
+    /* destroy on this logger does not close the file */
+
+void xtl_logger_destroy(struct xentoollog_logger *logger /* 0 is ok */);
+
+
+/*---------- facilities for generating log messages ----------*/
+
+void xtl_logv(struct xentoollog_logger *logger,
+              xentoollog_level level,
+              int errnoval /* or -1 */,
+              const char *context /* eg "xc", "xenstore", "xl", may be 0 */,
+              const char *format /* does not contain \n */,
+              va_list) __attribute__((format(printf,5,0)));
+
+void xtl_log(struct xentoollog_logger *logger,
+             xentoollog_level level,
+             int errnoval /* or -1 */,
+             const char *context /* eg "xc", "xenstore", "xl" */,
+             const char *format /* does not contain \n */,
+             ...) __attribute__((format(printf,5,6)));
+
+void xtl_progress(struct xentoollog_logger *logger,
+                  const char *context /* see above, may be 0 */,
+                  const char *doing_what,
+                  unsigned long done, unsigned long total);
+
+
+/*---------- facilities for defining log message consumers ----------*/
+
+const char *xtl_level_to_string(xentoollog_level); /* never fails */
+
+
+#define XTL_NEW_LOGGER(LOGGER,buffer) ({                                \
+    xentoollog_logger_##LOGGER *new_consumer;                           \
+                                                                        \
+    (buffer).vtable.vmessage = LOGGER##_vmessage;                       \
+    (buffer).vtable.progress = LOGGER##_progress;                       \
+    (buffer).vtable.destroy  = LOGGER##_destroy;                        \
+                                                                        \
+    new_consumer = malloc(sizeof(*new_consumer));                       \
+    if (!new_consumer) {                                                \
+        xtl_log((xentoollog_logger*)&buffer,                            \
+                XTL_CRITICAL, errno, "xtl",                             \
+                "failed to allocate memory for new message logger");    \
+    } else {                                                            \
+        *new_consumer = buffer;                                         \
+    }                                                                   \
+                                                                        \
+    new_consumer;                                                       \
+});
+
+
+#endif /* XENTOOLLOG_H */
diff --git a/tools/libxc/xtl_core.c b/tools/libxc/xtl_core.c
new file mode 100644
index 0000000..2a6a53f
--- /dev/null
+++ b/tools/libxc/xtl_core.c
@@ -0,0 +1,69 @@
+/*
+ * xtl_core.c
+ *
+ * core code including functions for generating log messages
+ *
+ * Copyright (c) 2010 Citrix
+ * Part of a generic logging interface used by various dom0 userland libraries.
+ */
+
+#include "xentoollog.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+
+static const char *level_strings[XTL_NUM_LEVELS]= {
+    "[BUG:XTL_NONE]",
+    "debug", "verbose", "detail",  /* normally off by default */
+    "progress", "info", "notice",  /* not a problem */
+    "warning", "error", "critical" /* problems and errors */
+};
+
+const char *xtl_level_to_string(xentoollog_level level) {
+    assert(level >= 0 && level < XTL_NUM_LEVELS);
+    return level_strings[level];
+}
+
+void xtl_logv(struct xentoollog_logger *logger,
+              xentoollog_level level,
+              int errnoval /* or -1 */,
+              const char *context /* eg "xc", "xenstore", "xl" */,
+              const char *format /* does not contain \n */,
+              va_list al) {
+    int errno_save = errno;
+    assert(level > XTL_NONE && level < XTL_NUM_LEVELS);
+    logger->vmessage(logger,level,errnoval,context,format,al);
+    errno = errno_save;
+}
+
+void xtl_log(struct xentoollog_logger *logger,
+             xentoollog_level level,
+             int errnoval /* or -1 */,
+             const char *context /* eg "xc", "xenstore", "xl" */,
+             const char *format /* does not contain \n */,
+             ...) {
+    va_list al;
+    va_start(al,format);
+    xtl_logv(logger,level,errnoval,context,format,al);
+    va_end(al);
+}
+
+void xtl_progress(struct xentoollog_logger *logger,
+                  const char *context, const char *doing_what,
+                  unsigned long done, unsigned long total) {
+    int percent;
+
+    if (!logger->progress) return;
+
+    percent = (total < LONG_MAX/100)
+        ? (done * 100) / total
+        : done / ((total + 99) / 100);
+
+    logger->progress(logger, context, doing_what, percent, done, total);
+}
+
+void xtl_logger_destroy(struct xentoollog_logger *logger) {
+    if (!logger) return;
+    logger->destroy(logger);
+}
diff --git a/tools/libxc/xtl_logger_stdio.c b/tools/libxc/xtl_logger_stdio.c
new file mode 100644
index 0000000..587c67d
--- /dev/null
+++ b/tools/libxc/xtl_logger_stdio.c
@@ -0,0 +1,122 @@
+/*
+ * xtl_logger_stdio.c
+ *
+ * log message consumer that writes to stdio
+ *
+ * Copyright (c) 2010 Citrix
+ * Part of a generic logging interface used by various dom0 userland libraries.
+ */
+
+#include "xentoollog.h"
+
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+struct xentoollog_logger_stdiostream {
+    xentoollog_logger vtable;
+    FILE *f;
+    xentoollog_level min_level;
+    unsigned flags;
+    int progress_erase_len, progress_last_percent;
+};
+
+static void progress_erase(xentoollog_logger_stdiostream *lg) {
+    if (lg->progress_erase_len)
+        fprintf(lg->f, "\r%*s\r", lg->progress_erase_len, "");
+}
+
+static void stdiostream_vmessage(xentoollog_logger *logger_in,
+                                 xentoollog_level level,
+                                 int errnoval,
+                                 const char *context,
+                                 const char *format,
+                                 va_list al) {
+    xentoollog_logger_stdiostream *lg = (void*)logger_in;
+
+    progress_erase(lg);
+
+    if (lg->flags & XTL_STDIOSTREAM_SHOW_DATE) {
+        struct tm lt_buf;
+        time_t now = time(0);
+        struct tm *lt= localtime_r(&now, &lt_buf);
+        fprintf(lg->f, "%04d-%02d-%02d %02d:%02d:%02d %s ",
+                lt->tm_year+1900, lt->tm_mon+1, lt->tm_mday,
+                lt->tm_hour, lt->tm_min, lt->tm_sec,
+                tzname[daylight ? !!lt->tm_isdst : 0]);
+    }
+    if (lg->flags & XTL_STDIOSTREAM_SHOW_PID)
+        fprintf(lg->f, "[%lu] ", (unsigned long)getpid());
+
+    if (context)
+        fprintf(lg->f, "%s: ", context);
+
+    fprintf(lg->f, "%s: ", xtl_level_to_string(level));
+
+    vfprintf(lg->f, format, al);
+
+    if (errnoval >= 0)
+        vfprintf(lg->f, ": %s", strerror(errnoval));
+
+    putc('\n', lg->f);
+    fflush(lg->f);
+}
+
+static void stdiostream_progress(struct xentoollog_logger *logger_in,
+                                 const char *context,
+                                 const char *doing_what, int percent,
+                                 unsigned long done, unsigned long total) {
+    xentoollog_logger_stdiostream *lg = (void*)logger_in;
+    int newpel, extra_erase;
+    xentoollog_level this_level;
+
+    if (percent < lg->progress_last_percent) {
+        this_level = XTL_PROGRESS;
+    } else if (percent == lg->progress_last_percent) {
+        return;
+    } else if (percent < lg->progress_last_percent + 5) {
+        this_level = XTL_DETAIL;
+    } else {
+        this_level = XTL_PROGRESS;
+    }
+
+    if (lg->min_level < this_level)
+        return;
+
+    if (lg->progress_erase_len)
+        putc('\r', lg->f);
+
+    newpel = fprintf(lg->f, "%s%s" "%s: %lu/%lu  %3d%%",
+                     context?context:"", context?": ":"",
+                     doing_what, done, total, percent);
+
+    extra_erase = lg->progress_erase_len - newpel;
+    if (extra_erase > 0)
+        fprintf(lg->f, "%*s\r", extra_erase, "");
+
+    lg->progress_erase_len = newpel;
+}
+
+static void stdiostream_destroy(struct xentoollog_logger *logger_in) {
+    xentoollog_logger_stdiostream *lg = (void*)logger_in;
+    progress_erase(lg);
+    free(lg);
+}
+
+
+xentoollog_logger_stdiostream *xtl_createlogger_stdiostream
+        (FILE *f, xentoollog_level min_level, unsigned flags) {
+    xentoollog_logger_stdiostream newlogger;
+
+    newlogger.f = f;
+    newlogger.min_level = min_level;
+    newlogger.flags = flags;
+
+    if (newlogger.flags & XTL_STDIOSTREAM_SHOW_DATE) tzset();
+
+    newlogger.progress_erase_len = 0;
+
+    return XTL_NEW_LOGGER(stdiostream, newlogger);
+}
-- 
1.5.6.5

  reply	other threads:[~2010-05-27 15:55 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-05-27 15:55 [PATCH 00/14] Logging cleanups, libxc API change Ian Jackson
2010-05-27 15:55 ` [PATCH] xl: Combine headers into one header file Ian Jackson
2010-05-27 15:55   ` [PATCH] xl: Move "extern" declarations to xl.h Ian Jackson
2010-05-27 15:55     ` [PATCH] stubdom/newlib: Provide correct names for time.h timezone variables Ian Jackson
2010-05-27 15:55       ` [PATCH] libxc: xc_domain_save.c: rename "write_exact" macro Ian Jackson
2010-05-27 15:55         ` [PATCH] libelf: Tidy up logging and remove dependency on stdio Ian Jackson
2010-05-27 15:55           ` Ian Jackson [this message]
2010-05-27 15:55             ` [PATCH] libxc: eliminate static variables, use xentoollog; API change Ian Jackson
2010-05-27 15:55               ` [PATCH] libxc: Use new DBGPRINTF for a few debugging output messages Ian Jackson
2010-05-27 15:55                 ` [PATCH] libxl: Fix up some incorrect printf formats Ian Jackson
2010-05-27 15:55                   ` [PATCH] libxl: Use the caller's logger (xentoollog) Ian Jackson
2010-05-27 15:55                     ` [PATCH] xl: Allow control of logging level Ian Jackson
2010-05-27 15:55                       ` [PATCH] libxc: save/restore error handling fixes Ian Jackson
2010-05-27 15:55                         ` [PATCH] libxc: remove \n from strings passed to PERROR Ian Jackson
2010-05-27 15:55                           ` [PATCH] xl/libxtl: Remove glitch in xl migrate log output Ian Jackson
2010-05-27 15:58 ` [PATCH 00/14] Logging cleanups, libxc API change Ian Jackson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1274975721-3777-7-git-send-email-ian.jackson@eu.citrix.com \
    --to=ian.jackson@eu.citrix.com \
    --cc=xen-devel@lists.xensource.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).