changeset 115:9a8f321371f7

Irccd: add filter system in logging, #491
author David Demelier <markand@malikania.fr>
date Thu, 28 Apr 2016 20:48:23 +0200
parents 8cbbce7b4327
children 1e43405991ee
files lib/irccd/logger.cpp lib/irccd/logger.hpp tests/CMakeLists.txt tests/logger/CMakeLists.txt tests/logger/main.cpp
diffstat 5 files changed, 236 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/lib/irccd/logger.cpp	Thu Apr 28 19:39:51 2016 +0200
+++ b/lib/irccd/logger.cpp	Thu Apr 28 20:48:23 2016 +0200
@@ -45,6 +45,7 @@
 
 std::atomic<bool> verbose{false};
 std::unique_ptr<Interface> iface{new Console};
+std::unique_ptr<Filter> filter{new Filter};
 
 /*
  * Buffer -- output buffer.
@@ -65,27 +66,27 @@
 private:
 	Level m_level;
 
-	void debug(const std::string &line)
+	void debug(std::string line)
 	{
 	/* Print only in debug mode, the buffer is flushed anyway */
 #if !defined(NDEBUG)
-		iface->debug(line);
+		iface->debug(filter->preDebug(std::move(line)));
 #else
 		(void)line;
 #endif
 	}
 
-	void info(const std::string &line)
+	void info(std::string line)
 	{
 		/* Print only if verbose, the buffer will be flushed anyway. */
 		if (verbose) {
-			iface->info(line);
+			iface->info(filter->preInfo(std::move(line)));
 		}
 	}
 
-	void warning(const std::string &line)
+	void warning(std::string line)
 	{
-		iface->warning(line);
+		iface->warning(filter->preWarning(std::move(line)));
 	}
 
 public:
@@ -108,13 +109,13 @@
 
 			switch (m_level) {
 			case Level::Debug:
-				debug(line);
+				debug(std::move(line));
 				break;
 			case Level::Info:
-				info(line);
+				info(std::move(line));
 				break;
 			case Level::Warning:
-				warning(line);
+				warning(std::move(line));
 				break;
 			default:
 				break;
@@ -257,6 +258,13 @@
 	iface = std::move(newiface);
 }
 
+void setFilter(std::unique_ptr<Filter> newfilter) noexcept
+{
+	assert(filter);
+
+	filter = std::move(newfilter);
+}
+
 std::ostream &info(const std::string &message)
 {
 	if (!message.empty()) {
--- a/lib/irccd/logger.hpp	Thu Apr 28 19:39:51 2016 +0200
+++ b/lib/irccd/logger.hpp	Thu Apr 28 20:48:23 2016 +0200
@@ -62,6 +62,16 @@
 	virtual ~Interface() = default;
 
 	/**
+	 * Write a debug message.
+	 *
+	 * This function is called only if NDEBUG is not defined.
+	 *
+	 * \param data the data
+	 * \see log::debug
+	 */
+	virtual void debug(const std::string &line) = 0;
+
+	/**
 	 * Write a information message.
 	 *
 	 * The function is called only if verbose is true.
@@ -80,16 +90,62 @@
 	 * \see log::warning
 	 */
 	virtual void warning(const std::string &line) = 0;
+};
+
+/*
+ * Filter -- modify messages before printing
+ * ------------------------------------------------------------------
+ */
+
+/**
+ * \brief Filter messages before printing them.
+ *
+ * Derive from this class and use log::setFilter.
+ */
+class Filter {
+public:
+	/**
+	 * Default constructor.
+	 */
+	Filter() = default;
+
+	/**
+	 * Virtual destructor defaulted.
+	 */
+	virtual ~Filter() = default;
 
 	/**
-	 * Write a debug message.
+	 * Update the debug message.
 	 *
-	 * This function is called only if NDEBUG is not defined.
+	 * \param input the message
+	 * \return the updated message
+	 */
+	virtual std::string preDebug(std::string input) const
+	{
+		return input;
+	}
+
+	/**
+	 * Update the information message.
 	 *
-	 * \param data the data
-	 * \see log::debug
+	 * \param input the message
+	 * \return the updated message
 	 */
-	virtual void debug(const std::string &line) = 0;
+	virtual std::string preInfo(std::string input) const
+	{
+		return input;
+	}
+
+	/**
+	 * Update the warning message.
+	 *
+	 * \param input the message
+	 * \return the updated message
+	 */
+	virtual std::string preWarning(std::string input) const
+	{
+		return input;
+	}
 };
 
 /*
@@ -103,6 +159,11 @@
 class Console : public Interface {
 public:
 	/**
+	 * \copydoc Interface::debug
+	 */
+	void debug(const std::string &line) override;
+
+	/**
 	 * \copydoc Interface::info
 	 */
 	void info(const std::string &line) override;
@@ -111,11 +172,6 @@
 	 * \copydoc Interface::warning
 	 */
 	void warning(const std::string &line) override;
-
-	/**
-	 * \copydoc Interface::debug
-	 */
-	void debug(const std::string &line) override;
 };
 
 /*
@@ -141,6 +197,11 @@
 	File(std::string normal, std::string errors);
 
 	/**
+	 * \copydoc Interface::debug
+	 */
+	void debug(const std::string &line) override;
+
+	/**
 	 * \copydoc Interface::info
 	 */
 	void info(const std::string &line) override;
@@ -149,11 +210,6 @@
 	 * \copydoc Interface::warning
 	 */
 	void warning(const std::string &line) override;
-
-	/**
-	 * \copydoc Interface::debug
-	 */
-	void debug(const std::string &line) override;
 };
 
 /*
@@ -169,6 +225,11 @@
 class Silent : public Interface {
 public:
 	/**
+	 * \copydoc Interface::debug
+	 */
+	void debug(const std::string &line) override;
+
+	/**
 	 * \copydoc Interface::info
 	 */
 	void info(const std::string &line) override;
@@ -177,11 +238,6 @@
 	 * \copydoc Interface::warning
 	 */
 	void warning(const std::string &line) override;
-
-	/**
-	 * \copydoc Interface::debug
-	 */
-	void debug(const std::string &line) override;
 };
 
 /*
@@ -207,6 +263,11 @@
 	~Syslog();
 
 	/**
+	 * \copydoc Interface::debug
+	 */
+	void debug(const std::string &line) override;
+
+	/**
 	 * \copydoc Interface::info
 	 */
 	void info(const std::string &line) override;
@@ -215,11 +276,6 @@
 	 * \copydoc Interface::warning
 	 */
 	void warning(const std::string &line) override;
-
-	/**
-	 * \copydoc Interface::debug
-	 */
-	void debug(const std::string &line) override;
 };
 
 #endif // !HAVE_SYSLOG
@@ -232,11 +288,20 @@
 /**
  * Update the logger interface.
  *
+ * \pre iface must not be null
  * \param iface the new interface
  */
 void setInterface(std::unique_ptr<Interface> iface) noexcept;
 
 /**
+ * Set an optional filter.
+ *
+ * \pre filter must not be null
+ * \param filter the filter
+ */
+void setFilter(std::unique_ptr<Filter> filter) noexcept;
+
+/**
  * Get the stream for informational messages.
  *
  * If message is specified, a new line character is appended.
--- a/tests/CMakeLists.txt	Thu Apr 28 19:39:51 2016 +0200
+++ b/tests/CMakeLists.txt	Thu Apr 28 20:48:23 2016 +0200
@@ -22,6 +22,7 @@
 if (WITH_TESTS)
 	# Misc
 	add_subdirectory(elapsedtimer)
+	add_subdirectory(logger)
 	add_subdirectory(path)
 	add_subdirectory(rules)
 	add_subdirectory(timer)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/logger/CMakeLists.txt	Thu Apr 28 20:48:23 2016 +0200
@@ -0,0 +1,23 @@
+#
+# CMakeLists.txt -- CMake build system for irccd
+#
+# Copyright (c) 2013-2016 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+irccd_define_test(
+	NAME logger
+	SOURCES main.cpp
+	LIBRARIES libirccd
+)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/logger/main.cpp	Thu Apr 28 20:48:23 2016 +0200
@@ -0,0 +1,105 @@
+/*
+ * main.cpp -- test logger functions
+ *
+ * Copyright (c) 2013-2016 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <algorithm>
+
+#include <gtest/gtest.h>
+
+#include <irccd/logger.hpp>
+
+using namespace irccd;
+
+namespace {
+
+std::string lineDebug;
+std::string lineInfo;
+std::string lineWarning;
+
+} // !namespace
+
+class MyInterface : public log::Interface {
+public:
+	void debug(const std::string &line) override
+	{
+		lineDebug = line;
+	}
+
+	void info(const std::string &line) override
+	{
+		lineInfo = line;
+	}
+
+	void warning(const std::string &line) override
+	{
+		lineWarning = line;
+	}
+};
+
+class MyFilter : public log::Filter {
+public:
+	std::string preDebug(std::string input) const override
+	{
+		return std::reverse(input.begin(), input.end()), input;
+	}
+
+	std::string preInfo(std::string input) const override
+	{
+		return std::reverse(input.begin(), input.end()), input;
+	}
+
+	std::string preWarning(std::string input) const override
+	{
+		return std::reverse(input.begin(), input.end()), input;
+	}
+};
+
+#if !defined(NDEBUG)
+
+TEST(Logger, debug)
+{
+	log::debug("debug");
+
+	ASSERT_EQ("gubed", lineDebug);
+}
+
+#endif
+
+TEST(Logger, info)
+{
+	log::info("info");
+
+	ASSERT_EQ("ofni", lineInfo);
+}
+
+TEST(Logger, warning)
+{
+	log::warning("warning");
+
+	ASSERT_EQ("gninraw", lineWarning);
+}
+
+int main(int argc, char **argv)
+{
+	log::setVerbose(true);
+	log::setInterface(std::make_unique<MyInterface>());
+	log::setFilter(std::make_unique<MyFilter>());
+
+	testing::InitGoogleTest(&argc, argv);
+
+	return RUN_ALL_TESTS();
+}