diff --git a/src/coreComponents/common/logger/ErrorHandling.cpp b/src/coreComponents/common/logger/ErrorHandling.cpp index 6881e11259a..f68de5aca15 100644 --- a/src/coreComponents/common/logger/ErrorHandling.cpp +++ b/src/coreComponents/common/logger/ErrorHandling.cpp @@ -18,6 +18,7 @@ */ #include "ErrorHandling.hpp" +#include "LvArray/src/system.hpp" #include "common/DataTypes.hpp" #include "common/logger/Logger.hpp" #include "common/format/StringUtilities.hpp" @@ -45,6 +46,11 @@ ErrorLogger g_errorLogger{}; ErrorLogger & ErrorLogger::global() { return g_errorLogger; } +ErrorLogger::ErrorLogger() +{ + setDiagnosticInfoLevel( DiagnosticInfoLevel::Basic ); +} + std::string ErrorContext::attributeToString( ErrorContext::Attribute attribute ) { switch( attribute ) @@ -277,7 +283,29 @@ void ErrorLogger::createFile() } } -std::string ErrorLogger::toString( MsgType const type ) +void ErrorLogger::setDiagnosticInfoLevel( DiagnosticInfoLevel const level ) +{ + switch( level ) + { + case DiagnosticInfoLevel::Basic: + m_msgTypeSourceInfoEnabled.fill( false ); + break; + case DiagnosticInfoLevel::ErrorSources: + m_msgTypeSourceInfoEnabled.fill( true ); + m_msgTypeSourceInfoEnabled[integer( MsgType::Warning )] = false; + break; + case DiagnosticInfoLevel::WarningSources: + m_msgTypeSourceInfoEnabled.fill( true ); + break; + default: + // if option has a wrong value, we output every details for any messages + m_msgTypeSourceInfoEnabled.fill( true ); + break; + } +} + + +std::string ErrorLogger::typeToString( MsgType const type ) { switch( type ) { @@ -289,12 +317,26 @@ std::string ErrorLogger::toString( MsgType const type ) } } -void ErrorLogger::formatMsgForLog( DiagnosticMsg const & errMsg, std::ostream & os ) +bool ErrorLogger::isSourceInfoEnabled( MsgType const type ) const +{ + switch( type ) + { + case MsgType::Error: return m_msgTypeSourceInfoEnabled[integer( MsgType::Error )]; + case MsgType::Warning: return m_msgTypeSourceInfoEnabled[integer( MsgType::Warning )]; + case MsgType::Exception: return m_msgTypeSourceInfoEnabled[integer( MsgType::Exception )]; + case MsgType::ExternalError: return m_msgTypeSourceInfoEnabled[integer( MsgType::ExternalError )]; + default: return m_msgTypeSourceInfoEnabled[integer( MsgType::Undefined )]; + } +} + +void ErrorLogger::formatMsgForLog( DiagnosticMsg const & errMsg, + std::ostream & os, + bool enableSourceInfo ) { static constexpr string_view PREFIX = "***** "; // --- HEADER --- - os << PREFIX << ErrorLogger::toString( errMsg.m_type ) << "\n"; - if( !errMsg.m_file.empty()) + os << PREFIX << typeToString( errMsg.m_type ) << "\n"; + if( enableSourceInfo && !errMsg.m_file.empty() ) { os << PREFIX<< "LOCATION: " << errMsg.m_file; if( errMsg.m_line > 0 ) @@ -332,7 +374,7 @@ void ErrorLogger::formatMsgForLog( DiagnosticMsg const & errMsg, std::ostream & } } // --- STACKTRACE --- - if( !errMsg.m_sourceCallStack.empty() ) + if( enableSourceInfo && !errMsg.m_sourceCallStack.empty() ) { os << "\n***** StackTrace of "<< errMsg.m_sourceCallStack.size() << " frames\n"; for( size_t i = 0; i < errMsg.m_sourceCallStack.size(); i++ ) @@ -353,7 +395,9 @@ void ErrorLogger::formatMsgForLog( DiagnosticMsg const & errMsg, std::ostream & void ErrorLogger::writeToLogStream( DiagnosticMsg & errMsg ) { std::lock_guard< std::mutex > guard( m_errorHandlerAsciiMutex ); - formatMsgForLog( errMsg, m_stream ); + formatMsgForLog( errMsg, + m_stream, + isSourceInfoEnabled( errMsg.m_type ) ); m_stream.flush(); } @@ -364,7 +408,7 @@ void ErrorLogger::writeToYamlStream( DiagnosticMsg & errMsg ) if( yamlFile.is_open() ) { // General errors info (type, rank on which the error occured) - yamlFile << g_level1Start << "type: " << ErrorLogger::toString( errMsg.m_type ) << "\n"; + yamlFile << g_level1Start << "type: " << typeToString( errMsg.m_type ) << "\n"; yamlFile << g_level1Next << "rank: " << stringutilities::join( errMsg.m_ranksInfo, "," ); yamlFile << "\n"; diff --git a/src/coreComponents/common/logger/ErrorHandling.hpp b/src/coreComponents/common/logger/ErrorHandling.hpp index 38df2a2566c..2c95b108971 100644 --- a/src/coreComponents/common/logger/ErrorHandling.hpp +++ b/src/coreComponents/common/logger/ErrorHandling.hpp @@ -23,6 +23,7 @@ #include "common/DataTypes.hpp" #include "common/format/Format.hpp" #include "common/format/StringUtilities.hpp" + #include namespace geos @@ -111,13 +112,28 @@ struct ErrorContext * @enum MsgType * Enum listing the different types of possible diagnostics */ -enum class MsgType +enum class MsgType : integer { + Undefined, Error, ExternalError, Warning, Exception, - Undefined + Count // internal use, keep at last +}; + +/** + * @enum DiagnosticInfoLevel + * Enum listing the different types of possible diagnostic information levels + */ +enum class DiagnosticInfoLevel : integer +{ + /// basic information (default) + Basic = 0, + /// errors source-code information + ErrorSources= 1, + /// warnings & errors source-code information + WarningSources = 2, }; /** @@ -295,6 +311,8 @@ class ErrorLogger */ GEOS_HOST static ErrorLogger & global(); + ErrorLogger(); + /** * @brief Create the YAML file or overwrite the contents if a YAML file of the same name already exists * And write its header when the command line option is enabled @@ -322,6 +340,14 @@ class ErrorLogger void setOutputFilename( std::string_view filename ) { m_filename = filename; } + /** + * @brief Set the diagnostic messages information level. The higher, the more verbose and + * developper-oriented the messages will be. + * @param level the desired information level. If level is not an DiagnosticInfoLevel enum label, + * the behaviour of DiagnosticInfoLevel::Basic. + */ + void setDiagnosticInfoLevel( DiagnosticInfoLevel level ); + /** * @return The file name of the output error file */ @@ -333,7 +359,13 @@ class ErrorLogger * @param type the message type label * @return the string representation of the message type */ - static std::string toString( MsgType type ); + static std::string typeToString( MsgType type ); + + /** + * @param type the message type label + * @return true if the message type source information output is enabled + */ + bool isSourceInfoEnabled( MsgType type ) const; /** * @return Return the const general log stream @@ -384,8 +416,11 @@ class ErrorLogger * @brief Format all information in ErrorMsg and write it to the specified output stream * @param errMsg The struct containing the error/warning object * @param os The output stream + * @param enableSourceInfo if true, information on source code is included in the message */ - static void formatMsgForLog( DiagnosticMsg const & errMsg, std::ostream & os ); + static void formatMsgForLog( DiagnosticMsg const & errMsg, + std::ostream & os, + bool enableSourceInfo ); /** * @brief Write the ErrorMsg into the log stream output stream @@ -407,6 +442,8 @@ class ErrorLogger std::mutex m_errorHandlerAsciiMutex; /// Avoid concurrent access between threads for yaml outputs std::mutex m_errorHandlerYamlMutex; + /// Indicated if the source file information output is enabled for a given message type + stdArray< bool, size_t( MsgType::Count ) > m_msgTypeSourceInfoEnabled; /** * @brief Write all the information retrieved about the error/warning message into the YAML stream diff --git a/src/coreComponents/common/logger/GeosExceptions.cpp b/src/coreComponents/common/logger/GeosExceptions.cpp index 4aa13914337..3746d41e703 100644 --- a/src/coreComponents/common/logger/GeosExceptions.cpp +++ b/src/coreComponents/common/logger/GeosExceptions.cpp @@ -30,7 +30,9 @@ void Exception::prepareWhat( DiagnosticMsg & msg ) noexcept m_formattingOSS.str( "" ); m_formattingOSS.clear(); - ErrorLogger::formatMsgForLog( msg, m_formattingOSS ); + ErrorLogger::formatMsgForLog( msg, + m_formattingOSS, + ErrorLogger::global().isSourceInfoEnabled( msg.m_type ) ); m_cachedWhat = m_formattingOSS.bad() ? "Exception formatting error!" : m_formattingOSS.str(); } diff --git a/src/coreComponents/dataRepository/unitTests/testErrorHandling.cpp b/src/coreComponents/dataRepository/unitTests/testErrorHandling.cpp index 33e95b745d4..ee7c274db08 100644 --- a/src/coreComponents/dataRepository/unitTests/testErrorHandling.cpp +++ b/src/coreComponents/dataRepository/unitTests/testErrorHandling.cpp @@ -321,7 +321,7 @@ TEST( ErrorHandling, testLogFileExceptionOutput ) additionalContext.toString(), testErrorLogger.getCurrentExceptionMsg().m_sourceCallStack ); std::ostringstream oss; - ErrorLogger::formatMsgForLog( testErrorLogger.getCurrentExceptionMsg(), oss ); + ErrorLogger::formatMsgForLog( testErrorLogger.getCurrentExceptionMsg(), oss, true ); GEOS_ERROR_IF_EQ_MSG( oss.str().find( streamExpected ), string::npos, "The error message was not containing the expected sequence.\n" << "The error message was not containing the expected sequence.\n" << @@ -347,7 +347,7 @@ TEST( ErrorHandling, testStdException ) .addCallStackInfo( LvArray::system::stackTrace( true ) ); std::ostringstream oss; - ErrorLogger::formatMsgForLog( testErrorLogger.getCurrentExceptionMsg(), oss ); + ErrorLogger::formatMsgForLog( testErrorLogger.getCurrentExceptionMsg(), oss, true ); string const streamExpected = GEOS_FMT( "***** Exception\n" "***** Rank 0\n" diff --git a/src/coreComponents/integrationTests/dataRepositoryTests/testGroupPath.cpp b/src/coreComponents/integrationTests/dataRepositoryTests/testGroupPath.cpp index 37724a42378..e047c9466ee 100644 --- a/src/coreComponents/integrationTests/dataRepositoryTests/testGroupPath.cpp +++ b/src/coreComponents/integrationTests/dataRepositoryTests/testGroupPath.cpp @@ -114,7 +114,7 @@ TEST( testGroupPath, testGlobalPaths ) "The children of Mesh are: { mesh1 }"; // checks if the exception contains the expected message std::ostringstream stream; - geos::ErrorLogger::formatMsgForLog( ErrorLogger::global().getCurrentExceptionMsg(), stream ); + geos::ErrorLogger::formatMsgForLog( ErrorLogger::global().getCurrentExceptionMsg(), stream, false ); GEOS_ERROR_IF_EQ_MSG( string( e.what() ).find( expectedMsg ), string::npos, "The error message was not containing the expected sequence.\n" << " Error message :\n" << e.what() << diff --git a/src/coreComponents/mainInterface/initialization.cpp b/src/coreComponents/mainInterface/initialization.cpp index 39367cbb263..03bae3884fb 100644 --- a/src/coreComponents/mainInterface/initialization.cpp +++ b/src/coreComponents/mainInterface/initialization.cpp @@ -14,6 +14,7 @@ */ #include "initialization.hpp" +#include "common/logger/ErrorHandling.hpp" #include "version.hpp" #include "common/DataTypes.hpp" @@ -97,6 +98,7 @@ std::unique_ptr< CommandLineOptions > parseCommandLineOptions( int argc, char * ZPAR, SCHEMA, VALIDATE_INPUT, + DIAGNOSTIC_INFO_LEVEL, NONBLOCKING_MPI, SUPPRESS_PINNED, PROBLEMNAME, @@ -121,6 +123,10 @@ std::unique_ptr< CommandLineOptions > parseCommandLineOptions( int argc, char * { ZPAR, 0, "z", "zpartitions", Arg::numeric, "\t-z, --z-partitions, \t Number of partitions in the z-direction" }, { SCHEMA, 0, "s", "schema", Arg::nonEmpty, "\t-s, --schema, \t Name of the output schema" }, { VALIDATE_INPUT, 0, "v", "validate-input", Arg::None, "\t-v, --validate-input, \t Only do the loading phase, and not actual simulation. Useful to validate 'input'." }, + { DIAGNOSTIC_INFO_LEVEL, 0, "d", "diagnostic-info-level", Arg::numeric, "\t-d, --diagnostic-info-level, \t Diagnostic message information level:\n" + "\t \t 0 = basic information (default),\n" + "\t \t 1 = errors source-code information,\n" + "\t \t 2 = warnings & errors source-code information." }, { NONBLOCKING_MPI, 0, "b", "use-nonblocking", Arg::None, "\t-b, --use-nonblocking, \t Use non-blocking MPI communication" }, { PROBLEMNAME, 0, "n", "name", Arg::nonEmpty, "\t-n, --name, \t Name of the problem, used for output" }, { SUPPRESS_PINNED, 0, "s", "suppress-pinned", Arg::None, "\t-s, --suppress-pinned, \t Suppress usage of pinned memory for MPI communication buffers" }, @@ -222,6 +228,12 @@ std::unique_ptr< CommandLineOptions > parseCommandLineOptions( int argc, char * commandLineOptions->onlyValidateInput = true; } break; + case DIAGNOSTIC_INFO_LEVEL: + { + DiagnosticInfoLevel infoLevel = DiagnosticInfoLevel( std::stoi( opt.arg ) ); + ErrorLogger::global().setDiagnosticInfoLevel( infoLevel ); + } + break; case PROBLEMNAME: { commandLineOptions->problemName = opt.arg;