#include #include #include #include #include #include #include #include #include #include namespace mbgl { namespace { std::unique_ptr currentObserver; constexpr auto SeverityCount = underlying_type(EventSeverity::SeverityCount); std::atomic useThread[SeverityCount] = {true, true, true, false}; std::mutex mutex; } // namespace class Log::Impl { public: Impl() : scheduler(Scheduler::GetSequenced()) {} void record(EventSeverity severity, Event event, int64_t code, const std::string& msg) try { if (useThread[underlying_type(severity)]) { auto threadName = platform::getCurrentThreadName(); scheduler->schedule([=]() { Log::record(severity, event, code, msg, threadName); }); } else { Log::record(severity, event, code, msg, {}); } } catch (...) { // ignore exceptions during logging // What would we do, log them? #if !defined(NDEBUG) [[maybe_unused]] auto ex = std::current_exception(); assert(!"unhandled exception while logging"); #endif } private: const std::shared_ptr scheduler; }; Log::Log() : impl(std::make_unique()) {} Log::~Log() = default; Log* Log::get() noexcept { static Log instance; return &instance; } void Log::useLogThread(bool enable) noexcept { useLogThread(enable, EventSeverity::Debug); useLogThread(enable, EventSeverity::Info); useLogThread(enable, EventSeverity::Warning); useLogThread(enable, EventSeverity::Error); } void Log::useLogThread(bool enable, EventSeverity severity) noexcept { const auto index = underlying_type(severity); if (index < SeverityCount) { useThread[index] = enable; } } void Log::setObserver(std::unique_ptr observer) { std::lock_guard lock(mutex); currentObserver = std::move(observer); } std::unique_ptr Log::removeObserver() { std::lock_guard lock(mutex); std::unique_ptr observer; std::swap(observer, currentObserver); return observer; } void Log::record(EventSeverity severity, Event event, const std::string& msg) noexcept { get()->impl->record(severity, event, -1, msg); } void Log::record(EventSeverity severity, Event event, int64_t code, const std::string& msg) noexcept { get()->impl->record(severity, event, code, msg); } void Log::record(EventSeverity severity, Event event, int64_t code, const std::string& msg, const std::optional& threadName) { std::lock_guard lock(mutex); if (currentObserver && severity != EventSeverity::Debug && currentObserver->onRecord(severity, event, code, msg)) { return; } std::stringstream logStream; logStream << "{" << threadName.value_or(platform::getCurrentThreadName()) << "}"; logStream << "[" << Enum::toString(event) << "]"; if (code >= 0) { logStream << "(" << code << ")"; } if (!msg.empty()) { logStream << ": " << msg; } platformRecord(severity, logStream.str()); } } // namespace mbgl