advanced error reporting / stack capture
This commit is contained in:
parent
74709a4983
commit
b35f6880c6
4 changed files with 141 additions and 0 deletions
|
|
@ -55,6 +55,7 @@ set( sources
|
|||
src/json_rpc_tcp_connection.cpp
|
||||
src/json_rpc_tcp_server.cpp
|
||||
src/json_rpc_error_object.cpp
|
||||
src/error_report.cpp
|
||||
src/value.cpp
|
||||
src/lexical_cast.cpp
|
||||
src/spin_lock.cpp
|
||||
|
|
|
|||
60
include/fc/error_report.hpp
Normal file
60
include/fc/error_report.hpp
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
#pragma once
|
||||
#include <fc/vector.hpp>
|
||||
#include <fc/string.hpp>
|
||||
#include <fc/value.hpp>
|
||||
#include <fc/optional.hpp>
|
||||
|
||||
namespace fc {
|
||||
|
||||
/**
|
||||
* Represents one stack frame within an error_report.
|
||||
*/
|
||||
class error_frame {
|
||||
public:
|
||||
error_frame( const fc::string& file, uint64_t line, const fc::string& method, const fc::string& desc, fc::value m );
|
||||
error_frame(){}
|
||||
error_frame(const error_frame& );
|
||||
error_frame(error_frame&& );
|
||||
|
||||
error_frame& operator=(const error_frame& );
|
||||
error_frame& operator=(error_frame&& );
|
||||
|
||||
fc::string desc;
|
||||
fc::string file;
|
||||
int64_t line;
|
||||
fc::string method;
|
||||
uint64_t time;
|
||||
fc::optional<fc::value> meta;
|
||||
};
|
||||
typedef fc::vector<error_frame> error_context;
|
||||
|
||||
/**
|
||||
* This class is used for rich error reporting that captures relevant errors the
|
||||
* whole way up the stack. By using FC_THROW_REPORT(...) and FC_REPORT_PUSH( e, ...)
|
||||
* you can capture the file, line, and method where the error was caught / rethrown.
|
||||
*/
|
||||
class error_report {
|
||||
public:
|
||||
error_report();
|
||||
error_report( const fc::string& file, uint64_t line, const fc::string& method, const fc::string& desc, fc::value meta = fc::value() );
|
||||
|
||||
error_frame& current();
|
||||
error_report& pop_frame();
|
||||
error_report& push_frame( const fc::string& file, uint64_t line, const fc::string& method, const fc::string& desc, fc::value meta = fc::value() );
|
||||
error_report& append( const error_report& e );
|
||||
|
||||
error_context stack; ///< Human readable stack of what we were atempting to do.
|
||||
};
|
||||
|
||||
} // namespace fc
|
||||
|
||||
#include <fc/reflect.hpp>
|
||||
FC_REFLECT( fc::error_frame, (desc)(file)(line)(method)(time)(meta) )
|
||||
FC_REFLECT( fc::error_report, (stack) )
|
||||
|
||||
#include <fc/exception.hpp>
|
||||
#define FC_REPORT( X, ... ) fc::error_report X( __FILE__, __LINE__, __func__, __VA_ARGS__ )
|
||||
#define FC_THROW_REPORT( ... ) FC_THROW( fc::error_report( __FILE__, __LINE__, __func__, __VA_ARGS__ ))
|
||||
#define FC_REPORT_CURRENT(ER, ... ) (ER).pop_frame().push_frame( __FILE__, __LINE__, __func__, __VA_ARGS__ )
|
||||
#define FC_REPORT_PUSH( ER, ... ) (ER).push_frame( __FILE__, __LINE__, __func__, __VA_ARGS__ );
|
||||
#define FC_REPORT_POP(ER) (ER).pop_frame()
|
||||
73
src/error_report.cpp
Normal file
73
src/error_report.cpp
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
#include <fc/error_report.hpp>
|
||||
|
||||
namespace fc {
|
||||
|
||||
error_frame::error_frame( const fc::string& f, uint64_t l, const fc::string& m, const fc::string& d, fc::value met )
|
||||
:desc(d),file(f),line(l),method(m),meta(fc::move(met)){}
|
||||
|
||||
error_report::error_report()
|
||||
{
|
||||
}
|
||||
error_frame::error_frame(const fc::error_frame& e)
|
||||
:desc(e.desc),file(e.file),line(e.line),method(e.method),time(e.time),meta(e.meta){}
|
||||
|
||||
error_frame::error_frame(fc::error_frame&& e)
|
||||
:desc(fc::move(e.desc)),
|
||||
file(fc::move(e.file)),
|
||||
line(e.line),
|
||||
method(fc::move(e.method)),
|
||||
time(e.time),
|
||||
meta(fc::move(e.meta))
|
||||
{}
|
||||
|
||||
fc::error_frame& fc::error_frame::operator=(const fc::error_frame& f ) {
|
||||
auto tmp = f;
|
||||
fc_swap( tmp, *this );
|
||||
return *this;
|
||||
}
|
||||
fc::error_frame& fc::error_frame::operator=(fc::error_frame&& e )
|
||||
{
|
||||
desc=fc::move(e.desc);
|
||||
file=fc::move(e.file);
|
||||
line=fc::move(e.line);
|
||||
method=fc::move(e.method);
|
||||
time=e.time;
|
||||
meta=fc::move(e.meta);
|
||||
return *this;
|
||||
}
|
||||
|
||||
error_report::error_report( const fc::string& file, uint64_t line, const fc::string& method, const fc::string& desc, fc::value meta )
|
||||
{
|
||||
push_frame( file, line, method, desc, meta );
|
||||
}
|
||||
|
||||
|
||||
fc::error_frame& error_report::current()
|
||||
{
|
||||
if( !stack.size() ) stack.resize(1);
|
||||
return stack.back();
|
||||
}
|
||||
|
||||
fc::error_report& error_report::pop_frame()
|
||||
{
|
||||
stack.pop_back();
|
||||
return *this;
|
||||
}
|
||||
|
||||
fc::error_report& error_report::push_frame( const fc::string& file, uint64_t line, const fc::string& method, const fc::string& desc, fc::value meta )
|
||||
{
|
||||
stack.push_back( fc::error_frame( file, line, method, desc, meta ) );
|
||||
return *this;
|
||||
}
|
||||
|
||||
fc::error_report& error_report::append( const error_report& e )
|
||||
{
|
||||
// TODO: what to do about the 'failure...?'
|
||||
stack.reserve( stack.size()+e.stack.size());
|
||||
for( uint32_t i = 0; i < e.stack.size(); ++i ) {
|
||||
stack.push_back( e.stack[i] );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace fc
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
#include <fc/log.hpp>
|
||||
#include <fc/thread.hpp>
|
||||
#include <fc/error.hpp>
|
||||
#include <fc/error_report.hpp>
|
||||
#include <fc/json_rpc_error_object.hpp>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
|
@ -72,6 +73,12 @@ namespace fc { namespace json {
|
|||
auto id = value_cast<uint64_t>(id_itr->val);
|
||||
try {
|
||||
send_result( id, smeth->second->call(params) );
|
||||
} catch ( fc::error_report& eo ) {
|
||||
if( eo.stack.size() ) {
|
||||
send_error( id, error_object( eo.current().desc, fc::value(eo) ) );
|
||||
} else {
|
||||
send_error( id, error_object( "error report", fc::value(eo) ) );
|
||||
}
|
||||
} catch ( const fc::json::error_object& eo ) {
|
||||
send_error( id, eo );
|
||||
} catch ( ... ) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue