// Copyright Epic Games, Inc. All Rights Reserved. #include #if ZEN_PLATFORM_WINDOWS # include # include # include ZEN_THIRD_PARTY_INCLUDES_START # include ZEN_THIRD_PARTY_INCLUDES_END namespace zen::logging { // Default formatter for MSVC debug output: [level] message\n // For error/critical messages with source info, prepends file(line): so that // the message is clickable in the Visual Studio Output window. class DefaultMsvcFormatter : public Formatter { public: void Format(const LogMessage& Msg, MemoryBuffer& Dest) override { const auto& Source = Msg.GetSource(); if (Msg.GetLevel() >= LogLevel::Err && Source) { helpers::AppendStringView(Source.Filename, Dest); Dest.push_back('('); helpers::AppendInt(Source.Line, Dest); Dest.push_back(')'); Dest.push_back(':'); Dest.push_back(' '); } Dest.push_back('['); helpers::AppendStringView(helpers::LevelToShortString(Msg.GetLevel()), Dest); Dest.push_back(']'); Dest.push_back(' '); helpers::AppendStringView(Msg.GetPayload(), Dest); Dest.push_back('\n'); } std::unique_ptr Clone() const override { return std::make_unique(); } }; MsvcSink::MsvcSink() : m_Formatter(std::make_unique()) { } void MsvcSink::Log(const LogMessage& Msg) { std::lock_guard Lock(m_Mutex); MemoryBuffer Formatted; m_Formatter->Format(Msg, Formatted); // Null-terminate for OutputDebugStringA Formatted.push_back('\0'); OutputDebugStringA(Formatted.data()); } void MsvcSink::Flush() { // Nothing to flush for OutputDebugString } void MsvcSink::SetFormatter(std::unique_ptr InFormatter) { std::lock_guard Lock(m_Mutex); m_Formatter = std::move(InFormatter); } } // namespace zen::logging #endif // ZEN_PLATFORM_WINDOWS