Skip to content

Instantly share code, notes, and snippets.

@dwcullop
Last active August 2, 2021 21:05
Show Gist options
  • Save dwcullop/1b8633614b1b21d14e935b557818b6de to your computer and use it in GitHub Desktop.
Save dwcullop/1b8633614b1b21d14e935b557818b6de to your computer and use it in GitHub Desktop.
Debug Logging on Windows in Modern C++
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// DebuggingHelpers.h : Debug Logging on Windows in Modern C++
//
// Author Name :
// Darrin W. Cullop ([email protected])
//
// License :
// CC-BY 4.0 (https://creativecommons.org/licenses/by/4.0/)
//
// Abstract :
// Simple "PrintF" Logging to the Debugger on Windows. Works with ANSI and Wide Strings (use %S when mixing).
// Use "DebugTrace" to only emit in Debug Builds. Use "Trace" to always emit.
//
// Example Usages:
// dwc::Trace( "Hello, World! The number is %d!\r\n", 37 );
// dwc::DebugTrace( L"Hello, World! The number is %d!\r\n", 42 );
// dwc::Trace( "Received Wide String: [%S]\r\n", lpszWideString ); // Uses wide with a skinny format
// dwc::Trace( L"Received Wide String: [%s]\r\n", lpszWideString );
// dwc::DebugTrace( L"Received Skinny String: [%S]\r\n", lpszSkinnyString ); // Uses skinny with a wide format
// dwc::DebugTrace( "Received Skinny String: [%s]\r\n", lpszSkinnyString );
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma once
#include <string>
#include <cstdio>
#include <cwchar>
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// dwc Namespace
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace dwc
{
template<typename... Args>
inline void Trace( const char* const lpszFormat, Args&&... args ) noexcept
{
try
{
// Don't allocate a buffer unless extra arguments are provided
if constexpr ( sizeof...( args ) > 0 )
{
const auto charsNeeded = std::snprintf( nullptr, 0, lpszFormat, args... );
auto output = std::string( charsNeeded + 1UL, '\0' );
const auto charsUsed = std::snprintf( output.data(), output.size(), lpszFormat, args... );
// Emit the formatted buffer
::OutputDebugStringA( output.c_str() );
}
else
{
// Only one argument provided, so just emit the string
::OutputDebugStringA( lpszFormat );
}
return;
}
catch( ... )
{
::OutputDebugStringA( "Trace Failure!" );
return;
}
}
template<typename... Args>
inline void Trace( const wchar_t* const lpszFormat, Args&&... args ) noexcept
{
try
{
// Don't allocate a buffer unless extra arguments are provided
if constexpr ( sizeof...( args ) > 0 )
{
const auto charsNeeded = std::swprintf( nullptr, 0, lpszFormat, args... );
auto output = std::wstring( charsNeeded + 1ULL, L'\0' );
const auto charsUsed = std::swprintf( output.data(), output.size(), lpszFormat, args... );
// Emit the formatted buffer
::OutputDebugStringW( output.c_str() );
}
else
{
// Only one argument provided, so just emit the string
::OutputDebugStringW( lpszFormat );
}
return;
}
catch (...)
{
::OutputDebugStringW( L"Trace Failure!" );
return;
}
}
template<typename... Args>
inline void DebugTrace( Args&&... args ) noexcept
{
#if defined(_DEBUG) || defined(DEBUG)
// If the caller forgot something, help them out with a better error message
static_assert( (sizeof...( args ) > 0), "Please provide at least one parameter" );
// Will dispatch to the correct overload
Trace( std::forward<Args>(args)... );
#endif
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
} // namespace dwc
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// End of DebuggingHelpers.h
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment