// Copyright (C) 2009-2021, Panagiotis Christopoulos Charitos and contributors. // All rights reserved. // Code licensed under the BSD License. // http://www.anki3d.org/LICENSE #pragma once #include #include #include namespace anki { // Forward class File; /// @addtogroup util_other /// @{ /// Logger message type. /// @memberof Logger enum class LoggerMessageType : U8 { NORMAL, VERBOSE, ERROR, WARNING, FATAL, COUNT }; /// Used as parammeter when emitting the signal. /// @memberof Logger class LoggerMessageInfo { public: const char* m_file; I32 m_line; const char* m_func; LoggerMessageType m_type; const char* m_msg; const char* m_subsystem; ThreadId m_tid; }; /// The message handler callback. /// @memberof Logger using LoggerMessageHandlerCallback = void (*)(void*, const LoggerMessageInfo& info); /// The logger singleton class. The logger cannot print errors or throw exceptions, it has to recover somehow. It's /// thread safe. /// To add a new signal: /// @code logger.addMessageHandler((void*)obj, &function) @endcode class Logger { public: /// Initialize the logger and add the default message handler Logger(); ~Logger(); /// Add a new message handler. void addMessageHandler(void* data, LoggerMessageHandlerCallback callback); /// Remove a message handler. void removeMessageHandler(void* data, LoggerMessageHandlerCallback callback); /// Add file message handler. void addFileMessageHandler(File* file); /// Send a message. void write(const char* file, int line, const char* func, const char* subsystem, LoggerMessageType type, ThreadId tid, const char* msg); /// Send a formated message. ANKI_CHECK_FORMAT(7, 8) void writeFormated(const char* file, int line, const char* func, const char* subsystem, LoggerMessageType type, ThreadId tid, const char* fmt, ...); /// Enable or disable logger verbosity. void enableVerbosity(Bool enable) { m_verbosityEnabled = enable; } private: class Handler { public: void* m_data = nullptr; LoggerMessageHandlerCallback m_callback = nullptr; Handler() = default; Handler(const Handler&) = default; Handler(void* data, LoggerMessageHandlerCallback callback) : m_data(data) , m_callback(callback) { } }; Mutex m_mutex; ///< For thread safety Array m_handlers; U32 m_handlersCount = 0; Bool m_verbosityEnabled = false; static void defaultSystemMessageHandler(void*, const LoggerMessageInfo& info); static void fileMessageHandler(void* file, const LoggerMessageInfo& info); }; using LoggerSingleton = Singleton; #define ANKI_LOG(subsystem_, t, ...) \ do \ { \ LoggerSingleton::get().writeFormated(ANKI_FILE, __LINE__, ANKI_FUNC, subsystem_, LoggerMessageType::t, \ Thread::getCurrentThreadId(), __VA_ARGS__); \ } while(false); /// @} /// @addtogroup util_logging /// @{ /// Log information message. #define ANKI_LOGI(...) ANKI_LOG(nullptr, NORMAL, __VA_ARGS__) /// Log verbose information message. #define ANKI_LOGV(...) ANKI_LOG(nullptr, VERBOSE, __VA_ARGS__) /// Log warning message. #define ANKI_LOGW(...) ANKI_LOG(nullptr, WARNING, __VA_ARGS__) /// Log error message. #define ANKI_LOGE(...) ANKI_LOG(nullptr, ERROR, __VA_ARGS__) /// Log fatal message. It will will abort. #define ANKI_LOGF(...) ANKI_LOG(nullptr, FATAL, __VA_ARGS__) /// @} } // end namespace anki