137 #include "util/stacktrace.h"
157 #include "TargetConditionals.h"
161 #include <mach-o/dyld.h>
165 #define LOG_DEQUE_SIZE 1024
171 #include <sys/timeb.h>
174 LONG Win32FaultHandler(
struct _EXCEPTION_POINTERS* ExInfo);
175 void LogStackFrames(
void* FaultAdress,
char*);
177 #else // else if NOT _WIN32
190 #if defined(__APPLE__)
191 #ifndef _XOPEN_SOURCE
192 #define _XOPEN_SOURCE 600
200 #endif // defined __APPLE__
204 #ifndef ucontext_h_seen
205 #define ucontext_h_seen
207 #include <asm/sigcontext.h>
208 #include <asm/signal.h>
210 typedef struct ucontext
213 struct ucontext* uc_link;
215 struct sigcontext uc_mcontext;
219 #endif // ucontext_h_seen
223 #include <ucontext.h>
225 #include <execinfo.h>
228 #include <sys/resource.h>
234 #include <sys/stat.h>
238 #include <android/log.h>
241 #define LOGFILE_PRE "log-"
242 #define LOGFILE_EXT ".log"
243 #define GLOBAL_LOGNAME "init"
244 #define GLOBAL_LOGFILE "init.log"
251 OTLog* OTLog::pLogger =
nullptr;
254 const OTString OTLog::m_strPathSeparator =
"/";
266 , logLevel(_logLevel)
268 , pBuffer(new char[1024])
281 if (c !=
'\n' && next < 1000) {
285 pBuffer[next++] =
'\0';
302 if (
nullptr == pLogger) {
303 pLogger =
new OTLog();
304 pLogger->m_bInitialized =
false;
309 if (!pLogger->m_bInitialized) {
310 pLogger->logDeque = std::deque<OTString*>();
311 pLogger->m_strThreadContext = strThreadContext;
313 pLogger->m_nLogLevel = nLogLevel;
315 if (!strThreadContext.
Exists() ||
323 pLogger->m_strLogFileName.
Format(
329 if (!config.Load()) {
335 pLogger->m_strLogFileName,
336 pLogger->m_strLogFileName, bIsNew)) {
340 if (!config.Save()) {
351 pLogger->m_strLogFileName)) {
355 pLogger->m_bInitialized =
true;
361 pLogAssert =
nullptr;
373 return nullptr != pLogger && pLogger->m_bInitialized;
379 if (
nullptr != pLogger) {
388 bool OTLog::CheckLogger(
OTLog* pLogger)
390 if (
nullptr != pLogger && pLogger->m_bInitialized)
return true;
414 return m_strPathSeparator;
421 return pLogger->m_strThreadContext;
430 return pLogger->m_strLogFilePath;
436 if (
nullptr != pLogger)
437 return pLogger->m_nLogLevel;
445 if (
nullptr == pLogger) {
449 pLogger->m_nLogLevel = nLogLevel;
466 std::cerr << strOutput;
472 bool bHaveLogger(
false);
473 if (
nullptr != pLogger)
477 if (bHaveLogger) CheckLogger(OTLog::pLogger);
479 bool bSuccess =
false;
483 if ((strOutput.
Exists()) &&
484 (OTLog::pLogger->m_strLogFilePath.
Exists())) {
485 std::ofstream logfile;
488 if (!logfile.fail()) {
489 logfile << strOutput;
502 CheckLogger(OTLog::pLogger);
504 uint32_t uIndex =
static_cast<uint32_t
>(nIndex);
506 if ((nIndex < 0) || (uIndex >= OTLog::pLogger->logDeque.size())) {
507 otErr << __FUNCTION__ <<
": index out of bounds: " << nIndex <<
"\n";
511 if (
nullptr != OTLog::pLogger->logDeque.at(uIndex))
516 const OTString strLogEntry = *OTLog::pLogger->logDeque.at(uIndex);
529 CheckLogger(OTLog::pLogger);
531 return static_cast<int32_t
>(OTLog::pLogger->logDeque.size());
537 CheckLogger(OTLog::pLogger);
539 if (OTLog::pLogger->logDeque.size() <= 0)
return nullptr;
541 if (
nullptr != OTLog::pLogger->logDeque.front())
546 const OTString strLogEntry = *OTLog::pLogger->logDeque.front();
557 CheckLogger(OTLog::pLogger);
559 if (OTLog::pLogger->logDeque.size() <= 0)
return nullptr;
561 if (
nullptr != OTLog::pLogger->logDeque.back())
566 const OTString strLogEntry = *OTLog::pLogger->logDeque.back();
578 CheckLogger(OTLog::pLogger);
580 if (OTLog::pLogger->logDeque.size() <= 0)
return false;
582 OTString* strLogFront = OTLog::pLogger->logDeque.front();
583 if (
nullptr != strLogFront)
delete strLogFront;
584 strLogFront =
nullptr;
586 OTLog::pLogger->logDeque.pop_front();
595 CheckLogger(OTLog::pLogger);
597 if (OTLog::pLogger->logDeque.size() <= 0)
return false;
599 OTString* strLogBack = OTLog::pLogger->logDeque.back();
600 if (
nullptr != strLogBack)
delete strLogBack;
601 strLogBack =
nullptr;
603 OTLog::pLogger->logDeque.pop_back();
612 CheckLogger(OTLog::pLogger);
616 OTLog::pLogger->logDeque.push_front(
new OTString(strLog));
630 CheckLogger(OTLog::pLogger);
634 OTLog::pLogger->logDeque.push_back(
new OTString(strLog));
643 Sleep(static_cast<DWORD>(1000 * lSeconds));
654 Sleep(static_cast<DWORD>(lMilliseconds));
656 usleep(lMilliseconds * 1000);
665 size_t OTLog::logAssert(
const char* szFilename,
size_t nLinenumber,
666 const char* szMessage)
668 if (
nullptr != szMessage) {
669 #ifndef ANDROID // if NOT android
670 std::cerr << szMessage <<
"\n";
676 __android_log_write(ANDROID_LOG_FATAL,
"OT Assert (or Fail)",
683 if ((
nullptr != szFilename)) {
684 #ifndef ANDROID // if NOT android
689 strTemp.Format(
"\nOT_ASSERT in %s at line %d\n", szFilename,
694 OTString strAndroidAssertMsg;
695 strAndroidAssertMsg.Format(
"\nOT_ASSERT in %s at line %d\n", szFilename,
697 __android_log_write(ANDROID_LOG_FATAL,
"OT Assert",
698 (
const char*)strAndroidAssertMsg.Get());
712 bool bHaveLogger(
false);
713 if (
nullptr != pLogger)
717 if (bHaveLogger) CheckLogger(OTLog::pLogger);
722 if ((nVerbosity >
LogLevel()) || (
nullptr == szOutput) ||
729 #ifndef ANDROID // if NOT android
733 #else // if IS Android
747 switch (nVerbosity) {
750 __android_log_write(ANDROID_LOG_INFO,
"OT Output", szOutput);
754 __android_log_write(ANDROID_LOG_DEBUG,
"OT Debug", szOutput);
758 __android_log_write(ANDROID_LOG_VERBOSE,
"OT Verbose", szOutput);
761 __android_log_write(ANDROID_LOG_UNKNOWN,
"OT Unknown", szOutput);
770 bool bHaveLogger(
false);
771 if (
nullptr != pLogger)
775 if (bHaveLogger) CheckLogger(OTLog::pLogger);
780 (
nullptr == szOutput))
784 va_start(args, szOutput);
786 std::string strOutput;
802 bool bHaveLogger(
false);
803 if (
nullptr != pLogger)
807 if (bHaveLogger) CheckLogger(OTLog::pLogger);
809 if ((
nullptr == szError))
return;
812 va_start(args, szError);
814 std::string strOutput;
833 bool bHaveLogger(
false);
834 if (
nullptr != pLogger)
838 if (bHaveLogger) CheckLogger(OTLog::pLogger);
840 if ((
nullptr == szError))
return;
845 #ifndef ANDROID // if NOT android
850 __android_log_write(ANDROID_LOG_ERROR,
"OT Error", szError);
861 bool bHaveLogger(
false);
862 if (
nullptr != pLogger)
866 if (bHaveLogger) CheckLogger(OTLog::pLogger);
868 const int32_t errnum = errno;
873 char* szErrString =
nullptr;
878 #if defined(_GNU_SOURCE) && defined(__linux__) && !defined(ANDROID)
879 szErrString = strerror_r(errnum, buf, 127);
880 #elif(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600)
881 nstrerr = strerror_r(errnum, buf,
885 const char* szFunc =
"OTLog::Errno";
886 const char* sz_location = (
nullptr == szLocation) ?
"" : szLocation;
888 if (
nullptr == szErrString) szErrString = buf;
891 otErr << szFunc <<
" " << sz_location <<
": errno " << errnum <<
": "
892 << (szErrString[0] !=
'\0' ? szErrString :
"") <<
".\n";
894 otErr << szFunc <<
" " << sz_location <<
": errno: " << errnum
895 <<
". (Unable to retrieve error string for that number.)\n";
901 int32_t iLength,
const char* szAppend)
903 std::string strString(szString);
905 if (
nullptr != szAppend) strString.append(szAppend);
907 for (; (
static_cast<int32_t
>(strString.length()) < iLength);
908 strString.append(
" "))
911 out_strString.
Set(strString.c_str());
931 #pragma warning(push)
932 #pragma warning(disable : 4800) // warning C4800: forcing constant value.
936 static const bool SET_TERMINATE = std::set_terminate(
ot_terminate);
946 if (
auto e = std::current_exception()) {
948 std::rethrow_exception(e);
950 catch (
const std::exception& e) {
951 std::cerr <<
"ot_terminate: " << __FUNCTION__
952 <<
" caught unhandled exception."
953 <<
" type: " <<
typeid(e).name()
954 <<
" what(): " << e.what() << std::endl;
957 std::cerr <<
"ot_terminate: " << __FUNCTION__
958 <<
" caught unknown/unhandled exception." << std::endl;
968 #ifdef _WIN32 // Windows SIGNALS
979 static int32_t nCount = 0;
983 SetUnhandledExceptionFilter(
984 (LPTOP_LEVEL_EXCEPTION_FILTER)Win32FaultHandler);
988 #else // if _WIN32, else: UNIX -- SIGNALS
1008 void crit_err_hdlr(int32_t sig_num, siginfo_t* info,
void* ucontext);
1011 #if defined(OT_NO_DEMANGLING_STACK_TRACE)
1014 void crit_err_hdlr(int32_t sig_num, siginfo_t* info,
void* ucontext)
1017 void* caller_address;
1022 static std::mutex the_Mutex;
1024 std::lock_guard<std::mutex> lock(the_Mutex);
1026 uc =
static_cast<sig_ucontext_t*
>(ucontext);
1029 caller_address = (
void*)uc->uc_mcontext.eip;
1031 fprintf(stderr,
"signal %d (%s), address is %p from %p\n", sig_num,
1032 strsignal(sig_num), info->si_addr, (
void*)caller_address);
1034 size = backtrace(array, 50);
1038 array[1] = caller_address;
1040 messages = backtrace_symbols(array, size);
1044 for (i = 1; i < size && messages !=
nullptr; ++i) {
1045 fprintf(stderr,
"[bt]: (%d) %s\n", i, messages[i]);
1053 #else // #if no demangling, #else...
1144 static std::mutex the_Mutex;
1146 std::lock_guard<std::mutex> lock(the_Mutex);
1151 typedef uint64_t ot_ulong;
1153 typedef uint32_t ot_ulong;
1157 ucontext_t* uc = (ucontext_t*)v;
1159 #if defined(__APPLE__)
1161 _STRUCT_MCONTEXT* mc;
1163 mc = uc->uc_mcontext;
1167 mc = uc->uc_mcontext;
1169 eip = mc->__ss.__rip;
1171 eip = mc->__ss.__eip;
1174 #elif defined(__linux__)
1176 struct sigcontext* ctx;
1177 mc = &uc->uc_mcontext;
1178 ctx = (
struct sigcontext*)mc;
1184 #elif defined(__FreeBSD__)
1186 mc = &uc->uc_mcontext;
1189 #elif defined(__amd64__)
1192 ot_ulong addr = (ot_ulong)info->si_addr;
1193 if (__FreeBSD__ < 7) {
1211 r = mincore((
void*)addr, 1, &vec);
1214 if (r < 0 || vec == 0)
1220 #error "Unknown OS in sigsegv"
1223 void* caller_address = (
void*)eip;
1225 std::cerr <<
"signal " << sig_num <<
" (" << strsignal(sig_num)
1226 <<
"), address is " << info->si_addr <<
" from " << caller_address
1227 << std::endl << std::endl;
1230 int32_t size = backtrace(array, 50);
1232 array[1] = caller_address;
1234 char** messages = backtrace_symbols(array, size);
1237 for (int32_t i = 1; i < size && messages !=
nullptr; ++i) {
1238 char* mangled_name = 0, *offset_begin = 0, *offset_end = 0;
1241 for (
char* p = messages[i]; *p; ++p) {
1245 else if (*p ==
'+') {
1248 else if (*p ==
')') {
1255 if (mangled_name && offset_begin && offset_end &&
1256 mangled_name < offset_begin) {
1257 *mangled_name++ =
'\0';
1258 *offset_begin++ =
'\0';
1259 *offset_end++ =
'\0';
1262 char* real_name = abi::__cxa_demangle(mangled_name, 0, 0, &status);
1266 std::cerr <<
"[bt]: (" << i <<
") " << messages[i] <<
" : "
1267 << real_name <<
"+" << offset_begin << offset_end
1273 std::cerr <<
"[bt]: (" << i <<
") " << messages[i] <<
" : "
1274 << mangled_name <<
"+" << offset_begin << offset_end
1281 std::cerr <<
"[bt]: (" << i <<
") " << messages[i] << std::endl;
1284 std::cerr << std::endl;
1287 #endif // #ifndef ANDROID
1291 #endif // defined(OT_NO_DEMANGLING_STACK_TRACE)
1293 #ifndef OT_HANDLE_SIGNAL
1294 #define OT_HANDLE_SIGNAL(OT_SIGNAL_TYPE) \
1296 struct sigaction new_action, old_action; \
1297 new_action.sa_sigaction = crit_err_hdlr; \
1298 sigemptyset(&new_action.sa_mask); \
1299 new_action.sa_flags = SA_RESTART | SA_SIGINFO; \
1301 sigaction(OT_SIGNAL_TYPE, nullptr, &old_action); \
1303 if (old_action.sa_handler != SIG_IGN) { \
1304 if (sigaction(OT_SIGNAL_TYPE, &new_action, nullptr) != 0) { \
1305 otErr << "OTLog::SetupSignalHandler: Failed setting signal " \
1306 "handler for error " << OT_SIGNAL_TYPE << " (" \
1307 << strsignal(OT_SIGNAL_TYPE) << ")\n"; \
1317 static int32_t nCount = 0;
1356 #endif // #if windows, #else (unix) #endif. (SIGNAL handling.)
1360 #ifdef _WIN32 // Windows SIGNALS
1362 LONG Win32FaultHandler(
struct _EXCEPTION_POINTERS* ExInfo)
1366 switch (ExInfo->ExceptionRecord->ExceptionCode) {
1367 case EXCEPTION_ACCESS_VIOLATION:
1368 FaultTx =
"ACCESS VIOLATION";
1370 case EXCEPTION_DATATYPE_MISALIGNMENT:
1371 FaultTx =
"DATATYPE MISALIGNMENT";
1373 case EXCEPTION_BREAKPOINT:
1374 FaultTx =
"BREAKPOINT";
1376 case EXCEPTION_SINGLE_STEP:
1377 FaultTx =
"SINGLE STEP";
1379 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
1380 FaultTx =
"ARRAY BOUNDS EXCEEDED";
1382 case EXCEPTION_FLT_DENORMAL_OPERAND:
1383 FaultTx =
"FLT DENORMAL OPERAND";
1385 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
1386 FaultTx =
"FLT DIVIDE BY ZERO";
1388 case EXCEPTION_FLT_INEXACT_RESULT:
1389 FaultTx =
"FLT INEXACT RESULT";
1391 case EXCEPTION_FLT_INVALID_OPERATION:
1392 FaultTx =
"FLT INVALID OPERATION";
1394 case EXCEPTION_FLT_OVERFLOW:
1395 FaultTx =
"FLT OVERFLOW";
1397 case EXCEPTION_FLT_STACK_CHECK:
1398 FaultTx =
"FLT STACK CHECK";
1400 case EXCEPTION_FLT_UNDERFLOW:
1401 FaultTx =
"FLT UNDERFLOW";
1403 case EXCEPTION_INT_DIVIDE_BY_ZERO:
1404 FaultTx =
"INT DIVIDE BY ZERO";
1406 case EXCEPTION_INT_OVERFLOW:
1407 FaultTx =
"INT OVERFLOW";
1409 case EXCEPTION_PRIV_INSTRUCTION:
1410 FaultTx =
"PRIV INSTRUCTION";
1412 case EXCEPTION_IN_PAGE_ERROR:
1413 FaultTx =
"IN PAGE ERROR";
1415 case EXCEPTION_ILLEGAL_INSTRUCTION:
1416 FaultTx =
"ILLEGAL INSTRUCTION";
1418 case EXCEPTION_NONCONTINUABLE_EXCEPTION:
1419 FaultTx =
"NONCONTINUABLE EXCEPTION";
1421 case EXCEPTION_STACK_OVERFLOW:
1422 FaultTx =
"STACK OVERFLOW";
1424 case EXCEPTION_INVALID_DISPOSITION:
1425 FaultTx =
"INVALID DISPOSITION";
1427 case EXCEPTION_GUARD_PAGE:
1428 FaultTx =
"GUARD PAGE";
1431 FaultTx =
"(unknown)";
1434 int32_t wsFault = ExInfo->ExceptionRecord->ExceptionCode;
1435 void* CodeAdress = ExInfo->ExceptionRecord->ExceptionAddress;
1440 if (stderr !=
nullptr) {
1442 "****************************************************\n");
1443 fprintf(stderr,
"*** A Programm Fault occured:\n");
1444 fprintf(stderr,
"*** Error code %08X: %s\n", wsFault, FaultTx);
1446 "****************************************************\n");
1447 fprintf(stderr,
"*** Address: %08X\n", (int32_t)CodeAdress);
1448 fprintf(stderr,
"*** Flags: %08X\n",
1449 ExInfo->ExceptionRecord->ExceptionFlags);
1451 #if defined(_CONSOLE)
1453 printf(
"*** A Programm Fault occured:\n");
1454 printf(
"*** Error code %08X: %s\n", wsFault, FaultTx);
1469 LogStackFrames(CodeAdress, (
char*)ExInfo->ContextRecord->Ebp);
1486 printf(
"*** Terminating\n");
1488 return EXCEPTION_EXECUTE_HANDLER;
1494 void LogStackFrames(
void* FaultAdress,
char* eNextBP)
1499 typedef USHORT(WINAPI * CaptureStackBackTraceType)(
1500 __in ULONG, __in ULONG, __out PVOID*, __out_opt PULONG);
1502 HMODULE lLoadedLib = LoadLibrary(L
"kernel32.dll");
1503 if (
nullptr == lLoadedLib)
OT_FAIL;
1504 CaptureStackBackTraceType func = (CaptureStackBackTraceType)(
1505 GetProcAddress(lLoadedLib,
"RtlCaptureStackBackTrace"));
1507 if (func ==
nullptr)
return;
1513 const int32_t kMaxCallers = 62;
1515 void* callers[kMaxCallers];
1516 int32_t count = (func)(0, kMaxCallers, callers,
nullptr);
1517 for (int32_t i = 0; i < count; i++)
1518 fprintf(stderr,
"*** %d called from %p\n", i, callers[i]);
1520 #elif defined(_WIN32) // not _WIN64 ? Must be _WIN32
1522 char* pBP =
nullptr;
1523 uint32_t i = 0, x = 0, BpPassed = 0;
1524 static int32_t CurrentlyInTheStackDump = 0;
1526 if (CurrentlyInTheStackDump) {
1527 fprintf(stderr,
"\n***\n*** Recursive Stack Dump skipped\n***\n");
1531 fprintf(stderr,
"****************************************************\n");
1532 fprintf(stderr,
"*** CallStack:\n");
1533 fprintf(stderr,
"****************************************************\n");
1549 CurrentlyInTheStackDump = 1;
1551 BpPassed = (eNextBP !=
nullptr);
1554 _asm mov eNextBP, eBp
1557 fprintf(stderr,
"\n Fault Occured At $ADDRESS:%08LX\n",
1558 (int32_t)FaultAdress);
1561 for (i = 0; eNextBP && i < 100; i++) {
1563 eNextBP = *(
char**)pBP;
1568 fprintf(stderr,
" with ");
1569 for (x = 0; p < eNextBP && x < 20; p++, x++)
1570 fprintf(stderr,
"%02X ", *(uint8_t*)p);
1572 fprintf(stderr,
"\n\n");
1574 if (i == 1 && !BpPassed)
1576 "****************************************************\n"
1577 " Fault Occured Here:\n");
1580 fprintf(stderr,
"*** %2d called from $ADDRESS:%08X\n", i,
1581 *(
char**)(pBP + 4));
1583 if (*(
char**)(pBP + 4) ==
nullptr)
break;
1587 "************************************************************\n");
1588 fprintf(stderr,
"\n\n");
1590 CurrentlyInTheStackDump = 0;
1593 #endif // _WIN64 else (_WIN32) endif
static EXPORT void vError(const char *szError,...)
OTLOG_IMPORT OTLogStream otLog4
virtual int overflow(int c)
struct sigcontext uc_mcontext
static EXPORT void Output(int32_t nVerbosity, const char *szOutput)
static EXPORT const OTString & GetVersion()
static EXPORT const OTString & GetThreadContext()
static EXPORT bool PopMemlogBack()
static EXPORT bool LogToFile(const OTString &strOutput)
static EXPORT const char * PathSeparator()
static EXPORT bool SetLogLevel(const int32_t &nLogLevel)
static EXPORT OTString GetMemlogAtIndex(int32_t nIndex)
OTLOG_IMPORT OTLogStream otOut
OTLOG_IMPORT OTLogStream otLog3
#define OT_HANDLE_SIGNAL(OT_SIGNAL_TYPE)
static EXPORT int32_t GetMemlogSize()
EXPORT bool Exists() const
static EXPORT void Error(const char *szError)
static EXPORT bool PopMemlogFront()
static Assert * s_pAssert
static EXPORT const OTString & AppDataFolder()
EXPORT void Format(const char *fmt,...)
static EXPORT bool Init(const OTString &strThreadContext="", const int32_t &nLogLevel=0)
static EXPORT const char * Version()
EXPORT bool Compare(const char *compare) const
static EXPORT void SetupSignalHandler()
EXPORT void Set(const char *data, uint32_t enforcedMaxLength=0)
OTLogStream(int _logLevel)
static EXPORT const char * LogFilePath()
static EXPORT OTString PeekMemlogBack()
static EXPORT bool Cleanup()
#define OPENTXS_VERSION_STRING
static EXPORT bool IsInitialized()
static EXPORT bool PushMemlogBack(const OTString &strLog)
struct ucontext * uc_link
OTLOG_IMPORT OTLogStream otInfo
static EXPORT bool SleepMilliseconds(int64_t lMilliseconds)
static EXPORT bool SleepSeconds(int64_t lSeconds)
static EXPORT int32_t LogLevel()
EXPORT bool CheckSet_str(const OTString &strSection, const OTString &strKey, const OTString &strDefault, OTString &out_strResult, bool &out_bIsNew, const OTString &strComment="")
OTLOG_IMPORT OTLogStream otWarn
EXPORT const char * Get() const
OTLOG_IMPORT OTLogStream otErr
static EXPORT const OTString & GetPathSeparator()
EXPORT bool Exists(std::string strFolder, std::string oneStr="", std::string twoStr="", std::string threeStr="")
static EXPORT const OTString & GetLogFilePath()
static EXPORT void Errno(const char *szLocation=nullptr)
static EXPORT bool StringFill(OTString &out_strString, const char *szString, int32_t iLength, const char *szAppend=nullptr)
void crit_err_hdlr(int32_t sig_num, siginfo_t *info, void *ucontext)
static EXPORT bool AppendFile(OTString &out_strPath, const OTString &strBasePath, const OTString &strFileName)
static bool vformat(const char *fmt, std::va_list *pvl, std::string &s)
static EXPORT void vOutput(int32_t nVerbosity, const char *szOutput,...)
static EXPORT const OTString & HomeFolder()
static EXPORT const OTString & GlobalConfigFile()
static EXPORT bool PushMemlogFront(const OTString &strLog)
static EXPORT OTString PeekMemlogFront()
OTLOG_IMPORT OTLogStream otLog5