]> git.ipfire.org Git - thirdparty/libcgroup.git/commitdiff
Reworked libcgroup logging
authorPeter Schiffer <pschiffe@redhat.com>
Tue, 2 Apr 2013 08:52:59 +0000 (10:52 +0200)
committerIvana Hutarova Varekova <varekova@redhat.com>
Tue, 2 Apr 2013 08:52:59 +0000 (10:52 +0200)
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 <pschiffe@redhat.com>
Acked-by: Ivana Hutarova Varekova <varekova@redhat.com>
include/Makefile.am
include/libcgroup.h
include/libcgroup/log.h [new file with mode: 0644]
src/Makefile.am
src/libcgroup-internal.h
src/libcgroup.map
src/log.c [new file with mode: 0644]

index a7602a9fbb1793a7a69a9cfa96db1ca2af219212..752a624ca1255a4aacd8c5230da101efd8153011 100644 (file)
@@ -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
index 543bd13a9f868f1294247ef34dfbecbf5eb82b72..1c7d409a7ab10972254f426c3f8e19cdf569a585 100644 (file)
@@ -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 (file)
index 0000000..d504ae3
--- /dev/null
@@ -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 */
index 18a2ef020afe4aeb4d9e98d57fb9e1356875aca4..3a92d5963c29877011eea6b5f692f578ad2cdaad 100644 (file)
@@ -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)
index dbb8e9a2496b16b190de1583e851a215fbf95698..47ee2abe3839b84957b1e8138bdd7e819f202491 100644 (file)
@@ -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))
 
index 7dce2dfcf28dbbbbb4803cefc8f4615986d2574d..df651b5600a1f5bcb2b451dfcb80a25013373213 100644 (file)
@@ -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 (file)
index 0000000..d0a6854
--- /dev/null
+++ b/src/log.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright Red Hat, Inc. 2012
+ *
+ * Author:     Jan Safranek <jsafrane@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;
+       }
+}