diff --git a/Documentation/Examples/logger_example.cc b/Documentation/Examples/logger_example.cc index 5455f7d5ea6295d7ec5cfcf118942db5ec71800d..d8212e6612dc2f45eb73990571d5d4c4125562ce 100644 --- a/Documentation/Examples/logger_example.cc +++ b/Documentation/Examples/logger_example.cc @@ -2,6 +2,7 @@ #include <string> #include <iostream> +#include <fstream> #include <boost/format.hpp> @@ -13,10 +14,10 @@ main() { cout << "writing to \"another.log\"" << endl; ofstream logfile("another.log"); - typedef Sink<ofstream, StdBuffer> SinkFile; - SinkFile sink(logfile, StdBuffer(10000)); - logger<SinkFile, messageconst> info("\033[32m", "info", sink); - logger<SinkFile, messageconst> err("\033[31m", "error", sink); + logger::sink::SinkStream unbuffered_sink(logfile); + logger::sink::BufferedSinkStream sink(logfile, logger::sink::StdBuffer(10000)); + logger::Logger<logger::MessageOn, logger::sink::BufferedSinkStream> info("\033[32m", "info", sink); + logger::Logger<logger::MessageOn, logger::sink::BufferedSinkStream> err("\033[31m", "error", sink); //logger<ostream,messageconst,StdBuffer> info(std::cout, StdBuffer(10000)); /* @@ -26,14 +27,14 @@ main() */ for (int i=0; i<100000; ++i) { - LOG(info, "irgendwas"," ", string("and more")," ", boost::format("error: %i message: %s. done."), i, "stupido"); - LOG(err, "Fehler"); + LOG(info, "irgendwas"," ", string("and more")," ", boost::format("error: %i message: %s. done."), i, "stupido"); + LOG(err, "Fehler"); } } - + { - NoSink off; - logger<NoSink, MessageOff> info("", "", off); + logger::sink::NoSink off; + logger::Logger<logger::MessageOff> info("", "", off); for (int i=0; i<100000; ++i) { LOG(info, "irgendwas", string("and more"), boost::format("error: %i message: %s. done."), i, "stupido", "a-number:", 8.99, "ENDE" ); diff --git a/Framework/Logging/BufferedSink.h b/Framework/Logging/BufferedSink.h new file mode 100644 index 0000000000000000000000000000000000000000..9934744dc1d069e603ec4f72f4ea25652eb97e4c --- /dev/null +++ b/Framework/Logging/BufferedSink.h @@ -0,0 +1,65 @@ +#ifndef _include_BufferedSink_h_ +#define _include_BufferedSink_h_ + +namespace logger { + + namespace sink { + + + /** + Output buffer template. NoBuffer does nothingk. + */ + /* + struct NoBuffer { + inline bool Test(const std::string&) const { return false; } + inline std::string GetString() const { return std::string(""); } + inline void Clear() {} + inline void Add(const std::string&) {} + }; + */ + /** + Output buffer template. StdBuffer records fSize characters in + local memeory before passing it on to further output stages. + */ + + struct StdBuffer { + StdBuffer(const int size) : fSize(size) {} + inline bool Test(const std::string& s) { return int(fBuffer.tellp())+s.length() < fSize; } + inline std::string GetString() const { return fBuffer.str(); } + inline void Clear() { fBuffer.str(""); } + inline void Add(const std::string& s) { fBuffer << s; } + private: + int fSize; + std::ostringstream fBuffer; + }; + + + /** + Definition of Sink for log output. + */ + template<typename TStream, typename TBuffer=StdBuffer> + class BufferedSink { + public: + BufferedSink(TStream& out, TBuffer buffer = {} ) : fOutput(out), fBuffer(std::move(buffer)) {} + void operator<<(const std::string& msg) { + if (!fBuffer.Test(msg)) { + fOutput << fBuffer.GetString(); + fBuffer.Clear(); + } + if (!fBuffer.Test(msg)) + fOutput << msg; + else + fBuffer.Add(msg); + } + void Close() { fOutput << fBuffer.GetString(); } + private: + TStream& fOutput; + TBuffer fBuffer; + }; + + typedef BufferedSink<std::ostream, StdBuffer> BufferedSinkStream; + + }// end namespace +} // end namespace + +#endif diff --git a/Framework/Logging/CMakeLists.txt b/Framework/Logging/CMakeLists.txt index 51da77cf702a67e44ecfa5ba810a086b147951dd..7b684deb1cff09f2d77db017cf27a58c59d91d71 100644 --- a/Framework/Logging/CMakeLists.txt +++ b/Framework/Logging/CMakeLists.txt @@ -8,6 +8,6 @@ target_include_directories (CORSIKAlogging INTERFACE $<BUILD_INTERFACE:${PROJECT $<INSTALL_INTERFACE:include/Framework> ) -install (FILES Logger.h +install (FILES Logger.h Sink.h MessageOn.h MessageOff.h NoSink.h Sink.h BufferedSink.h DESTINATION include/Logging) diff --git a/Framework/Logging/Logger.h b/Framework/Logging/Logger.h index 73275ceb130a01c1ca148c2040cfcb2566e287f9..b98654d3f224711bf1d3315564f316c63544759e 100644 --- a/Framework/Logging/Logger.h +++ b/Framework/Logging/Logger.h @@ -1,142 +1,66 @@ #ifndef _include_logger_h_ #define _include_logger_h_ +#include <iosfwd> #include <string> #include <sstream> -#include <iostream> #include <typeinfo> -#include <fstream> #include <boost/format.hpp> - -using namespace std; -using namespace boost; - - -class MessageOff { - protected: - template<typename First, typename ... Strings> std::string message(const First& arg, const Strings&... rest) { - return ""; - } -}; - -class messageconst { - protected: - std::string message() { return "\n"; } - - template<typename First, typename ... Strings> std::string message(const First& arg, const Strings&... rest) { - std::ostringstream ss; - ss << arg << message(rest...); - return ss.str(); - } - - template<typename ... Strings> std::string message(const int& arg, const Strings&... rest) { - return std::to_string(arg) + message(rest...); - } - - template<typename ... Strings> std::string message(const double& arg, const Strings&... rest) { - return std::to_string(arg) + message(rest...); - } - - template<typename ... Strings> std::string message(char const * arg, const Strings&... rest) { - return std::string(arg) + message(rest...); - } - - template<typename ... Strings> std::string message(const std::string& arg, const Strings&... rest) { - return arg + message(rest...); - } - - // ---------------------- - // boost format - template<typename ... Strings> std::string message(const boost::format& fmt, const Strings&... rest) { - boost::format FMT(fmt); - return bformat(FMT, rest...); - } - - template<typename Arg, typename ... Strings> std::string bformat(boost::format& fmt, const Arg& arg, const Strings&... rest) { - fmt % arg; - return bformat(fmt, rest...); - } - - std::string bformat(boost::format& fmt) { return fmt.str() + "\n"; } -}; - - -struct NoBuffer { - inline bool Test(const std::string&) const { return false; } - inline std::string GetString() const { return std::string(""); } - inline void Clear() {} - inline void Add(const std::string&) {} -}; - -struct StdBuffer { - StdBuffer(const int size) : fSize(size) {} - inline bool Test(const std::string& s) { return int(fBuffer.tellp())+s.length() < fSize; } - inline std::string GetString() const { return fBuffer.str(); } - inline void Clear() { fBuffer.str(""); } - inline void Add(const std::string& s) { fBuffer << s; } -private: - int fSize; - std::ostringstream fBuffer; -}; - - -template<typename TStream, typename TBuffer=StdBuffer> -class Sink { - public: - Sink(TStream& out, TBuffer buffer = {} ) : fOutput(out), fBuffer(std::move(buffer)) {} - void operator<<(const std::string& msg) { - if (!fBuffer.Test(msg)) { - fOutput << fBuffer.GetString(); - fBuffer.Clear(); - } - if (!fBuffer.Test(msg)) - fOutput << msg; - else - fBuffer.Add(msg); - } - void Close() { fOutput << fBuffer.GetString(); } - private: - TStream& fOutput; - TBuffer fBuffer; -}; +#include <Logging/MessageOn.h> +#include <Logging/MessageOff.h> +#include <Logging/Sink.h> +#include <Logging/NoSink.h> +#include <Logging/BufferedSink.h> -struct NoSink { inline void operator<<(const std::string&) {} inline void Close() {} }; - +using namespace std; +using namespace boost; -template<typename TSink=NoSink,typename M=messageconst> -class logger : private M { - - using M::message; +/** + Everything around logfile generation and text output. +*/ - public: - // logger() : fName("") {} - logger(const std::string color, const std::string name, TSink& sink) : fSink(sink), fName(color+"["+name+"]\033[39m ") {} - ~logger() { fSink.Close(); } +namespace logger { - // logger(const logger&) = delete; - - template<typename ... Strings> - void log(const Strings&... inputs) { - fSink << M::message(inputs...); - } - - const std::string& GetName() const { return fName; } - - private: - TSink& fSink; - std::string fName; -}; - - - -#define LOG(__LOGGER,...) \ - __LOGGER.log(__LOGGER.GetName(), __FILE__,":", __LINE__, " (", __func__, ") -> ", ##__VA_ARGS__); - - - + /** + Defines one stream to accept messages, and to wrote those into + TSink. The helper class MessageOn will convert input at + compile-time into message strings. The helper class MessageOff, + will just do nothing and will be optimized away at compile time. + */ + template<typename MSG=MessageOn, typename TSink=sink::NoSink> + class Logger : private MSG { + + using MSG::Message; + + public: + // Logger() : fName("") {} + Logger(const std::string color, const std::string name, TSink& sink) : fSink(sink), fName(color+"["+name+"]\033[39m ") {} + ~Logger() { fSink.Close(); } + // Logger(const Logger&) = delete; + + /** + Function to add string-concatenation of all inputs to output + sink. + */ + template<typename ... Strings> + void Log(const Strings&... inputs) { + fSink << MSG::Message(inputs...); + } + + const std::string& GetName() const { return fName; } + + private: + TSink& fSink; + std::string fName; + }; + +} // end namesapce + +#define LOG(__LOGGER,...) \ + __LOGGER.Log(__LOGGER.GetName(), __FILE__,":", __LINE__, " (", __func__, ") -> ", ##__VA_ARGS__); #endif diff --git a/Framework/Logging/MessageOff.h b/Framework/Logging/MessageOff.h new file mode 100644 index 0000000000000000000000000000000000000000..ef62e2577eedae957767888156bbe04474e71c0b --- /dev/null +++ b/Framework/Logging/MessageOff.h @@ -0,0 +1,19 @@ +#ifndef _include_MessageOff_h_ +#define _include_MessageOff_h_ + +namespace logger { + + /** + Helper class to ignore all arguments to MessagesOn::Message and + always return empty string "". + */ + class MessageOff { + protected: + template<typename First, typename ... Strings> std::string Message(const First& arg, const Strings&... rest) { + return ""; + } + }; + +} // end namespace + +#endif diff --git a/Framework/Logging/MessageOn.h b/Framework/Logging/MessageOn.h new file mode 100644 index 0000000000000000000000000000000000000000..43b847448a5b92d3b3c48d5768db874663a9d8a1 --- /dev/null +++ b/Framework/Logging/MessageOn.h @@ -0,0 +1,54 @@ +#ifndef _include_MessageOn_h_ +#define _include_MessageOn_h_ + + +namespace logger { + + /** + Helper class to convert all input arguments of MessageOn::Message + into string-concatenated version and return this as string. + */ + class MessageOn { + protected: + std::string Message() { return "\n"; } + + template<typename First, typename ... Strings> std::string Message(const First& arg, const Strings&... rest) { + std::ostringstream ss; + ss << arg << Message(rest...); + return ss.str(); + } + + template<typename ... Strings> std::string Message(const int& arg, const Strings&... rest) { + return std::to_string(arg) + Message(rest...); + } + + template<typename ... Strings> std::string Message(const double& arg, const Strings&... rest) { + return std::to_string(arg) + Message(rest...); + } + + template<typename ... Strings> std::string Message(char const * arg, const Strings&... rest) { + return std::string(arg) + Message(rest...); + } + + template<typename ... Strings> std::string Message(const std::string& arg, const Strings&... rest) { + return arg + Message(rest...); + } + + // ---------------------- + // boost format + template<typename ... Strings> std::string Message(const boost::format& fmt, const Strings&... rest) { + boost::format FMT(fmt); + return bformat(FMT, rest...); + } + + template<typename Arg, typename ... Strings> std::string bformat(boost::format& fmt, const Arg& arg, const Strings&... rest) { + fmt % arg; + return bformat(fmt, rest...); + } + + std::string bformat(boost::format& fmt) { return fmt.str() + "\n"; } + }; + +}// end namesapce + +#endif diff --git a/Framework/Logging/NoSink.h b/Framework/Logging/NoSink.h new file mode 100644 index 0000000000000000000000000000000000000000..13e37f3b9a511182f792d81922e7dfba4c62d8ef --- /dev/null +++ b/Framework/Logging/NoSink.h @@ -0,0 +1,16 @@ +#ifndef _include_NoSink_h_ +#define _include_NoSink_h_ + +namespace logger { + + namespace sink { + + struct NoSink { + inline void operator<<(const std::string&) {} + inline void Close() {} + }; + + }// end namespace +} // end namespace + +#endif diff --git a/Framework/Logging/Sink.h b/Framework/Logging/Sink.h new file mode 100644 index 0000000000000000000000000000000000000000..6ee615176036f03c74a1deb50493bfdcd6cddd1b --- /dev/null +++ b/Framework/Logging/Sink.h @@ -0,0 +1,37 @@ +#ifndef _include_Sink_h_ +#define _include_Sink_h_ + +namespace logger { + + /** + a sink for the logger must implement the two functions + operator<<(const std::string&) + and + Close() + + See example: NoSink + */ + + namespace sink { + + /** + Definition of Sink for log output. + */ + template<typename TStream> + class Sink { + public: + Sink(TStream& out) : fOutput(out) {} + void operator<<(const std::string& msg) { + fOutput << msg; + } + void Close() {} + private: + TStream& fOutput; + }; + + typedef Sink<std::ostream> SinkStream; + + }// end namespace +} // end namespace + +#endif