From 7991c141ee82592bba789d5de09c1a9e55eb5f6b Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Mon, 13 Apr 2026 19:05:16 +0200 Subject: [PATCH 01/11] =?UTF-8?q?=E2=9C=A8=20Separate=20GEOS=20/=20LvArray?= =?UTF-8?q?=20error=20detection?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/initializeEnvironment.cpp | 39 ++++++++++++++----- .../common/logger/ErrorHandling.cpp | 10 +++++ .../common/logger/ErrorHandling.hpp | 24 ++++++++++++ src/coreComponents/common/logger/Logger.hpp | 2 +- src/main/main.cpp | 4 +- 5 files changed, 66 insertions(+), 13 deletions(-) diff --git a/src/coreComponents/common/initializeEnvironment.cpp b/src/coreComponents/common/initializeEnvironment.cpp index e43263c8528..62772b42a7c 100644 --- a/src/coreComponents/common/initializeEnvironment.cpp +++ b/src/coreComponents/common/initializeEnvironment.cpp @@ -70,9 +70,9 @@ void setupLogger() { // setup error handling (using LvArray helper system functions) + ///// set external error handling behaviour ///// ExternalErrorHandler::instance().enableStderrPipeDeviation( true ); - ///// set external error handling behaviour ///// ExternalErrorHandler::instance().setErrorHandling( []( string_view errorMsg, string_view detectionLocation ) { @@ -105,25 +105,44 @@ void setupLogger() // Disable signal handling to prevent catching exit signal (infinite loop) LvArray::system::setSignalHandling( nullptr ); - // first of all, external error can await to be output, we must output them + // first of all, there can be external error that await to be output ExternalErrorHandler::instance().flush( "before signal error output" ); // error message output std::string const stackHistory = LvArray::system::stackTrace( true ); DiagnosticMsg diagnosticMsg; - ErrorLogger::global().flushErrorMsg( DiagnosticMsgBuilder::init( diagnosticMsg, - MsgType::ExternalError, "", - ::geos::logger::internal::g_rank ) - .addSignal( signal ) - .addCallStackInfo( stackHistory ) - .getDiagnosticMsg() ); + DiagnosticMsgBuilder::init( diagnosticMsg, + MsgType::ExternalError, "", + ::geos::logger::internal::g_rank ) + .addSignal( signal ) + .addCallStackInfo( stackHistory ); + ErrorLogger::global().flushErrorMsg( diagnosticMsg ); // call program termination - LvArray::system::callErrorHandler(); + ErrorHandler::instance().abortProgram(); } ); - ///// set Post-Handled Error behaviour ///// + ///// set LvArray to use the GEOS error behaviour in a way that can be traced ///// LvArray::system::setErrorHandler( []() + { + // first of all, there can be external error that await to be output + ExternalErrorHandler::instance().flush( "after LvArray error detection" ); + + // default error message output + DiagnosticMsg diagnosticMsg; + DiagnosticMsgBuilder::init( diagnosticMsg, + MsgType::ExternalError, + "LvArray Runtime Error", + ::geos::logger::internal::g_rank ) + .addCallStackInfo( LvArray::system::stackTrace( true ) ); + ErrorLogger::global().flushErrorMsg( diagnosticMsg ); + + // call program termination + ErrorHandler::instance().abortProgram(); + } ); + + ///// set Post-Handled Error behaviour ///// + ErrorHandler::instance().setProgramAborter( []() { #if defined( GEOS_USE_MPI ) int mpi = 0; diff --git a/src/coreComponents/common/logger/ErrorHandling.cpp b/src/coreComponents/common/logger/ErrorHandling.cpp index 6881e11259a..9624f5efebd 100644 --- a/src/coreComponents/common/logger/ErrorHandling.cpp +++ b/src/coreComponents/common/logger/ErrorHandling.cpp @@ -453,4 +453,14 @@ void ErrorLogger::flushCurrentExceptionMessage() } } +ErrorHandler::ErrorHandler() + : m_abortingFunctor( []() { std::abort(); } ) +{} + +ErrorHandler & ErrorHandler::instance() +{ + static ErrorHandler s_instance; + return s_instance; +} + } /* namespace geos */ diff --git a/src/coreComponents/common/logger/ErrorHandling.hpp b/src/coreComponents/common/logger/ErrorHandling.hpp index 38df2a2566c..7bab2763210 100644 --- a/src/coreComponents/common/logger/ErrorHandling.hpp +++ b/src/coreComponents/common/logger/ErrorHandling.hpp @@ -424,7 +424,31 @@ class ErrorLogger std::string_view indent ); }; +class ErrorHandler +{ +public: + + static ErrorHandler & instance(); + + void setProgramAborter( std::function< void() > const & abortingFunctor ) + { m_abortingFunctor = abortingFunctor; } + + /** + * @brief Post error-handling function that terminates the program. + */ + void abortProgram() + { m_abortingFunctor(); } +private: + + std::function< void() > m_abortingFunctor; + + /** + * @brief Static class, no public constructor + */ + ErrorHandler(); + +}; } /* namespace geos */ diff --git a/src/coreComponents/common/logger/Logger.hpp b/src/coreComponents/common/logger/Logger.hpp index b23ba87a39d..355b6f86596 100644 --- a/src/coreComponents/common/logger/Logger.hpp +++ b/src/coreComponents/common/logger/Logger.hpp @@ -164,7 +164,7 @@ .addCallStackInfo( LvArray::system::stackTrace( true ) ) \ .addContextInfo( GEOS_DETAIL_REST_ARGS( __VA_ARGS__ )); \ GEOS_GLOBAL_LOGGER.flushCurrentExceptionMessage(); \ - LvArray::system::callErrorHandler(); \ + ErrorHandler::instance().abortProgram(); \ } \ }while( false ) #elif __CUDA_ARCH__ diff --git a/src/main/main.cpp b/src/main/main.cpp index 00c7a560ef6..e2836d1f1db 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -81,7 +81,7 @@ int main( int argc, char *argv[] ) { // GEOS generated exceptions management ErrorLogger::global().flushCurrentExceptionMessage(); basicCleanup( true ); - LvArray::system::callErrorHandler(); + ErrorHandler::instance().abortProgram(); } catch( std::exception const & e ) { // native exceptions management @@ -91,7 +91,7 @@ int main( int argc, char *argv[] ) .addCallStackInfo( LvArray::system::stackTrace( true ) ) .getDiagnosticMsg()); basicCleanup( true ); - LvArray::system::callErrorHandler(); + ErrorHandler::instance().abortProgram(); } return 0; } From 88f6c5a14a9aa145826efbb43014134c8f0ae630 Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Thu, 11 Jun 2026 18:05:52 +0200 Subject: [PATCH 02/11] =?UTF-8?q?=F0=9F=90=9B=20typo=20fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/coreComponents/mainInterface/initialization.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreComponents/mainInterface/initialization.cpp b/src/coreComponents/mainInterface/initialization.cpp index d371259f990..32218d27d71 100644 --- a/src/coreComponents/mainInterface/initialization.cpp +++ b/src/coreComponents/mainInterface/initialization.cpp @@ -129,7 +129,7 @@ std::unique_ptr< CommandLineOptions > parseCommandLineOptions( int argc, char * { TRACE_DATA_MIGRATION, 0, "", "trace-data-migration", Arg::None, "\t--trace-data-migration, \t Trace host-device data migration" }, { MEMORY_USAGE, 0, "m", "memory-usage", Arg::nonEmpty, "\t-m, --memory-usage, \t Minimum threshold for printing out memory allocations in a member of the data repository." }, { PAUSE_FOR, 0, "", "pause-for", Arg::numeric, "\t--pause-for, \t Pause geosx for a given number of seconds before starting execution" }, - { ERRORSOUTPUT, 0, "e", "errorsOutput", Arg::nonEmpty, "\t-e, --errors-output, \t Output path for the errors file (\".yaml\" supported)" }, + { ERRORSOUTPUT, 0, "e", "errors-output", Arg::nonEmpty, "\t-e, --errors-output, \t Output path for the errors file (\".yaml\" supported)" }, { 0, 0, nullptr, nullptr, nullptr, nullptr } }; From 9995c40aa4387b1aa98fb760a824dcf3a41d6001 Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Fri, 12 Jun 2026 15:40:37 +0200 Subject: [PATCH 03/11] =?UTF-8?q?=F0=9F=90=9B=20repairing=20external=20exc?= =?UTF-8?q?eption=20test=20->=20testLvArrayAndStdException?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/initializeEnvironment.cpp | 2 +- .../common/logger/ErrorHandling.hpp | 7 +- .../unitTests/testErrorHandling.cpp | 99 +++++++++++++------ src/main/main.cpp | 1 + 4 files changed, 75 insertions(+), 34 deletions(-) diff --git a/src/coreComponents/common/initializeEnvironment.cpp b/src/coreComponents/common/initializeEnvironment.cpp index 62772b42a7c..3bc54e8a60d 100644 --- a/src/coreComponents/common/initializeEnvironment.cpp +++ b/src/coreComponents/common/initializeEnvironment.cpp @@ -68,7 +68,7 @@ void setupLogger() logger::InitializeLogger(); #endif - { // setup error handling (using LvArray helper system functions) + { // setup error handling ///// set external error handling behaviour ///// ExternalErrorHandler::instance().enableStderrPipeDeviation( true ); diff --git a/src/coreComponents/common/logger/ErrorHandling.hpp b/src/coreComponents/common/logger/ErrorHandling.hpp index 9f6ee0fd2ca..a2897237cb8 100644 --- a/src/coreComponents/common/logger/ErrorHandling.hpp +++ b/src/coreComponents/common/logger/ErrorHandling.hpp @@ -430,6 +430,8 @@ class ErrorHandler static ErrorHandler & instance(); + ErrorHandler(); + void setProgramAborter( std::function< void() > const & abortingFunctor ) { m_abortingFunctor = abortingFunctor; } @@ -443,11 +445,6 @@ class ErrorHandler std::function< void() > m_abortingFunctor; - /** - * @brief Static class, no public constructor - */ - ErrorHandler(); - }; } /* namespace geos */ diff --git a/src/coreComponents/dataRepository/unitTests/testErrorHandling.cpp b/src/coreComponents/dataRepository/unitTests/testErrorHandling.cpp index d2a2d16257a..ea375bc0425 100644 --- a/src/coreComponents/dataRepository/unitTests/testErrorHandling.cpp +++ b/src/coreComponents/dataRepository/unitTests/testErrorHandling.cpp @@ -48,6 +48,14 @@ DataFileContext const context = DataFileContext( "Base Test Class", "/path/to/fi DataFileContext const additionalContext = DataFileContext( "Additional Test Class", "/path/to/file.xml", 32 ); DataFileContext const importantAdditionalContext = DataFileContext( "Important Additional Test Class", "/path/to/file.xml", 64 ); +// original error handler to backup to +ErrorHandler defaultErrorhandler; + +/** + * @name Helper functions + */ +///@{ + /** * @brief begin a test with a local logger * @param errorLogger local error logger instance @@ -105,11 +113,26 @@ void endLocalLoggerTest( ErrorLogger & errorLogger, fs::remove( filename ); } +template< typename LAMBDA > +void beginLocalHandlerTest( LAMBDA && lambda ) +{ + defaultErrorhandler = ErrorHandler::instance(); + ErrorHandler::instance() = ErrorHandler(); + ErrorHandler::instance().setProgramAborter( lambda ); +} + +void endLocalHandlerTest() +{ + ErrorHandler::instance() = defaultErrorhandler; +} + +///@} + TEST( ErrorHandling, testYamlFileWarningOutput ) { ErrorLogger testErrorLogger; - beginLocalLoggerTest( testErrorLogger, "warningTestOutput.yaml" ); + beginLocalLoggerTest( testErrorLogger, "testYamlFileWarningOutput.yaml" ); GET_LINE( line1 ); GEOS_WARNING( "Conflicting pressure boundary conditions" ); GET_LINE( line2 ); GEOS_WARNING_IF_GT_MSG( testValue, testMaxPrecision, "Pressure value is too high." ); @@ -170,7 +193,7 @@ TEST( ErrorHandling, testYamlFileWarningOutput ) TEST( ErrorHandling, testYamlFileExceptionOutput ) { ErrorLogger testErrorLogger; - string const file = "exceptionTestOutput.yaml"; + string const file = "testYamlFileExceptionOutput.yaml"; beginLocalLoggerTest( testErrorLogger, file ); size_t line1; @@ -241,7 +264,7 @@ TEST( ErrorHandling, testYamlFileErrorOutput ) { ErrorLogger testErrorLogger; - beginLocalLoggerTest( testErrorLogger, "errorTestOutput.yaml" ); + beginLocalLoggerTest( testErrorLogger, "testYamlFileErrorOutput.yaml" ); EXPECT_EXIT( GEOS_ERROR_IF_GT_MSG( testValue, testMaxPrecision, GEOS_FMT( "{}: option should be lower than {}.", @@ -287,7 +310,6 @@ TEST( ErrorHandling, testYamlFileErrorOutput ) } ); } - TEST( ErrorHandling, testLogFileExceptionOutput ) { ErrorLogger testErrorLogger; @@ -327,7 +349,6 @@ TEST( ErrorHandling, testLogFileExceptionOutput ) ErrorLogger::formatMsgForLog( testErrorLogger.getCurrentExceptionMsg(), oss ); GEOS_ERROR_IF_EQ_MSG( oss.str().find( streamExpected ), string::npos, GEOS_FMT( "The error message was not containing the expected sequence.\n" - "The error message was not containing the expected sequence.\n" " Error message :\n{}" " expected sequence :\n{}", oss.str(), @@ -335,45 +356,67 @@ TEST( ErrorHandling, testLogFileExceptionOutput ) } } -TEST( ErrorHandling, testStdException ) +// testing the capture & processing of lvarray exceptions, also testing what happens in case of an +// std::exception (as this is what lvarray throws). +TEST( ErrorHandling, testLvArrayAndStdException ) { ErrorLogger testErrorLogger; + size_t line1; + + beginLocalLoggerTest( testErrorLogger, "testLvArrayAndStdException.yaml" ); + // Standard exception thrown by LvArray try { - - throw std::invalid_argument( "received negative value" ); + // no ',' in between numbers will throw an exception + array1d< localIndex > dummy; + line1 = __LINE__; LvArray::input::stringToArray( dummy, "{123 456}" ); } - catch( std::exception & e ) + catch( geos::Exception & e ) { - - testErrorLogger.initCurrentExceptionMessage( MsgType::Exception, e.what(), + EXPECT_FALSE( true ) << "Exception not correctly handled."; + } + catch( std::exception const & e ) + { + // mimic "main()" exception logging behaviour + testErrorLogger.flushErrorMsg( testErrorLogger.initCurrentExceptionMessage( + MsgType::Exception, e.what(), ::geos::logger::internal::g_rank ) - .addCallStackInfo( LvArray::system::stackTrace( true ) ); + .setCause( "A dependency has thrown an exception" ) + .addCallStackInfo( LvArray::system::stackTrace( true ) ) + .getDiagnosticMsg() ); - std::ostringstream oss; - ErrorLogger::formatMsgForLog( testErrorLogger.getCurrentExceptionMsg(), oss ); - string const streamExpected = GEOS_FMT( - "***** Exception\n" - "***** Rank 0\n" - "***** Message :\n" - "{}\n", - testErrorLogger.getCurrentExceptionMsg().m_msg ); - GEOS_ERROR_IF_EQ_MSG( oss.str().find( streamExpected ), string::npos, - GEOS_FMT( "The error message was not containing the expected sequence.\n" - "The error message was not containing the expected sequence.\n" - " Error message :\n{}" - " expected sequence :\n{}", - oss.str(), - streamExpected ) ); + // we continue without aborting to check the yaml results + } + catch( ... ) + { + EXPECT_FALSE( true ) << "Exception not correctly handled."; } + + // we have to inherint the LvArray formatting here + endLocalLoggerTest( testErrorLogger, { + R"(errors:)", + + // LvArray Exception + R"(- type: Exception + rank: 0 + message: >-)", + GEOS_FMT( "{}:{}", __FILE__, line1 ), + "Array value sequence specified without ',' delimiter: {123 456}", + R"(cause: >- + A dependency has thrown an exception)", + "sourceCallStack:", + "- frame0: ", + "- frame1: ", + "- frame2: " + } ); } TEST( ErrorHandling, testYamlFileAssertOutput ) { ErrorLogger testErrorLogger; - beginLocalLoggerTest( testErrorLogger, "assertTestOutput.yaml" ); + beginLocalLoggerTest( testErrorLogger, "testYamlFileAssertOutput.yaml" ); EXPECT_EXIT( GEOS_ASSERT_MSG( testValue > testMinPrecision && testValue < testMaxPrecision, GEOS_FMT( "{}: value should be between {} and {}, but is {}.", diff --git a/src/main/main.cpp b/src/main/main.cpp index e2836d1f1db..7d43b3e2596 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -88,6 +88,7 @@ int main( int argc, char *argv[] ) ErrorLogger::global().flushErrorMsg( ErrorLogger::global().initCurrentExceptionMessage( MsgType::Exception, e.what(), ::geos::logger::internal::g_rank ) + .setCause( "A dependency has thrown an exception" ) .addCallStackInfo( LvArray::system::stackTrace( true ) ) .getDiagnosticMsg()); basicCleanup( true ); From 1789501f3e5d05a9ba59424e756353a7ece4e66a Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Wed, 24 Jun 2026 17:01:30 +0200 Subject: [PATCH 04/11] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20moved=20every=20erro?= =?UTF-8?q?r=20handling=20in=20the=20ErrorHandler=20class,=20in=20its=20ow?= =?UTF-8?q?n=20file=20->=20allow=20to=20have=20test=20instances?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/coreComponents/common/CMakeLists.txt | 6 +- .../common/initializeEnvironment.cpp | 109 +++------------ .../common/initializeEnvironment.hpp | 5 + .../common/logger/ErrorHandler.cpp | 130 ++++++++++++++++++ .../common/logger/ErrorHandler.hpp | 113 +++++++++++++++ .../{ErrorHandling.cpp => ErrorLogger.cpp} | 14 +- .../{ErrorHandling.hpp => ErrorLogger.hpp} | 25 +--- .../common/logger/ExternalErrorHandler.cpp | 2 +- .../common/logger/ExternalErrorHandler.hpp | 4 +- .../common/logger/GeosExceptions.hpp | 2 +- src/coreComponents/common/logger/Logger.hpp | 2 +- .../multifluid/blackOil/BlackOilFluidBase.cpp | 2 +- .../dataRepository/DataContext.hpp | 2 +- .../unitTests/testErrorHandling.cpp | 27 ++-- .../dataRepositoryTests/testGroupPath.cpp | 2 +- src/main/main.cpp | 2 +- 16 files changed, 301 insertions(+), 146 deletions(-) create mode 100644 src/coreComponents/common/logger/ErrorHandler.cpp create mode 100644 src/coreComponents/common/logger/ErrorHandler.hpp rename src/coreComponents/common/logger/{ErrorHandling.cpp => ErrorLogger.cpp} (98%) rename src/coreComponents/common/logger/{ErrorHandling.hpp => ErrorLogger.hpp} (97%) diff --git a/src/coreComponents/common/CMakeLists.txt b/src/coreComponents/common/CMakeLists.txt index d0143b9564b..25dd41d776e 100644 --- a/src/coreComponents/common/CMakeLists.txt +++ b/src/coreComponents/common/CMakeLists.txt @@ -41,7 +41,8 @@ set( common_headers MemoryInfos.hpp logger/GeosExceptions.hpp logger/Logger.hpp - logger/ErrorHandling.hpp + logger/ErrorHandler.hpp + logger/ErrorLogger.hpp logger/ExternalErrorHandler.hpp MpiWrapper.hpp Path.hpp @@ -80,7 +81,8 @@ set( common_sources format/StringUtilities.cpp logger/GeosExceptions.cpp logger/Logger.cpp - logger/ErrorHandling.cpp + logger/ErrorHandler.cpp + logger/ErrorLogger.cpp logger/ExternalErrorHandler.cpp BufferAllocator.cpp MemoryInfos.cpp diff --git a/src/coreComponents/common/initializeEnvironment.cpp b/src/coreComponents/common/initializeEnvironment.cpp index 3bc54e8a60d..11520246bd9 100644 --- a/src/coreComponents/common/initializeEnvironment.cpp +++ b/src/coreComponents/common/initializeEnvironment.cpp @@ -19,8 +19,7 @@ #include "Path.hpp" #include "LvArray/src/system.hpp" #include "common/LifoStorageCommon.hpp" -#include "logger/ErrorHandling.hpp" -#include "logger/ExternalErrorHandler.hpp" +#include "logger/ErrorHandler.hpp" #include // TPL includes #include @@ -68,92 +67,13 @@ void setupLogger() logger::InitializeLogger(); #endif - { // setup error handling - - ///// set external error handling behaviour ///// - ExternalErrorHandler::instance().enableStderrPipeDeviation( true ); - - ExternalErrorHandler::instance().setErrorHandling( []( string_view errorMsg, - string_view detectionLocation ) - { - // Filter out INFO level messages from external libraries (e.g., VTK) - // ( error / signal lambda would calls either an error function or an info function, depending on a filtering function ) - if( ExternalErrorHandler::isNotAnErrorMsg( errorMsg ) ) - { - // Just print the message without error formatting - GEOS_LOG( errorMsg ); - return; - } - else - { - std::string const stackHistory = LvArray::system::stackTrace( true ); - DiagnosticMsg diagnosticMsg; - ErrorLogger::global().flushErrorMsg( DiagnosticMsgBuilder::init( diagnosticMsg, - MsgType::Error, errorMsg, - ::geos::logger::internal::g_rank ) - .addCallStackInfo( stackHistory ) - .addDetectionLocation( detectionLocation ) - .getDiagnosticMsg() ); - - // we do not terminate the program as 1. the error could be non-fatal, 2. there may be more messages to output. - } - } ); - - ///// set signal handling behaviour ///// - LvArray::system::setSignalHandling( []( int const signal ) - { - // Disable signal handling to prevent catching exit signal (infinite loop) - LvArray::system::setSignalHandling( nullptr ); - - // first of all, there can be external error that await to be output - ExternalErrorHandler::instance().flush( "before signal error output" ); - - // error message output - std::string const stackHistory = LvArray::system::stackTrace( true ); - DiagnosticMsg diagnosticMsg; - DiagnosticMsgBuilder::init( diagnosticMsg, - MsgType::ExternalError, "", - ::geos::logger::internal::g_rank ) - .addSignal( signal ) - .addCallStackInfo( stackHistory ); - ErrorLogger::global().flushErrorMsg( diagnosticMsg ); - - // call program termination - ErrorHandler::instance().abortProgram(); - } ); - - ///// set LvArray to use the GEOS error behaviour in a way that can be traced ///// - LvArray::system::setErrorHandler( []() - { - // first of all, there can be external error that await to be output - ExternalErrorHandler::instance().flush( "after LvArray error detection" ); - - // default error message output - DiagnosticMsg diagnosticMsg; - DiagnosticMsgBuilder::init( diagnosticMsg, - MsgType::ExternalError, - "LvArray Runtime Error", - ::geos::logger::internal::g_rank ) - .addCallStackInfo( LvArray::system::stackTrace( true ) ); - ErrorLogger::global().flushErrorMsg( diagnosticMsg ); - - // call program termination - ErrorHandler::instance().abortProgram(); - } ); - - ///// set Post-Handled Error behaviour ///// - ErrorHandler::instance().setProgramAborter( []() - { - #if defined( GEOS_USE_MPI ) - int mpi = 0; - MPI_Initialized( &mpi ); - if( mpi ) - { - MPI_Abort( MPI_COMM_WORLD, EXIT_FAILURE ); - } - #endif - std::abort(); - } ); + { + ErrorHandler defaultErrorHandler; + defaultErrorHandler.setLogger( &ErrorLogger::global() ); + defaultErrorHandler.enableExternalErrorPipeDeviation( true ); + defaultErrorHandler.setProgramAborter( abortGeos ); + + ErrorHandler::setupErrorHandlingStrategy( std::move( defaultErrorHandler ) ); } } @@ -358,4 +278,17 @@ void cleanupEnvironment( bool inError ) finalizeMPI( inError ); } +void abortGeos() +{ + #if defined( GEOS_USE_MPI ) + int mpi = 0; + MPI_Initialized( &mpi ); + if( mpi ) + { + MPI_Abort( MPI_COMM_WORLD, EXIT_FAILURE ); + } + #endif + std::abort(); +} + } // namespace geos diff --git a/src/coreComponents/common/initializeEnvironment.hpp b/src/coreComponents/common/initializeEnvironment.hpp index f01c1e7df2b..6ff05ff7c26 100644 --- a/src/coreComponents/common/initializeEnvironment.hpp +++ b/src/coreComponents/common/initializeEnvironment.hpp @@ -195,6 +195,11 @@ void pushStatsIntoAdiak( string const & name, T const value ) #endif } +/** + * @brief Post-Handling error behaviour + */ +void abortGeos(); + } // namespace geos #endif // GEOS_COMMON_INITIALIZEENVIRONMENT_HPP_ diff --git a/src/coreComponents/common/logger/ErrorHandler.cpp b/src/coreComponents/common/logger/ErrorHandler.cpp new file mode 100644 index 00000000000..4fd4766b6ae --- /dev/null +++ b/src/coreComponents/common/logger/ErrorHandler.cpp @@ -0,0 +1,130 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ErrorHandler.cpp + */ + +#include "ErrorHandler.hpp" + +#include "ExternalErrorHandler.hpp" +#include "Logger.hpp" + +namespace geos +{ + +ErrorHandler ErrorHandler::s_errorHandlerInstance; + +ErrorHandler::ErrorHandler() + : m_logger( &ErrorLogger::global() ) + , m_abortingFunctor( [this]() { std::abort(); } ) +{} + +ErrorHandler const & ErrorHandler::getInstance() +{ + return s_errorHandlerInstance; +} + +void ErrorHandler::setupErrorHandlingStrategy( ErrorHandler && instance ) +{ + s_errorHandlerInstance = instance; + s_errorHandlerInstance.setupExternalErrorManagment(); + s_errorHandlerInstance.setupSignalHandling(); + s_errorHandlerInstance.setupLvArrayErrorHandling(); +} + +void ErrorHandler::setupExternalErrorManagment() +{ + ExternalErrorHandler::instance().enableStderrPipeDeviation( true ); + + ExternalErrorHandler::instance().setErrorHandling( [&]( string_view errorMsg, + string_view detectionLocation ) + { + // Filter out INFO level messages from external libraries (e.g., VTK) + // ( error / signal lambda would calls either an error function or an info function, depending on a filtering function ) + if( ExternalErrorHandler::isNotAnErrorMsg( errorMsg ) ) + { + // Just print the message without error formatting + GEOS_LOG( errorMsg ); + return; + } + else + { + std::string const stackHistory = LvArray::system::stackTrace( true ); + DiagnosticMsg diagnosticMsg; + m_logger->flushErrorMsg( DiagnosticMsgBuilder::init( diagnosticMsg, + MsgType::Error, errorMsg, + ::geos::logger::internal::g_rank ) + .addCallStackInfo( stackHistory ) + .addDetectionLocation( detectionLocation ) + .getDiagnosticMsg() ); + + // we do not terminate the program as 1. the error could be non-fatal, 2. there may be more messages to output. + } + } ); +} + +void ErrorHandler::setupSignalHandling() +{ + LvArray::system::setSignalHandling( []( int const signal ) + { + // setSignalHandling() cannot take capturing lambda, so we get the instance with the static function. + ErrorHandler const & instance = ErrorHandler::getInstance(); + + // Disable signal handling to prevent catching exit signal (infinite loop) + LvArray::system::setSignalHandling( nullptr ); + + // first of all, there can be external error that await to be output + ExternalErrorHandler::instance().flush( "before signal error output" ); + + // error message output + std::string const stackHistory = LvArray::system::stackTrace( true ); + DiagnosticMsg diagnosticMsg; + DiagnosticMsgBuilder::init( diagnosticMsg, + MsgType::ExternalError, "", + ::geos::logger::internal::g_rank ) + .addSignal( signal ) + .addCallStackInfo( stackHistory ); + instance.m_logger->flushErrorMsg( diagnosticMsg ); + + // call program termination + instance.abortProgram(); + } ); +} + +void ErrorHandler::setupLvArrayErrorHandling() +{ + LvArray::system::setErrorHandler( [&]() + { + // first of all, there can be external error that await to be output + ExternalErrorHandler::instance().flush( "before LvArray error handling" ); + + // default error message output + DiagnosticMsg diagnosticMsg; + DiagnosticMsgBuilder::init( diagnosticMsg, + MsgType::ExternalError, + "LvArray Runtime Error", + ::geos::logger::internal::g_rank ) + .addCallStackInfo( LvArray::system::stackTrace( true ) ) + .addDetectionLocation( "LvArray Error Handler" ); + m_logger->flushErrorMsg( diagnosticMsg ); + + // call program termination + abortProgram(); + } ); +} + + +} /* namespace geos */ diff --git a/src/coreComponents/common/logger/ErrorHandler.hpp b/src/coreComponents/common/logger/ErrorHandler.hpp new file mode 100644 index 00000000000..cb4e14145f4 --- /dev/null +++ b/src/coreComponents/common/logger/ErrorHandler.hpp @@ -0,0 +1,113 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * SPDX-License-Identifier: LGPL-2.1-only + * + * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC + * Copyright (c) 2018-2024 TotalEnergies + * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University + * Copyright (c) 2023-2024 Chevron + * Copyright (c) 2019- GEOS/GEOSX Contributors + * All rights reserved + * + * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details. + * ------------------------------------------------------------------------------------------------------------ + */ + +/** + * @file ErrorHandler.hpp + */ + +#ifndef INITIALIZATION_ERROR_HANDLER_HPP +#define INITIALIZATION_ERROR_HANDLER_HPP + +#include "ErrorLogger.hpp" + +namespace geos +{ + +class ErrorHandler +{ +public: + + /** + * @brief Singleton pattern (as we can only have one strategy of handling at the same time). + * Update the current error handling strategy. Once setup, the instance is not meant to be mutable. + * @return ErrorHandler const& + */ + static void setupErrorHandlingStrategy( ErrorHandler && instance ); + + /** + * @brief Singleton pattern (as we can only have one strategy of handling at the same time). + * @return Handler instance currently setup. + */ + static ErrorHandler const & getInstance(); + + /** + * @brief Construct a new Error Handler object. To use it as the current error handling strategy, + * setupErrorHandlingStrategy() must be called on this instance after setting it up. + */ + ErrorHandler(); + + /** + * @brief Enable pipe deviation of external stderr messages, + * @see ExternalErrorHandler + */ + void enableExternalErrorPipeDeviation( bool enable ) + { m_isPipeDeviationEnabled = enable; } + + /** + * @brief Set the callback to call when post-error program abortion is requested. + * @param abortingFunctor a void() functor that terminates the program in a safe way. + */ + void setProgramAborter( std::function< void() > const & abortingFunctor ) + { m_abortingFunctor = abortingFunctor; } + + /** + * @brief the ErrorLogger where error messages are rooted + * @param logger the instance of the logger, ErrorLogger::instance() or a local one. + */ + void setLogger( ErrorLogger * logger ) + { m_logger = logger; } + + /** + * @return the ErrorLogger where error messages are rooted + */ + ErrorLogger & getLogger() const + { return *m_logger; } + + /** + * @brief Post error-handling function that terminates the program. + */ + void abortProgram() const + { m_abortingFunctor(); } + +private: + + static ErrorHandler s_errorHandlerInstance; + + ErrorLogger * m_logger; + + bool m_isPipeDeviationEnabled = false; + + std::function< void() > m_abortingFunctor; + + /** + * @brief set external error handling behaviour + */ + void setupExternalErrorManagment(); + + /** + * @brief set signal handling behaviour + */ + void setupSignalHandling(); + + /** + * @brief Set LvArray to use the GEOS error behaviour in a way that can be traced + */ + void setupLvArrayErrorHandling(); + +}; + +} /* namespace geos */ + +#endif diff --git a/src/coreComponents/common/logger/ErrorHandling.cpp b/src/coreComponents/common/logger/ErrorLogger.cpp similarity index 98% rename from src/coreComponents/common/logger/ErrorHandling.cpp rename to src/coreComponents/common/logger/ErrorLogger.cpp index f31dc81dc7c..8a0ef1b529c 100644 --- a/src/coreComponents/common/logger/ErrorHandling.cpp +++ b/src/coreComponents/common/logger/ErrorLogger.cpp @@ -14,10 +14,10 @@ */ /** - * @file ErrorHandling.cpp + * @file ErrorLogger.cpp */ -#include "ErrorHandling.hpp" +#include "ErrorLogger.hpp" #include "common/DataTypes.hpp" #include "common/logger/Logger.hpp" #include "common/format/StringUtilities.hpp" @@ -453,14 +453,4 @@ void ErrorLogger::flushCurrentExceptionMessage() } } -ErrorHandler::ErrorHandler() - : m_abortingFunctor( []() { std::abort(); } ) -{} - -ErrorHandler & ErrorHandler::instance() -{ - static ErrorHandler s_instance; - return s_instance; -} - } /* namespace geos */ diff --git a/src/coreComponents/common/logger/ErrorHandling.hpp b/src/coreComponents/common/logger/ErrorLogger.hpp similarity index 97% rename from src/coreComponents/common/logger/ErrorHandling.hpp rename to src/coreComponents/common/logger/ErrorLogger.hpp index a2897237cb8..4f17ce8d0bb 100644 --- a/src/coreComponents/common/logger/ErrorHandling.hpp +++ b/src/coreComponents/common/logger/ErrorLogger.hpp @@ -14,7 +14,7 @@ */ /** - * @file ErrorHandling.hpp + * @file ErrorLogger.hpp */ #ifndef INITIALIZATION_ERROR_LOGGER_HPP @@ -424,29 +424,6 @@ class ErrorLogger std::string_view indent ); }; -class ErrorHandler -{ -public: - - static ErrorHandler & instance(); - - ErrorHandler(); - - void setProgramAborter( std::function< void() > const & abortingFunctor ) - { m_abortingFunctor = abortingFunctor; } - - /** - * @brief Post error-handling function that terminates the program. - */ - void abortProgram() - { m_abortingFunctor(); } - -private: - - std::function< void() > m_abortingFunctor; - -}; - } /* namespace geos */ #endif diff --git a/src/coreComponents/common/logger/ExternalErrorHandler.cpp b/src/coreComponents/common/logger/ExternalErrorHandler.cpp index 903d461b78c..2603e2f02c5 100644 --- a/src/coreComponents/common/logger/ExternalErrorHandler.cpp +++ b/src/coreComponents/common/logger/ExternalErrorHandler.cpp @@ -14,7 +14,7 @@ */ /** - * @file ErrorHandling.cpp + * @file ErrorHandler.cpp */ #include "ExternalErrorHandler.hpp" diff --git a/src/coreComponents/common/logger/ExternalErrorHandler.hpp b/src/coreComponents/common/logger/ExternalErrorHandler.hpp index fc641de9db9..cc0e687ce72 100644 --- a/src/coreComponents/common/logger/ExternalErrorHandler.hpp +++ b/src/coreComponents/common/logger/ExternalErrorHandler.hpp @@ -14,7 +14,7 @@ */ /** - * @file ErrorHandling.hpp + * @file ExternalErrorHandler.hpp * @brief This file provides the infrastructure to capture external errors. * @note Below is the architecture of the external error managment, in the scenario of a problematic * infrastructure which deviates (thus breaks) stderr. @@ -52,7 +52,7 @@ #ifndef LOGGER_EXTERNALERRORHANDLER_HPP #define LOGGER_EXTERNALERRORHANDLER_HPP -#include "ErrorHandling.hpp" +#include "ErrorLogger.hpp" #include #include diff --git a/src/coreComponents/common/logger/GeosExceptions.hpp b/src/coreComponents/common/logger/GeosExceptions.hpp index f3934bebbc3..08999997b7a 100644 --- a/src/coreComponents/common/logger/GeosExceptions.hpp +++ b/src/coreComponents/common/logger/GeosExceptions.hpp @@ -18,7 +18,7 @@ */ -#include "common/logger/ErrorHandling.hpp" +#include "common/logger/ErrorHandler.hpp" namespace geos { diff --git a/src/coreComponents/common/logger/Logger.hpp b/src/coreComponents/common/logger/Logger.hpp index 355b6f86596..6c4e263a9d6 100644 --- a/src/coreComponents/common/logger/Logger.hpp +++ b/src/coreComponents/common/logger/Logger.hpp @@ -164,7 +164,7 @@ .addCallStackInfo( LvArray::system::stackTrace( true ) ) \ .addContextInfo( GEOS_DETAIL_REST_ARGS( __VA_ARGS__ )); \ GEOS_GLOBAL_LOGGER.flushCurrentExceptionMessage(); \ - ErrorHandler::instance().abortProgram(); \ + ErrorHandler::getInstance().abortProgram(); \ } \ }while( false ) #elif __CUDA_ARCH__ diff --git a/src/coreComponents/constitutive/fluid/multifluid/blackOil/BlackOilFluidBase.cpp b/src/coreComponents/constitutive/fluid/multifluid/blackOil/BlackOilFluidBase.cpp index 098fcefacad..f4c2f0c6bd2 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/blackOil/BlackOilFluidBase.cpp +++ b/src/coreComponents/constitutive/fluid/multifluid/blackOil/BlackOilFluidBase.cpp @@ -15,7 +15,7 @@ #include "BlackOilFluidBase.hpp" -#include "common/logger/ErrorHandling.hpp" +#include "common/logger/ErrorLogger.hpp" #include "constitutive/fluid/multifluid/MultiFluidUtils.hpp" #include "constitutive/fluid/multifluid/CO2Brine/functions/PVTFunctionHelpers.hpp" #include "functions/FunctionManager.hpp" diff --git a/src/coreComponents/dataRepository/DataContext.hpp b/src/coreComponents/dataRepository/DataContext.hpp index 8a43381b438..20b48d13bc5 100644 --- a/src/coreComponents/dataRepository/DataContext.hpp +++ b/src/coreComponents/dataRepository/DataContext.hpp @@ -24,7 +24,7 @@ #include "common/logger/Logger.hpp" #include "xmlWrapper.hpp" #include "common/format/Format.hpp" -#include "common/logger/ErrorHandling.hpp" +#include "common/logger/ErrorLogger.hpp" namespace geos { diff --git a/src/coreComponents/dataRepository/unitTests/testErrorHandling.cpp b/src/coreComponents/dataRepository/unitTests/testErrorHandling.cpp index ea375bc0425..7341c25ee1e 100644 --- a/src/coreComponents/dataRepository/unitTests/testErrorHandling.cpp +++ b/src/coreComponents/dataRepository/unitTests/testErrorHandling.cpp @@ -15,11 +15,10 @@ // forcefully enable asserts macros for this unit test #include "LvArray/src/system.hpp" -#include "common/logger/ExternalErrorHandler.hpp" #include "gtest/gtest.h" #define GEOS_ASSERT_ENABLED -#include "common/logger/ErrorHandling.hpp" +#include "common/logger/ErrorHandler.hpp" #include "common/logger/Logger.hpp" #include "dataRepository/DataContext.hpp" #include "common/initializeEnvironment.hpp" @@ -104,7 +103,7 @@ void endLocalLoggerTest( ErrorLogger & errorLogger, << "-----------------------\n"; testFailed |= !foundFileBit; } - EXPECT_FALSE( testFailed ) << "Generated error file content:\n" + EXPECT_FALSE( testFailed ) << "Generated error file content ("< -void beginLocalHandlerTest( LAMBDA && lambda ) +void beginLocalErrorHandlerTest( ErrorLogger & logger, LAMBDA && abortCustomFunc ) { - defaultErrorhandler = ErrorHandler::instance(); - ErrorHandler::instance() = ErrorHandler(); - ErrorHandler::instance().setProgramAborter( lambda ); + ErrorHandler testErrorHandler; + testErrorHandler.setProgramAborter( abortCustomFunc ); + testErrorHandler.setLogger( &logger ); + + // backup and change + defaultErrorhandler = ErrorHandler::getInstance(); + ErrorHandler::setupErrorHandlingStrategy( std::move( testErrorHandler ) ); } -void endLocalHandlerTest() +void endLocalErrorHandlerTest() { - ErrorHandler::instance() = defaultErrorhandler; + // restore backup + ErrorHandler defaultErrorHandlerBackup = defaultErrorhandler; + ErrorHandler::setupErrorHandlingStrategy( std::move( defaultErrorHandlerBackup ) ); } ///@} @@ -358,7 +363,7 @@ TEST( ErrorHandling, testLogFileExceptionOutput ) // testing the capture & processing of lvarray exceptions, also testing what happens in case of an // std::exception (as this is what lvarray throws). -TEST( ErrorHandling, testLvArrayAndStdException ) +TEST( ErrorHandling, testLvArrayStdException ) { ErrorLogger testErrorLogger; size_t line1; @@ -381,7 +386,7 @@ TEST( ErrorHandling, testLvArrayAndStdException ) // mimic "main()" exception logging behaviour testErrorLogger.flushErrorMsg( testErrorLogger.initCurrentExceptionMessage( MsgType::Exception, e.what(), - ::geos::logger::internal::g_rank ) + ::geos::logger::internal::g_rank ) .setCause( "A dependency has thrown an exception" ) .addCallStackInfo( LvArray::system::stackTrace( true ) ) .getDiagnosticMsg() ); diff --git a/src/coreComponents/integrationTests/dataRepositoryTests/testGroupPath.cpp b/src/coreComponents/integrationTests/dataRepositoryTests/testGroupPath.cpp index c177254e825..b5bd092e8c5 100644 --- a/src/coreComponents/integrationTests/dataRepositoryTests/testGroupPath.cpp +++ b/src/coreComponents/integrationTests/dataRepositoryTests/testGroupPath.cpp @@ -14,7 +14,7 @@ */ // Source includes -#include "common/logger/ErrorHandling.hpp" +#include "common/logger/ErrorLogger.hpp" #include "mainInterface/ProblemManager.hpp" #include "mainInterface/initialization.hpp" #include "mainInterface/GeosxState.hpp" diff --git a/src/main/main.cpp b/src/main/main.cpp index 7d43b3e2596..976940a3198 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -14,7 +14,7 @@ */ // Source includes -#include "common/logger/ErrorHandling.hpp" +#include "common/logger/ErrorLogger.hpp" #include "common/logger/Logger.hpp" #include "common/MemoryInfos.hpp" #include "common/TimingMacros.hpp" From 92a854e30e35dcc150d7dec34ccc6d9779087292 Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Wed, 24 Jun 2026 17:02:56 +0200 Subject: [PATCH 05/11] =?UTF-8?q?=F0=9F=90=9B=20fix=20VerifySignalHandlerL?= =?UTF-8?q?ogs=20by=20having=20ErrorHandler=20test=20instance=20+=20change?= =?UTF-8?q?d=20tested=20signal=20to=20SIGFPE=20to=20avoid=20messing=20with?= =?UTF-8?q?=20debuggers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../unitTests/testErrorHandling.cpp | 42 ++++++++----------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/src/coreComponents/dataRepository/unitTests/testErrorHandling.cpp b/src/coreComponents/dataRepository/unitTests/testErrorHandling.cpp index 7341c25ee1e..60114d8f4c0 100644 --- a/src/coreComponents/dataRepository/unitTests/testErrorHandling.cpp +++ b/src/coreComponents/dataRepository/unitTests/testErrorHandling.cpp @@ -460,44 +460,38 @@ TEST( ErrorHandling, testYamlFileAssertOutput ) } ); } - TEST( ErrorHandling, VerifySignalHandlerLogs ) { ErrorLogger testErrorLogger; + bool signalHappened = false; - beginLocalLoggerTest( testErrorLogger, "errors.yaml" ); + beginLocalLoggerTest( testErrorLogger, "VerifySignalHandlerLogs.yaml" ); + beginLocalErrorHandlerTest( testErrorLogger, [&]() + { + signalHappened = true; + // we do not really abort, we want to test signal handling behaviour + } ); - setupLogger(); + raise( SIGFPE ); + EXPECT_TRUE( signalHappened ); - bool signalHappened = false; - LvArray::system::setErrorHandler( [&]() - { - endLocalLoggerTest( testErrorLogger, { - R"(- type: ExternalError + endLocalErrorHandlerTest(); + endLocalLoggerTest( testErrorLogger, { + R"(- type: ExternalError rank: 0 message: >- - Signal encountered (no. 2): Interrupt + Floating point error encountered: + Unknown reason. contexts: - priority: 0 description: Signal (detected from Signal Handler) detectionLocation: Signal handler - signal: 2 + signal: 8 sourceCallStack:)", - "- frame0: ", - "- frame1: ", - "- frame2: " - } ); - - signalHappened = true; + "- frame0: ", + "- frame1: ", + "- frame2: " } ); - - ErrorLogger::global().enableFileOutput( true ); - - raise( SIGINT ); - - EXPECT_TRUE( signalHappened ); - - setupLogger(); } int main( int ac, char * av[] ) From e29c0c80053bb93902c462d05389a2aca975af1d Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Wed, 24 Jun 2026 17:49:55 +0200 Subject: [PATCH 06/11] =?UTF-8?q?=E2=9C=85=20test=20LvArray=20error?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../unitTests/testErrorHandling.cpp | 44 ++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/src/coreComponents/dataRepository/unitTests/testErrorHandling.cpp b/src/coreComponents/dataRepository/unitTests/testErrorHandling.cpp index 60114d8f4c0..ba12d46afe6 100644 --- a/src/coreComponents/dataRepository/unitTests/testErrorHandling.cpp +++ b/src/coreComponents/dataRepository/unitTests/testErrorHandling.cpp @@ -417,6 +417,48 @@ TEST( ErrorHandling, testLvArrayStdException ) } ); } +// testing the capture & processing of lvarray error, also testing what happens when a dependency terminates +TEST( ErrorHandling, testLvArrayError ) +{ + ErrorLogger testErrorLogger; + + beginLocalLoggerTest( testErrorLogger, "testLvArrayAndStdError.yaml" ); + beginLocalErrorHandlerTest( testErrorLogger, abortGeos ); + + // Standard error caused by LvArray: not existing MemorySpace will cause an error with defined behaviour. + LvArray::MemorySpace const badValue = LvArray::MemorySpace( -2 ); + EXPECT_EXIT( LvArray::operator<<( std::cout, badValue ), ::testing::ExitedWithCode( 1 ), ".*" ); + + endLocalErrorHandlerTest(); + + // we have to inherint the LvArray formatting here + endLocalLoggerTest( testErrorLogger, { + R"(errors:)", + + R"( - type: ExternalError + rank: 0 + message: >- + LvArray Runtime Error + contexts: + - priority: 0 + description: LvArray Error Handler + detectionLocation: LvArray Error Handler)", + + // LvArray Error + // Exact reason is deactivated: For now, we cannot capture the lvarray error reason, because the lvarray error + // handler does not communicate the error message (excepted directly in std::cout). + // "Unrecognized memory space -2", + + // LvArray also does not communicate the error line. + // GEOS_FMT( "{}:{}", __FILE__, line1 ), + + "sourceCallStack:", + "- frame0: ", + "- frame1: ", + "- frame2: " + } ); +} + TEST( ErrorHandling, testYamlFileAssertOutput ) { ErrorLogger testErrorLogger; @@ -460,7 +502,7 @@ TEST( ErrorHandling, testYamlFileAssertOutput ) } ); } -TEST( ErrorHandling, VerifySignalHandlerLogs ) +TEST( ErrorHandling, testSignalHandling ) { ErrorLogger testErrorLogger; bool signalHappened = false; From be3f828835c2fbc2ea90f201ab9575cc9b2d0e3b Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Wed, 24 Jun 2026 17:52:27 +0200 Subject: [PATCH 07/11] =?UTF-8?q?=F0=9F=94=8A=20added=20small=20explainati?= =?UTF-8?q?on=20to=20hint=20that=20a=20dependancy=20used=20the=20error=20p?= =?UTF-8?q?ipe?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/coreComponents/common/logger/ErrorHandler.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/coreComponents/common/logger/ErrorHandler.cpp b/src/coreComponents/common/logger/ErrorHandler.cpp index 4fd4766b6ae..88a24da6e70 100644 --- a/src/coreComponents/common/logger/ErrorHandler.cpp +++ b/src/coreComponents/common/logger/ErrorHandler.cpp @@ -69,6 +69,7 @@ void ErrorHandler::setupExternalErrorManagment() ::geos::logger::internal::g_rank ) .addCallStackInfo( stackHistory ) .addDetectionLocation( detectionLocation ) + .setCause( "Error pipe output from a dependency" ) .getDiagnosticMsg() ); // we do not terminate the program as 1. the error could be non-fatal, 2. there may be more messages to output. From 35e22ad26146d90ebd1c5fb979356037fe37b24a Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Thu, 25 Jun 2026 11:42:58 +0200 Subject: [PATCH 08/11] =?UTF-8?q?=F0=9F=90=9B=20affected=20main=20entry=20?= =?UTF-8?q?point?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/main.cpp b/src/main/main.cpp index 976940a3198..3a624a5b9cf 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -81,7 +81,7 @@ int main( int argc, char *argv[] ) { // GEOS generated exceptions management ErrorLogger::global().flushCurrentExceptionMessage(); basicCleanup( true ); - ErrorHandler::instance().abortProgram(); + ErrorHandler::getInstance().abortProgram(); } catch( std::exception const & e ) { // native exceptions management @@ -92,7 +92,7 @@ int main( int argc, char *argv[] ) .addCallStackInfo( LvArray::system::stackTrace( true ) ) .getDiagnosticMsg()); basicCleanup( true ); - ErrorHandler::instance().abortProgram(); + ErrorHandler::getInstance().abortProgram(); } return 0; } From 0c1f6f3d351a00aa0b9f037370fe4b583f235b1d Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Thu, 25 Jun 2026 15:53:12 +0200 Subject: [PATCH 09/11] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20optimise=20double=20?= =?UTF-8?q?callstack=20calculation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/coreComponents/common/logger/ErrorLogger.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/coreComponents/common/logger/ErrorLogger.cpp b/src/coreComponents/common/logger/ErrorLogger.cpp index 8a0ef1b529c..3b845df4c0e 100644 --- a/src/coreComponents/common/logger/ErrorLogger.cpp +++ b/src/coreComponents/common/logger/ErrorLogger.cpp @@ -62,12 +62,10 @@ DiagnosticMsgBuilder ErrorLogger::initCurrentExceptionMessage( MsgType msgType, std::string_view msgContent, integer rank ) { - DiagnosticMsg diagnosticMsg; - m_getCurrentExceptionMsg = DiagnosticMsgBuilder::init( diagnosticMsg, - msgType, msgContent, - rank ) - .addCallStackInfo( LvArray::system::stackTrace( true ) ) - .getDiagnosticMsg(); + m_getCurrentExceptionMsg = DiagnosticMsg(); + DiagnosticMsgBuilder::init( m_getCurrentExceptionMsg, + msgType, msgContent, + rank ); return DiagnosticMsgBuilder::modify( m_getCurrentExceptionMsg ); } From b80659741bb12e0c65974c4a092ecea96d0cac21 Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Fri, 26 Jun 2026 16:35:06 +0200 Subject: [PATCH 10/11] =?UTF-8?q?=F0=9F=90=9B=20consolidate=20unit-test,?= =?UTF-8?q?=20centralize=20std=20exception=20handling=20in=20ErrorHandler?= =?UTF-8?q?=20instance=20(global=20or=20unit=20test=20one)=20+=20check=20e?= =?UTF-8?q?xception=20happened=20in=20unit=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/logger/ErrorHandler.cpp | 11 ++++++++ .../common/logger/ErrorHandler.hpp | 10 +++++++ .../unitTests/testErrorHandling.cpp | 26 +++++++++++-------- src/main/main.cpp | 9 +++---- 4 files changed, 39 insertions(+), 17 deletions(-) diff --git a/src/coreComponents/common/logger/ErrorHandler.cpp b/src/coreComponents/common/logger/ErrorHandler.cpp index 88a24da6e70..4eb2f3fc59a 100644 --- a/src/coreComponents/common/logger/ErrorHandler.cpp +++ b/src/coreComponents/common/logger/ErrorHandler.cpp @@ -127,5 +127,16 @@ void ErrorHandler::setupLvArrayErrorHandling() } ); } +void ErrorHandler::manageException( std::exception const & e, + string_view causeMessage, + string_view stackTrace ) const +{ + m_logger->flushErrorMsg( m_logger->initCurrentExceptionMessage( MsgType::Exception, + e.what(), + ::geos::logger::internal::g_rank ) + .setCause( causeMessage ) + .addCallStackInfo( stackTrace ) + .getDiagnosticMsg()); +} } /* namespace geos */ diff --git a/src/coreComponents/common/logger/ErrorHandler.hpp b/src/coreComponents/common/logger/ErrorHandler.hpp index cb4e14145f4..27a31204c02 100644 --- a/src/coreComponents/common/logger/ErrorHandler.hpp +++ b/src/coreComponents/common/logger/ErrorHandler.hpp @@ -75,6 +75,16 @@ class ErrorHandler ErrorLogger & getLogger() const { return *m_logger; } + /** + * @brief Output the error message for a std exception. Std exception are likely thrown from a + * dependency, as geos::exception is the standard exception type to throw from GEOS. + * @param e + * @param stack_trace + */ + void manageException( std::exception const & e, + string_view causeMessage, + string_view stackTrace ) const; + /** * @brief Post error-handling function that terminates the program. */ diff --git a/src/coreComponents/dataRepository/unitTests/testErrorHandling.cpp b/src/coreComponents/dataRepository/unitTests/testErrorHandling.cpp index ba12d46afe6..e80a25c2a1e 100644 --- a/src/coreComponents/dataRepository/unitTests/testErrorHandling.cpp +++ b/src/coreComponents/dataRepository/unitTests/testErrorHandling.cpp @@ -366,16 +366,17 @@ TEST( ErrorHandling, testLogFileExceptionOutput ) TEST( ErrorHandling, testLvArrayStdException ) { ErrorLogger testErrorLogger; - size_t line1; + bool exceptionHappened = false; beginLocalLoggerTest( testErrorLogger, "testLvArrayAndStdException.yaml" ); + beginLocalErrorHandlerTest( testErrorLogger, abortGeos ); // Standard exception thrown by LvArray try { // no ',' in between numbers will throw an exception array1d< localIndex > dummy; - line1 = __LINE__; LvArray::input::stringToArray( dummy, "{123 456}" ); + LvArray::input::stringToArray( dummy, "{123 456}" ); } catch( geos::Exception & e ) { @@ -383,22 +384,24 @@ TEST( ErrorHandling, testLvArrayStdException ) } catch( std::exception const & e ) { - // mimic "main()" exception logging behaviour - testErrorLogger.flushErrorMsg( testErrorLogger.initCurrentExceptionMessage( - MsgType::Exception, e.what(), - ::geos::logger::internal::g_rank ) - .setCause( "A dependency has thrown an exception" ) - .addCallStackInfo( LvArray::system::stackTrace( true ) ) - .getDiagnosticMsg() ); + exceptionHappened = true; + // mimic "main()" exception logging behaviour + { + string_view constexpr causeMessage = "A dependency has thrown an exception"; + auto const stackTrace = LvArray::system::stackTrace( true ); // auto const for compatibility with stacktrace library + ErrorHandler::getInstance().manageException( e, causeMessage, stackTrace ); + } // we continue without aborting to check the yaml results } catch( ... ) { - EXPECT_FALSE( true ) << "Exception not correctly handled."; + EXPECT_FALSE( true ) << "Unexpected exception."; } + EXPECT_TRUE( exceptionHappened ) << "Exception has not been thrown"; // we have to inherint the LvArray formatting here + endLocalErrorHandlerTest(); endLocalLoggerTest( testErrorLogger, { R"(errors:)", @@ -406,8 +409,9 @@ TEST( ErrorHandling, testLvArrayStdException ) R"(- type: Exception rank: 0 message: >-)", - GEOS_FMT( "{}:{}", __FILE__, line1 ), + "Array value sequence specified without ',' delimiter: {123 456}", + R"(cause: >- A dependency has thrown an exception)", "sourceCallStack:", diff --git a/src/main/main.cpp b/src/main/main.cpp index 3a624a5b9cf..633c452eb92 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -85,12 +85,9 @@ int main( int argc, char *argv[] ) } catch( std::exception const & e ) { // native exceptions management - ErrorLogger::global().flushErrorMsg( ErrorLogger::global().initCurrentExceptionMessage( - MsgType::Exception, e.what(), - ::geos::logger::internal::g_rank ) - .setCause( "A dependency has thrown an exception" ) - .addCallStackInfo( LvArray::system::stackTrace( true ) ) - .getDiagnosticMsg()); + string_view constexpr causeMessage = "A dependency has thrown an exception"; + auto const stackTrace = LvArray::system::stackTrace( true ); // auto const for compatibility with stacktrace library + ErrorHandler::getInstance().manageException( e, causeMessage, stackTrace ); basicCleanup( true ); ErrorHandler::getInstance().abortProgram(); } From 6adcb0a1d785a9b41c4131179f3a0f10bf5b4959 Mon Sep 17 00:00:00 2001 From: MelReyCG Date: Fri, 26 Jun 2026 17:03:54 +0200 Subject: [PATCH 11/11] =?UTF-8?q?=F0=9F=90=9B=20unused=20capture?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/coreComponents/common/logger/ErrorHandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreComponents/common/logger/ErrorHandler.cpp b/src/coreComponents/common/logger/ErrorHandler.cpp index 4eb2f3fc59a..00918d2b341 100644 --- a/src/coreComponents/common/logger/ErrorHandler.cpp +++ b/src/coreComponents/common/logger/ErrorHandler.cpp @@ -29,7 +29,7 @@ ErrorHandler ErrorHandler::s_errorHandlerInstance; ErrorHandler::ErrorHandler() : m_logger( &ErrorLogger::global() ) - , m_abortingFunctor( [this]() { std::abort(); } ) + , m_abortingFunctor( []() { std::abort(); } ) {} ErrorHandler const & ErrorHandler::getInstance()