# HG changeset patch # User David Demelier # Date 1461869303 -7200 # Node ID 9a8f321371f72650aec4830974b33154cae6304b # Parent 8cbbce7b43272310b0295f63f98fd6145aab2902 Irccd: add filter system in logging, #491 diff -r 8cbbce7b4327 -r 9a8f321371f7 lib/irccd/logger.cpp --- 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 verbose{false}; std::unique_ptr iface{new Console}; +std::unique_ptr 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 newfilter) noexcept +{ + assert(filter); + + filter = std::move(newfilter); +} + std::ostream &info(const std::string &message) { if (!message.empty()) { diff -r 8cbbce7b4327 -r 9a8f321371f7 lib/irccd/logger.hpp --- 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 iface) noexcept; /** + * Set an optional filter. + * + * \pre filter must not be null + * \param filter the filter + */ +void setFilter(std::unique_ptr filter) noexcept; + +/** * Get the stream for informational messages. * * If message is specified, a new line character is appended. diff -r 8cbbce7b4327 -r 9a8f321371f7 tests/CMakeLists.txt --- 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) diff -r 8cbbce7b4327 -r 9a8f321371f7 tests/logger/CMakeLists.txt --- /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 +# +# 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 +) diff -r 8cbbce7b4327 -r 9a8f321371f7 tests/logger/main.cpp --- /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 + * + * 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 + +#include + +#include + +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()); + log::setFilter(std::make_unique()); + + testing::InitGoogleTest(&argc, argv); + + return RUN_ALL_TESTS(); +}