Skip to content

Instantly share code, notes, and snippets.

@qzchenwl
Last active December 27, 2015 16:19
Show Gist options
  • Save qzchenwl/7353623 to your computer and use it in GitHub Desktop.
Save qzchenwl/7353623 to your computer and use it in GitHub Desktop.
Log stack trace for cpp
#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();
}
}
}
}
}
#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
#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