YSTest: Debug.cpp 源文件

YSTest PreAlpha_b800_20170810 The YSLib Test Project

- 首页
- 相关页面
- 模块
- 命名空间
- 类
- 文件

- 文件列表
- 文件成员

Debug.cpp
浏览该文件的文档.
1 /*
2 © 2011-2016 FrankHB.
3
4 This file is part of the YSLib project, and may only be used,
5 modified, and distributed under the terms of the YSLib project
6 license, LICENSE.TXT. By continuing to use, modify, or distribute
7 this file you indicate that you have read the license and
8 understand and accept it fully.
9 */
10
28 #include "YCLib/YModules.h"
29 #include YFM_YCLib_Debug // for wstring, string_view, std::puts, std::fflush;
30 #if YCL_Win32
31 # include YFM_Win32_YCLib_Consoles // for platform_ex::WConsole,
32 // STD_OUTPUT_HANDLE, STD_ERROR_HANDLE, platform_ex::Win32Exception;
33 # include YFM_Win32_YCLib_NLS // for platform_ex::UTF8ToWCS;
34 # include YFM_YCLib_NativeAPI // for ::OutputDebugStringA, ::MessageBoxA;
35 # include <csignal> // for std::raise, SIGABRT;
36 #elif YCL_Android
37 # include <android/log.h>
38 #endif
39 #include YFM_YCLib_Host // for platfrom_ex::EncodeArg;
40 #if YF_Multithread == 1
41 # include <ystdex/concurrency.h>
42 #endif
43 #if !YCL_DS
44 # include <iostream> // for std::cerr;
45 #endif
46 #include <cstdarg> // for std::va_list, va_start, va_end;
47
48 namespace platform
49 {
50
51 namespace
52 {
53
55 inline PDefH(const char*, chk_null, const char* s)
56 ImplRet(s && *s != char()? s : "<unknown>")
57
58 #if YF_Multithread == 1
59 std::string
61 FetchCurrentThreadID() ynothrow
62 {
63 TryRet(ystdex::get_this_thread_id())
64 // XXX: Nothing more can be done.
65 CatchIgnore(...)
66 return {};
67 }
68 #endif
69
70 #if YCL_Win32
71 YB_NONNULL(3) size_t
73 WConsoleOutput(wstring& wstr, unsigned long h, const char* str)
74 {
75 using namespace platform_ex;
76
77 wstr = UTF8ToWCS(str) + L'\n';
78 return WConsole(h).WriteString(wstr);
79 }
80 #elif YCL_Android
81 template<typename... _tParams>
83 inline int
84 PrintAndroidLog(Descriptions::RecordLevel lv, const char* tag, const char *fmt,
85 _tParams&&... args)
86 {
87 return ::__android_log_print(platform_ex::MapAndroidLogLevel(lv),
88 Nonnull(tag), Nonnull(fmt), yforward(args)...);
89 }
90 #endif
91
93 using namespace Concurrency;
94
95 } // unnamed namespace;
96
97 bool
98 Echo(string_view sv) ynoexcept(YF_Platform == YF_Platform_DS)
99 {
100 #if YCL_DS
101 return std::puts(Nonnull(sv.data())) >= 0 && std::fflush(stdout) == 0;
102 #elif YCL_Win32
103 wstring wstr;
104 size_t n(0);
105
106 TryExpr(n = WConsoleOutput(wstr, STD_OUTPUT_HANDLE, sv.data()))
107 CatchIgnore(platform_ex::Win32Exception&)
108 if(n < wstr.length())
109 std::cout << &wstr[n];
110 return bool(std::cout.flush());
111 #elif YF_Hosted
112 return bool(std::cout << platform_ex::EncodeArg(sv) << std::endl);
113 #else
114 return bool(std::cout << sv << std::endl);
115 #endif
116 }
117
118
119 void
120 Logger::SetFilter(Filter f)
121 {
122 if(f)
123 filter = std::move(f);
124 }
125 void
126 Logger::SetSender(Sender s)
127 {
128 if(s)
129 sender = std::move(s);
130 }
131
132 bool
133 Logger::DefaultFilter(Level lv, Logger& logger) ynothrow
134 {
135 return lv <= logger.FilterLevel;
136 }
137
138 void
139 Logger::DefaultSendLog(Level lv, Logger& logger, const char* str) ynothrowv
140 {
141 #if YCL_DS
142 yunused(lv), yunused(logger), yunused(str);
143 #else
144 SendLog(std::cerr, lv, logger, str);
145 #endif
146 }
147
148 void
149 Logger::DefaultSendLogToFile(Level lv, Logger& logger, const char* str)
150 ynothrowv
151 {
152 SendLogToFile(stderr, lv, logger, str);
153 }
154
155 void
156 Logger::DoLog(Level level, const char* str)
157 {
158 if(str)
159 {
160 lock_guard<recursive_mutex> lck(record_mutex);
161
162 DoLogRaw(level, str);
163 }
164 }
165
166 void
167 Logger::DoLogRaw(Level level, const char* str)
168 {
169 sender(level, *this, Nonnull(str));
170 }
171
172 void
173 Logger::DoLogException(Level lv, const std::exception& e) ynothrow
174 {
175 const auto do_log_excetpion_raw([this](const char* msg) YB_NONNULL(1)
176 ynothrow{
177 try
178 {
179 DoLogRaw(Descriptions::Emergent,
180 "Another exception thrown when handling exception.");
181 DoLogRaw(Descriptions::Emergent, msg);
182 }
183 CatchExpr(...,
184 ystdex::ytrace(stderr, Descriptions::Emergent, Descriptions::Notice,
185 __FILE__, __LINE__, "Logging error: unhandled exception."))
186 });
187 const auto& msg(e.what());
188 lock_guard<recursive_mutex> lck(record_mutex);
189
190 try
191 {
192 // XXX: Provide no throw guarantee and put it out of the critical
193 // section?
194 // XXX: Log demangled type name.
195 DoLogRaw(lv, sfmt("<%s>: %s", typeid(e).name(), msg));
196 }
197 CatchExpr(std::exception& ex, do_log_excetpion_raw(ex.what()))
198 CatchExpr(..., do_log_excetpion_raw({}))
199 }
200
201 Logger::Sender
202 Logger::FetchDefaultSender(string_view tag)
203 {
204 YAssertNonnull(tag.data());
205 #if YCL_Win32
206 return [](Level lv, Logger& logger, const char* str){
207 // TODO: Avoid throwing of %WriteString here for better performance?
208 // FIXME: Output may be partially updated?
209 try
210 {
211 wstring wstr;
212
213 WConsoleOutput(wstr, STD_ERROR_HANDLE, str);
214 }
215 CatchExpr(platform_ex::Win32Exception&, DefaultSendLog(lv, logger, str))
216 };
217 #elif YCL_Android
218 return platform_ex::AndroidLogSender(tag);
219 #else
220 return DefaultSendLog;
221 #endif
222 }
223
224 void
225 Logger::SendLog(std::ostream& os, Level lv, Logger&, const char* str)
226 ynothrowv
227 {
228 try
229 {
230 #if YF_Multithread == 1
231 const auto& t_id(FetchCurrentThreadID());
232
233 if(!t_id.empty())
234 os << ystdex::sfmt("[%s:%#X]: %s\n", t_id.c_str(), unsigned(lv),
235 Nonnull(str));
236 else
237 #endif
238 os << ystdex::sfmt("[%#X]: %s\n", unsigned(lv), Nonnull(str));
239 os.flush();
240 }
241 CatchIgnore(...)
242 }
243
244 void
245 Logger::SendLogToFile(std::FILE* stream, Level lv, Logger&, const char* str)
246 ynothrowv
247 {
248 YAssertNonnull(stream);
249 #if YF_Multithread == 1
250 const auto& t_id(FetchCurrentThreadID());
251
252 if(!t_id.empty())
253 std::fprintf(stream, "[%s:%#X]: %s\n", t_id.c_str(), unsigned(lv),
254 Nonnull(str));
255 else
256 #endif
257 std::fprintf(stream, "[%#X]: %s\n", unsigned(lv), Nonnull(str));
258 std::fflush(stream);
259 }
260
261
262 Logger&
263 FetchCommonLogger()
264 {
265 static Logger logger;
266
267 return logger;
268 }
269
270
271 string
272 LogWithSource(const char* file, int line, const char* fmt, ...) ynothrow
273 {
274 try
275 {
276 std::va_list args;
277
278 va_start(args, fmt);
279
280 string str(vsfmt(fmt, args));
281
282 va_end(args);
283 return sfmt("\"%s\":%i:\n", chk_null(file), line) + std::move(str);
284 }
285 CatchExpr(...,
286 ystdex::ytrace(stderr, Descriptions::Emergent, Descriptions::Notice,
287 chk_null(file), line, "LogWithSource error: unhandled exception."))
288 return {};
289 }
290
291 } // namespace platform;
292
293 using namespace platform;
294
295 namespace platform_ex
296 {
297
298 #if YF_Multithread == 1
299 void
300 LogAssert(const char* expr_str, const char* file, int line,
301 const char* msg) ynothrow
302 {
303 # if YCL_Android
304 ::__android_log_assert(expr_str, "YFramework",
305 "Assertion failed @ \"%s\":%i:\n %s .\nMessage: \n%s\n", file, line,
306 expr_str, msg);
307 # else
308 # if YCL_Win32
309 try
310 {
311 char prog[MAX_PATH]{"<unknown>"};
312
313 ::GetModuleFileNameA({}, prog, MAX_PATH);
314
315 const auto& errstr(sfmt("Assertion failed @ program %s: "
316 "\"%s\":%i:\n %s .\nMessage: \n%s\n", prog, chk_null(file),
317 line, chk_null(expr_str), chk_null(msg)));
318
319 ::OutputDebugStringA(errstr.c_str());
320 // XXX: Not safe in windows procedure, but not used in YFramework.
321 // TODO: Use custom windows creation?
322 switch(::MessageBoxA({}, errstr.c_str(),
323 "YCLib Runtime Assertion", MB_ABORTRETRYIGNORE | MB_ICONHAND
324 | MB_SETFOREGROUND | MB_TASKMODAL))
325 {
326 case IDIGNORE:
327 return;
328 case IDABORT:
329 std::raise(SIGABRT);
330 default:
331 break;
332 }
333 std::terminate();
334 }
335 catch(...)
336 {
337 YF_TraceRaw(Descriptions::Emergent, "Unknown exception found.");
338 ystdex::yassert(expr_str, file, line, msg);
339 }
340 # endif
341 TryExpr(FetchCommonLogger().AccessRecord([=]{
342 ystdex::yassert(expr_str, file, line, msg);
343 }))
344 catch(...)
345 {
346 std::fprintf(stderr, "Fetch logger failed.");
347 std::fflush(stderr);
348 }
349 ystdex::yassert(expr_str, file, line, msg);
350 # endif
351 }
352 #endif
353
354
355 #if YCL_Win32
356 void
357 SendDebugString(Logger::Level lv, Logger&, const char* str) ynothrowv
358 {
359 try
360 {
361 const auto& t_id(FetchCurrentThreadID());
362
363 // TODO: Use %::WaitForDebugEventEx if possible. See https://msdn.microsoft.com/en-us/library/windows/desktop/mt171594(v=vs.85).aspx.
364 ::OutputDebugStringA((!t_id.empty() ? ystdex::sfmt("[%s:%#X]: %s",
365 t_id.c_str(), unsigned(lv), Nonnull(str)) : ystdex::sfmt(
366 "[%#X]: %s", unsigned(lv), Nonnull(str))).c_str());
367 }
368 CatchIgnore(...)
369 }
370 #elif YCL_Android
371 int
372 MapAndroidLogLevel(Descriptions::RecordLevel lv)
373 {
374 return lv < Descriptions::Critical ? ANDROID_LOG_FATAL
375 : ANDROID_LOG_FATAL - (std::uint8_t(lv) - 0x40) / 0x20;
376 }
377
378
379 AndroidLogSender::AndroidLogSender(string_view sv)
380 : tag((Nonnull(sv.data()), sv))
381 {}
382 AndroidLogSender::~AndroidLogSender()
383 {}
384
385 void
386 AndroidLogSender::operator()(Level lv, Logger& logger, const char* str) const
387 {
388 Logger::DefaultSendLog(lv, logger, str);
389 if(lv < Descriptions::Critical)
390 ::__android_log_assert("", "YFramework", "[%#X]: %s\n",
391 unsigned(lv), str);
392 else
393 PrintAndroidLog(lv, tag.c_str(), "[%#X]: %s\n", unsigned(lv), str);
394 }
395
396 #endif
397
398 } // namespace platform_ex;
399
platform::Logger::sender
Sender sender
Definition: Debug.h:112
ystdex::yassert
void yassert(const char *, const char *, int, const char *)
YBase 默认断言函数。
Definition: cassert.cpp:36
platform::containers::wstring
basic_string< wchar_t > wstring
Definition: Container.h:108
platform::msg
const string & msg
Definition: Debug.h:464
platform::Echo
YF_API bool Echo(string_view) ynoexcept(YF_Platform
使用标准输出流打印字符串并刷新。
YF_Platform
#define YF_Platform
目标平台。
Definition: Platform.h:231
ystdex::ytrace
void ytrace(std::FILE *, std::uint8_t, std::uint8_t, const char *, int, const char *,...)
YCLib 调试跟踪函数。
YF_TraceRaw
#define YF_TraceRaw(_lv,...)
YFramework 跟踪。
Definition: Debug.h:279
platform
默认平台命名空间。
Definition: Container.h:47
platform::size_t
YF_API size_t
Definition: FileIO.h:1353
platform::Logger::filter
Filter filter
Definition: Debug.h:110
CHRLib::f
f(d, s)
platform::bool
std::FILE *fp bool
Definition: FileIO.h:1280
platform::PDefH
const string const char *sig PDefH(string, ComposeMessageWithSignature, const char *msg, const char *sig) ImplRet(string(Nonnull(msg))+" @ "+Nonnull(sig)) template< class _type > inline YB_NONNULL(2) string ComposeMessageWithSignature(const _type &msg
YAssertNonnull
#define YAssertNonnull(_expr)
Definition: cassert.h:120
platform::Descriptions::Emergent
Definition: YCommon.h:163
platform::Logger::Sender
std::function< void(Level, Logger &, const char *)> Sender
Definition: Debug.h:100
platform::Logger::record_mutex
Concurrency::recursive_mutex record_mutex
日志记录锁。
Definition: Debug.h:120
TryRet
#define TryRet(...)
指定表达式在 try 块中求值并返回。
Definition: YBaseMacro.h:124
CHRLib::args
_tParams && args
Definition: CharacterProcessing.h:538
platform::containers::string
basic_string< char > string
Definition: Container.h:101
CatchIgnore
#define CatchIgnore(_ex)
指定异常处理器忽略指定异常。
Definition: YBaseMacro.h:133
ystdex::data
auto data(_tRange &c) -> decltype(c.data())
Definition: range.hpp:280
platform::Logger::SetSender
void SetSender(Sender)
设置发送器。
platform::ImplRet
const string const char *sig ImplRet(msg+" @ "+Nonnull(sig)) inline YB_NONNULL(1
platform::KeyCodes::DS::L
Definition: Keys.h:227
platform::Logger::DefaultFilter
static bool DefaultFilter(Level, Logger &) ynothrow
默认过滤：仅允许等级不大于阈值的日志被记录。
platform_ex::Windows::unsigned
YF_API unsigned
Definition: NLS.h:52
platform::Descriptions::RecordLevel
RecordLevel
记录等级。
Definition: YCommon.h:161
TryExpr
#define TryExpr(...)
指定表达式在 try 块中求值。
Definition: YBaseMacro.h:120
YSLib::level
YF_API size_t level
Definition: YException.h:142
platform::Logger::FetchDefaultSender
sv data())) private sv static data())) public Sender FetchDefaultSender(string_view="YFramework")
转发等级和异常对象至发送器。
CatchExpr
#define CatchExpr(_ex,...)
指定表达式作为异常处理器。
Definition: YBaseMacro.h:129
ystdex::get_this_thread_id
std::string get_this_thread_id()
取当前线程标识的字符串表示。
Definition: concurrency.h:78
CHRLib::s
_tDst const _tSrc * s
Definition: CharacterProcessing.h:140
platform::if
if(!p) p
ystdex::sfmt
auto sfmt(const _tChar *fmt,...) -> decltype(vsfmt(fmt, std::declval< std::va_list >()))
以 C 标准输出格式的输出 std::basic_string 实例的对象。
Definition: string.hpp:1200
platform::Descriptions::Critical
Definition: YCommon.h:165
platform::ynothrowv
YF_API int amode ynothrowv
Definition: FileIO.h:528
platform::YB_NONNULL
YB_NONNULL(2) PDefH(string
组合消息和函数签名字符串。
platform::Logger::DoLog
void DoLog(Level, const char *)
转发等级和日志至发送器。
YModules.h
concurrency.h
并发操作。
platform::Descriptions::Notice
Definition: YCommon.h:168
YF_Platform_DS
#define YF_Platform_DS
目标平台标识。
Definition: Platform.h:130
yunused
#define yunused(...)
标记未使用的表达式。
Definition: ydef.h:968
platform::LogWithSource
YF_API string LogWithSource(const char *, int, const char *,...) ynothrow
platform::Logger
日志记录器。
Definition: Debug.h:94
CHRLib::e
const char const char * e
Definition: CharacterProcessing.h:109
platform_ex::Windows::UTF8ToWCS
UTF8ToWCS
Definition: NLS.h:72
std
Definition: memory.hpp:1183
platform::Nonnull
_type && Nonnull(_type &&p) ynothrowv
断言并返回非空参数。
Definition: Debug.h:422
platform::FetchCommonLogger
YF_API Logger & FetchCommonLogger()
取公共日志记录器。
platform::terminate
YB_NORETURN YF_API void terminate() ynothrow
异常终止函数。
Definition: YCommon.cpp:47
platform_ex
平台扩展命名空间。
Definition: Android.h:45
YSLib::UI::name
yconstfn const string & name
Definition: Loader.h:130
YSLib::Text::str
const char const char * str
Definition: TextFile.h:81
yforward
#define yforward(_expr)
根据参数类型使用 std::forward 传递对应参数。
Definition: ydef.h:995
platform::Logger::Level
Descriptions::RecordLevel Level
Definition: Debug.h:97
ystdex::string_view
basic_string_view< char > string_view
Definition: string_view.hpp:415
ystdex::vsfmt
_tString vsfmt(const _tChar *fmt, std::va_list args)
以 C 标准输出格式的输出 std::basic_string 实例的对象。
Definition: string.hpp:1171
ynoexcept
#define ynoexcept(...)
YSLib 无异常抛出保证：指定特定的异常规范。
Definition: ydef.h:746
YSLib::lv
RecordLevel lv
Definition: YException.cpp:58
platform::ynothrow
const _tString &path ynothrow
Definition: YCLib/FileSystem.h:274