Magic_Game/src/kiwano/utils/Logger.h

372 lines
9.1 KiB
C
Raw Normal View History

2019-04-11 14:40:54 +08:00
// Copyright (c) 2016-2018 Kiwano - Nomango
2020-01-21 10:09:55 +08:00
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
2020-01-21 10:09:55 +08:00
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
2020-01-21 10:09:55 +08:00
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#pragma once
#include <mutex>
2020-05-17 20:15:58 +08:00
#include <iomanip>
#include <streambuf>
#include <fstream>
2020-07-26 00:22:32 +08:00
#include <kiwano/core/Common.h>
#include <kiwano/core/Time.h>
#include <kiwano/base/ObjectBase.h>
2019-10-10 15:09:38 +08:00
#ifndef KGE_DEBUG_LOG
2020-01-21 10:09:55 +08:00
#ifdef KGE_DEBUG
#define KGE_DEBUG_LOG(...) ::kiwano::Logger::GetInstance().Log(::kiwano::LogLevel::Debug, __VA_ARGS__)
2020-01-21 10:09:55 +08:00
#else
#define KGE_DEBUG_LOG __noop
2020-01-21 10:09:55 +08:00
#endif
#endif
#ifndef KGE_LOG
#define KGE_LOG(...) ::kiwano::Logger::GetInstance().Log(::kiwano::LogLevel::Info, __VA_ARGS__)
#endif
#ifndef KGE_NOTICE
#define KGE_NOTICE(...) ::kiwano::Logger::GetInstance().Log(::kiwano::LogLevel::Notice, __VA_ARGS__)
#endif
2019-12-17 20:47:55 +08:00
#ifndef KGE_WARN
#define KGE_WARN(...) ::kiwano::Logger::GetInstance().Log(::kiwano::LogLevel::Warning, __VA_ARGS__)
#endif
2019-12-17 20:47:55 +08:00
#ifndef KGE_ERROR
#define KGE_ERROR(...) ::kiwano::Logger::GetInstance().Log(::kiwano::LogLevel::Error, __VA_ARGS__)
2019-08-14 21:52:49 +08:00
#endif
#ifndef KGE_DEBUG_LOGF
#ifdef KGE_DEBUG
#define KGE_DEBUG_LOGF(FORMAT, ...) ::kiwano::Logger::GetInstance().Logf(::kiwano::LogLevel::Debug, FORMAT, __VA_ARGS__)
#else
#define KGE_DEBUG_LOGF __noop
#endif
2019-08-14 21:52:49 +08:00
#endif
2019-12-25 18:07:57 +08:00
#ifndef KGE_LOGF
#define KGE_LOGF(FORMAT, ...) ::kiwano::Logger::GetInstance().Logf(::kiwano::LogLevel::Info, FORMAT, __VA_ARGS__)
#endif
#ifndef KGE_NOTICEF
#define KGE_NOTICEF(FORMAT, ...) ::kiwano::Logger::GetInstance().Logf(::kiwano::LogLevel::Notice, FORMAT, __VA_ARGS__)
#endif
#ifndef KGE_WARNF
#define KGE_WARNF(FORMAT, ...) ::kiwano::Logger::GetInstance().Logf(::kiwano::LogLevel::Warning, FORMAT, __VA_ARGS__)
2020-05-17 20:15:58 +08:00
#endif
#ifndef KGE_ERRORF
#define KGE_ERRORF(FORMAT, ...) ::kiwano::Logger::GetInstance().Logf(::kiwano::LogLevel::Error, FORMAT, __VA_ARGS__)
2020-05-17 20:15:58 +08:00
#endif
2020-07-26 00:22:32 +08:00
#ifndef KGE_THROW
#define KGE_THROW(MESSAGE) \
do \
{ \
KGE_ERRORF("An exception occurred: %s", MESSAGE); \
kiwano::StackTracer().Print(); \
throw kiwano::RuntimeError(MESSAGE); \
} while (0)
#endif
2020-10-04 04:39:22 +08:00
#ifndef KGE_THROW_IF
#define KGE_THROW_IF(EXPRESSION, MESSAGE) \
if (EXPRESSION) \
{ \
KGE_THROW(MESSAGE); \
}
#endif
2020-07-26 00:22:32 +08:00
#ifndef KGE_THROW_SYSTEM_ERROR
#define KGE_THROW_SYSTEM_ERROR(ERRCODE, MESSAGE) \
do \
{ \
KGE_ERRORF("An exception occurred (%#x): %s", ERRCODE, MESSAGE); \
kiwano::StackTracer().Print(); \
throw kiwano::SystemError(std::error_code(kiwano::error_enum(ERRCODE)), MESSAGE); \
} while (0)
#endif
#ifdef KGE_PLATFORM_WINDOWS
#ifndef KGE_THROW_IF_FAILED
#define KGE_THROW_IF_FAILED(HR, MESSAGE) \
if (FAILED(HR)) \
{ \
KGE_THROW_SYSTEM_ERROR(HR, MESSAGE); \
}
#endif
#endif // KGE_PLATFORM_WINDOWS
2019-04-11 14:40:54 +08:00
namespace kiwano
{
KGE_DECLARE_SMART_PTR(LogFormater);
KGE_DECLARE_SMART_PTR(LogProvider);
/**
* \~chinese
* @brief <EFBFBD><EFBFBD>־<EFBFBD>ȼ<EFBFBD>
*/
enum class LogLevel
{
Debug, ///< <20><><EFBFBD><EFBFBD>
Info, ///< <20><>Ϣ
Notice, ///< ע<><D7A2>
Warning, ///< <20><><EFBFBD><EFBFBD>
Error, ///< <20><><EFBFBD><EFBFBD>
};
/**
* \~chinese
* @brief <EFBFBD><EFBFBD>־<EFBFBD><EFBFBD>ʽ<EFBFBD><EFBFBD>
*/
class KGE_API LogFormater : public ObjectBase
{
public:
2020-07-30 16:05:45 +08:00
virtual void FormatHeader(std::ostream& out, LogLevel level, ClockTime time) = 0;
2020-07-20 00:26:00 +08:00
2020-07-30 16:05:45 +08:00
virtual void FormatFooter(std::ostream& out, LogLevel level) = 0;
String GetLevelLabel(LogLevel level) const;
};
/**
* \~chinese
* @brief <EFBFBD><EFBFBD>־<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
2020-07-25 15:57:14 +08:00
class KGE_API LogBuffer : public std::streambuf
{
public:
2020-07-17 16:02:52 +08:00
LogBuffer(size_t buffer_size);
void Resize(size_t size);
void Reset();
const char* GetRaw() const;
2020-07-17 16:02:52 +08:00
LogBuffer(const LogBuffer&) = delete;
LogBuffer& operator=(const LogBuffer&) = delete;
protected:
int_type overflow(int_type ch) override;
int_type underflow() override;
pos_type seekpos(pos_type sp, std::ios_base::openmode which) override;
pos_type seekoff(off_type off, std::ios_base::seekdir dir,
std::ios_base::openmode which = std::ios_base::in) override;
private:
2020-07-17 16:02:52 +08:00
Vector<char_type> buf_;
char_type* seek_high_;
};
2020-01-21 10:09:55 +08:00
/**
* \~chinese
2020-07-26 00:22:32 +08:00
* @brief <EFBFBD><EFBFBD>־<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
class KGE_API LogProvider : public ObjectBase
{
public:
virtual ~LogProvider();
virtual void Init();
virtual void Flush();
2020-07-20 10:50:55 +08:00
void Write(LogLevel level, const char* msg);
void SetLevel(LogLevel level);
protected:
LogProvider();
2020-07-20 10:50:55 +08:00
virtual void WriteMessage(LogLevel level, const char* msg) = 0;
protected:
LogLevel level_;
};
/**
* \~chinese
2020-07-26 00:22:32 +08:00
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>̨<EFBFBD><EFBFBD>־<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
class KGE_API ConsoleLogProvider : public LogProvider
{
public:
2020-07-22 21:08:48 +08:00
ConsoleLogProvider();
virtual ~ConsoleLogProvider();
void Init() override;
void Flush() override;
2020-07-17 16:02:52 +08:00
protected:
2020-07-20 10:50:55 +08:00
void WriteMessage(LogLevel level, const char* msg) override;
2020-07-17 16:02:52 +08:00
private:
typedef std::ostream&(*ConsoleColor)(std::ostream&);
ConsoleColor GetColor(LogLevel level);
};
/**
* \~chinese
2020-07-26 00:22:32 +08:00
* @brief <EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD>־<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*/
class KGE_API FileLogProvider : public LogProvider
{
public:
2020-07-22 21:08:48 +08:00
FileLogProvider(const String& filepath, std::ios_base::openmode mode = std::ios_base::out);
virtual ~FileLogProvider();
void Init() override;
void Flush() override;
protected:
2020-07-20 10:50:55 +08:00
void WriteMessage(LogLevel level, const char* msg) override;
private:
std::ofstream ofs_;
};
/**
* \~chinese
* @brief <EFBFBD><EFBFBD>־<EFBFBD><EFBFBD>¼<EFBFBD><EFBFBD>
2020-01-21 10:09:55 +08:00
*/
2020-07-23 17:21:44 +08:00
class KGE_API Logger final : public Singleton<Logger>
2020-01-21 10:09:55 +08:00
{
friend Singleton<Logger>;
public:
/// \~chinese
/// @brief <20><>ӡ<EFBFBD><D3A1>־
/// @param level <20><>־<EFBFBD><D6BE><EFBFBD><EFBFBD>
/// @param format <20><>ʽ<EFBFBD>ַ<EFBFBD><D6B7><EFBFBD>
void Logf(LogLevel level, const char* format, ...);
2020-01-21 10:09:55 +08:00
/// \~chinese
/// @brief <20><>ӡ<EFBFBD><D3A1>־
/// @param level <20><>־<EFBFBD><D6BE><EFBFBD><EFBFBD>
/// @param args <20><><EFBFBD><EFBFBD>
2020-01-21 10:09:55 +08:00
template <typename... _Args>
void Log(LogLevel level, _Args&&... args);
2020-01-21 10:09:55 +08:00
/// \~chinese
/// @brief ˢ<><CBA2><EFBFBD><EFBFBD>־<EFBFBD><D6BE><EFBFBD><EFBFBD>
void Flush();
2020-01-21 10:09:55 +08:00
/// \~chinese
/// @brief <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>־
2020-01-21 10:09:55 +08:00
void Enable();
/// \~chinese
/// @brief <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>־
2020-01-21 10:09:55 +08:00
void Disable();
/// \~chinese
/// @brief <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>־<EFBFBD>ȼ<EFBFBD>
void SetLevel(LogLevel level);
/// \~chinese
2020-07-26 00:22:32 +08:00
/// @brief <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>־<EFBFBD><D6BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/// @param provider <20><>־<EFBFBD><D6BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
void AddProvider(LogProviderPtr provider);
2020-01-21 10:09:55 +08:00
/// \~chinese
/// @brief <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>־<EFBFBD><D6BE>ʽ
/// @param formater <20><>־<EFBFBD><D6BE>ʽ<EFBFBD><CABD>
void SetFormater(LogFormaterPtr formater);
2020-01-21 10:09:55 +08:00
/// \~chinese
/// @brief <20><>ȡ<EFBFBD><C8A1>־<EFBFBD><D6BE>ʽ
/// @return <20><>־<EFBFBD><D6BE>ʽ
LogFormaterPtr GetFormater();
2020-01-21 10:09:55 +08:00
/// \~chinese
/// @brief <20><><EFBFBD><EFBFBD><E8BBBA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С
/// @param buffer_size <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С
void ResizeBuffer(size_t buffer_size);
2020-01-21 10:09:55 +08:00
/// \~chinese
/// @brief <20><>ʾ<EFBFBD><CABE><EFBFBD>رտ<D8B1><D5BF><EFBFBD>̨
void ShowConsole(bool show);
2020-01-21 10:09:55 +08:00
virtual ~Logger();
2020-06-08 20:20:06 +08:00
2020-01-21 10:09:55 +08:00
private:
Logger();
2020-07-20 00:26:00 +08:00
std::iostream& GetFormatedStream(LogLevel level, LogBuffer* buffer);
void WriteToProviders(LogLevel level, LogBuffer* buffer);
2020-01-21 10:09:55 +08:00
private:
bool enabled_;
LogLevel level_;
LogFormaterPtr formater_;
2020-07-17 16:02:52 +08:00
LogBuffer buffer_;
2020-07-20 00:26:00 +08:00
std::iostream stream_;
Vector<LogProviderPtr> providers_;
std::mutex mutex_;
2020-01-21 10:09:55 +08:00
};
inline void Logger::Enable()
{
enabled_ = true;
}
2020-01-21 10:09:55 +08:00
inline void Logger::Disable()
{
enabled_ = false;
}
inline void Logger::SetFormater(LogFormaterPtr formater)
2020-01-21 10:09:55 +08:00
{
formater_ = formater;
2020-01-21 10:09:55 +08:00
}
2020-01-21 10:09:55 +08:00
template <typename... _Args>
inline void Logger::Log(LogLevel level, _Args&&... args)
2020-01-21 10:09:55 +08:00
{
if (!enabled_)
return;
if (level < level_)
return;
2020-07-20 10:50:55 +08:00
std::lock_guard<std::mutex> lock(mutex_);
// build message
2020-07-20 00:26:00 +08:00
auto& stream = this->GetFormatedStream(level, &this->buffer_);
(void)std::initializer_list<int>{ ((stream << ' ' << args), 0)... };
// write message
2020-07-20 00:26:00 +08:00
this->WriteToProviders(level, &this->buffer_);
2020-01-21 10:09:55 +08:00
}
} // namespace kiwano