Converge FileLogger with the other logger replacements

Use the same `CLogger` constructor.
Never take ownership of the streams.

Comments by: @Stan
Differential Revision: https://code.wildfiregames.com/D5203
This was SVN commit r28140.
This commit is contained in:
phosit 2024-07-06 14:48:44 +00:00
parent 9e328ec617
commit cd814d00ef
3 changed files with 67 additions and 93 deletions

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2023 Wildfire Games.
/* Copyright (C) 2024 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -50,7 +50,7 @@ struct BlackHoleStreamBuf : public std::streambuf
{
} blackHoleStreamBuf;
std::ostream blackHoleStream(&blackHoleStreamBuf);
CLogger nullLogger(&blackHoleStream, &blackHoleStream, false, true);
CLogger nullLogger{blackHoleStream, blackHoleStream, true};
CLogger* g_Logger = &nullLogger;
@ -68,44 +68,13 @@ const char* html_header0 =
const char* html_header1 = "</h2>\n";
CLogger::CLogger()
CLogger::CLogger(std::ostream& mainLog, std::ostream& interestingLog, const bool useDebugPrintf) :
m_MainLog{mainLog},
m_InterestingLog{interestingLog},
m_UseDebugPrintf{useDebugPrintf}
{
OsPath mainlogPath(psLogDir() / (L"mainlog" + g_UniqueLogPostfix + L".html"));
m_MainLog = new std::ofstream(OsString(mainlogPath).c_str(), std::ofstream::out | std::ofstream::trunc);
debug_printf("FILES| Main log written to '%s'\n", mainlogPath.string8().c_str());
OsPath interestinglogPath(psLogDir() / (L"interestinglog" + g_UniqueLogPostfix + L".html"));
m_InterestingLog = new std::ofstream(OsString(interestinglogPath).c_str(), std::ofstream::out | std::ofstream::trunc);
debug_printf("FILES| Interesting log written to '%s'\n", interestinglogPath.string8().c_str());
m_OwnsStreams = true;
m_UseDebugPrintf = true;
Init();
}
CLogger::CLogger(std::ostream* mainLog, std::ostream* interestingLog, bool takeOwnership, bool useDebugPrintf)
{
m_MainLog = mainLog;
m_InterestingLog = interestingLog;
m_OwnsStreams = takeOwnership;
m_UseDebugPrintf = useDebugPrintf;
Init();
}
void CLogger::Init()
{
m_RenderLastEraseTime = -1.0;
// this is called too early to allow us to call timer_Time(),
// so we'll fill in the initial value later
m_NumberOfMessages = 0;
m_NumberOfErrors = 0;
m_NumberOfWarnings = 0;
*m_MainLog << html_header0 << engine_version << ") Main log" << html_header1;
*m_InterestingLog << html_header0 << engine_version << ") Main log (warnings and errors only)" << html_header1;
m_MainLog << html_header0 << engine_version << ") Main log" << html_header1;
m_InterestingLog << html_header0 << engine_version << ") Main log (warnings and errors only)" << html_header1;
}
CLogger::~CLogger()
@ -122,17 +91,11 @@ CLogger::~CLogger()
//Write closing text
*m_MainLog << "<p>Engine exited successfully on " << currentDate;
*m_MainLog << " at " << currentTime << buffer << "</p>\n";
m_MainLog << "<p>Engine exited successfully on " << currentDate;
m_MainLog << " at " << currentTime << buffer << "</p>\n";
*m_InterestingLog << "<p>Engine exited successfully on " << currentDate;
*m_InterestingLog << " at " << currentTime << buffer << "</p>\n";
if (m_OwnsStreams)
{
SAFE_DELETE(m_InterestingLog);
SAFE_DELETE(m_MainLog);
}
m_InterestingLog << "<p>Engine exited successfully on " << currentDate;
m_InterestingLog << " at " << currentTime << buffer << "</p>\n";
}
static std::string ToHTML(const char* message)
@ -153,8 +116,8 @@ void CLogger::WriteMessage(const char* message, bool doRender = false)
// if (m_UseDebugPrintf)
// debug_printf("MESSAGE: %s\n", message);
*m_MainLog << "<p>" << cmessage << "</p>\n";
m_MainLog->flush();
m_MainLog << "<p>" << cmessage << "</p>\n";
m_MainLog.flush();
if (doRender)
{
@ -175,11 +138,11 @@ void CLogger::WriteError(const char* message)
debug_printf("ERROR: %.16000s\n", message);
if (g_Console) g_Console->InsertMessage(std::string("ERROR: ") + message);
*m_InterestingLog << "<p class=\"error\">ERROR: " << cmessage << "</p>\n";
m_InterestingLog->flush();
m_InterestingLog << "<p class=\"error\">ERROR: " << cmessage << "</p>\n";
m_InterestingLog.flush();
*m_MainLog << "<p class=\"error\">ERROR: " << cmessage << "</p>\n";
m_MainLog->flush();
m_MainLog << "<p class=\"error\">ERROR: " << cmessage << "</p>\n";
m_MainLog.flush();
PushRenderMessage(Error, message);
}
@ -195,11 +158,11 @@ void CLogger::WriteWarning(const char* message)
debug_printf("WARNING: %s\n", message);
if (g_Console) g_Console->InsertMessage(std::string("WARNING: ") + message);
*m_InterestingLog << "<p class=\"warning\">WARNING: " << cmessage << "</p>\n";
m_InterestingLog->flush();
m_InterestingLog << "<p class=\"warning\">WARNING: " << cmessage << "</p>\n";
m_InterestingLog.flush();
*m_MainLog << "<p class=\"warning\">WARNING: " << cmessage << "</p>\n";
m_MainLog->flush();
m_MainLog << "<p class=\"warning\">WARNING: " << cmessage << "</p>\n";
m_MainLog.flush();
PushRenderMessage(Warning, message);
}
@ -311,13 +274,9 @@ void CLogger::CleanupRenderQueue()
m_RenderMessages.erase(m_RenderMessages.begin(), m_RenderMessages.end() - RENDER_LIMIT);
}
CLogger::ScopedReplacement::ScopedReplacement() :
m_OldLogger{std::exchange(g_Logger, &m_ThisLogger)}
{}
CLogger::ScopedReplacement::ScopedReplacement(std::ostream* mainLog, std::ostream* interestingLog,
const bool takeOwnership, const bool useDebugPrintf) :
m_ThisLogger{mainLog, interestingLog, takeOwnership, useDebugPrintf},
CLogger::ScopedReplacement::ScopedReplacement(std::ostream& mainLog, std::ostream& interestingLog,
const bool useDebugPrintf) :
m_ThisLogger{mainLog, interestingLog, useDebugPrintf},
m_OldLogger{std::exchange(g_Logger, &m_ThisLogger)}
{}
@ -326,8 +285,24 @@ CLogger::ScopedReplacement::~ScopedReplacement()
g_Logger = m_OldLogger;
}
namespace
{
std::ofstream OpenLogFile(const wchar_t* filePrefix, const char* logName)
{
OsPath path{psLogDir() / (filePrefix + g_UniqueLogPostfix + L".html")};
debug_printf("FILES| %s written to '%s'\n", logName, path.string8().c_str());
return std::ofstream{OsString(path).c_str(), std::ofstream::trunc};
}
}
FileLogger::FileLogger() :
m_MainLog{OpenLogFile(L"mainlog", "Main log")},
m_InterestingLog{OpenLogFile(L"interestinglog", "Interesting log")},
m_ScopedReplacement{m_MainLog, m_InterestingLog, true}
{}
TestLogger::TestLogger() :
m_ScopedReplacement{&m_Stream, &blackHoleStream, false, false}
m_ScopedReplacement{m_Stream, blackHoleStream, false}
{}
std::string TestLogger::GetOutput()
@ -336,5 +311,5 @@ std::string TestLogger::GetOutput()
}
TestStdoutLogger::TestStdoutLogger() :
m_ScopedReplacement{&std::cout, &blackHoleStream, false, false}
m_ScopedReplacement{std::cout, blackHoleStream, false}
{}

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2023 Wildfire Games.
/* Copyright (C) 2024 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -20,6 +20,7 @@
#include <deque>
#include <fmt/printf.h>
#include <fstream>
#include <mutex>
#include <string>
#include <sstream>
@ -56,12 +57,7 @@ public:
Warning
};
// Default constructor - outputs to normal log files
CLogger();
// Special constructor (mostly for testing) - outputs to provided streams.
// Can take ownership of streams and delete them in the destructor.
CLogger(std::ostream* mainLog, std::ostream* interestingLog, bool takeOwnership, bool useDebugPrintf);
CLogger(std::ostream& mainLog, std::ostream& interestingLog, const bool useDebugPrintf);
~CLogger();
@ -83,18 +79,17 @@ private:
void CleanupRenderQueue();
// the output streams
std::ostream* m_MainLog;
std::ostream* m_InterestingLog;
bool m_OwnsStreams;
std::ostream& m_MainLog;
std::ostream& m_InterestingLog;
// whether errors should be reported via debug_printf (default)
// or suppressed (for tests that intentionally trigger errors)
bool m_UseDebugPrintf;
// vars to hold message counts
int m_NumberOfMessages;
int m_NumberOfErrors;
int m_NumberOfWarnings;
int m_NumberOfMessages{0};
int m_NumberOfErrors{0};
int m_NumberOfWarnings{0};
// Used for Render()
struct RenderedMessage
@ -104,7 +99,10 @@ private:
std::string message;
};
std::deque<RenderedMessage> m_RenderMessages;
double m_RenderLastEraseTime;
// The logger might be constructed too early to allow us to call timer_Time(),
// so we'll fill in the initial value later
double m_RenderLastEraseTime{-1.0};
// Lock for all state modified by logging commands
std::mutex m_Mutex;
@ -116,9 +114,7 @@ private:
class CLogger::ScopedReplacement
{
public:
ScopedReplacement();
ScopedReplacement(std::ostream* mainLog, std::ostream* interestingLog, const bool takeOwnership,
const bool useDebugPrintf);
ScopedReplacement(std::ostream& mainLog, std::ostream& interestingLog, const bool useDebugPrintf);
ScopedReplacement(const ScopedReplacement&) = delete;
ScopedReplacement& operator=(const ScopedReplacement&) = delete;
@ -136,7 +132,11 @@ private:
*/
class FileLogger
{
public:
FileLogger();
private:
std::ofstream m_MainLog;
std::ofstream m_InterestingLog;
CLogger::ScopedReplacement m_ScopedReplacement;
};

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2022 Wildfire Games.
/* Copyright (C) 2024 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -58,16 +58,15 @@ public:
//////////////////////////////////////////////////////////////////////////
CLogger* logger;
std::stringstream* mainlog;
std::stringstream* interestinglog;
std::stringstream mainlog;
std::stringstream interestinglog;
std::vector<std::string> lines;
void setUp()
{
mainlog = new std::stringstream();
interestinglog = new std::stringstream();
logger = new CLogger(mainlog, interestinglog, true, false);
mainlog.str({});
interestinglog.str({});
logger = new CLogger(mainlog, interestinglog, false);
lines.clear();
}
@ -82,7 +81,7 @@ public:
{
const std::string header_end = "</h2>\n";
std::string s = mainlog->str();
std::string s = mainlog.str();
size_t start = s.find(header_end);
TS_ASSERT_DIFFERS(start, s.npos);
s.erase(0, start + header_end.length());