diff --git a/src/coreComponents/common/logger/ErrorHandling.cpp b/src/coreComponents/common/logger/ErrorHandling.cpp index ef526f2b7bf..3c7e797389d 100644 --- a/src/coreComponents/common/logger/ErrorHandling.cpp +++ b/src/coreComponents/common/logger/ErrorHandling.cpp @@ -131,6 +131,7 @@ ErrorLogger::ErrorMsg & ErrorLogger::ErrorMsg::addRank( int rank ) ErrorLogger::ErrorMsg & ErrorLogger::ErrorMsg::addCallStackInfo( std::string_view ossStackTrace ) { std::string str = std::string( ossStackTrace ); + m_stringCallStack = str; std::istringstream iss( str ); std::string stackLine; std::size_t index; @@ -188,74 +189,78 @@ void ErrorLogger::streamMultilineYamlAttribute( std::string_view msg, std::ofstr } } -void ErrorLogger::flushErrorMsg( ErrorLogger::ErrorMsg & errorMsg ) +void ErrorLogger::flushErrorMsg( ErrorLogger::ErrorMsg & errorMsg, std::ostringstream & msgoss ) { - std::ofstream yamlFile( std::string( m_filename ), std::ios::app ); - if( yamlFile.is_open() && isOutputFileEnabled() ) + if( isOutputFileEnabled() ) { - // General errors info (type, rank on which the error occured) - yamlFile << g_level1Start << "type: " << ErrorLogger::toString( errorMsg.m_type ) << "\n"; - yamlFile << g_level1Next << "rank: " << stringutilities::join( errorMsg.m_ranksInfo, "," ); - yamlFile << "\n"; + std::ofstream yamlFile( std::string( m_filename ), std::ios::app ); + if( yamlFile.is_open() && isOutputFileEnabled() ) + { + // General errors info (type, rank on which the error occured) + yamlFile << g_level1Start << "type: " << ErrorLogger::toString( errorMsg.m_type ) << "\n"; + yamlFile << g_level1Next << "rank: " << stringutilities::join( errorMsg.m_ranksInfo, "," ); + yamlFile << "\n"; - // Error message - yamlFile << g_level1Next << "message: >-\n"; - streamMultilineYamlAttribute( errorMsg.m_msg, yamlFile, g_level2Next ); + // Error message + yamlFile << g_level1Next << "message: >-\n"; + streamMultilineYamlAttribute( errorMsg.m_msg, yamlFile, g_level2Next ); - // context information - if( !errorMsg.m_contextsInfo.empty() ) - { - // Sort contextual information by decreasing priority - std::sort( errorMsg.m_contextsInfo.begin(), errorMsg.m_contextsInfo.end(), - []( const ErrorLogger::ErrorContext & a, const ErrorLogger::ErrorContext & b ) { - return a.m_priority > b.m_priority; - } ); - // Additional informations about the context of the error and priority information of each context - yamlFile << g_level1Next << "contexts:\n"; - for( ErrorContext const & ctxInfo : errorMsg.m_contextsInfo ) + // context information + if( !errorMsg.m_contextsInfo.empty() ) { - yamlFile << g_level3Start << "priority: " << ctxInfo.m_priority << "\n"; - for( auto const & [key, value] : ctxInfo.m_attributes ) + // Sort contextual information by decreasing priority + std::sort( errorMsg.m_contextsInfo.begin(), errorMsg.m_contextsInfo.end(), + []( const ErrorLogger::ErrorContext & a, const ErrorLogger::ErrorContext & b ) { + return a.m_priority > b.m_priority; + } ); + // Additional informations about the context of the error and priority information of each context + yamlFile << g_level1Next << "contexts:\n"; + for( ErrorContext const & ctxInfo : errorMsg.m_contextsInfo ) { - yamlFile << g_level3Next << ErrorContext::attributeToString( key ) << ": " << value << "\n"; + yamlFile << g_level3Start << "priority: " << ctxInfo.m_priority << "\n"; + for( auto const & [key, value] : ctxInfo.m_attributes ) + { + yamlFile << g_level3Next << ErrorContext::attributeToString( key ) << ": " << value << "\n"; + } } } - } - // error cause - if( !errorMsg.m_cause.empty() ) - { - yamlFile << g_level1Next << "cause: >-\n"; - streamMultilineYamlAttribute( errorMsg.m_cause, yamlFile, g_level2Next ); - } + // error cause + if( !errorMsg.m_cause.empty() ) + { + yamlFile << g_level1Next << "cause: >-\n"; + streamMultilineYamlAttribute( errorMsg.m_cause, yamlFile, g_level2Next ); + } - // Location of the error in the code - yamlFile << g_level1Next << "sourceLocation:\n"; - yamlFile << g_level2Next << "file: " << errorMsg.m_file << "\n"; - yamlFile << g_level2Next << "line: " << errorMsg.m_line << "\n"; + // Location of the error in the code + yamlFile << g_level1Next << "sourceLocation:\n"; + yamlFile << g_level2Next << "file: " << errorMsg.m_file << "\n"; + yamlFile << g_level2Next << "line: " << errorMsg.m_line << "\n"; - // Information about the stack trace - if( !errorMsg.m_sourceCallStack.empty() ) - { - yamlFile << g_level1Next << "sourceCallStack:\n"; - for( size_t i = 0; i < errorMsg.m_sourceCallStack.size(); i++ ) + // Information about the stack trace + if( !errorMsg.m_sourceCallStack.empty() ) { - yamlFile << ( errorMsg.isValidStackTrace() ? - GEOS_FMT( "{}frame{}: {}\n", g_level3Start, i, errorMsg.m_sourceCallStack[i] ) : - GEOS_FMT( "{}{}\n", g_level3Start, errorMsg.m_sourceCallStack[i] ) ); + yamlFile << g_level1Next << "sourceCallStack:\n"; + for( size_t i = 0; i < errorMsg.m_sourceCallStack.size(); i++ ) + { + yamlFile << ( errorMsg.isValidStackTrace() ? + GEOS_FMT( "{}frame{}: {}\n", g_level3Start, i, errorMsg.m_sourceCallStack[i] ) : + GEOS_FMT( "{}{}\n", g_level3Start, errorMsg.m_sourceCallStack[i] ) ); + } } - } - yamlFile << "\n"; - yamlFile.flush(); - errorMsg = ErrorMsg(); - GEOS_LOG_RANK( GEOS_FMT( "The error file {} was appended.", m_filename ) ); - } - else - { - GEOS_LOG_RANK( GEOS_FMT( "Unable to open error file for writing.\n- Error file: {}\n- Error file enabled = {}.\n", - m_filename, isOutputFileEnabled() ) ); + yamlFile << "\n"; + yamlFile.flush(); + errorMsg = ErrorMsg(); + GEOS_LOG_RANK( GEOS_FMT( "The error file {} was appended.", m_filename ) ); + } + else + { + GEOS_LOG_RANK( GEOS_FMT( "Unable to open error file for writing.\n- Error file: {}\n- Error file enabled = {}.\n", + m_filename, g_errorLogger.isOutputFileEnabled() ) ); + } } + ErrorLogger::formatMsgToAscii( errorMsg, ::geos::logger::internal::g_rankString, msgoss ); } } /* namespace geos */ diff --git a/src/coreComponents/common/logger/ErrorHandling.hpp b/src/coreComponents/common/logger/ErrorHandling.hpp index a1275433a14..e2cf0ae3f5c 100644 --- a/src/coreComponents/common/logger/ErrorHandling.hpp +++ b/src/coreComponents/common/logger/ErrorHandling.hpp @@ -22,6 +22,7 @@ #include "common/DataTypes.hpp" + namespace geos { @@ -37,7 +38,7 @@ class ErrorLogger * @enum MsgType * Enum listing the different types of possible errors */ - enum class MsgType + enum class MsgType : integer { Error, Warning, @@ -117,6 +118,9 @@ class ErrorLogger std::vector< ErrorContext > m_contextsInfo; /// the stack trace std::vector< std::string > m_sourceCallStack; + /// the string stack trace + std::string m_stringCallStack; + /** * @brief Construct a default Error Message @@ -218,6 +222,23 @@ class ErrorLogger bool m_isValidStackTrace = false; }; + /** + * @brief Retrieve all informations from the ErrorLogger and format into an ascii message + * @param errMsg Class containing all the error/warning information + * @param rank The rank where the error/warning happened + * @param msgoss The output stream. By default std::cout + */ + static void formatMsgToAscii( ErrorLogger::ErrorMsg const & errMsg, string const & rank, + std::ostringstream & msgoss ) + { + + msgoss << "***** " << ErrorLogger::toString( errMsg.m_type ) << "\n"; + msgoss << "***** LOCATION: " << errMsg.m_file<< "\n"; + msgoss << "***** " << errMsg.m_cause << "\n"; + msgoss << "***** Rank " << rank << ": " << errMsg.m_msg << "\n"; + msgoss << errMsg.m_stringCallStack; + } + /** * @return Global instance of the ErrorLogger class used for error/warning reporting. * @details This global instance is used across the codebase to log errors, warnings, and exceptions, @@ -281,7 +302,7 @@ class ErrorLogger * and reset the errorMsg instance to its initial state * @param errorMsg a constant reference to the error */ - void flushErrorMsg( ErrorMsg & errorMsg ); + void flushErrorMsg( ErrorMsg & errorMsg, std::ostringstream & oss ); private: /// The error constructed via exceptions diff --git a/src/coreComponents/common/logger/Logger.hpp b/src/coreComponents/common/logger/Logger.hpp index e59cfa05256..1116a1bf434 100644 --- a/src/coreComponents/common/logger/Logger.hpp +++ b/src/coreComponents/common/logger/Logger.hpp @@ -156,36 +156,24 @@ { \ if( COND ) \ { \ - std::ostringstream __msgoss; \ - __msgoss << GEOS_DETAIL_FIRST_ARG( __VA_ARGS__ ); \ - std::string __message = __msgoss.str(); \ - __msgoss = std::ostringstream(); \ - __msgoss << CAUSE_MESSAGE; \ - std::string __cause = __msgoss.str(); \ - std::ostringstream __oss; \ - __oss << "***** ERROR\n"; \ - __oss << "***** LOCATION: " LOCATION "\n"; \ - __oss << "***** " << __cause << "\n"; \ - __oss << "***** Rank " << ::geos::logger::internal::g_rankString << ": " << __message << "\n"; \ - std::string stackHistory = LvArray::system::stackTrace( true ); \ - __oss << stackHistory; \ - std::cout << __oss.str() << std::endl; \ - if( GEOS_ERROR_LOGGER_INSTANCE.isOutputFileEnabled() ) \ - { \ - ErrorLogger::ErrorMsg msgStruct( ErrorLogger::MsgType::Error, \ - __message, \ - ::geos::logger::internal::g_rank, \ - __FILE__, \ - __LINE__ ); \ - msgStruct.setCause( __cause ); \ - msgStruct.addCallStackInfo( stackHistory ); \ - msgStruct.addContextInfo( GEOS_DETAIL_REST_ARGS( __VA_ARGS__ ) ); \ - GEOS_ERROR_LOGGER_INSTANCE.flushErrorMsg( msgStruct ); \ - } \ + std::ostringstream flushoss; \ + std::ostringstream msgoss; \ + msgoss << GEOS_DETAIL_FIRST_ARG( __VA_ARGS__ ); \ + std::ostringstream causemsgsoss; \ + causemsgsoss << CAUSE_MESSAGE; \ + ErrorLogger::ErrorMsg msgStruct( ErrorLogger::MsgType::Error, \ + msgoss.str(), \ + ::geos::logger::internal::g_rank, \ + __FILE__, \ + __LINE__ ); \ + msgStruct.setCause( causemsgsoss.str() ); \ + msgStruct.addCallStackInfo( LvArray::system::stackTrace( true ) ); \ + msgStruct.addContextInfo( GEOS_DETAIL_REST_ARGS( __VA_ARGS__ ) ); \ + GEOS_ERROR_LOGGER_INSTANCE.flushErrorMsg( msgStruct, flushoss ); \ LvArray::system::callErrorHandler(); \ } \ - } while( false ) -#elif __CUDA_ARCH__ + }while( false ) + #elif __CUDA_ARCH__ #define GEOS_ERROR_IF_CAUSE( COND, CAUSE_MESSAGE, ... ) \ do \ { \ @@ -230,44 +218,35 @@ * - Mandatory first parameter, the type of the exception to throw * - Optional following parameters, context information on the current error (DataContext) */ -#if !defined(GEOS_DEVICE_COMPILE) + #if !defined(GEOS_DEVICE_COMPILE) #define GEOS_THROW_IF_CAUSE( COND, CAUSE_MESSAGE, MSG, ... ) \ do \ { \ if( COND ) \ { \ - std::ostringstream __msgoss; \ - __msgoss << MSG; \ - std::string __message = __msgoss.str(); \ - __msgoss = std::ostringstream(); \ - __msgoss << CAUSE_MESSAGE; \ - std::string __cause = __msgoss.str(); \ - std::ostringstream __oss; \ - __oss << "***** EXCEPTION\n"; \ - __oss << "***** LOCATION: " LOCATION "\n"; \ - __oss << "***** " << __cause << "\n"; \ - __oss << "***** Rank " << ::geos::logger::internal::g_rankString << ": " << __message << "\n"; \ - std::string stackHistory = LvArray::system::stackTrace( true ); \ - __oss << stackHistory; \ - if( GEOS_ERROR_LOGGER_INSTANCE.isOutputFileEnabled() ) \ - { \ - if( GEOS_ERROR_LOGGER_INSTANCE.currentErrorMsg().m_type == ErrorLogger::MsgType::Undefined ) \ - { /* first throw site, we initialize the error message completly */ \ - GEOS_ERROR_LOGGER_INSTANCE.currentErrorMsg() \ - .setType( ErrorLogger::MsgType::Exception ) \ - .setCodeLocation( __FILE__, __LINE__ ) \ - .setCause( __cause ) \ - .addRank( ::geos::logger::internal::g_rank ) \ - .addCallStackInfo( stackHistory ); \ - } \ + std::ostringstream flushoss; \ + std::ostringstream msgoss; \ + msgoss << MSG; \ + std::ostringstream causemsgsoss; \ + causemsgsoss << CAUSE_MESSAGE; \ + if( GEOS_ERROR_LOGGER_INSTANCE.currentErrorMsg().m_type == ErrorLogger::MsgType::Undefined ) \ + { /* first throw site, we initialize the error message completly */ \ GEOS_ERROR_LOGGER_INSTANCE.currentErrorMsg() \ - .addToMsg( __message ) \ - .addContextInfo( GEOS_DETAIL_REST_ARGS( __VA_ARGS__ ) ); \ + .setType( ErrorLogger::MsgType::Exception ) \ + .setCodeLocation( __FILE__, __LINE__ ) \ + .setCause( causemsgsoss.str() ) \ + .addRank( ::geos::logger::internal::g_rank ) \ + .addCallStackInfo( LvArray::system::stackTrace( true ) ); \ } \ - throw GEOS_DETAIL_FIRST_ARG( __VA_ARGS__ )( __oss.str() ); \ + GEOS_ERROR_LOGGER_INSTANCE.currentErrorMsg() \ + .addToMsg( msgoss.str() ) \ + .addContextInfo( GEOS_DETAIL_REST_ARGS( __VA_ARGS__ ) ); \ + ErrorLogger::formatMsgToAscii( GEOS_ERROR_LOGGER_INSTANCE.currentErrorMsg(), \ + ::geos::logger::internal::g_rankString, flushoss ); \ + throw GEOS_DETAIL_FIRST_ARG( __VA_ARGS__ )( flushoss.str()); \ } \ } while( false ) -#elif __CUDA_ARCH__ + #elif __CUDA_ARCH__ #define GEOS_THROW_IF_CAUSE( COND, CAUSE_MESSAGE, MSG, ... ) \ do \ { \ @@ -319,29 +298,19 @@ { \ if( COND ) \ { \ - std::ostringstream __msgoss; \ - __msgoss << GEOS_DETAIL_FIRST_ARG( __VA_ARGS__ ); \ - std::string __message = __msgoss.str(); \ - __msgoss = std::ostringstream(); \ - __msgoss << CAUSE_MESSAGE; \ - std::string __cause = __msgoss.str(); \ - std::ostringstream __oss; \ - __oss << "***** WARNING\n"; \ - __oss << "***** LOCATION: " LOCATION "\n"; \ - __oss << "***** " << __cause << "\n"; \ - __oss << "***** Rank " << ::geos::logger::internal::g_rankString << ": " << __message << "\n"; \ - std::cout << __oss.str() << std::endl; \ - if( GEOS_ERROR_LOGGER_INSTANCE.isOutputFileEnabled() ) \ - { \ - ErrorLogger::ErrorMsg msgStruct( ErrorLogger::MsgType::Warning, \ - __message, \ - ::geos::logger::internal::g_rank, \ - __FILE__, \ - __LINE__ ); \ - msgStruct.setCause( __cause ); \ - msgStruct.addContextInfo( GEOS_DETAIL_REST_ARGS( __VA_ARGS__ ) ); \ - GEOS_ERROR_LOGGER_INSTANCE.flushErrorMsg( msgStruct ); \ - } \ + std::ostringstream flushoss; \ + std::ostringstream msgoss; \ + msgoss << GEOS_DETAIL_FIRST_ARG( __VA_ARGS__ ); \ + std::ostringstream causemsgsoss; \ + causemsgsoss << CAUSE_MESSAGE; \ + ErrorLogger::ErrorMsg msgStruct( ErrorLogger::MsgType::Warning, \ + msgoss.str(), \ + ::geos::logger::internal::g_rank, \ + __FILE__, \ + __LINE__ ); \ + msgStruct.setCause( causemsgsoss.str() ); \ + msgStruct.addContextInfo( GEOS_DETAIL_REST_ARGS( __VA_ARGS__ ) ); \ + GEOS_ERROR_LOGGER_INSTANCE.flushErrorMsg( msgStruct, flushoss ); \ } \ } while( false ) #elif __CUDA_ARCH__ @@ -1043,7 +1012,7 @@ extern std::string g_rankString; extern std::ostream * g_rankStream; -} // namespace internal +} // namespace internal #if defined(GEOS_USE_MPI) /** @@ -1065,8 +1034,9 @@ void InitializeLogger( const std::string & rank_output_dir="" ); */ void FinalizeLogger(); -} // namespace logger +} // namespace logger + -} // namespace geos +} // namespace geos #endif /* GEOS_COMMON_LOGGER_HPP */ diff --git a/src/coreComponents/dataRepository/unitTests/testErrorHandling.cpp b/src/coreComponents/dataRepository/unitTests/testErrorHandling.cpp index 39103cc5580..ae65e5ae4fb 100644 --- a/src/coreComponents/dataRepository/unitTests/testErrorHandling.cpp +++ b/src/coreComponents/dataRepository/unitTests/testErrorHandling.cpp @@ -14,6 +14,7 @@ */ // forcefully enable asserts macros for this unit test +#include #define GEOS_ASSERT_ENABLED #include "common/logger/ErrorHandling.hpp" @@ -182,14 +183,15 @@ TEST( ErrorHandling, testYamlFileExceptionOutput ) .addToMsg( errorMsg ) .addContextInfo( additionalContext.getContextInfo() ) .addContextInfo( importantAdditionalContext.getContextInfo().setPriority( 2 ) ); - } - testErrorLogger.flushErrorMsg( testErrorLogger.currentErrorMsg() ); - endLocalLoggerTest( testErrorLogger, { - R"(errors:)", - GEOS_FMT( - R"(- type: Exception + std::ostringstream flushoss; + testErrorLogger.flushErrorMsg( testErrorLogger.currentErrorMsg(), flushoss ); + endLocalLoggerTest( testErrorLogger, { + R"(errors:)", + + GEOS_FMT( + R"(- type: Exception rank: 0 message: >- Table input error. @@ -210,11 +212,12 @@ TEST( ErrorHandling, testYamlFileExceptionOutput ) file: {} line: {} sourceCallStack:)", - __FILE__, line1 ), - "- frame0: ", - "- frame1: ", - "- frame2: " - } ); + __FILE__, line1 ), + "- frame0: ", + "- frame1: ", + "- frame2: " + } ); + } } TEST( ErrorHandling, testYamlFileErrorOutput ) diff --git a/src/main/main.cpp b/src/main/main.cpp index 14750a4d4a1..0ffe5941574 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -76,11 +76,9 @@ int main( int argc, char *argv[] ) } catch( std::exception const & e ) { - GEOS_LOG( e.what() ); - if( ErrorLogger::global().isOutputFileEnabled() ) - { - ErrorLogger::global().flushErrorMsg( ErrorLogger::global().currentErrorMsg() ); - } + std::ostringstream flushoss; + ErrorLogger::global().flushErrorMsg( ErrorLogger::global().currentErrorMsg(), flushoss ); + LvArray::system::callErrorHandler(); basicCleanup(); std::abort();