Whole new logging with following goals is here:
 - more log levels.
 - allow applications to log somewhere else than stdout using their custom
   callback.
 - provide simple stdout logger for 'lazy' applications.

The logging is off by default, i.e. no message appears on stdout unless
application initializes the logging explicitly. But see following patches!

Internally, nothing changes, cgroup_dbg is still working. In addition,
cgroup_err, cgroup_warn and cgroup_info appeared. Description what message
should use which log level is in doxygen info, together with new public API
incl. simple example, I won't copy it here

Also the cgroup_log function is made public. I am not sure if it is the
right thing to do, but that's currently the simplest way how to use the
logging from our tools (which link only the public libcgroup API).

Changelog:
  - fixed typo in cgroup_log doxygen comment

Signed-off-by: Peter Schiffer <pschi...@redhat.com>
---
 include/Makefile.am      |    2 -
 include/libcgroup.h      |    1 
 include/libcgroup/log.h  |  138 ++++++++++++++++++++++++++++++++++++++++++++++
 src/Makefile.am          |    2 -
 src/libcgroup-internal.h |    8 ++-
 src/libcgroup.map        |    4 +
 src/log.c                |   76 +++++++++++++++++++++++++
 7 files changed, 228 insertions(+), 3 deletions(-)
 create mode 100644 include/libcgroup/log.h
 create mode 100644 src/log.c

diff --git a/include/Makefile.am b/include/Makefile.am
index a7602a9..752a624 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -1,2 +1,2 @@
 # Using 'nobase_', we what groups.h in /usr/include/libcgroup/ directory
-nobase_include_HEADERS = libcgroup.h libcgroup/error.h libcgroup/init.h 
libcgroup/groups.h libcgroup/tasks.h libcgroup/iterators.h libcgroup/config.h
+nobase_include_HEADERS = libcgroup.h libcgroup/error.h libcgroup/init.h 
libcgroup/groups.h libcgroup/tasks.h libcgroup/iterators.h libcgroup/config.h 
libcgroup/log.h
diff --git a/include/libcgroup.h b/include/libcgroup.h
index 543bd13..1c7d409 100644
--- a/include/libcgroup.h
+++ b/include/libcgroup.h
@@ -24,6 +24,7 @@
 #include <libcgroup/groups.h>
 #include <libcgroup/tasks.h>
 #include <libcgroup/config.h>
+#include <libcgroup/log.h>
 
 #undef _LIBCGROUP_H_INSIDE
 
diff --git a/include/libcgroup/log.h b/include/libcgroup/log.h
new file mode 100644
index 0000000..d504ae3
--- /dev/null
+++ b/include/libcgroup/log.h
@@ -0,0 +1,138 @@
+#ifndef _LIBCGROUP_LOG_H
+#define _LIBCGROUP_LOG_H
+
+#ifndef _LIBCGROUP_H_INSIDE
+#error "Only <libcgroup.h> should be included directly."
+#endif
+
+#ifndef SWIG
+#include <features.h>
+#endif
+
+#include <stdarg.h>
+
+__BEGIN_DECLS
+
+/**
+ * @defgroup group_log 7. Logging
+ * @{
+ *
+ * @name Logging
+ * @{
+ * Libcgroup allows applications to register a callback function which
+ * libcgroup will call when it wants to log something. Each log message
+ * has associated a log level. As described in previous chapter, most libcgroup
+ * functions return an error code, which described root cause of the failure
+ * and log messages might provide further details about these failures and 
other
+ * notable events.
+ *
+ * @par
+ * The logging callback can be set at any time, but setting the callback before
+ * any other libcgroup function (including cgroup_init()) is highly 
recommended.
+ *
+ * @par Setting log level
+ * Some of the functions below set the log level as integer.
+ * Application can set directly a value of enum #cgroup_log_level or use
+ * value <tt>-1</tt> to set the log level automatically. In this case, 
libcgroup
+ * inspects environment variable <tt>CGROUP_LOGLEVEL</tt> if it is set
+ * and contains any of these values: <tt>ERROR</tt>, <tt>WARNING</tt>,
+ * <tt>INFO</tt>, <tt>DEBUG</tt> or integer number representing value from
+ * enum #cgroup_log_level. If <tt>CGROUP_LOGLEVEL</tt> is not set or its value
+ * is not valid, <tt>CGROUP_LOG_ERROR</tt> is set as default log level.
+ *
+ * @par Example:
+ * Following short example shows custom libcgroup logger sending all log
+ * messages to <tt>stderr</tt>:
+ * @code
+ * static void my_logger(void *userdata, int level, const char *fmt, va_list 
ap)
+ * {
+ *     vfprintf(stderr, fmt, ap);
+ * }
+ *
+ * int main(int argc, char **argv)
+ * {
+ *     int ret;
+ *
+ *     cgroup_set_logger(my_logger, -1, NULL);
+ *     ret = cgroup_init();
+ *     if (ret) {
+ *             ...
+ *     }
+ *     ...
+ * @endcode
+ */
+
+/**
+ * Level of importance of a log message.
+ */
+enum cgroup_log_level {
+       /**
+        * Something serious happened and libcgroup failed to perform requested
+        * operation.
+        */
+       CGROUP_LOG_ERROR = 1,
+       /**
+        * Something bad happened but libcgroup recovered from the error.
+        */
+       CGROUP_LOG_WARNING,
+       /**
+        * Something interesting happened and the message might be useful to the
+        * user.
+        */
+       CGROUP_LOG_INFO,
+       /**
+        * Debugging messages useful to libcgroup developers.
+        */
+       CGROUP_LOG_DEBUG,
+};
+
+typedef void (*cgroup_logger_callback)(void *userdata, int level,
+               const char *fmt, va_list ap);
+
+/**
+ * Set libcgroup logging callback. All log messages with equal or lower log
+ * level will be sent to the application's callback. There can be only
+ * one callback logger set, the previous callback is replaced with the new one
+ * by calling this function.
+ * Use NULL as the logger callback to completely disable libcgroup logging.
+ *
+ * @param logger The callback.
+ * @param loglevel The log level. Use value -1 to automatically discover the
+ * level from CGROUP_LOGLEVEL environment variable.
+ * @param userdata Application's data which will be provided back to the
+ * callback.
+ */
+extern void cgroup_set_logger(cgroup_logger_callback logger, int loglevel,
+               void *userdata);
+
+/**
+ * Set libcgroup logging to stdout. All messages with the given loglevel
+ * or below will be sent to standard output. Previous logger set by
+ * cgroup_set_logger() is replaced.
+ *
+ * @param loglevel The log level. Use value -1 to automatically discover the
+ * level from CGROUP_LOGLEVEL environment variable.
+ */
+extern void cgroup_set_default_logger(int loglevel);
+
+/**
+ * Change current loglevel.
+ * @param loglevel The log level. Use value -1 to automatically discover the
+ * level from CGROUP_LOGLEVEL environment variable.
+ */
+extern void cgroup_set_loglevel(int loglevel);
+
+/**
+ * Libcgroup log function. This is for applications which are too lazy to set
+ * up their own complex logging and miss-use libcgroup for that purpose.
+ * I.e. this function should be used only by simple command-line tools.
+ * This logging automatically benefits from CGROUP_LOGLEVEL env. variable.
+ */
+extern void cgroup_log(int loglevel, const char *fmt, ...);
+/**
+ * @}
+ * @}
+ */
+__END_DECLS
+
+#endif /* _LIBCGROUP_LOG_H */
diff --git a/src/Makefile.am b/src/Makefile.am
index 18a2ef0..3a92d59 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -11,7 +11,7 @@ CLEANFILES = lex.c parse.c parse.h
 
 INCLUDES = -I$(top_srcdir)/include
 lib_LTLIBRARIES = libcgroup.la
-libcgroup_la_SOURCES = parse.h parse.y lex.l api.c config.c 
libcgroup-internal.h libcgroup.map wrapper.c
+libcgroup_la_SOURCES = parse.h parse.y lex.l api.c config.c 
libcgroup-internal.h libcgroup.map wrapper.c log.c
 libcgroup_la_LIBADD = -lpthread
 libcgroup_la_LDFLAGS = -Wl,--version-script,$(srcdir)/libcgroup.map \
        -version-number 
$(LIBRARY_VERSION_MAJOR):$(LIBRARY_VERSION_MINOR):$(LIBRARY_VERSION_RELEASE)
diff --git a/src/libcgroup-internal.h b/src/libcgroup-internal.h
index dbb8e9a..47ee2ab 100644
--- a/src/libcgroup-internal.h
+++ b/src/libcgroup-internal.h
@@ -61,12 +61,18 @@ __BEGIN_DECLS
 #define CGROUP_RULE_MAXLINE    (FILENAME_MAX + CGROUP_RULE_MAXKEY + \
        CG_CONTROLLER_MAX + 3)
 
+#define cgroup_err(x...) cgroup_log(CGROUP_LOG_ERROR, x)
+#define cgroup_warn(x...) cgroup_log(CGROUP_LOG_WARNING, x)
+#define cgroup_info(x...) cgroup_log(CGROUP_LOG_INFO, x)
+
 #ifdef CGROUP_DEBUG
-#define cgroup_dbg(x...) printf(x)
+#define cgroup_dbg(x...) cgroup_log(CGROUP_LOG_DEBUG, x)
 #else
 #define cgroup_dbg(x...) do {} while (0)
 #endif
 
+#define CGROUP_DEFAULT_LOGLEVEL CGROUP_LOG_ERROR
+
 #define max(x,y) ((y)<(x)?(x):(y))
 #define min(x,y) ((y)>(x)?(x):(y))
 
diff --git a/src/libcgroup.map b/src/libcgroup.map
index 7dce2df..df651b5 100644
--- a/src/libcgroup.map
+++ b/src/libcgroup.map
@@ -111,4 +111,8 @@ CGROUP_0.39 {
        cgroup_init_templates_cache;
        cgroup_config_create_template_group;
        cgroup_change_all_cgroups;
+       cgroup_set_logger;
+       cgroup_set_default_logger;
+       cgroup_set_loglevel;
+       cgroup_log;
 } CGROUP_0.38;
diff --git a/src/log.c b/src/log.c
new file mode 100644
index 0000000..d0a6854
--- /dev/null
+++ b/src/log.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright Red Hat, Inc. 2012
+ *
+ * Author:     Jan Safranek <jsafr...@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2.1 of the GNU Lesser General Public License
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <libcgroup.h>
+#include <libcgroup-internal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+static cgroup_logger_callback cgroup_logger;
+static void *cgroup_logger_userdata;
+static int cgroup_loglevel;
+
+static void cgroup_default_logger(void *userdata, int level, const char *fmt,
+                                 va_list ap)
+{
+       vfprintf(stdout, fmt, ap);
+}
+
+void cgroup_log(int level, const char *fmt, ...)
+{
+       va_list ap;
+
+       if (!cgroup_logger)
+               return;
+
+       if (level > cgroup_loglevel)
+               return;
+
+       va_start(ap, fmt);
+       cgroup_logger(cgroup_logger_userdata, level, fmt, ap);
+       va_end(ap);
+}
+
+void cgroup_set_logger(cgroup_logger_callback logger, int loglevel,
+               void *userdata)
+{
+       cgroup_logger = logger;
+       cgroup_set_loglevel(loglevel);
+       cgroup_logger_userdata = userdata;
+}
+
+void cgroup_set_default_logger(int level)
+{
+       if (!cgroup_logger)
+               cgroup_set_logger(cgroup_default_logger, level, NULL);
+}
+
+void cgroup_set_loglevel(int loglevel)
+{
+       if (loglevel != -1)
+               cgroup_loglevel = loglevel;
+       else {
+               char *level_str = getenv("CGROUP_LOGLEVEL");
+               if (level_str != NULL)
+                       /*
+                        * TODO: add better loglevel detection, e.g. strings
+                        * instead of plain numbers.
+                        */
+                       cgroup_loglevel = atoi(level_str);
+               else
+                       cgroup_loglevel = CGROUP_DEFAULT_LOGLEVEL;
+       }
+}


------------------------------------------------------------------------------
Everyone hates slow websites. So do we.
Make your web apps faster with AppDynamics
Download AppDynamics Lite for free today:
http://p.sf.net/sfu/appdyn_d2d_feb
_______________________________________________
Libcg-devel mailing list
Libcg-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libcg-devel

Reply via email to