//---------------------------------------------------------------------------------------------------------------------- // Copyright (c) Microsoft Corporation. All Rights Reserved. //---------------------------------------------------------------------------------------------------------------------- #pragma once #include "LogTestResults.h" // Allow anyone who has defined a LogTrace, or Trace macro to compile with this header file included #pragma push_macro("LogTrace") #undef LogTrace #pragma push_macro("Trace") #undef Trace // Just including and using intptr_t/uintptr_t caused build breaks for some existing users. // Work around this for now by defining our own pointer-sized ints for MSVC++. #if defined(_MSC_VER) # ifdef _WIN64 # define WEX_INTPTR __int64 # define WEX_UINTPTR unsigned __int64 # else # define WEX_INTPTR int # define WEX_UINTPTR unsigned int # endif #else # include # define WEX_INTPTR intptr_t # define WEX_UINTPTR uintptr_t #endif #if defined(__linux__) # define WEX_LOGGER_NO_WCHAR_API # include // for size_t #endif #pragma warning(push) // Disable "Prefer enum class over enum". #pragma warning(disable:26812) // Disable "copy constructor was implicitly defined as deleted" and "assignment operator was implicitly defined as deleted". // It is intentional that the derived classes have implicitly deleted copy constructors and assignment operators. #pragma warning(disable:4625 4626) // Disable "Local declaration of 'Error' hides previous declaration at line '77' of '...\winrt\asyncinfo.h'." // This is a false positive. #pragma warning(disable:6244) namespace WEX { namespace Logging { namespace LogTraceAttachment { enum Attachment : WEX_UINTPTR { None = 0x0, ScreenCapture = 0x1, MiniDump = 0x2, }; inline Attachment operator|(Attachment p1, Attachment p2) { return static_cast(static_cast(p1) | static_cast(p2)); } inline Attachment& operator|=(Attachment& p1, Attachment p2) { return p1 = p1 | p2; } }/* namespace LogTraceAttachment */ // When using this, it is recommended that you use it all in one statement. Here is an example: // // Log::Trace(ErrorTrace{L"Message"}.WithContext(L"MyTestLib").WithXmlAnnotation(L"")); // // The strings are not copied by the trace classes; so if you use temporary strings and don't use the trace class right away, // you may end up reading freed memory. Using the trace class on the same line as the Log::Trace call avoids the issue. // // You can also add source info to a trace like this: // // Log::Trace(ErrorTrace{L"Message"}.WithSourceInfo(WEX_LOGGER_CURRENT_SOURCE_INFO)); // // WEX_LOGGER_CURRENT_SOURCE_INFO expands to the current file, function, and line number, but you can also pass the parameters manually. class LogTrace { friend class LogTraceFriend; public: #if !defined(WEX_LOGGER_NO_WCHAR_API) LogTrace&& WithContext(const wchar_t* pszContext) && noexcept { m_pszContext = pszContext; return static_cast(*this); } #endif // !defined(WEX_LOGGER_NO_WCHAR_API) LogTrace&& WithContext(const char* pszContext) && noexcept { m_pszContext = pszContext; // Set flags to indicate the context is UTF-8. m_traceTypeAndFlags |= 0x00020080; return static_cast(*this); } #if defined(__cpp_char8_t) LogTrace&& WithContext(const char8_t* pszContext) && noexcept { m_pszContext = pszContext; // Set flags to indicate the context is UTF-8. m_traceTypeAndFlags |= 0x00020080; return static_cast(*this); } #endif // #if defined(__cpp_char8_t) #if !defined(WEX_LOGGER_NO_WCHAR_API) # define WEX_LOGGER_CURRENT_SOURCE_INFO __FILEW__, __FUNCTIONW__, __LINE__ LogTrace&& WithSourceInfo(const wchar_t* pszFile, const wchar_t* pszFunction, int line) && noexcept { m_pszFile = pszFile; m_pszFunction = pszFunction; m_line = static_cast(line); return static_cast(*this); } #else # define WEX_LOGGER_CURRENT_SOURCE_INFO __FILE__, __FUNCTION__, __LINE__ #endif LogTrace&& WithSourceInfo(const char* pszFile, const char* pszFunction, int line) && noexcept { m_pszFile = pszFile; m_pszFunction = pszFunction; m_line = static_cast(line); // Set flags to indicate m_pszFile and m_pszFunction are UTF-8. m_traceTypeAndFlags |= 0x00040080; return static_cast(*this); } #if !defined(WEX_LOGGER_NO_WCHAR_API) // The XML annotation is added to the WTT log file for this trace. It can contain any contents, but it should be valid // XML or the log file will be corrupted. LogTrace&& WithXmlAnnotation(const wchar_t* pszXmlAnnotation) && noexcept { m_pszXmlAnnotation = pszXmlAnnotation; return static_cast(*this); } #endif // !defined(WEX_LOGGER_NO_WCHAR_API) // The XML annotation is added to the WTT log file for this trace. It can contain any contents, but it should be valid // XML or the log file will be corrupted. LogTrace&& WithXmlAnnotation(const char* pszXmlAnnotation) && noexcept { m_pszXmlAnnotation = pszXmlAnnotation; // Set flags to indicate the XML annotation is UTF-8. m_traceTypeAndFlags |= 0x00080080; return static_cast(*this); } #if defined(__cpp_char8_t) LogTrace&& WithXmlAnnotation(const char8_t* pszXmlAnnotation) && noexcept { m_pszXmlAnnotation = pszXmlAnnotation; // Set flags to indicate the XML annotation is UTF-8. m_traceTypeAndFlags |= 0x00080080; return static_cast(*this); } #endif // #if defined(__cpp_char8_t) // You can attach a screenshot and/or minidump to any trace using this method. LogTrace&& WithAttachment(::WEX::Logging::LogTraceAttachment::Attachment attachment) && noexcept { m_traceTypeAndFlags |= static_cast(attachment) << 8; return static_cast(*this); } // Prevent copying of trace classes. LogTrace(const LogTrace&) = delete; LogTrace& operator=(const LogTrace&) = delete; // Prevent allocation of trace classes. static void* operator new(size_t) = delete; static void operator delete(void*) = delete; protected: enum TraceType : WEX_UINTPTR { Assert, Error, Warning, Comment, StartGroup, EndGroup, KnownBug, FileName, FileBuffer, Property, Xml, Result, LightweightStartGroup, LightweightEndGroup, TraceTypeCount }; #if !defined(WEX_LOGGER_NO_WCHAR_API) LogTrace(TraceType traceType, const wchar_t* pszMessage, WEX_UINTPTR traceTypeSpecificIntegralValue = 0, const void* pTraceTypeSpecificPointerValue = nullptr) noexcept : m_traceTypeAndFlags{static_cast(traceType)} , m_pszMessage{pszMessage} , m_traceTypeSpecificIntegralValue{traceTypeSpecificIntegralValue} , m_pTraceTypeSpecificPointerValue{pTraceTypeSpecificPointerValue} {} #endif // !defined(WEX_LOGGER_NO_WCHAR_API) LogTrace(TraceType traceType, const char* pszMessage, WEX_UINTPTR traceTypeSpecificIntegralValue = 0, const void* pTraceTypeSpecificPointerValue = nullptr) noexcept // Set flags to indicate the message is UTF-8. : m_traceTypeAndFlags{static_cast(traceType) | 0x00010080} , m_pszMessage{pszMessage} , m_traceTypeSpecificIntegralValue{traceTypeSpecificIntegralValue} , m_pTraceTypeSpecificPointerValue{pTraceTypeSpecificPointerValue} {} #if defined(__cpp_char8_t) LogTrace(TraceType traceType, const char8_t* pszMessage, WEX_UINTPTR traceTypeSpecificIntegralValue = 0, const void* pTraceTypeSpecificPointerValue = nullptr) noexcept // Set flags to indicate the message is UTF-8. : m_traceTypeAndFlags{static_cast(traceType) | 0x00010080} , m_pszMessage{pszMessage} , m_traceTypeSpecificIntegralValue{traceTypeSpecificIntegralValue} , m_pTraceTypeSpecificPointerValue{pTraceTypeSpecificPointerValue} {} #endif // #if defined(__cpp_char8_t) private: // All members are the same size to avoid having inconsistent padding across DLLs. // m_traceTypeAndFlags: // Bits 0-6: The TraceType enum value. // Bit 7: This is set if any of bits 10 through 31 are set. // (Bit 7 causes old Wex.Logger versions to fail even though they don't verify that reserved bits are zero.) // Bit 8: Attach a screen capture to the log trace. // Bit 9: Attach a minidump to the log trace. // Bits 10-15: Reserved. Must be zero. // Bit 16: Set: m_pszMessage is UTF-8. Clear: m_pszMessage is UTF-16. // Bit 16 also applies to m_pTraceTypeSpecificPointerValue if that is used for a string. // Bit 17: Set: m_pszContext is UTF-8. Clear: m_pszContext is UTF-16. // Bit 18: Set: m_pszFile and m_pszFunction are UTF-8. Clear: m_pszFile and m_pszFunction are UTF-16. // Bit 19: Set: m_pszXmlAnnotation is UTF-8. Clear: m_pszXmlAnnotation is UTF-16. // Bits 20-31: Reserved. Must be zero. // Bits 32-63: Ignored. (Unavailable on 32-bit builds.) WEX_UINTPTR m_traceTypeAndFlags; const void* const m_pszMessage; const WEX_UINTPTR m_traceTypeSpecificIntegralValue; const void* const m_pTraceTypeSpecificPointerValue; const void* m_pszContext = nullptr; const void* m_pszFile = nullptr; const void* m_pszFunction = nullptr; WEX_INTPTR m_line = -1; const void* m_pszXmlAnnotation = nullptr; }; class AssertTrace : public LogTrace { public: #if !defined(WEX_LOGGER_NO_WCHAR_API) explicit AssertTrace(const wchar_t* pszAssert) noexcept : LogTrace{Assert, pszAssert} {} #endif // !defined(WEX_LOGGER_NO_WCHAR_API) explicit AssertTrace(const char* pszAssert) noexcept : LogTrace{Assert, pszAssert} {} #if defined(__cpp_char8_t) explicit AssertTrace(const char8_t* pszAssert) noexcept : LogTrace{Assert, pszAssert} {} #endif // #if defined(__cpp_char8_t) }; class BugTrace : public LogTrace { public: #if !defined(WEX_LOGGER_NO_WCHAR_API) BugTrace(const wchar_t* pszBugDatabase, int bugId) noexcept : LogTrace{KnownBug, pszBugDatabase, static_cast(bugId)} {} #endif // !defined(WEX_LOGGER_NO_WCHAR_API) BugTrace(const char* pszBugDatabase, int bugId) noexcept : LogTrace{KnownBug, pszBugDatabase, static_cast(bugId)} {} #if defined(__cpp_char8_t) BugTrace(const char8_t* pszBugDatabase, int bugId) noexcept : LogTrace{KnownBug, pszBugDatabase, static_cast(bugId)} {} #endif // #if defined(__cpp_char8_t) }; class CommentTrace : public LogTrace { public: #if !defined(WEX_LOGGER_NO_WCHAR_API) explicit CommentTrace(const wchar_t* pszComment) noexcept : LogTrace{Comment, pszComment} {} #endif // !defined(WEX_LOGGER_NO_WCHAR_API) explicit CommentTrace(const char* pszComment) noexcept : LogTrace{Comment, pszComment} {} #if defined(__cpp_char8_t) explicit CommentTrace(const char8_t* pszComment) noexcept : LogTrace{Comment, pszComment} {} #endif // #if defined(__cpp_char8_t) }; class EndGroupTrace : public LogTrace { public: #if !defined(WEX_LOGGER_NO_WCHAR_API) explicit EndGroupTrace(const wchar_t* pszGroupName) noexcept : LogTrace{EndGroup, pszGroupName} {} #endif // !defined(WEX_LOGGER_NO_WCHAR_API) explicit EndGroupTrace(const char* pszGroupName) noexcept : LogTrace{EndGroup, pszGroupName} {} #if defined(__cpp_char8_t) explicit EndGroupTrace(const char8_t* pszGroupName) noexcept : LogTrace{EndGroup, pszGroupName} {} #endif // #if defined(__cpp_char8_t) }; class ErrorTrace : public LogTrace { public: #if !defined(WEX_LOGGER_NO_WCHAR_API) explicit ErrorTrace(const wchar_t* pszError) noexcept : LogTrace{Error, pszError} {} #endif // !defined(WEX_LOGGER_NO_WCHAR_API) explicit ErrorTrace(const char* pszError) noexcept : LogTrace{Error, pszError} {} #if defined(__cpp_char8_t) explicit ErrorTrace(const char8_t* pszError) noexcept : LogTrace{Error, pszError} {} #endif // #if defined(__cpp_char8_t) }; class FileTrace : public LogTrace { public: #if !defined(WEX_LOGGER_NO_WCHAR_API) explicit FileTrace(const wchar_t* pszFilePath) noexcept : LogTrace{FileName, pszFilePath} {} #endif // !defined(WEX_LOGGER_NO_WCHAR_API) explicit FileTrace(const char* pszFilePath) noexcept : LogTrace{FileName, pszFilePath} {} #if defined(__cpp_char8_t) explicit FileTrace(const char8_t* pszFilePath) noexcept : LogTrace{FileName, pszFilePath} {} #endif // #if defined(__cpp_char8_t) #if !defined(WEX_LOGGER_NO_WCHAR_API) FileTrace(const wchar_t* pszFileName, const unsigned char* pFileBuffer, size_t bufferSize) noexcept : LogTrace{FileBuffer, pszFileName, static_cast(bufferSize), pFileBuffer} {} #endif // !defined(WEX_LOGGER_NO_WCHAR_API) FileTrace(const char* pszFileName, const unsigned char* pFileBuffer, size_t bufferSize) noexcept : LogTrace{FileBuffer, pszFileName, static_cast(bufferSize), pFileBuffer} {} #if defined(__cpp_char8_t) FileTrace(const char8_t* pszFileName, const unsigned char* pFileBuffer, size_t bufferSize) noexcept : LogTrace{FileBuffer, pszFileName, static_cast(bufferSize), pFileBuffer} {} #endif // #if defined(__cpp_char8_t) }; class PropertyTrace : public LogTrace { public: #if !defined(WEX_LOGGER_NO_WCHAR_API) PropertyTrace(const wchar_t* pszName, const wchar_t* pszValue) noexcept : LogTrace{Property, pszName, 0, pszValue} {} #endif // !defined(WEX_LOGGER_NO_WCHAR_API) PropertyTrace(const char* pszName, const char* pszValue) noexcept : LogTrace{Property, pszName, 0, pszValue} {} #if defined(__cpp_char8_t) PropertyTrace(const char8_t* pszName, const char8_t* pszValue) noexcept : LogTrace{Property, pszName, 0, pszValue} {} #endif // #if defined(__cpp_char8_t) }; class ResultTrace : public LogTrace { public: explicit ResultTrace(TestResults::Result testResult) noexcept : LogTrace{Result, static_cast(nullptr), static_cast(testResult)} {} #if !defined(WEX_LOGGER_NO_WCHAR_API) ResultTrace(TestResults::Result testResult, const wchar_t* pszComment) noexcept : LogTrace{Result, pszComment, static_cast(testResult)} {} #endif // !defined(WEX_LOGGER_NO_WCHAR_API) ResultTrace(TestResults::Result testResult, const char* pszComment) noexcept : LogTrace{Result, pszComment, static_cast(testResult)} {} #if defined(__cpp_char8_t) ResultTrace(TestResults::Result testResult, const char8_t* pszComment) noexcept : LogTrace{Result, pszComment, static_cast(testResult)} {} #endif // #if defined(__cpp_char8_t) }; class StartGroupTrace : public LogTrace { public: #if !defined(WEX_LOGGER_NO_WCHAR_API) explicit StartGroupTrace(const wchar_t* pszGroupName) noexcept : LogTrace{StartGroup, pszGroupName} {} #endif // !defined(WEX_LOGGER_NO_WCHAR_API) explicit StartGroupTrace(const char* pszGroupName) noexcept : LogTrace{StartGroup, pszGroupName} {} #if defined(__cpp_char8_t) explicit StartGroupTrace(const char8_t* pszGroupName) noexcept : LogTrace{StartGroup, pszGroupName} {} #endif // #if defined(__cpp_char8_t) #if !defined(WEX_LOGGER_NO_WCHAR_API) StartGroupTrace(const wchar_t* pszGroupName, TestResults::Result defaultTestResult) noexcept : LogTrace{StartGroup, pszGroupName, static_cast(defaultTestResult)} {} #endif // !defined(WEX_LOGGER_NO_WCHAR_API) StartGroupTrace(const char* pszGroupName, TestResults::Result defaultTestResult) noexcept : LogTrace{StartGroup, pszGroupName, static_cast(defaultTestResult)} {} #if defined(__cpp_char8_t) StartGroupTrace(const char8_t* pszGroupName, TestResults::Result defaultTestResult) noexcept : LogTrace{StartGroup, pszGroupName, static_cast(defaultTestResult)} {} #endif // #if defined(__cpp_char8_t) }; class WarningTrace : public LogTrace { public: #if !defined(WEX_LOGGER_NO_WCHAR_API) explicit WarningTrace(const wchar_t* pszWarning) noexcept : LogTrace{Warning, pszWarning} {} #endif // !defined(WEX_LOGGER_NO_WCHAR_API) explicit WarningTrace(const char* pszWarning) noexcept : LogTrace{Warning, pszWarning} {} #if defined(__cpp_char8_t) explicit WarningTrace(const char8_t* pszWarning) noexcept : LogTrace{Warning, pszWarning} {} #endif // #if defined(__cpp_char8_t) }; class XmlTrace : public LogTrace { public: #if !defined(WEX_LOGGER_NO_WCHAR_API) explicit XmlTrace(const wchar_t* pszXml) noexcept // XML traces don't use the message field. : LogTrace{Xml, static_cast(nullptr), 0, pszXml} {} #endif // !defined(WEX_LOGGER_NO_WCHAR_API) explicit XmlTrace(const char* pszXml) noexcept // XML traces don't use the message field. : LogTrace{Xml, static_cast(nullptr), 0, pszXml} {} #if defined(__cpp_char8_t) explicit XmlTrace(const char8_t* pszXml) noexcept // XML traces don't use the message field. : LogTrace{Xml, static_cast(nullptr), 0, pszXml} {} #endif // #if defined(__cpp_char8_t) }; }/* namespace Logging */}/* namespace WEX */ #pragma warning(pop) #pragma pop_macro("Trace") #pragma pop_macro("LogTrace")