Files
xahaud/src/ripple/basics/impl/Log.cpp
2014-09-16 14:15:12 -07:00

329 lines
8.0 KiB
C++

//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <boost/algorithm/string.hpp>
// VFALCO TODO Use std::chrono
#include <boost/date_time/posix_time/posix_time.hpp>
#include <fstream>
namespace ripple {
Logs::Sink::Sink (std::string const& partition,
beast::Journal::Severity severity, Logs& logs)
: logs_(logs)
, partition_(partition)
{
beast::Journal::Sink::severity (severity);
}
void
Logs::Sink::write (beast::Journal::Severity level, std::string const& text)
{
logs_.write (level, partition_, text, console());
}
//------------------------------------------------------------------------------
Logs::File::File()
: m_stream (nullptr)
{
}
Logs::File::~File()
{
}
bool Logs::File::isOpen () const noexcept
{
return m_stream != nullptr;
}
bool Logs::File::open (boost::filesystem::path const& path)
{
close ();
bool wasOpened = false;
// VFALCO TODO Make this work with Unicode file paths
std::unique_ptr <std::ofstream> stream (
new std::ofstream (path.c_str (), std::fstream::app));
if (stream->good ())
{
m_path = path;
m_stream = std::move (stream);
wasOpened = true;
}
return wasOpened;
}
bool Logs::File::closeAndReopen ()
{
close ();
return open (m_path);
}
void Logs::File::close ()
{
m_stream = nullptr;
}
void Logs::File::write (char const* text)
{
if (m_stream != nullptr)
(*m_stream) << text;
}
void Logs::File::writeln (char const* text)
{
if (m_stream != nullptr)
{
(*m_stream) << text;
(*m_stream) << std::endl;
}
}
//------------------------------------------------------------------------------
Logs::Logs()
: level_ (beast::Journal::kWarning) // default severity
{
}
bool
Logs::open (boost::filesystem::path const& pathToLogFile)
{
return file_.open(pathToLogFile);
}
Logs::Sink&
Logs::get (std::string const& name)
{
std::lock_guard <std::mutex> lock (mutex_);
auto const result (sinks_.emplace (std::piecewise_construct,
std::forward_as_tuple(name), std::forward_as_tuple (name,
level_, *this)));
return result.first->second;
}
Logs::Sink&
Logs::operator[] (std::string const& name)
{
return get(name);
}
beast::Journal
Logs::journal (std::string const& name)
{
return beast::Journal (get(name));
}
beast::Journal::Severity
Logs::severity() const
{
return level_;
}
void
Logs::severity (beast::Journal::Severity level)
{
std::lock_guard <std::mutex> lock (mutex_);
level_ = level;
for (auto& sink : sinks_)
sink.second.severity (level);
}
std::vector<std::pair<std::string, std::string>>
Logs::partition_severities() const
{
std::vector<std::pair<std::string, std::string>> list;
std::lock_guard <std::mutex> lock (mutex_);
list.reserve (sinks_.size());
for (auto const& e : sinks_)
list.push_back(std::make_pair(e.first,
toString(fromSeverity(e.second.severity()))));
return list;
}
void
Logs::write (beast::Journal::Severity level, std::string const& partition,
std::string const& text, bool console)
{
std::string s;
format (s, text, level, partition);
std::lock_guard <std::mutex> lock (mutex_);
file_.writeln (s);
std::cerr << s << '\n';
// VFALCO TODO Fix console output
//if (console)
// out_.write_console(s);
}
std::string
Logs::rotate()
{
std::lock_guard <std::mutex> lock (mutex_);
bool const wasOpened = file_.closeAndReopen ();
if (wasOpened)
return "The log file was closed and reopened.";
return "The log file could not be closed and reopened.";
}
LogSeverity
Logs::fromSeverity (beast::Journal::Severity level)
{
using beast::Journal;
switch (level)
{
case Journal::kTrace: return lsTRACE;
case Journal::kDebug: return lsDEBUG;
case Journal::kInfo: return lsINFO;
case Journal::kWarning: return lsWARNING;
case Journal::kError: return lsERROR;
default:
bassertfalse;
case Journal::kFatal:
break;
}
return lsFATAL;
}
beast::Journal::Severity
Logs::toSeverity (LogSeverity level)
{
using beast::Journal;
switch (level)
{
case lsTRACE: return Journal::kTrace;
case lsDEBUG: return Journal::kDebug;
case lsINFO: return Journal::kInfo;
case lsWARNING: return Journal::kWarning;
case lsERROR: return Journal::kError;
default:
bassertfalse;
case lsFATAL:
break;
}
return Journal::kFatal;
}
std::string
Logs::toString (LogSeverity s)
{
switch (s)
{
case lsTRACE: return "Trace";
case lsDEBUG: return "Debug";
case lsINFO: return "Info";
case lsWARNING: return "Warning";
case lsERROR: return "Error";
case lsFATAL: return "Fatal";
default:
assert (false);
return "Unknown";
}
}
LogSeverity
Logs::fromString (std::string const& s)
{
if (boost::iequals (s, "trace"))
return lsTRACE;
if (boost::iequals (s, "debug"))
return lsDEBUG;
if (boost::iequals (s, "info") || boost::iequals (s, "information"))
return lsINFO;
if (boost::iequals (s, "warn") || boost::iequals (s, "warning") || boost::iequals (s, "warnings"))
return lsWARNING;
if (boost::iequals (s, "error") || boost::iequals (s, "errors"))
return lsERROR;
if (boost::iequals (s, "fatal") || boost::iequals (s, "fatals"))
return lsFATAL;
return lsINVALID;
}
// Replace the first secret, if any, with asterisks
std::string
Logs::scrub (std::string s)
{
using namespace std;
char const* secretToken = "\"secret\"";
// Look for the first occurrence of "secret" in the string.
size_t startingPosition = s.find (secretToken);
if (startingPosition != string::npos)
{
// Found it, advance past the token.
startingPosition += strlen (secretToken);
// Replace the next 35 characters at most, without overwriting the end.
size_t endingPosition = std::min (startingPosition + 35, s.size () - 1);
for (size_t i = startingPosition; i < endingPosition; ++i)
s [i] = '*';
}
return s;
}
void
Logs::format (std::string& output, std::string const& message,
beast::Journal::Severity severity, std::string const& partition)
{
output.reserve (message.size() + partition.size() + 100);
output = boost::posix_time::to_simple_string (
boost::posix_time::second_clock::universal_time ());
output += " ";
if (! partition.empty ())
output += partition + ":";
switch (severity)
{
case beast::Journal::kTrace: output += "TRC "; break;
case beast::Journal::kDebug: output += "DBG "; break;
case beast::Journal::kInfo: output += "NFO "; break;
case beast::Journal::kWarning: output += "WRN "; break;
case beast::Journal::kError: output += "ERR "; break;
default:
bassertfalse;
case beast::Journal::kFatal: output += "FTL "; break;
}
output += scrub (message);
if (output.size() > maximumMessageCharacters)
{
output.resize (maximumMessageCharacters - 3);
output += "...";
}
}
} // ripple