Journal console output improvements

This commit is contained in:
Vinnie Falco
2013-09-28 16:39:18 -07:00
parent 97f1b41b4d
commit 58a8a97177
10 changed files with 226 additions and 237 deletions

View File

@@ -171,7 +171,7 @@
// is being written.
//
#ifndef RIPPLE_USE_NEW_VALIDATORS
#define RIPPLE_USE_NEW_VALIDATORS 0
#define RIPPLE_USE_NEW_VALIDATORS 1
#endif
// Turning this on makes the Application object get destroyed,

View File

@@ -38,12 +38,15 @@ public:
/** Severity level of the message. */
enum Severity
{
kTrace,
kLowestSeverity = 0,
kTrace = kLowestSeverity,
kDebug,
kInfo,
kWarning,
kError,
kFatal
kFatal,
kDisabled
};
//--------------------------------------------------------------------------
@@ -57,15 +60,16 @@ public:
/** Write text to the sink at the specified severity. */
virtual void write (Severity severity, std::string const& text) = 0;
/** Returns `true` if text at the passed severity produces output.
The default implementation always returns `true`.
*/
virtual bool active (Severity);
/** Returns `true` if text at the passed severity produces output. */
virtual bool active (Severity severity) = 0;
/** Returns `true` if text at the severity goes to the Output window. */
virtual bool console ();
/** Returns `true` if a message is also written to the Output Window (MSVC). */
virtual bool console () = 0;
/** Set the minimum severity this sink will report. */
virtual void set_severity (Severity severity) = 0;
/** Set whether messages are also written to the Output Window (MSVC). */
virtual void set_console (bool to_console) = 0;
};
@@ -122,19 +126,26 @@ public:
/** Construct a stream which produces no logging output. */
Stream ();
/** Construct a stream that writes to the Sink at the given Severity. */
Stream (Sink& sink, Severity severity);
/** Construct or copy another Stream. */
/** @{ */
Stream (Stream const& other);
Stream& operator= (Stream const& other);
/** @} */
/** Returns `true` if the sink logs messages at the severity of this stream. */
bool active() const;
/** Returns `true` if the stream also logs messages to the Output window. */
bool console() const;
/** Returns the Sink that this Stream writes to. */
Sink& sink() const;
/** Returns the Severity of messages this Stream reports. */
Severity severity() const;
/** Returns `true` if sink logs anything at this stream's severity. */
bool active() const;
/** Output stream support. */
/** @{ */
ScopedStream operator<< (std::ostream& manip (std::ostream&)) const;
template <typename T>
@@ -142,6 +153,7 @@ public:
{
return ScopedStream (*this, t);
}
/** @} */
private:
Sink* m_sink;
@@ -155,16 +167,14 @@ public:
Journal (Journal const& other);
~Journal ();
/** Returns the Sink associated with this Journal. */
Sink& sink() const;
/** Returns a stream for this sink, with the specified severity. */
Stream stream (Severity severity) const;
Sink& sink() const;
/** Returns `true` if the sink logs messages at that severity. */
/** @{ */
/** Returns `true` if any message would be logged at this severity level. */
bool active (Severity severity) const;
bool console () const;
/** @} */
/** Convenience sink streams for each severity level. */
Stream const trace;

View File

@@ -22,15 +22,7 @@
namespace beast
{
bool Journal::Sink::active (Severity)
{
return true;
}
bool Journal::Sink::console ()
{
return false;
}
//------------------------------------------------------------------------------
// A Sink that does nothing.
class NullJournalSink : public Journal::Sink
@@ -45,7 +37,7 @@ public:
return false;
}
bool console (Journal::Severity)
bool console ()
{
return false;
}
@@ -94,11 +86,6 @@ Journal::ScopedStream::~ScopedStream ()
{
if (m_sink.active (m_severity))
m_sink.write (m_severity, m_ostream.str());
#if BEAST_MSVC
if (m_sink.console () && beast_isRunningUnderDebugger ())
Logger::outputDebugString (m_ostream.str());
#endif
}
}
@@ -116,7 +103,7 @@ std::ostringstream& Journal::ScopedStream::ostream () const
Journal::Stream::Stream ()
: m_sink (&getNullSink ())
, m_severity (kFatal)
, m_severity (kDisabled)
{
}
@@ -124,6 +111,7 @@ Journal::Stream::Stream (Sink& sink, Severity severity)
: m_sink (&sink)
, m_severity (severity)
{
bassert (severity != kDisabled);
}
Journal::Stream::Stream (Stream const& other)
@@ -132,16 +120,6 @@ Journal::Stream::Stream (Stream const& other)
{
}
bool Journal::Stream::active () const
{
return m_sink->active (m_severity);
}
bool Journal::Stream::console() const
{
return m_sink->console ();
}
Journal::Sink& Journal::Stream::sink () const
{
return *m_sink;
@@ -152,6 +130,11 @@ Journal::Severity Journal::Stream::severity () const
return m_severity;
}
bool Journal::Stream::active () const
{
return m_sink->active (m_severity);
}
Journal::Stream& Journal::Stream::operator= (Stream const& other)
{
m_sink = other.m_sink;
@@ -203,25 +186,20 @@ Journal::~Journal ()
{
}
Journal::Stream Journal::stream (Severity severity) const
{
return Stream (*m_sink, severity);
}
Journal::Sink& Journal::sink() const
{
return *m_sink;
}
/** Returns `true` if the sink logs messages at that severity. */
Journal::Stream Journal::stream (Severity severity) const
{
return Stream (*m_sink, severity);
}
bool Journal::active (Severity severity) const
{
bassert (severity != kDisabled);
return m_sink->active (severity);
}
bool Journal::console () const
{
return m_sink->console ();
}
}

View File

@@ -17,7 +17,6 @@
*/
//==============================================================================
#ifndef RIPPLE_VALIDATORS_MANAGER_H_INCLUDED
#define RIPPLE_VALIDATORS_MANAGER_H_INCLUDED
@@ -25,56 +24,55 @@ namespace ripple {
namespace Validators {
/** Maintains the list of chosen validators.
The algorithm for acquiring, building, and calculating metadata on
the list of chosen validators is critical to the health of the network.
All operations are performed asynchronously on an internal thread.
*/
class Manager : public RPC::Service
{
public:
/** Create a new Manager object.
@param parent The parent Stoppable.
@param journal Where to send log output.
*/
static Manager* New (Stoppable& parent, Journal journal);
/** Destroy the object.
Any pending source fetch operations are aborted.
There may be some listener calls made before the
destructor returns.
Any pending source fetch operations are aborted. This will block
until any pending database I/O has completed and the thread has
stopped.
*/
virtual ~Manager () { }
/** Add a static source of validators from a string array. */
/** Add a static source of validators.
The validators added using these methods will always be chosen when
constructing the UNL regardless of statistics. The fetch operation
is performed asynchronously, so this call returns immediately. A
failed fetch (depending on the source) is not retried. The caller
loses ownership of any dynamic objects.
Thread safety:
Can be called from any thread.
*/
/** @{ */
virtual void addStrings (String name,
std::vector <std::string> const& strings) = 0;
virtual void addStrings (String name,
StringArray const& stringArray) = 0;
virtual void addFile (File const& file) = 0;
virtual void addStaticSource (Source* source) = 0;
/** @} */
/** Add a static source of validators from a text file. */
virtual void addFile (File const& file) = 0;
/** Add a static source of validators.
The Source is called to fetch once and the results are kept
permanently. The fetch is performed asynchronously, this call
returns immediately. If the fetch fails, it is not reattempted.
The caller loses ownership of the object.
/** Add a live source of validators from a trusted URL.
The URL will be contacted periodically to update the list. The fetch
operation is performed asynchronously, this call doesn't block.
Thread safety:
Can be called from any thread.
*/
virtual void addStaticSource (Source* source) = 0;
/** Add a live source of validators from a trusted URL.
The URL will be contacted periodically to update the list.
*/
virtual void addURL (URL const& url) = 0;
/** Add a live source of validators.
The caller loses ownership of the object.
The caller loses ownership of the object. The fetch is performed
asynchronously, this call doesn't block.
Thread safety:
Can be called from any thread.
*/
@@ -82,12 +80,8 @@ public:
//--------------------------------------------------------------------------
// Trusted Validators
//virtual bool isPublicKeyTrusted (RipplePublicKey const& publicKey) = 0;
//--------------------------------------------------------------------------
/** Called when a validation with a proper signature is received. */
virtual void receiveValidation (ReceivedValidation const& rv) = 0;

View File

@@ -17,84 +17,82 @@
*/
//==============================================================================
/*
/** ChosenValidators (formerly known as UNL)
Information to track:
Motivation:
- Percentage of validations that the validator has signed
- Number of validations the validator signed that never got accepted
To protect the integrity of the shared ledger data structure, Validators
independently sign LedgerHash objects with their RipplePublicKey. These
signed Validations are propagated through the peer to peer network so
that other nodes may inspect them. Every peer and client on the network
gains confidence in a ledger and its associated chain of previous ledgers
by maintaining a suitably sized list of Validator public keys that it
trusts.
The most important factors in choosing Validators for a ChosenValidators
list (the name we will use to designate such a list) are the following:
- That different Validators are not controlled by one entity
- That each Validator participates in a majority of ledgers
- That a Validator does not sign ledgers which fail consensus
This module maintains ChosenValidators list. The list is built from a set
of independent Source objects, which may come from the configuration file,
a separate file, a URL from some trusted domain, or from the network itself.
In order that rippled administrators may publish their ChosenValidators
list at a URL on a trusted domain that they own, this module compiles
statistics on ledgers signed by validators and stores them in a database.
From this database reports and alerts may be generated so that up-to-date
information about the health of the set of ChosenValidators is always
availabile.
In addition to the automated statistics provided by the module, it is
expected that organizations and meta-organizations will form from
stakeholders such as gateways who publish their own lists and provide
"best practices" to further refine the quality of validators placed into
ChosenValidators list.
- Target number for Chosen
- Pseudo-randomly choose a subset from Chosen
----------------------------------------------------------------------------
Unorganized Notes:
David:
Maybe OC should have a URL that you can query to get the latest list of URI's
for OC-approved organzations that publish lists of validators. The server and
client can ship with that master trust URL and also the list of URI's at the
time it's released, in case for some reason it can't pull from OC. That would
make the default installation safe even against major changes in the
organizations that publish validator lists.
The difference is that if an organization that provides lists of validators
goes rogue, administrators don't have to act.
TODO:
Write up from end-user perspective on the deployment and administration
of this feature, on the wiki. "DRAFT" or "PROPOSE" to mark it as provisional.
Template: https://ripple.com/wiki/Federation_protocol
- What to do if you're a publisher of ValidatorList
- What to do if you're a rippled administrator
- Overview of how ChosenValidators works
Goal:
Goals:
Make default configuration of rippled secure.
* Ship with TrustedUriList
* Also have a preset RankedValidators
Eliminate administrative burden of maintaining
Produce the ChosenValidators list.
Allow quantitative analysis of network health.
Provide the listener with a ValidatorList.
- This forms the UNL
Task:
fetch ValidatorInfo array from a source
- We have the old one and the new one, compute the following:
* unchanged validators list
* new validators list
* removed validators list
- From the unchanged / new / removed, figure out what to do.
Two important questions:
- Are there any validators in my ChosenValidators that I dont want
* For example, they have dropped off all the trusted lists
- Do I have enough?
--------------------------------------------------------------------------------
ChosenValidators
--------------------------------------------------------------------------------
David:
Maybe OC should have a URL that you can query to get the latest list of URI's
for OC-approved organzations that publish lists of validators. The server and
client can ship with that master trust URL and also the list of URI's at the
time it's released, in case for some reason it can't pull from OC. That would
make the default installation safe even against major changes in the
organizations that publish validator lists.
The difference is that if an organization that provides lists of validators
goes rogue, administrators don't have to act.
TODO:
Write up from end-user perspective on the deployment and administration
of this feature, on the wiki. "DRAFT" or "PROPOSE" to mark it as provisional.
Template: https://ripple.com/wiki/Federation_protocol
- What to do if you're a publisher of ValidatorList
- What to do if you're a rippled administrator
- Overview of how ChosenValidators works
Goals:
Make default configuration of rippled secure.
* Ship with TrustedUriList
* Also have a preset RankedValidators
Eliminate administrative burden of maintaining
Produce the ChosenValidators list.
Allow quantitative analysis of network health.
What determines that a validator is good?
- Are they present (i.e. sending validations)
- Are they on the consensus ledger
- What percentage of consensus rounds do they participate in
- Are they stalling consensus
* Measurements of constructive/destructive behavior is
calculated in units of percentage of ledgers for which
the behavior is measured.
What determines that a validator is good?
- Are they present (i.e. sending validations)
- Are they on the consensus ledger
- What percentage of consensus rounds do they participate in
- Are they stalling consensus
* Measurements of constructive/destructive behavior is
calculated in units of percentage of ledgers for which
the behavior is measured.
*/
namespace ripple {
@@ -128,7 +126,13 @@ public:
, m_checkTimer (this)
, m_checkSources (true)
{
m_journal.sink().set_console (true);
#if BEAST_MSVC
if (beast_isRunningUnderDebugger())
{
m_journal.sink().set_console (true);
m_journal.sink().set_severity (Journal::kLowestSeverity);
}
#endif
}
~ManagerImp ()

View File

@@ -17,7 +17,6 @@
*/
//==============================================================================
#ifndef RIPPLE_BASICS_LOGJOURNAL_H_INCLUDED
#define RIPPLE_BASICS_LOGJOURNAL_H_INCLUDED
@@ -37,13 +36,22 @@ public:
public:
PartitionSink ()
: m_partition (LogPartition::get <Key> ())
, m_console (false)
, m_severity (Journal::kLowestSeverity)
, m_to_console (false)
{
}
void write (Journal::Severity severity, std::string const& text)
{
LogSink::get()->write (text, convertSeverity (severity), m_partition.getName());
std::string output;
LogSeverity const logSeverity (convertSeverity (severity));
LogSink::get()->format (output, text, logSeverity,
m_partition.getName());
LogSink::get()->write (output, logSeverity);
#if BEAST_MSVC
if (m_to_console && beast_isRunningUnderDebugger ())
Logger::outputDebugString (output.c_str());
#endif
}
bool active (Journal::Severity severity)
@@ -53,24 +61,24 @@ public:
bool console()
{
return m_console;
return m_to_console;
}
void set_severity (Journal::Severity severity)
{
// VFALCO TODO Per-partition severity levels
bassertfalse;
LogSeverity const logSeverity (convertSeverity (severity));
m_partition.setMinimumSeverity (logSeverity);
}
void set_console (bool to_console)
{
m_console = to_console;
m_to_console = to_console;
}
private:
LogPartition const& m_partition;
LogPartition& m_partition;
Journal::Severity m_severity;
bool m_console;
bool m_to_console;
};
//--------------------------------------------------------------------------

View File

@@ -47,6 +47,11 @@ std::vector< std::pair<std::string, std::string> > LogPartition::getSeverities (
//------------------------------------------------------------------------------
void LogPartition::setMinimumSeverity (LogSeverity severity)
{
mMinSeverity = severity;
}
bool LogPartition::setSeverity (const std::string& partition, LogSeverity severity)
{
for (LogPartition* p = headLog; p != NULL; p = p->mNextLog)

View File

@@ -21,17 +21,17 @@
#ifndef RIPPLE_BASICS_LOGPARTITION_H_INCLUDED
#define RIPPLE_BASICS_LOGPARTITION_H_INCLUDED
class LogPartition // : public List <LogPartition>::Node
class LogPartition
{
public:
LogPartition (const char* partitionName);
explicit LogPartition (const char* partitionName);
/** Retrieve the LogPartition associated with an object.
Each LogPartition is a singleton.
*/
template <class Key>
static LogPartition const& get ()
static LogPartition& get ()
{
struct LogPartitionType : LogPartition
{
@@ -53,6 +53,8 @@ public:
return mName;
}
void setMinimumSeverity (LogSeverity severity);
static bool setSeverity (const std::string& partition, LogSeverity severity);
static void setSeverity (LogSeverity severity);
static std::vector< std::pair<std::string, std::string> > getSeverities ();

View File

@@ -17,7 +17,6 @@
*/
//==============================================================================
LogSink::LogSink ()
: m_mutex ("Log", __FILE__, __LINE__)
, m_minSeverity (lsINFO)
@@ -71,47 +70,59 @@ std::string LogSink::rotateLog ()
}
}
void LogSink::format (
std::string& output,
std::string const& message,
LogSeverity severity,
std::string const& partitionName)
{
output.reserve (message.size() + partitionName.size() + 100);
output = boost::posix_time::to_simple_string (
boost::posix_time::second_clock::universal_time ());
output += " ";
if (! partitionName.empty ())
output += partitionName + ":";
switch (severity)
{
case lsTRACE: output += "TRC "; break;
case lsDEBUG: output += "DBG "; break;
case lsINFO: output += "NFO "; break;
case lsWARNING: output += "WRN "; break;
case lsERROR: output += "ERR "; break;
default:
bassertfalse;
case lsFATAL: output += "FTL ";
break;
}
output += replaceFirstSecretWithAsterisks (message);
if (output.size() > maximumMessageCharacters)
{
output.resize (maximumMessageCharacters - 3);
output += "...";
}
}
void LogSink::write (
std::string const& message,
LogSeverity severity,
std::string const& partitionName)
{
std::string text;
text.reserve (message.size() + partitionName.size() + 100);
std::string output;
text = boost::posix_time::to_simple_string (
boost::posix_time::second_clock::universal_time ());
format (output, message, severity, partitionName);
text += " ";
if (! partitionName.empty ())
text += partitionName + ":";
write (output, severity);
}
switch (severity)
{
case lsTRACE: text += "TRC "; break;
case lsDEBUG: text += "DBG "; break;
case lsINFO: text += "NFO "; break;
case lsWARNING: text += "WRN "; break;
case lsERROR: text += "ERR "; break;
default:
bassertfalse;
case lsFATAL: text += "FTL ";
break;
}
text += replaceFirstSecretWithAsterisks (message);
if (text.size() > maximumMessageCharacters)
{
text.resize (maximumMessageCharacters - 3);
text += "...";
}
{
ScopedLockType lock (m_mutex, __FILE__, __LINE__);
write (text, severity >= getMinSeverity(), lock);
}
void LogSink::write (std::string const& output, LogSeverity severity)
{
ScopedLockType lock (m_mutex, __FILE__, __LINE__);
write (output, severity >= getMinSeverity(), lock);
}
void LogSink::write (std::string const& text)
@@ -121,37 +132,13 @@ void LogSink::write (std::string const& text)
write (text, true, lock);
}
void LogSink::write (StringArray const& strings)
{
ScopedLockType lock (m_mutex, __FILE__, __LINE__);
for (int i = 0; i < strings.size (); ++i)
write (strings [i].toStdString (), true, lock);
}
void LogSink::write (std::string const& line, bool toStdErr, ScopedLockType&)
{
// Does nothing if not open.
m_logFile.writeln (line);
if (toStdErr)
{
#if 0
#if BEAST_MSVC
if (beast_isRunningUnderDebugger ())
{
// Send it to the attached debugger's Output window
//
Logger::outputDebugString (line);
}
else
#endif
#endif
{
std::cerr << line << std::endl;
}
}
std::cerr << line << std::endl;
}
//------------------------------------------------------------------------------

View File

@@ -17,7 +17,6 @@
*/
//==============================================================================
#ifndef RIPPLE_BASICS_LOGSINK_H_INCLUDED
#define RIPPLE_BASICS_LOGSINK_H_INCLUDED
@@ -31,7 +30,10 @@ public:
/** Returns the minimum severity required for also writing to stderr. */
LogSeverity getMinSeverity ();
/** Sets the minimum severity required for also writing to stderr. */
/** Sets the minimum severity required for also writing to stderr.
If 'all' is true this will set the minimum reporting severity for
all partitions.
*/
void setMinSeverity (LogSeverity, bool all);
/** Sets the path to the log file. */
@@ -44,14 +46,14 @@ public:
*/
std::string rotateLog ();
/** Format a log message. */
void format (std::string& output,
std::string const& message, LogSeverity severity,
std::string const& partitionName);
/** Write to log output.
All logging eventually goes through this function. If a debugger
is attached, the string goes to the debugging console, else it goes
to the standard error output. If a log file is open, then the message
is additionally written to the open log file.
The text should not contain a newline, it will be automatically
All logging eventually goes through these functios.
The text should not contain a final newline, it will be automatically
added as needed.
@note This acquires a global mutex.
@@ -60,10 +62,9 @@ public:
@param toStdErr `true` to also write to std::cerr
*/
/** @{ */
void write (std::string const& message,
LogSeverity severity, std::string const& partitionName);
void write (std::string const& message, LogSeverity severity, std::string const& partitionName);
void write (std::string const& text, LogSeverity severity);
void write (std::string const& text);
void write (StringArray const& strings);
/** @} */
/** Hides secret keys from log output. */