#pragma once #include #include // std::function #include // std::stringstream (buffer for log entries) #include #include #ifndef LOG_USEMUTEX #define LOG_USEMUTEX 0 #endif #ifndef LOG_ENABLEQT #define LOG_ENABLEQT 0 #endif #if LOG_ENABLEQT == 1 #include #include #endif #if LOG_ENABLEQT == 1 template QDebug operator<<(QDebug dbg, const T& str) { std::ostringstream stream; stream << str; QString conv = QString::fromStdString(stream.str()); QDebugStateSaver saver(dbg); dbg << conv; return dbg; } /* // string specialisation, not allowed, because multiple definitions of the same operator are not allowed template<> QDebug operator<<(QDebug dbg, const std::string& str) { QDebugStateSaver saver(dbg); QString conv = QString::fromStdString(str); dbg << conv; return dbg; } */ #endif namespace Log { enum class Level { off = 0, fatal, error, warn, note, info, debug, trace }; #if LOG_ENABLEQT == 1 void qtMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message); #endif // set up the logger with a ConsoleOutput void init(); // close all output streams void stop(); void addLogfile(const std::string& filename, Level max, bool truncate = false); void addLogfile(const std::string& filename, Level min, Level max, bool truncate = false); void setConsoleLogLevel(Level lvl); void setColoredOutput(bool enabled); // Log entry that can be formed with various mixed data types // by concatenation with the << operator // Inspired from https://stackoverflow.com/a/8337882 class Entry { private: std::stringstream ss; const Level lvl; #if LOG_ENABLEQT == 1 const QMessageLogContext* context = nullptr; Entry(Level lvl, const QMessageLogContext&); friend void qtMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message); #endif void addMetadataHeader(); public: explicit Entry(Level lvl); Entry(const Entry&) = delete; Entry& operator=(const Entry&) = delete; Entry(Entry&&) = default; Entry& operator=(Entry&&) = default; ~Entry(); Level getLevel() const { return lvl; } #if LOG_ENABLEQT == 1 constexpr const QMessageLogContext* getContext() const { return context; } #endif using MetaFunction = std::function; template Entry& operator<<(T&& msg) { ss << std::forward(msg); return *this; } }; // class to automatically stop the logger on destruction class Deleter { public: Deleter(); ~Deleter(); private: static std::atomic refCount; }; extern std::vector entryMetaFunctions; std::ostream& defaultEntryMetaTime(std::ostream&, const Entry&); std::ostream& defaultEntryMetaLevel(std::ostream&, const Entry&); // custom io-manip // FileSize is a iomanip to convert a filesize (fs) into a human readable format class FileSize { public: explicit FileSize(uint64_t fs) : fs(fs) {} FileSize(const FileSize&) = delete; FileSize& operator=(const FileSize&) = delete; operator std::string() const; private: uint64_t fs; friend std::ostream& operator<<(std::ostream& str, const FileSize& fs); }; struct PrintErrno {}; extern const PrintErrno err; std::ostream& operator<<(std::ostream& str, const PrintErrno&); std::ostream& operator<<(std::ostream& str, const FileSize& fs); // copy Level values in Log namespace constexpr Level off = Level::off; constexpr Level fatal = Level::fatal; constexpr Level error = Level::error; constexpr Level warn = Level::warn; constexpr Level note = Level::note; constexpr Level info = Level::info; constexpr Level debug = Level::debug; constexpr Level trace = Level::trace; // create Log lines (Entry objects) on using operator<< on Level values template Entry operator<<(const Level lvl, T&& msg) { Entry e{lvl}; e << std::forward(msg); return e; } } // namespace Log