Consistent error handling.

This commit is contained in:
Robin Sommer 2011-02-21 17:56:09 -08:00
parent cf148c8a25
commit ac936feb95
5 changed files with 92 additions and 40 deletions

View file

@ -1,21 +1,17 @@
List of the things not implemented yet:
- Cluster-style remote_print
- Rotation support
- Spawning writers in separate threads (not clear if we want that initially).
- Cluster-style remote_print.
- Rotation support.
- Not sure if the logging does the right thing with &optional and
&default values. Needs testing.
- Seems we could do some of the filter-related type checks
currently done dynamically at startup via a TraversalCallback.
- LogMgs' error handling
- Put script function/constants into namespace.
- Some typchecks are still missing.
- Cleanup code.
There's probably more missing.
- Spawning writers in separate threads (not clear if we want that initially).
Questions:
* Is giving the record column twice to create_stream too
* Is giving the record column twice to create_stream() too
redundant? (once directly, and once via the event)::
global ssh_log: event(rec: Log);

View file

@ -89,6 +89,28 @@ LogMgr::Stream* LogMgr::FindStream(EnumVal* stream_id)
return streams[idx];
}
void LogMgr::RemoveDisabledWriters(Stream* stream)
{
for ( list<Filter*>::iterator i = stream->filters.begin(); i != stream->filters.end(); ++i )
{
Filter* filter = (*i);
list<string> disabled;
for ( Filter::WriterMap::iterator j = filter->writers.begin(); j != filter->writers.end(); j++ )
{
if ( j->second->Disabled() )
{
delete j->second;
disabled.push_back(j->first);
}
}
for ( list<string>::iterator j = disabled.begin(); j != disabled.end(); j++ )
filter->writers.erase(*j);
}
}
bool LogMgr::CreateStream(EnumVal* stream_id, RecordType* columns, EventHandlerPtr handler)
{
// TODO: Should check that the record has only supported types.
@ -349,6 +371,8 @@ bool LogMgr::RemoveFilter(EnumVal* stream_id, StringVal* filter)
bool LogMgr::Write(EnumVal* stream_id, RecordVal* columns)
{
bool error = false;
Stream* stream = FindStream(stream_id);
if ( ! stream )
return false;
@ -440,7 +464,8 @@ bool LogMgr::Write(EnumVal* stream_id, RecordVal* columns)
// Alright, can do the write now.
LogVal** vals = RecordToFilterVals(filter, columns);
writer->Write(vals);
if ( ! writer->Write(vals) )
error = true;
#ifdef DEBUG
DBG_LOG(DBG_LOGGING, "Wrote record to filter '%s' on stream '%s'", filter->name.c_str(), stream->name.c_str());
@ -448,6 +473,10 @@ bool LogMgr::Write(EnumVal* stream_id, RecordVal* columns)
}
Unref(columns);
if ( error )
RemoveDisabledWriters(stream);
return true;
}
@ -545,9 +574,12 @@ bool LogMgr::SetBuf(EnumVal* stream_id, bool enabled)
j->second->SetBuf(enabled);
}
RemoveDisabledWriters(stream);
return true;
}
void LogMgr::Error(LogWriter* writer, const char* msg)
{
run_time(fmt("error with writer for %s: %s", writer->Path().c_str(), msg));
}

View file

@ -76,6 +76,7 @@ private:
bool TraverseRecord(Filter* filter, RecordType* rt, TableVal* include, TableVal* exclude, string path, list<int> indices);
LogVal** RecordToFilterVals(Filter* filter, RecordVal* columns);
Stream* FindStream(EnumVal* stream_id);
void RemoveDisabledWriters(Stream* stream);
vector<Stream *> streams; // Indexed by stream enum.
};

View file

@ -7,6 +7,7 @@ LogWriter::LogWriter()
buf = 0;
buf_len = 1024;
buffering = true;
disabled = false;
}
LogWriter::~LogWriter()
@ -22,7 +23,13 @@ bool LogWriter::Init(string arg_path, int arg_num_fields, LogField** arg_fields)
path = arg_path;
num_fields = arg_num_fields;
fields = arg_fields;
DoInit(arg_path, arg_num_fields, arg_fields);
if ( ! DoInit(arg_path, arg_num_fields, arg_fields) )
{
disabled = true;
return false;
}
return true;
}
@ -30,12 +37,11 @@ bool LogWriter::Write(LogVal** vals)
{
bool result = DoWrite(num_fields, fields, vals);
DeleteVals(vals);
return result;
}
void LogWriter::Finish()
{
DoFinish();
if ( ! result )
disabled = true;
return result;
}
bool LogWriter::SetBuf(bool enabled)
@ -45,7 +51,18 @@ bool LogWriter::SetBuf(bool enabled)
return true;
buffering = enabled;
return DoSetBuf(enabled);
if ( ! DoSetBuf(enabled) )
{
disabled = true;
return false;
}
return true;
}
void LogWriter::Finish()
{
DoFinish();
}
const char* LogWriter::Fmt(const char* format, ...)
@ -72,10 +89,9 @@ const char* LogWriter::Fmt(const char* format, ...)
return buf;
}
void LogWriter::Error(const char *msg)
{
run_time(msg);
log_mgr->Error(this, msg);
}
void LogWriter::DeleteVals(LogVal** vals)

View file

@ -31,38 +31,38 @@ public:
// occured, in which case the writer must not be used further.
bool Write(LogVal** vals);
// Sets the buffering status for the writer, if the writer supports
bool SetBuf(bool enabled);
// Finished writing to this logger. Will not be called if an error has
// been indicated earlier. After calling this, no more writing must be
// performed.
void Finish();
// Sets the buffering status for the writer, if the writer supports
bool SetBuf(bool enabled);
protected:
//// Methods for Writers to override.
// Methods for Writers to override. If any of these returs false, it will
// be assumed that a fatal error has occured that prevents the writer
// from further operation. It will then be disabled and deleted. In that
// case, the writer should also report the error via Error(). If a writer
// does not specifically implement one of the methods, it must still
// always return true.
// Called once for initialization of the Writer. Must return false if an
// error occured, in which case the writer will be disabled. The error
// reason should be reported via Error().
// Called once for initialization of the Writer.
virtual bool DoInit(string path, int num_fields, LogField** fields) = 0;
// Called once per entry to record. Must return false if an error
// occured, in which case the writer will be disabled. The error reason
// should be reported via Error().
// Called once per entry to record.
virtual bool DoWrite(int num_fields, LogField** fields, LogVal** vals) = 0;
// Called when the buffering status for this writer is changed. If
// buffering is disabled, the writer should attempt to write out
// information as quickly as possible even if that may have an
// performance impact. If enabled (which the writer should assume to be
// the default), then it can buffer things up as necessary and write out
// in a way optimized for performance. The current buffering state can
// alse be queried via IsBuf().
// information as quickly as possible even if doing so may have an
// performance impact. If enabled (which is the default), it can buffer
// things up as necessary and write out in a way optimized for
// performance. The current buffering state can be queried via IsBuf().
//
// A writer may ignore buffering if it doesn't fit with its semantics.
// Still return true in that case.
// A writer may ignore buffering changes if it doesn't fit with its
// semantics.
virtual bool DoSetBuf(bool enabled) = 0;
// Called when a log output is to be rotated. Most directly, this only
@ -83,7 +83,7 @@ protected:
// still call Error(), but return true.
//
// A writer may ignore rotation requests if it doesn't fit with its
// semantics. In that case, still return true.
// semantics.
virtual bool DoRotate(string rotated_path) = 0;
// Called once on termination. Not called when any of the other methods
@ -106,13 +106,20 @@ protected:
const string Path() const { return path; }
private:
// Delete values as passed into Write().
friend class LogMgr;
// When an error occurs, we set this flag. The LogMgr will check it an
// remove any disabled writers.
bool Disabled() { return disabled; }
// Deletes the values passed into Write().
void DeleteVals(LogVal** vals);
string path;
int num_fields;
LogField** fields;
bool buffering;
bool disabled;
// For Fmt().
char* buf;