--- /dev/null
+#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 */
--- /dev/null
+/*
+ * 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;
+ }
+}