YSTest: Debug.cpp 源文件

YSTest PreAlpha_b700_20160611 The YSLib Test Project

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

- 文件列表
- 文件成员

Debug.cpp
浏览该文件的文档.
1 /*
2 © 2011-2015 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
30 #include YFM_YCLib_Input
31 #include YFM_YCLib_Video // for platform::ColorSpace, platform::YConsoleInit;
32 #if YCL_DS
33 # include YFM_DS_YCLib_DSVideo // for platform_ex::DSConsoleInit;
34 #elif YCL_Win32
35 # include <csignal>
36 # include YFM_YCLib_NativeAPI // for ::OutputDebugStringA, ::MessageBoxA;
37 #elif YCL_Android
38 # include <android/log.h>
39 #endif
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>
47
48 namespace platform
49 {
50
51 namespace
52 {
53
55 inline const char*
56 chk_null(const char* s)
57 {
58 return s && *s != char()? s : "<unknown>";
59 }
60
61 #if YF_Multithread == 1
62 std::string
64 FetchCurrentThreadID() ynothrow
65 {
66 TryRet(ystdex::get_this_thread_id())
67 // XXX: Nothing more can be done.
68 CatchIgnore(...)
69 return {};
70 }
71 #endif
72
73 #if YCL_Android
74 template<typename... _tParams>
76 inline int
77 PrintAndroidLog(Descriptions::RecordLevel lv, const char* tag, const char *fmt,
78 _tParams&&... args)
79 {
80 return ::__android_log_print(platform_ex::MapAndroidLogLevel(lv),
81 Nonnull(tag), Nonnull(fmt), yforward(args)...);
82 }
83 #endif
84
86 using namespace Concurrency;
87
88 } // unnamed namespace;
89
90
91 void
92 Logger::SetFilter(Filter f)
93 {
94 if(f)
95 filter = std::move(f);
96 }
97 void
98 Logger::SetSender(Sender s)
99 {
100 if(s)
101 sender = std::move(s);
102 }
103
104 bool
105 Logger::DefaultFilter(Level lv, Logger& logger) ynothrow
106 {
107 return lv <= logger.FilterLevel;
108 }
109
110 void
111 Logger::DefaultSendLog(Level lv, Logger& logger, const char* str) ynothrowv
112 {
113 #if YCL_DS
114 yunused(lv), yunused(logger), yunused(str);
115 #else
116 SendLog(std::cerr, lv, logger, str);
117 #endif
118 }
119
120 void
121 Logger::DefaultSendLogToFile(Level lv, Logger& logger, const char* str)
122 ynothrowv
123 {
124 SendLogToFile(stderr, lv, logger, str);
125 }
126
127 void
128 Logger::DoLog(Level level, const char* str)
129 {
130 if(str)
131 {
132 lock_guard<recursive_mutex> lck(record_mutex);
133
134 DoLogRaw(level, str);
135 }
136 }
137
138 void
139 Logger::DoLogRaw(Level level, const char* str)
140 {
141 sender(level, *this, Nonnull(str));
142 }
143
144 void
145 Logger::DoLogException(Level lv, const std::exception& e) ynothrow
146 {
147 const auto do_log_excetpion_raw([this](const char* msg) YB_NONNULL(1)
148 ynothrow{
149 try
150 {
151 DoLogRaw(Descriptions::Emergent,
152 "Another exception thrown when handling exception.");
153 DoLogRaw(Descriptions::Emergent, msg);
154 }
155 CatchExpr(...,
156 ystdex::ytrace(stderr, Descriptions::Emergent, Descriptions::Notice,
157 __FILE__, __LINE__, "Logging error: unhandled exception."))
158 });
159 const auto& msg(e.what());
160 lock_guard<recursive_mutex> lck(record_mutex);
161
162 try
163 {
164 // XXX: Provide no throw guarantee and put it out of the critical
165 // section?
166 // XXX: Log demangled type name.
167 DoLogRaw(lv, sfmt("<%s>: %s", typeid(e).name(), msg));
168 }
169 CatchExpr(std::exception& ex, do_log_excetpion_raw(ex.what()))
170 CatchExpr(..., do_log_excetpion_raw({}))
171 }
172
173 Logger::Sender
174 Logger::FetchDefaultSender(string_view tag)
175 {
176 YAssertNonnull(tag.data());
177 #if YCL_Android
178 return platform_ex::AndroidLogSender(tag);
179 #else
180 return DefaultSendLog;
181 #endif
182 }
183
184 void
185 Logger::SendLog(std::ostream& os, Level lv, Logger&, const char* str)
186 ynothrowv
187 {
188 try
189 {
190 #if YF_Multithread == 1
191 const auto& t_id(FetchCurrentThreadID());
192
193 if(!t_id.empty())
194 os << ystdex::sfmt("[%s:%#X]: %s\n", t_id.c_str(), unsigned(lv),
195 Nonnull(str));
196 else
197 #endif
198 os << ystdex::sfmt("[%#X]: %s\n", unsigned(lv), Nonnull(str));
199 os.flush();
200 }
201 CatchIgnore(...)
202 }
203
204 void
205 Logger::SendLogToFile(std::FILE* stream, Level lv, Logger&, const char* str)
206 ynothrowv
207 {
208 YAssertNonnull(stream);
209 #if YF_Multithread == 1
210 const auto& t_id(FetchCurrentThreadID());
211
212 if(!t_id.empty())
213 std::fprintf(stream, "[%s:%#X]: %s\n", t_id.c_str(), unsigned(lv),
214 Nonnull(str));
215 else
216 #endif
217 std::fprintf(stream, "[%#X]: %s\n", unsigned(lv), Nonnull(str));
218 std::fflush(stream);
219 }
220
221
222 Logger&
223 FetchCommonLogger()
224 {
225 static Logger logger;
226
227 return logger;
228 }
229
230
231 string
232 LogWithSource(const char* file, int line, const char* fmt, ...) ynothrow
233 {
234 try
235 {
236 std::va_list args;
237
238 va_start(args, fmt);
239
240 string str(vsfmt(fmt, args));
241
242 va_end(args);
243 return sfmt("\"%s\":%i:\n", chk_null(file), line) + std::move(str);
244 }
245 CatchExpr(...,
246 ystdex::ytrace(stderr, Descriptions::Emergent, Descriptions::Notice,
247 chk_null(file), line, "LogWithSource error: unhandled exception."))
248 return {};
249 }
250
251 } // namespace platform;
252
253 using namespace platform;
254
255 namespace platform_ex
256 {
257
258 #if YF_Multithread == 1
259 void
260 LogAssert(const char* expr_str, const char* file, int line,
261 const char* msg) ynothrow
262 {
263 # if YCL_Android
264 ::__android_log_assert(expr_str, "YFramework",
265 "Assertion failed @ \"%s\":%i:\n %s .\nMessage: \n%s\n", file, line,
266 expr_str, msg);
267 # else
268 # if YCL_Win32
269 try
270 {
271 char prog[MAX_PATH]{"<unknown>"};
272
273 ::GetModuleFileNameA({}, prog, MAX_PATH);
274
275 const auto& errstr(sfmt("Assertion failed @ program %s: "
276 "\"%s\":%i:\n %s .\nMessage: \n%s\n", prog, chk_null(file),
277 line, chk_null(expr_str), chk_null(msg)));
278
279 ::OutputDebugStringA(errstr.c_str());
280 // XXX: Not safe in windows procedure, but not used in YFramework.
281 // TODO: Use custom windows creation?
282 switch(::MessageBoxA({}, errstr.c_str(),
283 "YCLib Runtime Assertion", MB_ABORTRETRYIGNORE | MB_ICONHAND
284 | MB_SETFOREGROUND | MB_TASKMODAL))
285 {
286 case IDIGNORE:
287 return;
288 case IDABORT:
289 std::raise(SIGABRT);
290 default:
291 break;
292 }
293 std::terminate();
294 }
295 catch(...)
296 {
297 YCL_TraceRaw(Descriptions::Emergent, "Unknown exception found.");
298 ystdex::yassert(expr_str, file, line, msg);
299 }
300 # endif
301 TryExpr(FetchCommonLogger().AccessRecord([=]{
302 ystdex::yassert(expr_str, file, line, msg);
303 }))
304 catch(...)
305 {
306 std::fprintf(stderr, "Fetch logger failed.");
307 std::fflush(stderr);
308 ystdex::yassert(expr_str, file, line, msg);
309 }
310 # endif
311 }
312 #endif
313
314
315 #if YCL_Win32
316 void
317 SendDebugString(Logger::Level lv, Logger&, const char* str) ynothrowv
318 {
319 try
320 {
321 const auto& t_id(FetchCurrentThreadID());
322
323 // TODO: Use %::WaitForDebugEventEx if possible. See https://msdn.microsoft.com/en-us/library/windows/desktop/mt171594(v=vs.85).aspx.
324 ::OutputDebugStringA((!t_id.empty() ? ystdex::sfmt("[%s:%#X]: %s",
325 t_id.c_str(), unsigned(lv), Nonnull(str)) : ystdex::sfmt(
326 "[%#X]: %s", unsigned(lv), Nonnull(str))).c_str());
327 }
328 CatchIgnore(...)
329 }
330 #elif YCL_Android
331 int
332 MapAndroidLogLevel(Descriptions::RecordLevel lv)
333 {
334 return lv < Descriptions::Critical ? ANDROID_LOG_FATAL
335 : ANDROID_LOG_FATAL - (std::uint8_t(lv) - 0x40) / 0x20;
336 }
337
338
339 AndroidLogSender::AndroidLogSender(string_view sv)
340 : tag((Nonnull(sv.data()), sv))
341 {}
342 AndroidLogSender::~AndroidLogSender()
343 {}
344
345 void
346 AndroidLogSender::operator()(Level lv, Logger& logger, const char* str) const
347 {
348 Logger::DefaultSendLog(lv, logger, str);
349 if(lv < Descriptions::Critical)
350 ::__android_log_assert("", "YFramework", "[%#X]: %s\n",
351 unsigned(lv), str);
352 else
353 PrintAndroidLog(lv, tag.c_str(), "[%#X]: %s\n", unsigned(lv), str);
354 }
355
356 #endif
357
358 } // namespace platform_ex;
359
YSLib::lv
RecordLevel lv
Definition: YException.cpp:58
ystdex::sfmt
auto sfmt(const _tChar *fmt,...) -> decltype(vsfmt(fmt, std::declval< std::va_list >()))
以 C 标准输出格式的输出 std::basic_string 实例的对象。
Definition: string.hpp:1140
ystdex::string_view
basic_string_view< char > string_view
Definition: string_view.hpp:415
platform::containers::string
basic_string< char > string
Definition: Container.h:101
platform::Nonnull
_type && Nonnull(_type &&p) ynothrow
断言并返回非空指针。
Definition: Debug.h:411
ystdex::ytrace
void ytrace(std::FILE *, std::uint8_t, std::uint8_t, const char *, int, const char *,...)
YCLib 调试跟踪函数。
NPL::A1::name
ctx const string & name
Definition: NPLA1.h:248
CHRLib::e
const char const char * e
Definition: CharacterProcessing.h:109
platform::Logger::SetSender
void SetSender(Sender)
设置发送器。
Definition: Debug.cpp:98
CatchExpr
#define CatchExpr(_ex,...)
指定表达式作为异常处理器。
Definition: YBaseMacro.h:129
yunused
#define yunused(...)
标记未使用的表达式。
Definition: ydef.h:942
ystdex::data
auto data(_tRange &c) -> decltype(c.data())
Definition: range.hpp:280
platform::Descriptions::Emergent
Definition: YCommon.h:153
ystdex::yassert
void yassert(const char *, const char *, int, const char *)
YBase 默认断言函数。
Definition: cassert.cpp:36
platform::LogWithSource
YF_API string LogWithSource(const char *, int, const char *,...) ynothrow
Definition: Debug.cpp:232
CatchIgnore
#define CatchIgnore(_ex)
指定异常处理器忽略指定异常。
Definition: YBaseMacro.h:133
platform_ex::Windows::unsigned
YF_API unsigned
Definition: MinGW32.h:630
platform::Logger::FetchDefaultSender
sv data())) private sv static data())) public Sender FetchDefaultSender(string_view="YFramework")
转发等级和异常对象至发送器。
Definition: Debug.cpp:174
platform
默认平台命名空间。
Definition: Container.h:47
platform::FetchCommonLogger
YF_API Logger & FetchCommonLogger()
取公共日志记录器。
Definition: Debug.cpp:223
platform::Logger::Sender
std::function< void(Level, Logger &, const char *)> Sender
Definition: Debug.h:92
YAssertNonnull
#define YAssertNonnull(_expr)
Definition: cassert.h:114
TryExpr
#define TryExpr(...)
指定表达式在 try 块中求值。
Definition: YBaseMacro.h:120
platform::ynothrow
const _tString &path ynothrow
Definition: YCLib/FileSystem.h:303
platform_ex
平台扩展命名空间。
Definition: Android.h:45
platform::Logger::filter
Filter filter
Definition: Debug.h:102
YCL_TraceRaw
#define YCL_TraceRaw(_lv,...)
YCLib 直接调试跟踪。
Definition: Debug.h:271
concurrency.h
并发操作。
YSLib::Text::str
const char const char * str
Definition: TextFile.h:77
TryRet
#define TryRet(...)
指定表达式在 try 块中求值并返回。
Definition: YBaseMacro.h:124
platform::Descriptions::Critical
Definition: YCommon.h:155
platform::Logger
日志记录器。
Definition: Debug.h:86
platform::Logger::DoLog
void DoLog(Level, const char *)
转发等级和日志至发送器。
Definition: Debug.cpp:128
YModules.h
ystdex::vsfmt
_tString vsfmt(const _tChar *fmt, std::va_list args)
以 C 标准输出格式的输出 std::basic_string 实例的对象。
Definition: string.hpp:1111
ystdex::get_this_thread_id
std::string get_this_thread_id()
取当前线程标识的字符串表示。
Definition: concurrency.h:79
ystdex::single_thread::lock_guard
Definition: pseudo_mutex.h:197
YSLib::level
YF_API size_t level
Definition: YException.h:141
platform::YB_NONNULL
YF_API YB_NONNULL(1) int uaccess(const char *path
测试路径可访问性。
Definition: YCLib/FileSystem.h:144
platform::terminate
YB_NORETURN YF_API void terminate() ynothrow
异常终止函数。
Definition: YCommon.cpp:42
yforward
#define yforward(_expr)
根据参数类型使用 std::forward 传递对应参数。
Definition: ydef.h:969
platform::ynothrowv
YF_API int amode ynothrowv
Definition: FileIO.h:491
platform::Descriptions::RecordLevel
RecordLevel
记录等级。
Definition: YCommon.h:151
YSLib::char
char
Definition: ValueNode.h:851
YSLib::IO::f
const string &path const String &path _func f
Definition: YSLib/Service/FileSystem.h:430
CHRLib::args
_tParams && args
Definition: CharacterProcessing.h:538
platform::Logger::DefaultFilter
static bool DefaultFilter(Level, Logger &) ynothrow
默认过滤：仅允许等级不大于阈值的日志被记录。
Definition: Debug.cpp:105
platform::Descriptions::Notice
Definition: YCommon.h:158
CHRLib::s
_tDst const _tSrc * s
Definition: CharacterProcessing.h:140
platform::Logger::sender
Sender sender
Definition: Debug.h:104
platform::Logger::record_mutex
Concurrency::recursive_mutex record_mutex
日志记录锁。
Definition: Debug.h:112