Last active
December 27, 2015 16:19
-
-
Save qzchenwl/7353623 to your computer and use it in GitHub Desktop.
Log stack trace for cpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "Log.h" | |
#include <tchar.h> | |
namespace Log | |
{ | |
__declspec(thread) Checkpoint* Checkpoint::s_pTop = NULL; | |
__declspec(thread) bool Checkpoint::exception_handled = false; | |
void PrintF_Internal(PCTSTR szFmt, const int* pParams, PTSTR szBuf, size_t nLenBuf, size_t nData) | |
{ | |
int nLen = _vsntprintf(szBuf+nData, nLenBuf-nData-3, szFmt, (va_list) pParams); | |
_tcscpy(szBuf+nLen+nData, _T("\r\n")); | |
OutputDebugString(szBuf); | |
} | |
void PrintCheckpoints() | |
{ | |
TCHAR sz[0x200]; | |
sz[0] = _T('\t'); | |
for (const Checkpoint* pCheckPoint = Checkpoint::s_pTop; pCheckPoint; pCheckPoint = pCheckPoint->m_pPrev) | |
PrintF_Internal(pCheckPoint->m_szFmt, pCheckPoint->m_pParams, sz, _countof(sz), 1); | |
} | |
void PrintF(PCTSTR szFmt, const int* pParams) | |
{ | |
TCHAR sz[0x200]; | |
PrintF_Internal(szFmt, pParams, sz, _countof(sz), 0); | |
} | |
} // namespace Log | |
// For tests | |
void TstLog() | |
{ | |
{ | |
CHECKPOINT(_T("WorkerThread=%d") << GetCurrentThreadId()) | |
CHECKPOINT(_T("Processing I/O")) | |
{ | |
CHECKPOINT(_T("Request from client ID=%u") << 246) | |
{ | |
CHECKPOINT(_T("Sending a file. Path=%s") << _T("C:\\Blablabla.bin")) | |
{ | |
PUTLOG(_T("Can't open file. Error=%u") << GetLastError()); | |
Log::PrintCheckpoints(); | |
} | |
} | |
} | |
} | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#define _CRT_NON_CONFORMING_SWPRINTFS | |
#define _CRT_SECURE_NO_WARNINGS | |
#define _SECURE_SCL 0 | |
#include <windows.h> | |
#include <tchar.h> | |
#include <exception> | |
#ifndef ASSERT | |
# ifdef _DEBUG | |
# define ASSERT(x) do { if (!(x)) __debugbreak(); } while (false) | |
# else | |
# define ASSERT(x) __noop | |
# endif | |
#endif | |
#pragma warning (disable: 4200) // zero-sized arrays | |
// Internally-used macro | |
#define BUILD_FMT_RECORD(rec, expr) \ | |
Log::Record<sizeof(Log::SizeCalc() << expr)> rec; \ | |
rec << expr; | |
// Macros to generate random identifiers | |
#define RAND_IDENTIFIER_2(x,y) x##y | |
#define RAND_IDENTIFIER_1(x,y) RAND_IDENTIFIER_2(x,y) | |
#define RAND_IDENTIFIER(prefix) RAND_IDENTIFIER_1(prefix, __LINE__) | |
// Put this in the log | |
#define PUTLOG(expr) \ | |
do { \ | |
BUILD_FMT_RECORD(RAND_IDENTIFIER(recAutoToLog), expr) \ | |
Log::PrintF(RAND_IDENTIFIER(recAutoToLog).m_szFmt, RAND_IDENTIFIER(recAutoToLog).m_pParams); \ | |
}while (false) | |
// Declare a checkpoint | |
#define CHECKPOINT(expr) \ | |
BUILD_FMT_RECORD(RAND_IDENTIFIER(var##_Record), expr) \ | |
Log::Checkpoint RAND_IDENTIFIER(var)(RAND_IDENTIFIER(var##_Record)); | |
namespace Log | |
{ | |
template <typename T> | |
struct StackAligned { | |
int m_pBuf[(sizeof(T) + sizeof(int)-1) / sizeof(int)]; | |
}; | |
struct Feed | |
{ | |
int* m_pPtr; | |
template <typename T> void Consume(const T& val) { | |
*((T*) m_pPtr) = val; | |
m_pPtr += sizeof(StackAligned<T>) / sizeof(int); | |
} | |
template <typename T> Feed& operator << (const T& val) { | |
Consume(val); | |
return *this; | |
} | |
Feed& operator << (PCSTR val) { | |
Consume<PCSTR>(val); | |
return *this; | |
} | |
Feed& operator << (PCWSTR val) { | |
Consume<PCWSTR>(val); | |
return *this; | |
} | |
}; | |
template <size_t nSize> | |
struct Record { | |
PCTSTR m_szFmt; | |
int m_pParams[nSize / sizeof(int)]; | |
Feed operator << (PCTSTR szFmt) { | |
m_szFmt = szFmt; | |
Feed feed; | |
feed.m_pPtr = m_pParams; | |
return feed; | |
} | |
}; | |
struct SizeCalc { | |
template <size_t nSize> | |
struct Nested { | |
char m_pBuf[nSize]; | |
Nested<nSize + sizeof(StackAligned<PCSTR>)> operator << (PCSTR); | |
Nested<nSize + sizeof(StackAligned<PCWSTR>)> operator << (PCWSTR); | |
template <typename T> Nested<nSize + sizeof(StackAligned<T>)> operator << (const T&); | |
}; | |
Nested<0> operator << (PCTSTR szFmt); | |
}; | |
void PrintF(PCTSTR szFmt, const int* pParams); | |
void PrintCheckpoints(); | |
struct Checkpoint { | |
__declspec(thread) static Checkpoint* s_pTop; | |
__declspec(thread) static bool exception_handled; | |
Checkpoint* m_pPrev; | |
PCTSTR m_szFmt; | |
const int* m_pParams; | |
template <size_t nSize> | |
Checkpoint(const Record<nSize>& rec) | |
:m_szFmt(rec.m_szFmt) | |
,m_pParams(rec.m_pParams) | |
{ | |
m_pPrev = s_pTop; | |
s_pTop = this; | |
} | |
~Checkpoint() | |
{ | |
if (std::uncaught_exception()) | |
{ | |
if (!exception_handled) | |
{ | |
exception_handled = true; | |
PUTLOG(_T("--> Unhandled exception")); | |
PrintCheckpoints(); | |
PUTLOG(_T("<-- Unhandled exception")); | |
} | |
} | |
else | |
{ | |
exception_handled = false; | |
} | |
ASSERT(this == s_pTop); | |
s_pTop = m_pPrev; | |
} | |
}; | |
} // namespace Log | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "Log.h" | |
#include <string> | |
#include <iostream> | |
using namespace std; | |
int main() | |
{ | |
CHECKPOINT(_T("main()")); | |
{ | |
try | |
{ | |
CHECKPOINT(_T("ONE")); | |
{ | |
CHECKPOINT(_T("TWO")); | |
// throw std::runtime_error("ha"); | |
std::string().at(1); | |
{ | |
CHECKPOINT(_T("THREE")); | |
} | |
} | |
} | |
catch (const exception& e) | |
{ | |
cout << "exception: " << e.what() << endl; | |
int x; cin >> x; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment