Rewrite log file and log rotation behavior

This commit is contained in:
Vinnie Falco
2013-07-03 19:07:59 -07:00
parent 437f10b247
commit 535d510b48
9 changed files with 211 additions and 109 deletions

View File

@@ -88,6 +88,12 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\ripple_basics\utility\ripple_LogFile.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\ripple_basics\utility\ripple_RandomNumbers.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
@@ -1321,6 +1327,7 @@
<ClInclude Include="..\..\modules\ripple_basics\utility\ripple_HashUtilities.h" />
<ClInclude Include="..\..\modules\ripple_basics\utility\ripple_IniFile.h" />
<ClInclude Include="..\..\modules\ripple_basics\utility\ripple_Log.h" />
<ClInclude Include="..\..\modules\ripple_basics\utility\ripple_LogFile.h" />
<ClInclude Include="..\..\modules\ripple_basics\utility\ripple_PlatformMacros.h" />
<ClInclude Include="..\..\modules\ripple_basics\utility\ripple_RandomNumbers.h" />
<ClInclude Include="..\..\modules\ripple_basics\utility\ripple_ScopedLock.h" />

View File

@@ -822,6 +822,9 @@
<ClCompile Include="..\..\modules\ripple_app\ripple_app_pt8.cpp">
<Filter>[1] Ripple\ripple_app</Filter>
</ClCompile>
<ClCompile Include="..\..\modules\ripple_basics\utility\ripple_LogFile.cpp">
<Filter>[1] Ripple\ripple_basics\utility</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\Subtrees\sqlite\sqlite3.h">
@@ -1533,6 +1536,9 @@
<ClInclude Include="..\..\src\cpp\ripple\ripple_ILoadManager.h">
<Filter>[1] Ripple\ripple_app\_main</Filter>
</ClInclude>
<ClInclude Include="..\..\modules\ripple_basics\utility\ripple_LogFile.h">
<Filter>[1] Ripple\ripple_basics\utility</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="..\..\src\cpp\ripple\ripple.proto" />

View File

@@ -56,6 +56,7 @@ namespace ripple
#include "containers/ripple_TaggedCache.cpp"
#include "utility/ripple_Log.cpp"
#include "utility/ripple_LogFile.cpp"
#include "utility/ripple_ByteOrder.cpp"
#include "utility/ripple_CountedObject.cpp"

View File

@@ -77,6 +77,7 @@ namespace ripple
using namespace beast;
#include "utility/ripple_LogFile.h"
#include "utility/ripple_Log.h" // Needed by others
#include "types/ripple_BasicTypes.h"

View File

@@ -4,14 +4,10 @@
*/
//==============================================================================
boost::recursive_mutex Log::sLock;
LogFile Log::s_logFile;
boost::recursive_mutex Log::s_lock;
LogSeverity Log::sMinSeverity = lsINFO;
std::ofstream* Log::outStream = NULL;
boost::filesystem::path* Log::pathToLog = NULL;
uint32 Log::logRotateCounter = 0;
//------------------------------------------------------------------------------
LogPartition* LogPartition::headLog = NULL;
@@ -43,25 +39,6 @@ std::vector< std::pair<std::string, std::string> > LogPartition::getSeverities (
//------------------------------------------------------------------------------
// VFALCO TODO remove original code once we know the replacement is correct.
// Original code
/*
std::string ls = oss.str();
size_t s = ls.find("\"secret\"");
if (s != std::string::npos)
{
s += 8;
size_t sEnd = ls.size() - 1;
if (sEnd > (s + 35))
sEnd = s + 35;
for (int i = s; i < sEnd; ++i)
ls[i] = '*';
}
logMsg += ls;
*/
//------------------------------------------------------------------------------
std::string Log::replaceFirstSecretWithAsterisks (std::string s)
{
using namespace std;
@@ -144,14 +121,10 @@ Log::~Log ()
void Log::print (std::string const& text, bool toStdErr)
{
boost::recursive_mutex::scoped_lock sl (sLock);
boost::recursive_mutex::scoped_lock sl (s_lock);
// Always write to the log file if it is open.
//
if (outStream != NULL)
{
(*outStream) << text << std::endl;
}
// Does nothing if not open.
s_logFile.writeln (text);
if (toStdErr)
{
@@ -170,61 +143,23 @@ void Log::print (std::string const& text, bool toStdErr)
}
}
std::string Log::rotateLog (void)
std::string Log::rotateLog ()
{
boost::recursive_mutex::scoped_lock sl (sLock);
boost::filesystem::path abs_path;
std::string abs_path_str;
bool const wasOpened = s_logFile.closeAndReopen ();
uint32 failsafe = 0;
std::string abs_new_path_str;
do
if (wasOpened)
{
std::string s;
std::stringstream out;
failsafe++;
if (failsafe == std::numeric_limits<uint32>::max ())
{
return "unable to create new log file; too many log files!";
}
abs_path = boost::filesystem::absolute ("");
abs_path /= *pathToLog;
abs_path_str = abs_path.parent_path ().string ();
out << logRotateCounter;
s = out.str ();
abs_new_path_str = abs_path_str + "/" + s + "_" + pathToLog->filename ().string ();
logRotateCounter++;
return "The log file was closed and reopened.";
}
while (boost::filesystem::exists (boost::filesystem::path (abs_new_path_str)));
outStream->close ();
try
else
{
boost::filesystem::rename (abs_path, boost::filesystem::path (abs_new_path_str));
return "The log file could not be closed and reopened.";
}
catch (...)
{
// unable to rename existing log file
}
setLogFile (*pathToLog);
return abs_new_path_str;
}
void Log::setMinSeverity (LogSeverity s, bool all)
{
boost::recursive_mutex::scoped_lock sl (sLock);
boost::recursive_mutex::scoped_lock sl (s_lock);
sMinSeverity = s;
@@ -234,7 +169,7 @@ void Log::setMinSeverity (LogSeverity s, bool all)
LogSeverity Log::getMinSeverity ()
{
boost::recursive_mutex::scoped_lock sl (sLock);
boost::recursive_mutex::scoped_lock sl (s_lock);
return sMinSeverity;
}
@@ -292,28 +227,11 @@ LogSeverity Log::stringToSeverity (const std::string& s)
void Log::setLogFile (boost::filesystem::path const& path)
{
std::ofstream* newStream = new std::ofstream (path.c_str (), std::fstream::app);
bool const wasOpened = s_logFile.open (path.c_str ());
if (!newStream->good ())
if (! wasOpened)
{
Log (lsFATAL) << "Unable to open logfile " << path;
delete newStream;
newStream = NULL;
}
boost::recursive_mutex::scoped_lock sl (sLock);
if (outStream != NULL)
delete outStream;
outStream = newStream;
if (pathToLog != &path)
{
if (pathToLog != NULL)
delete pathToLog;
pathToLog = new boost::filesystem::path (path);
}
}

View File

@@ -115,6 +115,13 @@ public:
static void setLogFile (boost::filesystem::path const& pathToLogFile);
/** Rotate the log file.
The log file is closed and reopened. This is for compatibility
with log management tools.
@return A human readable string describing the result of the operation.
*/
static std::string rotateLog ();
public:
@@ -185,18 +192,14 @@ private:
maximumMessageCharacters = 12 * 1024
};
// VFALCO TODO looks like there are really TWO classes in here.
// One is a stream target for '<<' operator and the other
// is a singleton. Split the singleton out to a new class.
//
static boost::recursive_mutex sLock;
static LogSeverity sMinSeverity;
static std::ofstream* outStream;
static boost::filesystem::path* pathToLog;
static uint32 logRotateCounter;
static std::string replaceFirstSecretWithAsterisks (std::string s);
// Singleton variables
//
static LogFile s_logFile;
static boost::recursive_mutex s_lock;
static LogSeverity sMinSeverity;
mutable std::ostringstream oss;
LogSeverity mSeverity;
std::string mPartitionName;

View File

@@ -0,0 +1,69 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
LogFile::LogFile ()
: m_stream (nullptr)
{
}
LogFile::~LogFile ()
{
}
bool LogFile::isOpen () const noexcept
{
return m_stream != nullptr;
}
bool LogFile::open (boost::filesystem::path const& path)
{
close ();
bool wasOpened = false;
// VFALCO TODO Make this work with Unicode file paths
ScopedPointer <std::ofstream> stream (
new std::ofstream (path.c_str (), std::fstream::app));
if (stream->good ())
{
m_path = path;
m_stream = stream.release ();
wasOpened = true;
}
return wasOpened;
}
bool LogFile::closeAndReopen ()
{
close ();
return open (m_path);
}
void LogFile::close ()
{
m_stream = nullptr;
}
void LogFile::write (char const* text)
{
if (m_stream != nullptr)
(*m_stream) << text;
}
void LogFile::writeln (char const* text)
{
if (m_stream != nullptr)
{
(*m_stream) << text;
(*m_stream) << std::endl;
}
}

View File

@@ -0,0 +1,93 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_LOGFILE_H_INCLUDED
#define RIPPLE_LOGFILE_H_INCLUDED
/** Manages a system file containing logged output.
The system file remains open during program execution. Interfaces
are provided for interoperating with standard log management
tools like logrotate(8):
http://linuxcommand.org/man_pages/logrotate8.html
@note None of the listed interfaces are thread-safe.
*/
class LogFile : Uncopyable
{
public:
/** Construct with no associated system file.
A system file may be associated later with @ref open.
@see open
*/
LogFile ();
/** Destroy the object.
If a system file is associated, it will be flushed and closed.
*/
~LogFile ();
/** Determine if a system file is associated with the log.
@return `true` if a system file is associated and opened for writing.
*/
bool isOpen () const noexcept;
/** Associate a system file with the log.
If the file does not exist an attempt is made to create it
and open it for writing. If the file already exists an attempt is
made to open it for appending.
If a system file is already associated with the log, it is closed first.
@return `true` if the file was opened.
*/
// VFALCO NOTE The parameter is unfortunately a boost type because it
// can be either wchar or char based depending on platform.
// TODO Replace with beast::File
//
bool open (boost::filesystem::path const& path);
/** Close and re-open the system file associated with the log
This assists in interoperating with external log management tools.
@return `true` if the file was opened.
*/
bool closeAndReopen ();
/** Close the system file if it is open.
*/
void close ();
/** write to the log file.
Does nothing if there is no associated system file.
*/
void write (char const* text);
/** write to the log file and append an end of line marker.
Does nothing if there is no associated system file.
*/
void writeln (char const* text);
/** Write to the log file using std::string.
*/
inline void write (std::string const& str) { write (str.c_str ()); }
inline void writeln (std::string const& str) { writeln (str.c_str ()); }
private:
ScopedPointer <std::ofstream> m_stream;
boost::filesystem::path m_path;
};
#endif

View File

@@ -128,7 +128,7 @@ public:
- The ledger is not advanced automatically.
- If no ledger is loaded, the default ledger with the root
account is created.
*/
*/
bool RUN_STANDALONE;
// Note: The following parameters do not relate to the UNL or trust at all
@@ -201,7 +201,11 @@ public:
*/
String const getRpcAddress ()
{
return String (m_rpcIP.c_str ()) << ":" << m_rpcPort;
String s;
s << m_rpcIP.c_str () << ":" << m_rpcPort;
return s;
}
private: