[deploy] Merge pull request #62 from KiwanoEngine/dev

Merge dev branch
This commit is contained in:
Haibo 2020-07-17 16:19:47 +08:00 committed by GitHub
commit d1c90ed4b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 907 additions and 403 deletions

View File

@ -37,7 +37,7 @@ AudioModule::~AudioModule() {}
void AudioModule::SetupModule()
{
KGE_SYS_LOG("Creating audio resources");
KGE_DEBUG_LOGF("Creating audio resources");
HRESULT hr = dlls::MediaFoundation::Get().MFStartup(MF_VERSION, MFSTARTUP_FULL);
@ -56,7 +56,7 @@ void AudioModule::SetupModule()
void AudioModule::DestroyModule()
{
KGE_SYS_LOG("Destroying audio resources");
KGE_DEBUG_LOGF("Destroying audio resources");
if (mastering_voice_)
{
@ -103,7 +103,7 @@ bool AudioModule::CreateSound(Sound& sound, const Transcoder::Buffer& buffer)
if (FAILED(hr))
{
KGE_ERROR("Create IXAudio2SourceVoice failed with HRESULT of %08X", hr);
KGE_ERRORF("Create IXAudio2SourceVoice failed with HRESULT of %08X", hr);
return false;
}
return true;

View File

@ -65,7 +65,7 @@ bool Sound::Load(const String& file_path)
{
if (!FileSystem::GetInstance().IsFileExists(file_path))
{
KGE_WARN("Media file '%s' not found", file_path.c_str());
KGE_WARNF("Media file '%s' not found", file_path.c_str());
return false;
}
@ -79,7 +79,7 @@ bool Sound::Load(const String& file_path)
HRESULT hr = transcoder_.LoadMediaFile(full_path);
if (FAILED(hr))
{
KGE_ERROR("Load media file failed with HRESULT of %08X", hr);
KGE_ERRORF("Load media file failed with HRESULT of %08X", hr);
return false;
}
@ -103,7 +103,7 @@ bool Sound::Load(const Resource& res)
HRESULT hr = transcoder_.LoadMediaResource(res);
if (FAILED(hr))
{
KGE_ERROR("Load media resource failed with HRESULT of %08X", hr);
KGE_ERRORF("Load media resource failed with HRESULT of %08X", hr);
return false;
}
@ -126,7 +126,7 @@ void Sound::Play(int loop_count)
{
if (!opened_)
{
KGE_ERROR("Sound must be opened first!");
KGE_ERRORF("Sound must be opened first!");
return;
}
@ -157,7 +157,7 @@ void Sound::Play(int loop_count)
if (FAILED(hr))
{
KGE_ERROR("Submitting source buffer failed with HRESULT of %08X", hr);
KGE_ERRORF("Submitting source buffer failed with HRESULT of %08X", hr);
}
playing_ = SUCCEEDED(hr);

View File

@ -105,7 +105,7 @@ HRESULT Transcoder::LoadMediaResource(const Resource& res)
if (stream == nullptr)
{
KGE_ERROR("SHCreateMemStream failed");
KGE_ERRORF("SHCreateMemStream failed");
return E_OUTOFMEMORY;
}
@ -198,7 +198,7 @@ HRESULT Transcoder::ReadSource(IMFSourceReader* reader)
if (data == nullptr)
{
KGE_ERROR("Low memory");
KGE_ERRORF("Low memory");
hr = E_OUTOFMEMORY;
}
else

View File

@ -298,7 +298,7 @@ void HttpModule::Perform(HttpRequestPtr request, HttpResponsePtr response)
ok = Curl::DeleteRequest(this, headers, url, &response_code, &response_data, &response_header, error_message);
break;
default:
KGE_ERROR("HttpModule: unknown request type, only GET, POST, PUT or DELETE is supported");
KGE_ERRORF("HttpModule: unknown request type, only GET, POST, PUT or DELETE is supported");
return;
}

View File

@ -535,7 +535,7 @@ void Actor::AddChild(ActorPtr child, int zorder)
{
if (parent == child)
{
KGE_ERROR("A actor cannot be its own parent");
KGE_ERRORF("A actor cannot be its own parent");
return;
}
}

View File

@ -263,12 +263,20 @@ public:
void SetPositionY(float y);
/// \~chinese
/// @brief 移动坐标
void Move(const Vec2& v);
/// @brief 移动坐标
void MoveTo(const Point& p);
/// \~chinese
/// @brief 移动坐标
void Move(float vx, float vy);
/// @brief 移动至坐标
void MoveTo(float x, float y);
/// \~chinese
/// @brief 移动相对坐标
void MoveBy(const Vec2& trans);
/// \~chinese
/// @brief 移动相对坐标
void MoveBy(float trans_x, float trans_y);
/// \~chinese
/// @brief 设置缩放比例,默认为 (1.0, 1.0)
@ -725,14 +733,24 @@ inline void Actor::SetPositionY(float y)
this->SetPosition(Point(transform_.position.x, y));
}
inline void Actor::Move(const Vec2& v)
inline void Actor::MoveTo(const Point& p)
{
this->SetPosition(transform_.position.x + v.x, transform_.position.y + v.y);
this->SetPosition(p);
}
inline void Actor::Move(float vx, float vy)
inline void Actor::MoveTo(float x, float y)
{
this->Move(Vec2(vx, vy));
this->SetPosition(Point(x, y));
}
inline void Actor::MoveBy(const Vec2& trans)
{
this->SetPosition(transform_.position.x + trans.x, transform_.position.y + trans.y);
}
inline void Actor::MoveBy(float trans_x, float trans_y)
{
this->MoveBy(Vec2(trans_x, trans_y));
}
inline void Actor::SetScale(float scalex, float scaley)

View File

@ -43,12 +43,12 @@ Stage::~Stage() {}
void Stage::OnEnter()
{
KGE_SYS_LOG("Stage entered");
KGE_DEBUG_LOGF("Stage entered");
}
void Stage::OnExit()
{
KGE_SYS_LOG("Stage exited");
KGE_DEBUG_LOGF("Stage exited");
}
void Stage::RenderBorder(RenderContext& ctx)

View File

@ -25,24 +25,24 @@
namespace kiwano
{
ActionGroupPtr ActionGroup::Create(const Vector<ActionPtr>& actions, bool sync)
ActionGroupPtr ActionGroup::Create(const Vector<ActionPtr>& actions, bool parallel)
{
ActionGroupPtr ptr = memory::New<ActionGroup>();
if (ptr)
{
ptr->sync_ = sync;
ptr->parallel_ = parallel;
ptr->AddActions(actions);
}
return ptr;
}
ActionGroup::ActionGroup()
: sync_(false)
: parallel_(false)
{
}
ActionGroup::ActionGroup(bool sync)
: sync_(sync)
ActionGroup::ActionGroup(bool parallel)
: parallel_(parallel)
{
}
@ -56,7 +56,7 @@ void ActionGroup::Init(Actor* target)
return;
}
if (sync_)
if (parallel_)
{
// init all actions
for (current_ = actions_.GetFirst(); current_; current_ = current_->GetNext())
@ -73,7 +73,7 @@ void ActionGroup::Init(Actor* target)
void ActionGroup::Update(Actor* target, Duration dt)
{
if (!sync_)
if (!parallel_)
{
if (current_)
{
@ -133,7 +133,7 @@ ActionPtr ActionGroup::Clone() const
actions.push_back(action->Clone());
}
}
return DoClone(ActionGroup::Create(actions, sync_));
return DoClone(ActionGroup::Create(actions, parallel_));
}
ActionPtr ActionGroup::Reverse() const
@ -146,7 +146,7 @@ ActionPtr ActionGroup::Reverse() const
actions.push_back(action->Reverse());
}
}
return DoClone(ActionGroup::Create(actions, sync_));
return DoClone(ActionGroup::Create(actions, parallel_));
}
} // namespace kiwano

View File

@ -40,12 +40,12 @@ public:
/// \~chinese
/// @brief 创建动画组合
/// @param actions 动画集合
/// @param sync 同步执行
static ActionGroupPtr Create(const Vector<ActionPtr>& actions, bool sync = false);
/// @param parallel 同步执行
static ActionGroupPtr Create(const Vector<ActionPtr>& actions, bool parallel = false);
ActionGroup();
ActionGroup(bool sync);
ActionGroup(bool parallel);
virtual ~ActionGroup();
@ -77,7 +77,7 @@ protected:
void Update(Actor* target, Duration dt) override;
private:
bool sync_;
bool parallel_;
ActionPtr current_;
ActionList actions_;
};

View File

@ -359,10 +359,10 @@ public:
/// \~chinese
/// @brief 动画组合
/// @param actions 动画集合
/// @param sync 同步执行
static inline ActionHelper Group(const Vector<ActionPtr>& actions, bool sync = false)
/// @param parallel 同步执行
static inline ActionHelper Group(const Vector<ActionPtr>& actions, bool parallel = false)
{
return ActionHelper(ActionGroup::Create(actions, sync));
return ActionHelper(ActionGroup::Create(actions, parallel));
}
};

View File

@ -195,7 +195,7 @@ public:
/// @brief 获取该动画的倒转
virtual ActionPtr Reverse() const override
{
KGE_ERROR("Reverse() not supported in ActionMoveTo");
KGE_ERRORF("Reverse() not supported in ActionMoveTo");
return nullptr;
}
@ -299,7 +299,7 @@ public:
/// @brief 获取该动画的倒转
virtual ActionPtr Reverse() const override
{
KGE_ERROR("Reverse() not supported in ActionJumpTo");
KGE_ERRORF("Reverse() not supported in ActionJumpTo");
return nullptr;
}
@ -398,7 +398,7 @@ public:
/// @brief 获取该动画的倒转
virtual ActionPtr Reverse() const override
{
KGE_ERROR("Reverse() not supported in ActionScaleTo");
KGE_ERRORF("Reverse() not supported in ActionScaleTo");
return nullptr;
}
@ -439,7 +439,7 @@ public:
/// @brief 获取该动画的倒转
virtual ActionPtr Reverse() const override
{
KGE_ERROR("Reverse() not supported in ActionFadeTo");
KGE_ERRORF("Reverse() not supported in ActionFadeTo");
return nullptr;
}
@ -544,7 +544,7 @@ public:
/// @brief 获取该动画的倒转
virtual ActionPtr Reverse() const override
{
KGE_ERROR("Reverse() not supported in ActionRotateTo");
KGE_ERRORF("Reverse() not supported in ActionRotateTo");
return nullptr;
}
@ -589,7 +589,7 @@ public:
/// @brief 获取该动画的倒转
ActionPtr Reverse() const override
{
KGE_ERROR("Reverse() not supported in ActionCustom");
KGE_ERRORF("Reverse() not supported in ActionCustom");
return nullptr;
}

View File

@ -122,13 +122,13 @@ void ObjectBase::StopTracingLeaks()
void ObjectBase::DumpTracingObjects()
{
KGE_SYS_LOG("-------------------------- All Objects --------------------------");
KGE_DEBUG_LOGF("-------------------------- All Objects --------------------------");
for (const auto object : tracing_objects)
{
KGE_SYS_LOG("{ class=\"%s\" id=%d refcount=%d name=\"%s\" }", typeid(*object).name(), object->GetObjectID(),
KGE_DEBUG_LOGF("{ class=\"%s\" id=%d refcount=%d name=\"%s\" }", typeid(*object).name(), object->GetObjectID(),
object->GetRefCount(), object->GetName().c_str());
}
KGE_SYS_LOG("------------------------- Total size: %d -------------------------", tracing_objects.size());
KGE_DEBUG_LOGF("------------------------- Total size: %d -------------------------", tracing_objects.size());
}
Vector<ObjectBase*>& ObjectBase::GetTracingObjects()

View File

@ -9,9 +9,9 @@
//#define KGE_ASSERT(EXPR) __noop // Disable asserts
//---- Define debug-output handler. Defaults to calling kiwano::logs::Messageln()/Warningln()/Errorln()
//#define KGE_SYS_LOG(FORMAT, ...) wprintf(FORMAT "\n", __VA_ARGS__)
//#define KGE_WARN(FORMAT, ...) wprintf(FORMAT "\n", __VA_ARGS__)
//#define KGE_ERROR(FORMAT, ...) wprintf(FORMAT "\n", __VA_ARGS__)
//#define KGE_LOGF(FORMAT, ...) printf(FORMAT "\n", __VA_ARGS__)
//#define KGE_WARNF(FORMAT, ...) printf(FORMAT "\n", __VA_ARGS__)
//#define KGE_ERRORF(FORMAT, ...) printf(FORMAT "\n", __VA_ARGS__)
//---- Define attributes of all API symbols declarations for DLL
//#define KGE_USE_DLL

View File

@ -181,7 +181,7 @@ DbgHelp g_DbgHelp;
void PrintErrorCode(LPCSTR lpszFunction)
{
KGE_ERROR("%s failed with HRESULT of %08X", lpszFunction, HRESULT_FROM_WIN32(GetLastError()));
KGE_ERRORF("%s failed with HRESULT of %08X", lpszFunction, HRESULT_FROM_WIN32(GetLastError()));
}
void PrintCallStackOnContext(PCONTEXT pContext)
@ -227,7 +227,7 @@ void PrintCallStackOnContext(PCONTEXT pContext)
constexpr int STACKWALK_MAX_NAMELEN = 1024;
BYTE symbolBuffer[sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN];
KGE_ERROR("========== Stack trace ==========");
KGE_ERRORF("========== Stack trace ==========");
while (true)
{
@ -263,11 +263,11 @@ void PrintCallStackOnContext(PCONTEXT pContext)
DWORD dwLineDisplacement;
if (g_DbgHelp.SymGetLineFromAddr64(hProcess, sf.AddrPC.Offset, &dwLineDisplacement, &lineInfo))
{
KGE_ERROR("%s (%d): %s", lineInfo.FileName, lineInfo.LineNumber, pSymbol->Name);
KGE_ERRORF("%s (%d): %s", lineInfo.FileName, lineInfo.LineNumber, pSymbol->Name);
}
else
{
KGE_ERROR("(filename not available): %s", pSymbol->Name);
KGE_ERRORF("(filename not available): %s", pSymbol->Name);
}
if (sf.AddrReturn.Offset == 0)

View File

@ -27,7 +27,7 @@
#define KGE_THROW(MESSAGE) \
do \
{ \
KGE_ERROR("An exception occurred: %s", MESSAGE); \
KGE_ERRORF("An exception occurred: %s", MESSAGE); \
kiwano::StackTracer().Print(); \
throw kiwano::RuntimeError(MESSAGE); \
} while (0)
@ -35,7 +35,7 @@
#define KGE_THROW_SYSTEM_ERROR(ERRCODE, MESSAGE) \
do \
{ \
KGE_ERROR("An exception occurred (%#x): %s", ERRCODE, MESSAGE); \
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)

View File

@ -48,28 +48,28 @@ Resource::Data Resource::GetData() const
HRSRC res_info = FindResourceA(nullptr, MAKEINTRESOURCEA(id_), type_.data());
if (res_info == nullptr)
{
KGE_ERROR("FindResource failed");
KGE_ERRORF("FindResource failed");
break;
}
HGLOBAL res_data = LoadResource(nullptr, res_info);
if (res_data == nullptr)
{
KGE_ERROR("LoadResource failed");
KGE_ERRORF("LoadResource failed");
break;
}
DWORD size = SizeofResource(nullptr, res_info);
if (size == 0)
{
KGE_ERROR("SizeofResource failed");
KGE_ERRORF("SizeofResource failed");
break;
}
LPVOID buffer = LockResource(res_data);
if (buffer == nullptr)
{
KGE_ERROR("LockResource failed");
KGE_ERRORF("LockResource failed");
break;
}

View File

@ -31,38 +31,52 @@ namespace strings
String Format(const char* format, ...)
{
String result;
if (format)
va_list args = nullptr;
va_start(args, format);
String result = FormatArgs(format, args);
va_end(args);
return result;
}
WideString Format(const wchar_t* format, ...)
{
va_list args = nullptr;
va_start(args, format);
WideString result = FormatArgs(format, args);
va_end(args);
return result;
}
String FormatArgs(const char* format, va_list args)
{
String result;
if (format)
{
const auto len = static_cast<size_t>(::_vscprintf(format, args) + 1);
if (len)
{
result.resize(len - 1);
::_vsnprintf_s(&result[0], len, len, format, args);
}
va_end(args);
}
return result;
}
WideString Format(const wchar_t* format, ...)
WideString FormatArgs(const wchar_t* format, va_list args)
{
WideString result;
if (format)
{
va_list args = nullptr;
va_start(args, format);
const auto len = static_cast<size_t>(::_vscwprintf(format, args) + 1);
if (len)
{
result.resize(len - 1);
::_vsnwprintf_s(&result[0], len, len, format, args);
}
va_end(args);
}
return result;
}

View File

@ -50,6 +50,14 @@ String Format(const char* format, ...);
/// @brief ¸ñʽ»¯×Ö·û´®
WideString Format(const wchar_t* format, ...);
/// \~chinese
/// @brief ¸ñʽ»¯×Ö·û´®
String FormatArgs(const char* format, va_list args);
/// \~chinese
/// @brief ¸ñʽ»¯×Ö·û´®
WideString FormatArgs(const wchar_t* format, va_list args);
/// \~chinese
/// @brief ¿í×Ö·û´®×ªÕ­×Ö·û´®
String WideToNarrow(const WideString& str);

View File

@ -606,7 +606,7 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA
{
if (SIZE_MAXHIDE == wparam || SIZE_MINIMIZED == wparam)
{
KGE_SYS_LOG("Window minimized");
KGE_DEBUG_LOGF("Window minimized");
is_minimized_ = true;
// Pause game when window is minimized
@ -614,7 +614,7 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA
}
else if (SIZE_MAXIMIZED == wparam)
{
KGE_SYS_LOG("Window maximized");
KGE_DEBUG_LOGF("Window maximized");
if (is_minimized_)
{
@ -626,7 +626,7 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA
{
if (is_minimized_)
{
KGE_SYS_LOG("Window restored");
KGE_DEBUG_LOGF("Window restored");
// the window was restored and was previously minimized
is_minimized_ = false;
@ -646,7 +646,7 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA
evt->height = this->GetHeight();
this->PushEvent(evt);
KGE_SYS_LOG("Window resized to (%d, %d)", this->width_, this->height_);
KGE_DEBUG_LOGF("Window resized to (%d, %d)", this->width_, this->height_);
}
}
}
@ -672,7 +672,7 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA
uint32_t client_height = uint32_t(client_rect.bottom - client_rect.top);
if (client_width != this->GetWidth() || client_height != this->GetHeight())
{
KGE_SYS_LOG("Window resized to (%d, %d)", client_width, client_height);
KGE_DEBUG_LOGF("Window resized to (%d, %d)", client_width, client_height);
this->width_ = client_width;
this->height_ = client_height;
@ -744,7 +744,7 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA
case WM_SETTEXT:
{
KGE_SYS_LOG("Window title changed");
KGE_DEBUG_LOGF("Window title changed");
this->title_ = strings::WideToNarrow(reinterpret_cast<LPCWSTR>(lparam));
@ -756,13 +756,13 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA
case WM_SETICON:
{
KGE_SYS_LOG("Window icon changed");
KGE_DEBUG_LOGF("Window icon changed");
}
break;
case WM_DISPLAYCHANGE:
{
KGE_SYS_LOG("The display resolution has changed");
KGE_DEBUG_LOGF("The display resolution has changed");
}
break;
@ -774,7 +774,7 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA
case WM_CLOSE:
{
KGE_SYS_LOG("Window is closing");
KGE_DEBUG_LOGF("Window is closing");
WindowClosedEventPtr evt = new WindowClosedEvent;
this->PushEvent(evt);
@ -785,7 +785,7 @@ LRESULT WindowWin32Impl::MessageProc(HWND hwnd, UINT32 msg, WPARAM wparam, LPARA
case WM_DESTROY:
{
KGE_SYS_LOG("Window was destroyed");
KGE_DEBUG_LOGF("Window was destroyed");
::PostQuitMessage(0);
return 0;

View File

@ -155,7 +155,7 @@ void RenderContextImpl::DrawTextLayout(const TextLayout& layout, const Point& of
}
else
{
KGE_ERROR("Failed to draw text layout with HRESULT of %08X", hr);
KGE_ERRORF("Failed to draw text layout with HRESULT of %08X", hr);
}
}
}

View File

@ -51,7 +51,7 @@ RendererImpl::RendererImpl()
void RendererImpl::MakeContextForWindow(WindowPtr window)
{
KGE_SYS_LOG("Creating device resources");
KGE_DEBUG_LOGF("Creating device resources");
KGE_THROW_IF_FAILED(::CoInitialize(nullptr), "CoInitialize failed");
@ -143,7 +143,7 @@ void RendererImpl::MakeContextForWindow(WindowPtr window)
void RendererImpl::Destroy()
{
KGE_SYS_LOG("Destroying device resources");
KGE_DEBUG_LOGF("Destroying device resources");
if (d2d_res_)
{
@ -194,7 +194,7 @@ void RendererImpl::CreateTexture(Texture& texture, const String& file_path)
if (!FileSystem::GetInstance().IsFileExists(file_path))
{
KGE_WARN("Texture file '%s' not found!", file_path.c_str());
KGE_WARNF("Texture file '%s' not found!", file_path.c_str());
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
}
@ -291,7 +291,7 @@ void RendererImpl::CreateTexture(Texture& texture, const Resource& resource)
if (FAILED(hr))
{
KGE_WARN("Load texture failed with HRESULT of %08X!", hr);
KGE_WARNF("Load texture failed with HRESULT of %08X!", hr);
}
}
@ -305,7 +305,7 @@ void RendererImpl::CreateGifImage(GifImage& gif, const String& file_path)
if (!FileSystem::GetInstance().IsFileExists(file_path))
{
KGE_WARN("Gif texture file '%s' not found!", file_path.c_str());
KGE_WARNF("Gif texture file '%s' not found!", file_path.c_str());
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
}
@ -324,7 +324,7 @@ void RendererImpl::CreateGifImage(GifImage& gif, const String& file_path)
if (FAILED(hr))
{
KGE_WARN("Load GIF texture failed with HRESULT of %08X!", hr);
KGE_WARNF("Load GIF texture failed with HRESULT of %08X!", hr);
}
}
@ -356,7 +356,7 @@ void RendererImpl::CreateGifImage(GifImage& gif, const Resource& resource)
if (FAILED(hr))
{
KGE_WARN("Load GIF texture failed with HRESULT of %08X!", hr);
KGE_WARNF("Load GIF texture failed with HRESULT of %08X!", hr);
}
}
@ -520,7 +520,7 @@ void RendererImpl::CreateGifImageFrame(GifImage::Frame& frame, const GifImage& g
if (FAILED(hr))
{
KGE_WARN("Load GIF frame failed with HRESULT of %08X!", hr);
KGE_WARNF("Load GIF frame failed with HRESULT of %08X!", hr);
}
}
@ -536,7 +536,7 @@ void RendererImpl::CreateFontCollection(Font& font, const String& file_path)
{
if (!FileSystem::GetInstance().IsFileExists(file_path))
{
KGE_WARN("Font file '%s' not found!", file_path.c_str());
KGE_WARNF("Font file '%s' not found!", file_path.c_str());
hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
}
}

View File

@ -19,10 +19,563 @@
// THE SOFTWARE.
#include <ctime>
#include <ios>
#include <fstream>
#include <iostream>
#include <kiwano/utils/Logger.h>
namespace kiwano
{
//
// LogFormater
//
String LogFormater::GetLevelLabel(LogLevel level) const
{
switch (level)
{
case kiwano::LogLevel::Debug:
return "[Debug]";
case kiwano::LogLevel::Info:
return "[Info]";
case kiwano::LogLevel::Notice:
return "[Notice]";
case kiwano::LogLevel::Warning:
return "[Warning]";
case kiwano::LogLevel::Error:
return "[Error]";
default:
break;
}
return String();
}
class TextFormater : public LogFormater
{
public:
void Format(std::iostream& out, LogLevel level, Time time, std::streambuf* raw_msg) override
{
// get timestamp
time_t unix = std::time(nullptr);
std::tm tmbuf;
localtime_s(&tmbuf, &unix);
// build message
out << GetLevelLabel(level) << std::put_time(&tmbuf, " %H:%M:%S ");
if (raw_msg->sgetc() != std::char_traits<char>::eof())
out << raw_msg;
out << "\n";
}
};
//
// LogProvider
//
LogProvider::~LogProvider() {}
#if defined(KGE_PLATFORM_WINDOWS)
void SetWindowConsoleColor(std::ostream& os, int foreground, int background)
{
static WORD defaultAttributes = 0;
// get terminal handle
HANDLE hTerminal = INVALID_HANDLE_VALUE;
if (&os == &std::cout)
hTerminal = GetStdHandle(STD_OUTPUT_HANDLE);
else if (&os == &std::cerr)
hTerminal = GetStdHandle(STD_ERROR_HANDLE);
if (hTerminal == INVALID_HANDLE_VALUE)
return;
// save default terminal attributes if it unsaved
if (!defaultAttributes)
{
CONSOLE_SCREEN_BUFFER_INFO info;
if (!GetConsoleScreenBufferInfo(hTerminal, &info))
return;
defaultAttributes = info.wAttributes;
}
// restore all default settings
if (foreground == -1 && background == -1)
{
SetConsoleTextAttribute(hTerminal, defaultAttributes);
return;
}
// get current settings
CONSOLE_SCREEN_BUFFER_INFO info;
if (!GetConsoleScreenBufferInfo(hTerminal, &info))
return;
if (foreground != -1)
{
info.wAttributes &= ~(info.wAttributes & 0x0F);
info.wAttributes |= static_cast<WORD>(foreground);
}
if (background != -1)
{
info.wAttributes &= ~(info.wAttributes & 0xF0);
info.wAttributes |= static_cast<WORD>(background);
}
SetConsoleTextAttribute(hTerminal, info.wAttributes);
}
#endif
template <int color>
std::ostream& ConsoleColorBrush(std::ostream& os)
{
#if defined(KGE_PLATFORM_WINDOWS)
if (color > 0)
{
switch (color)
{
case 31: // red
SetWindowConsoleColor(os, FOREGROUND_RED | FOREGROUND_INTENSITY, -1);
break;
case 32: // green
SetWindowConsoleColor(os, FOREGROUND_GREEN | FOREGROUND_INTENSITY, -1);
break;
case 33: // yellow
SetWindowConsoleColor(os, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY, -1);
break;
case 34: // blue
SetWindowConsoleColor(os, FOREGROUND_BLUE | FOREGROUND_INTENSITY, -1);
break;
case 36: // cyan
SetWindowConsoleColor(os, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY, -1);
break;
default:
break;
}
}
else if (color < 0)
{
SetWindowConsoleColor(os, -1, -1);
}
#else
if (color > 0)
{
os << "\033[1;" << color << "m";
}
else if (color < 0)
{
os << "\033[0m";
}
#endif
return os;
}
LogProviderPtr ConsoleLogProvider::Create()
{
LogProviderPtr ptr = new ConsoleLogProvider;
return ptr;
}
ConsoleLogProvider::~ConsoleLogProvider()
{
Flush();
}
void ConsoleLogProvider::Init()
{
}
void ConsoleLogProvider::WriteMessage(LogLevel level, LogBuffer* msg)
{
if (level != LogLevel::Error)
std::cout << GetColor(level) << msg << std::flush << ConsoleColorBrush<-1>;
else
std::cerr << GetColor(level) << msg << ConsoleColorBrush<-1>;
#if defined(KGE_PLATFORM_WINDOWS)
::OutputDebugStringA(msg->GetRaw());
#endif
}
void ConsoleLogProvider::Flush()
{
std::cout.flush();
std::cout.clear();
}
ConsoleLogProvider::ConsoleColor ConsoleLogProvider::GetColor(LogLevel level)
{
std::initializer_list<ConsoleColor> colors = {
ConsoleColorBrush<34>, // Debug Blue
ConsoleColorBrush<0>, // Info Default
ConsoleColorBrush<32>, // Notice Green
ConsoleColorBrush<33>, // Warn Yellow
ConsoleColorBrush<31>, // Error Red
};
if (size_t(level) < colors.size())
return *std::next(colors.begin(), ptrdiff_t(level));
return ConsoleColorBrush<0>;
}
LogProviderPtr FileLogProvider::Create(const String& filepath, std::ios_base::openmode mode)
{
SmartPtr<FileLogProvider> ptr = new FileLogProvider;
if (ptr)
{
ptr->ofs_.open(filepath, mode);
}
return ptr;
}
FileLogProvider::~FileLogProvider()
{
if (ofs_.is_open())
ofs_.close();
}
void FileLogProvider::Init() {}
void FileLogProvider::WriteMessage(LogLevel level, LogBuffer* msg)
{
if (ofs_)
{
ofs_ << msg << std::flush;
}
}
void FileLogProvider::Flush()
{
if (ofs_)
{
ofs_.flush();
ofs_.clear();
}
}
//
// LogBuffer
//
LogBuffer::LogBuffer(size_t buffer_size)
: buf_(buffer_size)
, seek_high_(nullptr)
{
Reset();
}
void LogBuffer::Resize(size_t size)
{
if (buf_.size() < size)
{
buf_.resize(size);
}
}
void LogBuffer::Reset()
{
const auto begin = buf_.data();
const auto size = buf_.size();
this->setp(begin, begin + size);
this->setg(begin, begin, begin);
seek_high_ = nullptr;
}
const char* LogBuffer::GetRaw() const
{
const auto pptr = this->pptr();
if (!pptr)
return "";
const auto data = buf_.data();
const auto size = buf_.size();
if (pptr == data)
return "";
if (pptr > data && pptr < data + size)
{
*pptr = '\0';
return data;
}
return "";
}
LogBuffer::int_type LogBuffer::overflow(int_type ch)
{
if (traits_type::eq_int_type(ch, traits_type::eof()))
return traits_type::not_eof(ch); // EOF, return success
const auto pptr = this->pptr();
if (pptr)
return traits_type::eof();
const auto epptr = this->epptr();
if (pptr < epptr)
{
seek_high_ = pptr + 1;
return ch;
}
const auto old_ptr = buf_.data();
const auto old_size = pptr - old_ptr;
size_t new_size = 0;
if (old_size < INT_MAX / 2)
new_size = old_size << 1;
else if (old_size < INT_MAX)
new_size = INT_MAX;
else
return traits_type::eof(); // buffer can't grow, fail
// grow
buf_.resize(new_size);
const auto new_ptr = buf_.data();
const auto new_pnext = new_ptr + old_size;
seek_high_ = new_pnext + 1;
this->setp(new_ptr, new_pnext, new_ptr + new_size);
this->setg(new_ptr, new_ptr + (this->gptr() - old_ptr), seek_high_);
return ch;
}
LogBuffer::int_type LogBuffer::underflow()
{
const auto gptr = this->gptr();
if (!gptr)
return traits_type::eof();
if (gptr < this->egptr())
return traits_type::to_int_type(*gptr);
const auto pptr = this->pptr();
if (!pptr)
return traits_type::eof();
const auto high = std::max(seek_high_, pptr);
if (high <= gptr)
return traits_type::eof();
seek_high_ = high;
this->setg(this->eback(), gptr, high);
return traits_type::to_int_type(*gptr);
}
LogBuffer::pos_type LogBuffer::seekpos(pos_type pos, std::ios_base::openmode mode)
{
const auto offset = static_cast<std::streamoff>(pos);
const auto old_gptr = this->gptr();
const auto olg_pptr = this->pptr();
if (olg_pptr && seek_high_ < olg_pptr)
{
seek_high_ = olg_pptr;
}
const auto seek_low = this->eback();
const auto seek_dist = seek_high_ - seek_low;
if (static_cast<unsigned long long>(offset) > static_cast<unsigned long long>(seek_dist))
{
return pos_type(off_type(-1));
}
if (offset != 0 && (((mode & std::ios_base::in) && !old_gptr) || ((mode & std::ios_base::out) && !olg_pptr)))
{
return pos_type(off_type(-1));
}
const auto new_ptr = seek_low + offset;
if ((mode & std::ios_base::in) && old_gptr)
{
this->setg(seek_low, new_ptr, seek_high_);
}
if ((mode & std::ios_base::out) && olg_pptr)
{
this->setp(seek_low, new_ptr, this->epptr());
}
return pos_type(offset);
}
LogBuffer::pos_type LogBuffer::seekoff(off_type offset, std::ios_base::seekdir way, std::ios_base::openmode mode)
{
const auto old_gptr = this->gptr();
const auto old_pptr = this->pptr();
if (old_pptr && seek_high_ < old_pptr)
{
seek_high_ = old_pptr;
}
const auto seek_low = this->eback();
const auto seek_dist = seek_high_ - seek_low;
off_type new_offset;
switch (way)
{
case std::ios_base::beg:
new_offset = 0;
break;
case std::ios_base::end:
new_offset = seek_dist;
break;
case std::ios_base::cur:
{
constexpr auto both = std::ios_base::in | std::ios_base::out;
if ((mode & both) != both)
{
if (mode & std::ios_base::in)
{
if (old_gptr || !seek_low)
{
new_offset = old_gptr - seek_low;
break;
}
}
else if ((mode & std::ios_base::out) && (old_pptr || !seek_low))
{
new_offset = old_pptr - seek_low;
break;
}
}
}
// fallthrough
default:
return pos_type(off_type(-1));
}
if (std::streamsize(offset) + new_offset > std::streamsize(seek_dist))
{
return pos_type(off_type(-1));
}
offset += new_offset;
if (offset != 0 && (((mode & std::ios_base::in) && !old_gptr) || ((mode & std::ios_base::out) && !old_pptr)))
{
return pos_type(off_type(-1));
}
const auto new_ptr = seek_low + offset;
if ((mode & std::ios_base::in) && old_gptr)
{
this->setg(seek_low, new_ptr, seek_high_);
}
if ((mode & std::ios_base::out) && old_pptr)
{
this->setp(seek_low, new_ptr, this->epptr());
}
return pos_type(offset);
}
//
// Logger
//
Logger::Logger()
: enabled_(true)
, level_(LogLevel::Debug)
, buffer_(1024)
{
LogFormaterPtr formater = new TextFormater;
SetFormater(formater);
LogProviderPtr provider = ConsoleLogProvider::Create();
AddProvider(provider);
}
Logger::~Logger()
{
}
void Logger::Logf(LogLevel level, const char* format, ...)
{
if (!enabled_)
return;
if (level < level_)
return;
// build message
va_list args = nullptr;
va_start(args, format);
StringStream sstream;
sstream << strings::FormatArgs(format, args);
va_end(args);
// write message
Write(level, sstream.rdbuf());
}
void Logger::Flush()
{
if (!enabled_)
return;
for (auto provider : providers_)
{
provider->Flush();
}
}
void Logger::SetLevel(LogLevel level)
{
level_ = level;
}
void Logger::AddProvider(LogProviderPtr provider)
{
if (provider)
{
provider->Init();
providers_.push_back(provider);
}
}
LogFormaterPtr Logger::GetFormater()
{
return formater_;
}
void Logger::ResizeBuffer(size_t buffer_size)
{
buffer_.Resize(buffer_size);
}
void Logger::Write(LogLevel level, std::streambuf* raw_msg)
{
std::lock_guard<std::mutex> lock(mutex_);
// reset buffer
buffer_.Reset();
// format message
std::iostream stream(&buffer_);
if (formater_)
{
formater_->Format(stream, level, Time::Now(), raw_msg);
}
else
{
stream << raw_msg << "\n";
}
// write message
for (auto provider : providers_)
{
buffer_.pubseekpos(0, std::ios_base::in);
provider->WriteMessage(level, &buffer_);
}
}
#if defined(KGE_PLATFORM_WINDOWS)
//
// Console log
//
namespace
{
std::streambuf *cin_buffer, *cout_buffer, *cerr_buffer;
@ -121,204 +674,11 @@ HWND GetAllocatedConsole()
}
} // namespace
namespace kiwano
{
namespace console_colors
{
const WORD blue = FOREGROUND_BLUE | FOREGROUND_INTENSITY;
const WORD green = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
const WORD red = FOREGROUND_RED | FOREGROUND_INTENSITY;
const WORD yellow = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;
const WORD white = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;
const WORD blue_bg = white | BACKGROUND_BLUE | BACKGROUND_INTENSITY;
const WORD green_bg = white | BACKGROUND_GREEN | BACKGROUND_INTENSITY;
const WORD red_bg = white | BACKGROUND_RED | BACKGROUND_INTENSITY;
const WORD yellow_bg = BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY;
const WORD white_bg = BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY;
const WORD Reset = white;
} // namespace console_colors
#define DECLARE_HANDLE_COLOR(NAME, HANDLE_NAME, COLOR) \
inline OutputStream&(NAME)(OutputStream & _out) \
{ \
::SetConsoleTextAttribute(::GetStdHandle(HANDLE_NAME), console_colors::##COLOR); \
return _out; \
}
#define DECLARE_COLOR(COLOR) \
DECLARE_HANDLE_COLOR(stdout_##COLOR, STD_OUTPUT_HANDLE, COLOR) \
DECLARE_HANDLE_COLOR(stderr_##COLOR, STD_ERROR_HANDLE, COLOR)
#define DECLARE_BG_COLOR(COLOR) \
DECLARE_HANDLE_COLOR(stdout_##COLOR##_bg, STD_OUTPUT_HANDLE, COLOR##_bg) \
DECLARE_HANDLE_COLOR(stderr_##COLOR##_bg, STD_ERROR_HANDLE, COLOR##_bg)
namespace console_colors
{
DECLARE_COLOR(red);
DECLARE_COLOR(green);
DECLARE_COLOR(yellow);
DECLARE_COLOR(blue);
DECLARE_COLOR(white);
DECLARE_COLOR(Reset);
DECLARE_BG_COLOR(red);
DECLARE_BG_COLOR(green);
DECLARE_BG_COLOR(yellow);
DECLARE_BG_COLOR(blue);
DECLARE_BG_COLOR(white);
} // namespace console_colors
Logger::Logger()
: enabled_(true)
, default_stdout_color_(0)
, default_stderr_color_(0)
, output_stream_(std::cout.rdbuf())
, error_stream_(std::cerr.rdbuf())
{
ResetStreamToStdStream();
}
Logger::~Logger()
{
FreeAllocatedConsole();
}
void Logger::Printf(Level level, const char* format, ...)
{
if (!enabled_)
return;
StringStream sstream;
Prepare(level, sstream);
// Format message
if (format)
{
va_list args = nullptr;
va_start(args, format);
static char temp_buffer[1024 * 3 + 1];
const auto len = ::_vscprintf(format, args) + 1;
::_vsnprintf_s(temp_buffer, len, len, format, args);
sstream << ' ' << temp_buffer << "\n";
va_end(args);
}
Output(level, sstream);
}
void Logger::Prepare(Level level, StringStream& sstream)
{
String prefix;
switch (level)
{
case Level::Info:
prefix = "[INFO] ";
break;
case Level::System:
prefix = "[SYSTEM] ";
break;
case Level::Warning:
prefix = "[WARN] ";
break;
case Level::Error:
prefix = "[ERROR] ";
break;
}
// Timestamp
time_t unix = std::time(nullptr);
std::tm tmbuf;
localtime_s(&tmbuf, &unix);
sstream << prefix << std::put_time(&tmbuf, "%H:%M:%S ");
}
void Logger::Output(Level level, StringStream& sstream)
{
using ConsoleColor = Function<OutputStream&(OutputStream&)>;
OutputStream* ostream = nullptr;
ConsoleColor color = nullptr;
switch (level)
{
case Level::Info:
ostream = &output_stream_;
color = Closure(this, &Logger::DefaultOutputColor);
break;
case Level::System:
ostream = &output_stream_;
color = console_colors::stdout_blue;
break;
case Level::Warning:
ostream = &output_stream_;
color = console_colors::stdout_yellow_bg;
break;
case Level::Error:
ostream = &error_stream_;
color = console_colors::stderr_red_bg;
break;
}
// Printing
if (ostream)
{
auto output = sstream.str();
color(*ostream) << output << std::flush;
::OutputDebugStringA(output.c_str());
ResetConsoleColor();
}
}
void Logger::ResetStreamToStdStream()
{
bool has_console = ::GetConsoleWindow() != nullptr;
if (has_console)
{
default_stdout_color_ = default_stderr_color_ =
FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;
CONSOLE_SCREEN_BUFFER_INFO stdout_info;
if (::GetConsoleScreenBufferInfo(::GetStdHandle(STD_OUTPUT_HANDLE), &stdout_info))
{
default_stdout_color_ = stdout_info.wAttributes;
}
CONSOLE_SCREEN_BUFFER_INFO stderr_info;
if (::GetConsoleScreenBufferInfo(::GetStdHandle(STD_ERROR_HANDLE), &stderr_info))
{
default_stderr_color_ = stderr_info.wAttributes;
}
// replace the C++ global locale with the user-preferred locale
(void)std::locale::global(std::locale());
(void)std::cout.imbue(std::locale());
(void)std::cerr.imbue(std::locale());
RedirectOutputStream(std::cout.rdbuf());
RedirectErrorStream(std::cerr.rdbuf());
}
}
std::streambuf* Logger::RedirectOutputStream(std::streambuf* buf)
{
return output_stream_.rdbuf(buf);
}
std::streambuf* Logger::RedirectErrorStream(std::streambuf* buf)
{
return error_stream_.rdbuf(buf);
}
#endif
void Logger::ShowConsole(bool show)
{
#if defined(KGE_PLATFORM_WINDOWS)
HWND current_console = ::GetConsoleWindow();
if (show)
{
@ -328,14 +688,13 @@ void Logger::ShowConsole(bool show)
}
else
{
HWND console = ::AllocateConsole();
if (!console)
HWND console = AllocateConsole();
if (console)
{
KGE_WARN("AllocConsole failed");
}
else
{
ResetStreamToStdStream();
// replace the C++ global locale with the user-preferred locale
(void)std::locale::global(std::locale());
(void)std::cout.imbue(std::locale());
(void)std::cerr.imbue(std::locale());
// disable the close button of console
HMENU hmenu = ::GetSystemMenu(console, FALSE);
@ -357,6 +716,10 @@ void Logger::ShowConsole(bool show)
}
}
}
#else
// NOT IMPLEMENT
#endif
}
} // namespace kiwano

View File

@ -19,83 +19,212 @@
// THE SOFTWARE.
#pragma once
#include <kiwano/core/Common.h>
#include <kiwano/core/Time.h>
#include <kiwano/base/ObjectBase.h>
#include <mutex>
#include <iomanip>
#include <streambuf>
#include <fstream>
#ifndef KGE_SYS_LOG
#ifndef KGE_DEBUG_LOG
#ifdef KGE_DEBUG
#define KGE_SYS_LOG(FORMAT, ...) \
::kiwano::Logger::GetInstance().Printf(::kiwano::Logger::Level::System, FORMAT, __VA_ARGS__)
#define KGE_DEBUG_LOG(...) ::kiwano::Logger::GetInstance().Log(::kiwano::LogLevel::Debug, __VA_ARGS__)
#else
#define KGE_SYS_LOG __noop
#define KGE_DEBUG_LOG __noop
#endif
#endif
#ifndef KGE_WARN
#define KGE_WARN(FORMAT, ...) ::kiwano::Logger::GetInstance().Printf(::kiwano::Logger::Level::Warning, FORMAT, __VA_ARGS__)
#endif
#ifndef KGE_ERROR
#define KGE_ERROR(FORMAT, ...) ::kiwano::Logger::GetInstance().Printf(::kiwano::Logger::Level::Error, FORMAT, __VA_ARGS__)
#endif
#ifndef KGE_LOG
#define KGE_LOG(...) ::kiwano::Logger::GetInstance().Println(::kiwano::Logger::Level::Info, __VA_ARGS__)
#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
#ifndef KGE_WARN
#define KGE_WARN(...) ::kiwano::Logger::GetInstance().Log(::kiwano::LogLevel::Warning, __VA_ARGS__)
#endif
#ifndef KGE_ERROR
#define KGE_ERROR(...) ::kiwano::Logger::GetInstance().Log(::kiwano::LogLevel::Error, __VA_ARGS__)
#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
#endif
#ifndef KGE_LOGF
#define KGE_LOGF(FORMAT, ...) ::kiwano::Logger::GetInstance().Printf(::kiwano::Logger::Level::Info, FORMAT, __VA_ARGS__)
#define KGE_LOGF(FORMAT, ...) ::kiwano::Logger::GetInstance().Logf(::kiwano::LogLevel::Info, FORMAT, __VA_ARGS__)
#endif
#ifndef KGE_LOG_STREAM
#define KGE_LOG_STREAM() ::kiwano::Logger::GetInstance().GetOutputStream()
#ifndef KGE_NOTICEF
#define KGE_NOTICEF(FORMAT, ...) ::kiwano::Logger::GetInstance().Logf(::kiwano::LogLevel::Notice, FORMAT, __VA_ARGS__)
#endif
#ifndef KGE_ERROR_STREAM
#define KGE_ERROR_STREAM() ::kiwano::Logger::GetInstance().GetErrorStream()
#ifndef KGE_WARNF
#define KGE_WARNF(FORMAT, ...) ::kiwano::Logger::GetInstance().Logf(::kiwano::LogLevel::Warning, FORMAT, __VA_ARGS__)
#endif
#ifndef KGE_ERRORF
#define KGE_ERRORF(FORMAT, ...) ::kiwano::Logger::GetInstance().Logf(::kiwano::LogLevel::Error, FORMAT, __VA_ARGS__)
#endif
namespace kiwano
{
KGE_DECLARE_SMART_PTR(LogFormater);
KGE_DECLARE_SMART_PTR(LogProvider);
KGE_DECLARE_SMART_PTR(Logger);
/**
* \~chinese
* @brief
* @brief
*/
enum class LogLevel
{
Debug, ///< 调试
Info, ///< 信息
Notice, ///< 注意
Warning, ///< 警告
Error, ///< 错误
};
/**
* \~chinese
* @brief
*/
class KGE_API LogFormater : public ObjectBase
{
public:
virtual void Format(std::iostream& out, LogLevel level, Time time, std::streambuf* raw_msg) = 0;
String GetLevelLabel(LogLevel level) const;
};
/**
* \~chinese
* @brief
*/
class LogBuffer : public std::streambuf
{
public:
LogBuffer(size_t buffer_size);
void Resize(size_t size);
void Reset();
const char* GetRaw() const;
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:
Vector<char_type> buf_;
char_type* seek_high_;
};
/**
* \~chinese
* @brief
*/
class KGE_API LogProvider : public ObjectBase
{
public:
virtual ~LogProvider();
virtual void Init() = 0;
virtual void WriteMessage(LogLevel level, LogBuffer* msg) = 0;
virtual void Flush() = 0;
};
/**
* \~chinese
* @brief
*/
class KGE_API ConsoleLogProvider : public LogProvider
{
public:
static LogProviderPtr Create();
virtual ~ConsoleLogProvider();
void Init() override;
void WriteMessage(LogLevel level, LogBuffer* msg) override;
void Flush() override;
private:
typedef std::ostream&(*ConsoleColor)(std::ostream&);
ConsoleColor GetColor(LogLevel level);
};
/**
* \~chinese
* @brief
*/
class KGE_API FileLogProvider : public LogProvider
{
public:
static LogProviderPtr Create(const String& filepath, std::ios_base::openmode mode = std::ios_base::out);
virtual ~FileLogProvider();
void Init() override;
void WriteMessage(LogLevel level, LogBuffer* msg) override;
void Flush() override;
private:
std::ofstream ofs_;
};
/**
* \~chinese
* @brief
*/
class KGE_API Logger : public Singleton<Logger>
{
friend Singleton<Logger>;
public:
/// \~chinese
/// @brief 日志级别
enum class Level
{
Info, ///< 信息
System, ///< 系统
Warning, ///< 警告
Error ///< 错误
};
/// \~chinese
/// @brief 打印日志
/// @param level 日志级别
/// @param format 格式字符串
void Printf(Level level, const char* format, ...);
void Logf(LogLevel level, const char* format, ...);
/// \~chinese
/// @brief 打印日志
/// @param level 日志级别
/// @param args 参数
template <typename... _Args>
void Print(Level level, _Args&&... args);
void Log(LogLevel level, _Args&&... args);
/// \~chinese
/// @brief 打印一行日志
/// @param level 日志级别
/// @param args 参数
template <typename... _Args>
void Println(Level level, _Args&&... args);
/// @brief 刷新日志缓冲
void Flush();
/// \~chinese
/// @brief 启用日志
@ -106,48 +235,51 @@ public:
void Disable();
/// \~chinese
/// @brief 获取输出流
OutputStream& GetOutputStream();
/// @brief 设置日志等级
void SetLevel(LogLevel level);
/// \~chinese
/// @brief 获取错误输出流
OutputStream& GetErrorStream();
/// @brief 添加日志提供者
/// @param provider 日志提供者
void AddProvider(LogProviderPtr provider);
/// \~chinese
/// @brief 重定向输出流
std::streambuf* RedirectOutputStream(std::streambuf* buf);
/// @brief 设置日志格式
/// @param formater 日志格式化
void SetFormater(LogFormaterPtr formater);
/// \~chinese
/// @brief 重定向错误输出流
std::streambuf* RedirectErrorStream(std::streambuf* buf);
/// @brief 获取日志格式
/// @return 日志格式
LogFormaterPtr GetFormater();
/// \~chinese
/// @brief 重设缓冲区大小
/// @param buffer_size 缓冲区大小
void ResizeBuffer(size_t buffer_size);
/// \~chinese
/// @brief 写入缓冲区
/// @param level 日志等级
/// @param raw_msg 日志内容
void Write(LogLevel level, std::streambuf* raw_msg);
/// \~chinese
/// @brief 显示或关闭控制台
/// @note 此操作会重定向输出流到标准输出流
void ShowConsole(bool show);
~Logger();
virtual ~Logger();
private:
Logger();
void Prepare(Level level, StringStream& sstream);
void Output(Level level, StringStream& sstream);
void ResetStreamToStdStream();
void ResetConsoleColor() const;
OutputStream& DefaultOutputColor(OutputStream& out);
private:
bool enabled_;
WORD default_stdout_color_;
WORD default_stderr_color_;
OutputStream output_stream_;
OutputStream error_stream_;
LogLevel level_;
LogFormaterPtr formater_;
LogBuffer buffer_;
Vector<LogProviderPtr> providers_;
std::mutex mutex_;
};
inline void Logger::Enable()
@ -160,57 +292,26 @@ inline void Logger::Disable()
enabled_ = false;
}
inline void Logger::SetFormater(LogFormaterPtr formater)
{
formater_ = formater;
}
template <typename... _Args>
void Logger::Print(Level level, _Args&&... args)
inline void Logger::Log(LogLevel level, _Args&&... args)
{
if (!enabled_)
return;
StringStream sstream;
Prepare(level, sstream);
// Format message
(void)std::initializer_list<int>{ ((sstream << ' ' << args), 0)... };
Output(level, sstream);
}
template <typename... _Args>
void Logger::Println(Level level, _Args&&... args)
{
if (!enabled_)
if (level < level_)
return;
// build message
StringStream sstream;
Prepare(level, sstream);
// Format message
(void)std::initializer_list<int>{ ((sstream << ' ' << args), 0)... };
sstream << "\r\n";
Output(level, sstream);
// write message
this->Write(level, sstream.rdbuf());
}
inline void Logger::ResetConsoleColor() const
{
::SetConsoleTextAttribute(::GetStdHandle(STD_OUTPUT_HANDLE), default_stdout_color_);
::SetConsoleTextAttribute(::GetStdHandle(STD_ERROR_HANDLE), default_stderr_color_);
}
inline OutputStream& Logger::DefaultOutputColor(OutputStream& out)
{
::SetConsoleTextAttribute(::GetStdHandle(STD_OUTPUT_HANDLE), default_stdout_color_);
return out;
}
inline OutputStream& Logger::GetOutputStream()
{
return output_stream_;
}
inline OutputStream& Logger::GetErrorStream()
{
return error_stream_;
}
} // namespace kiwano

View File

@ -60,7 +60,7 @@ bool ResourceCache::LoadFromJsonFile(const String& file_path)
{
if (!FileSystem::GetInstance().IsFileExists(file_path))
{
KGE_ERROR("%s failed: File not found.", __FUNCTION__);
KGE_ERRORF("%s failed: File not found.", __FUNCTION__);
return false;
}
@ -78,12 +78,12 @@ bool ResourceCache::LoadFromJsonFile(const String& file_path)
}
catch (std::wifstream::failure& e)
{
KGE_ERROR("%s failed: Cannot open file. (%s)", __FUNCTION__, e.what());
KGE_ERRORF("%s failed: Cannot open file. (%s)", __FUNCTION__, e.what());
return false;
}
catch (Json::exception& e)
{
KGE_ERROR("%s failed: Cannot parse to JSON. (%s)", __FUNCTION__, e.what());
KGE_ERRORF("%s failed: Cannot parse to JSON. (%s)", __FUNCTION__, e.what());
return false;
}
return LoadFromJson(json_data);
@ -106,12 +106,12 @@ bool ResourceCache::LoadFromJson(const Json& json_data)
}
else
{
KGE_ERROR("%s failed: unknown resource data version", __FUNCTION__);
KGE_ERRORF("%s failed: unknown resource data version", __FUNCTION__);
}
}
catch (Json::exception& e)
{
KGE_ERROR("%s failed: JSON data is invalid. (%s)", __FUNCTION__, e.what());
KGE_ERRORF("%s failed: JSON data is invalid. (%s)", __FUNCTION__, e.what());
return false;
}
return false;
@ -121,7 +121,7 @@ bool ResourceCache::LoadFromXmlFile(const String& file_path)
{
if (!FileSystem::GetInstance().IsFileExists(file_path))
{
KGE_ERROR("%s failed: File not found.", __FUNCTION__);
KGE_ERRORF("%s failed: File not found.", __FUNCTION__);
return false;
}
@ -136,7 +136,7 @@ bool ResourceCache::LoadFromXmlFile(const String& file_path)
}
else
{
KGE_ERROR("%s failed: XML [%s] parsed with errors: %s", __FUNCTION__, full_path.c_str(), result.description());
KGE_ERRORF("%s failed: XML [%s] parsed with errors: %s", __FUNCTION__, full_path.c_str(), result.description());
return false;
}
}
@ -160,7 +160,7 @@ bool ResourceCache::LoadFromXml(const XmlDocument& doc)
}
else
{
KGE_ERROR("%s failed: unknown resource data version", __FUNCTION__);
KGE_ERRORF("%s failed: unknown resource data version", __FUNCTION__);
}
}
return false;