#pragma once #include #include #include #include #include namespace WallpaperEngine::Logging { /** * Singleton class, simplifies logging for the whole app */ class Log { public: Log (); void addOutput (std::ostream* stream); void addError (std::ostream* stream); template void out (Data... data) { std::string str = this->buildBuffer (data...); // then send it to all the outputs configured for (const auto cur : this->mOutputs) *cur << str << std::endl; } template void debug (Data... data) { #if (!NDEBUG) && (!ERRORONLY) std::string str = this->buildBuffer (data...); // then send it to all the outputs configured for (const auto cur : this->mOutputs) *cur << str << std::endl; #endif /* DEBUG */ } template void debugerror (Data... data) { #if (!NDEBUG) && (ERRORONLY) std::string str = this->buildBuffer (data...); // then send it to all the outputs configured for (const auto cur : this->mOutputs) *cur << str << std::endl; #endif /* DEBUG */ } template void error (Data... data) { std::string str = this->buildBuffer (data...); // then send it to all the outputs configured for (const auto cur : this->mErrors) *cur << str << std::endl; } template [[noreturn]] void exception (Data... data) { std::string str = this->buildBuffer (data...); // then send it to all the outputs configured for (const auto cur : this->mErrors) *cur << str << std::endl; // now throw the exception throw EX (str); } template [[noreturn]] void exception (Data... data) { this->exception (data...); } static Log& get (); private: template std::string buildBuffer (Data... data) { // buffer the string first std::stringbuf buffer; std::ostream bufferStream (&buffer); ((bufferStream << std::forward (data)), ...); return buffer.str (); } std::vector mOutputs = {}; std::vector mErrors = {}; static std::unique_ptr sInstance; }; } // namespace WallpaperEngine::Logging #define sLog (WallpaperEngine::Logging::Log::get ())