diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml index dab98b9d5f7..601f5a454f6 100644 --- a/.github/workflows/ci_tests.yml +++ b/.github/workflows/ci_tests.yml @@ -150,47 +150,47 @@ jobs: fail-fast : false matrix: include: - - name: Ubuntu (20.04, gcc 9.4.0, open-mpi 4.0.3) - CMAKE_BUILD_TYPE: Release - DOCKER_REPOSITORY: geosx/ubuntu20.04-gcc9 - BUILD_SHARED_LIBS: ON - ENABLE_HYPRE: OFF - ENABLE_TRILINOS: ON - GEOS_ENABLE_BOUNDS_CHECK: ON - HOST_CONFIG: /spack-generated.cmake - - - name: Ubuntu debug (20.04, gcc 10.5.0, open-mpi 4.0.3) - github codespaces - BUILD_AND_TEST_CLI_ARGS: "--no-run-unit-tests" - CMAKE_BUILD_TYPE: Debug - DOCKER_REPOSITORY: geosx/ubuntu20.04-gcc10 - BUILD_SHARED_LIBS: ON - ENABLE_HYPRE: OFF - ENABLE_TRILINOS: ON - GEOS_ENABLE_BOUNDS_CHECK: ON - RUNS_ON: streak2 - NPROC: 8 - DOCKER_RUN_ARGS: "--cpus=8 --memory=256g --runtime=nvidia -v /etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro -v /etc/pki/tls/certs/ca-bundle.crt:/certs/ca-bundle.crt:ro" - - HOST_CONFIG: /spack-generated.cmake - - - name: Ubuntu (20.04, gcc 10.5.0, open-mpi 4.0.3) - github codespaces - CMAKE_BUILD_TYPE: Release - DOCKER_REPOSITORY: geosx/ubuntu20.04-gcc10 - BUILD_SHARED_LIBS: ON - ENABLE_HYPRE: OFF - ENABLE_TRILINOS: ON - GEOS_ENABLE_BOUNDS_CHECK: ON - HOST_CONFIG: /spack-generated.cmake - - - name: Ubuntu (22.04, gcc 11.4.0, open-mpi 4.1.2) - CMAKE_BUILD_TYPE: Release - DOCKER_REPOSITORY: geosx/ubuntu22.04-gcc11 - ENABLE_HYPRE: ON - ENABLE_TRILINOS: OFF - BUILD_SHARED_LIBS: ON - GEOS_ENABLE_BOUNDS_CHECK: OFF - GCP_BUCKET: geosx/ubuntu22.04-gcc11 - HOST_CONFIG: /spack-generated.cmake + # - name: Ubuntu (20.04, gcc 9.4.0, open-mpi 4.0.3) + # CMAKE_BUILD_TYPE: Release + # DOCKER_REPOSITORY: geosx/ubuntu20.04-gcc9 + # BUILD_SHARED_LIBS: ON + # ENABLE_HYPRE: OFF + # ENABLE_TRILINOS: ON + # GEOS_ENABLE_BOUNDS_CHECK: ON + # HOST_CONFIG: /spack-generated.cmake + + # - name: Ubuntu debug (20.04, gcc 10.5.0, open-mpi 4.0.3) - github codespaces + # BUILD_AND_TEST_CLI_ARGS: "--no-run-unit-tests" + # CMAKE_BUILD_TYPE: Debug + # DOCKER_REPOSITORY: geosx/ubuntu20.04-gcc10 + # BUILD_SHARED_LIBS: ON + # ENABLE_HYPRE: OFF + # ENABLE_TRILINOS: ON + # GEOS_ENABLE_BOUNDS_CHECK: ON + # RUNS_ON: streak2 + # NPROC: 8 + # DOCKER_RUN_ARGS: "--cpus=8 --memory=256g --runtime=nvidia -v /etc/pki/tls/certs/ca-bundle.crt:/etc/pki/tls/certs/ca-bundle.crt:ro -v /etc/pki/tls/certs/ca-bundle.crt:/certs/ca-bundle.crt:ro" + + # HOST_CONFIG: /spack-generated.cmake + + # - name: Ubuntu (20.04, gcc 10.5.0, open-mpi 4.0.3) - github codespaces + # CMAKE_BUILD_TYPE: Release + # DOCKER_REPOSITORY: geosx/ubuntu20.04-gcc10 + # BUILD_SHARED_LIBS: ON + # ENABLE_HYPRE: OFF + # ENABLE_TRILINOS: ON + # GEOS_ENABLE_BOUNDS_CHECK: OFF + # HOST_CONFIG: /spack-generated.cmake + + # - name: Ubuntu (22.04, gcc 11.4.0, open-mpi 4.1.2) + # CMAKE_BUILD_TYPE: Release + # DOCKER_REPOSITORY: geosx/ubuntu22.04-gcc11 + # ENABLE_HYPRE: ON + # ENABLE_TRILINOS: OFF + # BUILD_SHARED_LIBS: ON + # GEOS_ENABLE_BOUNDS_CHECK: OFF + # GCP_BUCKET: geosx/ubuntu22.04-gcc11 + # HOST_CONFIG: /spack-generated.cmake - name: Ubuntu (22.04, gcc 12.3.0, open-mpi 4.1.2) CMAKE_BUILD_TYPE: Release diff --git a/src/coreComponents/common/CMakeLists.txt b/src/coreComponents/common/CMakeLists.txt index 0e37ba56703..502f4727592 100644 --- a/src/coreComponents/common/CMakeLists.txt +++ b/src/coreComponents/common/CMakeLists.txt @@ -38,10 +38,14 @@ set( common_headers GEOS_RAJA_Interface.hpp GeosxMacros.hpp MemoryInfos.hpp + logger/DiagnosticMessage.hpp + logger/GeosExceptions.hpp logger/GeosExceptions.hpp logger/Logger.hpp logger/ErrorHandling.hpp logger/ExternalErrorHandler.hpp + logger/LogHistory.hpp + logger/MsgType.hpp MpiWrapper.hpp Path.hpp Span.hpp @@ -71,6 +75,7 @@ endif( ) # Specify all sources # set( common_sources + format/EnumStrings.cpp format/table/TableLayout.cpp format/table/TableFormatter.cpp format/table/TableData.cpp @@ -80,6 +85,7 @@ set( common_sources logger/Logger.cpp logger/ErrorHandling.cpp logger/ExternalErrorHandler.cpp + logger/LogHistory.cpp BufferAllocator.cpp MemoryInfos.cpp MpiWrapper.cpp diff --git a/src/coreComponents/common/StdContainerWrappers.hpp b/src/coreComponents/common/StdContainerWrappers.hpp index afb7506daab..51ce9af6025 100644 --- a/src/coreComponents/common/StdContainerWrappers.hpp +++ b/src/coreComponents/common/StdContainerWrappers.hpp @@ -43,17 +43,6 @@ namespace geos namespace internal { - - -/** - * Default allocator type for std::vector. - * This can be specialized if a different allocator is needed. - * Required to avoid recursive evaluation in StdVectorWrapper. - * @tparam T Type of elements in the vector. - */ -template< typename T > -using DefaultAllocator = std::allocator< T >; - /** * Wrapper for std::vector that allows toggling between bounds-checked access * (using at()) and unchecked access (using operator[]). @@ -63,7 +52,7 @@ using DefaultAllocator = std::allocator< T >; * If false, uses operator[] for unchecked access. */ template< typename T, - typename Allocator = DefaultAllocator< T >, + typename Allocator = std::allocator< T >, bool USE_BOUNDS_CHECKING = false > class StdVectorWrapper : public std::vector< T, Allocator > { diff --git a/src/coreComponents/common/format/EnumStrings.cpp b/src/coreComponents/common/format/EnumStrings.cpp new file mode 100644 index 00000000000..9bb7d59dc3d --- /dev/null +++ b/src/coreComponents/common/format/EnumStrings.cpp @@ -0,0 +1,42 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * 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 EnumStrings.cpp + */ + + #include "common/format/EnumStrings.hpp" + #include "common/logger/Logger.hpp" + +namespace geos +{ + +void internal::EnumErrorMessageToString( size_t index, + string const & typeName, + std::size_t size ) +{ + GEOS_THROW( "Invalid value " << index << " of type " << typeName<< ". Valid range is 0.." << size - 1, + InputError ); +} + +void internal::EnumErrorMessageFromString( string const & s, + string const & typeName, + string const & concat ) +{ + GEOS_THROW( "Invalid value '" << s << "' of type " << typeName << ". Valid options are: " << concat, + InputError ); +} + +} diff --git a/src/coreComponents/common/format/EnumStrings.hpp b/src/coreComponents/common/format/EnumStrings.hpp index 0bedb0f0081..21e9812968a 100644 --- a/src/coreComponents/common/format/EnumStrings.hpp +++ b/src/coreComponents/common/format/EnumStrings.hpp @@ -28,7 +28,6 @@ #include "common/format/StringUtilities.hpp" // #include "codingUtilities/RTTypes.hpp" #include "common/DataTypes.hpp" -#include "common/logger/Logger.hpp" #include "common/format/Format.hpp" #include @@ -40,6 +39,25 @@ namespace geos namespace internal { + +/** + * @brief Raise a throw error in case of bad use of enum::toString + * @param index The index of the enum causing the error + * @param typeName The enum name + * @param size The size of the enum + */ +void EnumErrorMessageToString( size_t index, string const & typeName, std::size_t size ); + +/** + * @brief Raise a throw error in case of bad use of enum::FromString + * @param s The string that not belonging to the enum + * @param typeName The enum name + * @param size The string concatenation of the enum + */ +void EnumErrorMessageFromString( string const & s, + string const & typeName, + string const & concat ); + /** * @brief Simple compile-time variadic function that counts its arguments. * @tparam ARGS variadic pack of argument types @@ -152,12 +170,10 @@ struct EnumStrings auto const & strings = get(); std::size_t size = std::distance( std::begin( strings ), std::end( strings ) ); base_type const index = static_cast< base_type >( e ); - GEOS_THROW_IF( index >= LvArray::integerConversion< base_type >( size ), - GEOS_FMT( "Invalid value {} of type {}. Valid range is 0..{}", - index, - getEnumTypeNameString( enum_type{} ), - size - 1 ), - InputError ); + if( index >= LvArray::integerConversion< base_type >( size )) + { + internal::EnumErrorMessageToString( index, getEnumTypeNameString( enum_type{} ), size - 1 ); + } return strings[ index ]; } @@ -170,12 +186,10 @@ struct EnumStrings { auto const & strings = get(); auto const it = std::find( std::begin( strings ), std::end( strings ), s ); - GEOS_THROW_IF( it == std::end( strings ), - GEOS_FMT( "Invalid value '{}' of type {}. Valid options are: {}", - s, - getEnumTypeNameString( enum_type{} ), - concat( ", " ) ), - InputError ); + if( it == std::end( strings )) + { + internal::EnumErrorMessageFromString( s, getEnumTypeNameString( enum_type{} ), EnumStrings::concat( ", " )); + } enum_type const e = static_cast< enum_type >( LvArray::integerConversion< base_type >( std::distance( std::begin( strings ), it ) ) ); return e; } diff --git a/src/coreComponents/common/format/LogPart.cpp b/src/coreComponents/common/format/LogPart.cpp index a9ce3c69da6..807799bedc0 100644 --- a/src/coreComponents/common/format/LogPart.cpp +++ b/src/coreComponents/common/format/LogPart.cpp @@ -18,18 +18,22 @@ #include "LogPart.hpp" #include "common/format/StringUtilities.hpp" +#include "common/logger/ErrorHandling.hpp" #include using namespace geos::stringutilities; namespace geos { -LogPart::LogPart( string_view logPartTitle, bool enableOutput ) +LogPart::LogPart( string const & logpartName, bool enableOutput ) { - m_formattedStartDescription.m_title = logPartTitle; - m_formattedEndDescription.m_title = GEOS_FMT( "{}{}", m_prefixEndTitle, logPartTitle ); + m_formattedStartDescription.m_title = logpartName; + m_formattedEndDescription.m_title = GEOS_FMT( "{}{}", m_prefixEndTitle, logpartName ); m_enableOutput = enableOutput; + + ErrorLogger::global().setCurrentLogPart( logpartName ); + } void LogPart::addDescription( string_view description ) diff --git a/src/coreComponents/common/format/LogPart.hpp b/src/coreComponents/common/format/LogPart.hpp index d4223c008b0..2367cf5edb8 100644 --- a/src/coreComponents/common/format/LogPart.hpp +++ b/src/coreComponents/common/format/LogPart.hpp @@ -19,9 +19,7 @@ #ifndef GEOS_COMMON_FORMAT_LOGPART_HPP #define GEOS_COMMON_FORMAT_LOGPART_HPP -#include "common/DataTypes.hpp" -#include "common/format/Format.hpp" -#include "common/format/StringUtilities.hpp" +#include "common/format/EnumStrings.hpp" namespace geos { @@ -39,7 +37,7 @@ class LogPart * @param logPartTitle The title who will be used for top and bottom LogPart * @param enableOutput Boolean to activate or not csv output */ - LogPart( string_view logPartTitle, bool enableOutput ); + LogPart( string const & logPartTitle, bool enableOutput ); /** * @brief Add a description to the top LogPart diff --git a/src/coreComponents/common/format/table/TableLayout.cpp b/src/coreComponents/common/format/table/TableLayout.cpp index 55446491cd2..659aa84dddf 100644 --- a/src/coreComponents/common/format/table/TableLayout.cpp +++ b/src/coreComponents/common/format/table/TableLayout.cpp @@ -40,15 +40,17 @@ void TableLayout::addColumns( stdVector< TableLayout::Column > const & columns ) } } -void TableLayout::addColumn( string_view columnName ) +TableLayout::Column & TableLayout::addColumn( string_view columnName ) { TableLayout::Column column = TableLayout::Column().setName( columnName ); m_tableColumns.emplace_back( column ); + return m_tableColumns.back(); } -void TableLayout::addColumn( TableLayout::Column const & column ) +TableLayout::Column & TableLayout::addColumn( TableLayout::Column const & column ) { m_tableColumns.emplace_back( column ); + return m_tableColumns.back(); } TableLayout & TableLayout::setTitle( string_view title ) diff --git a/src/coreComponents/common/format/table/TableLayout.hpp b/src/coreComponents/common/format/table/TableLayout.hpp index 4ef156ad760..456f5039d92 100644 --- a/src/coreComponents/common/format/table/TableLayout.hpp +++ b/src/coreComponents/common/format/table/TableLayout.hpp @@ -696,14 +696,16 @@ class TableLayout /** * @brief Create and add a column to the columns vector given a string * @param columnName The column name + * @return The current tableLayout */ - void addColumn( string_view columnName ); + TableLayout::Column & addColumn( string_view columnName ); /** * @brief Create and add a column to the columns vector given a Column * @param column Vector containing addition information on the column + * @return The current tableLayout */ - void addColumn( TableLayout::Column const & column ); + TableLayout::Column & addColumn( TableLayout::Column const & column ); protected: diff --git a/src/coreComponents/common/initializeEnvironment.cpp b/src/coreComponents/common/initializeEnvironment.cpp index f08ad7582c2..51fcdc8acb6 100644 --- a/src/coreComponents/common/initializeEnvironment.cpp +++ b/src/coreComponents/common/initializeEnvironment.cpp @@ -333,6 +333,9 @@ void setupEnvironment( int argc, char * argv[] ) void cleanupEnvironment() { MemoryLogging::getInstance().memoryStatsReport(); + if( ErrorLogger::global().getLoggerReportData().getDiagnosticHistory().size()>0 ) + ErrorLogger::global().getLoggerReportData().diagnosticStatsReport(); + LvArray::system::resetSignalHandling(); finalizeLogger(); finalizeCaliper(); diff --git a/src/coreComponents/common/logger/DiagnosticMessage.hpp b/src/coreComponents/common/logger/DiagnosticMessage.hpp new file mode 100644 index 00000000000..5fa110e2167 --- /dev/null +++ b/src/coreComponents/common/logger/DiagnosticMessage.hpp @@ -0,0 +1,254 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * 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 DiagnosticMessage.hpp + */ + +#include "common/logger/MsgType.hpp" + +namespace geos +{ + +/** + * @struct DiagnosticContext + * Store contextual information about the error that occurred and assign it a priority + * default is 0 + */ +struct DiagnosticContext +{ + + /** + * @enum Attribute + * Enumeration used to secure potential map keys + */ + enum class Attribute + { + InputFile, + InputLine, + DataPath, + DetectionLoc, + Signal, + }; + + /// String containing the target object name followed by the the file and line declaring it. + string m_formattedContext; + + /** + * @brief The map contains contextual information about the error + * It could be something like + * "file" = "/path/to/file.xml" + * "line" = "24" + * or something like + * "dataPath" = "/Functions/co2brine_philipsDensityTable + * The key is a field of the Attribute enumeration and is converted to a string for writing in the YAML + */ + map< Attribute, std::string > m_attributes; + + /** + * @brief Priority level assigned to an error context. + * @details Used to prioritize contexts (higher values = more relevant). Default is 0. + */ + integer m_priority = 0; + + /** + * @brief Construct to initialize DiagnosticContext + * @param formattedContext String containing the target object name followed by the the file and line declaring it. + * @param attributes Map containing contextual information about the error + */ + DiagnosticContext( string formattedContext, map< Attribute, std::string > attributes ): + m_formattedContext( formattedContext ), + m_attributes( attributes ) {}; + + /** + * @brief Construct to initialize DiagnosticContext given a string containing the context and his priority + * @param formattedContext String containing the target object name followed by the the file and line declaring it. + * @param attributes Map containing contextual information about the error + * @param priority Priority level assigned to an error context. + */ + DiagnosticContext( string formattedContext, map< Attribute, std::string > attributes, integer priority ): + m_formattedContext( formattedContext ), + m_attributes( attributes ), + m_priority( priority ) {}; + + /** + * @brief Set the priority value of the current error context information + * @param priority the new value to asign + * @return the reference to the corresponding error + */ + DiagnosticContext & setPriority( integer priority ) + { m_priority = priority; return *this; } + + /** + * @brief Convert a value from the Attribute enumeration to a string + * @param attribute the value of the enumeration to be converted + * @return a string representation of the enumeration value + */ + static std::string attributeToString( Attribute attribute ); +}; + + +/** + * @brief Struct to construct the diagnostic message object + */ +struct DiagnosticMsg +{ + /// Type of diagnostic (Warning, Error or Exception) + MsgType m_type = MsgType::Undefined; + /// the message that can be completed + std::string m_msg; + /// the cause of the error (erroneous condition, failed assertion...) if identified (optional) + std::string m_cause; + /// the rank(s) on which the diagnostic occured + std::set< int > m_ranksInfo; + /// the source location file + std::string m_file; + /// the source location line (default is 0) + integer m_line = 0; + /// Additional information about the diagnostic in the input file + std::vector< DiagnosticContext > m_contextsInfo; + /// the stack trace + std::vector< std::string > m_sourceCallStack; + /// Indicates whether the stored call stack trace is valid and usable. + bool m_isValidStackTrace = false; +}; + +/** + * @brief Builder class for constructing DiagnosticMsg objects + */ +class DiagnosticMsgBuilder +{ +public: + +/** + * @brief Initialize a new DiagnosticMsg + * @param msg The DiagnosticMsg being built + * @param msgType Type of the diagnostic + * @param msgContent The message of the diagnostic. It can be completed afterward + * @param rank The rank on which the diagnostic occured + * @return DiagnosticMsgBuilder + */ + static DiagnosticMsgBuilder init( DiagnosticMsg & msg, + MsgType msgType, + std::string_view msgContent, + integer rank ); + + /** + * @brief Modify an existing DiagnosticMsg + * @param errorMsg The existing DiagnosticMsg + * @return DiagnosticMsgBuilder + */ + static DiagnosticMsgBuilder modify( DiagnosticMsg & errorMsg ); + + /** + * @brief Append exception text to the message + * @param e The exception containing text to add + * @param toEnd If true, append at end; otherwise prepend + * @return Reference to the current instance for method chaining. + */ + DiagnosticMsgBuilder & addToMsg( std::exception const & e, bool toEnd = false ); + + /** + * @brief Append text to the message + * @param msg The text to add + * @param toEnd If true, append at end; otherwise prepend + * @return Reference to the current instance for method chaining. + */ + DiagnosticMsgBuilder & addToMsg( std::string_view msg, bool toEnd = false ); + /** + * @brief Adds one or more context elements to the error + * @tparam Args Variadic pack of compatible types (DiagnosticContext / DataContext) + * @param args List of context data structures. + * @return Reference to the current instance for method chaining. + */ + template< typename ... Args > + DiagnosticMsgBuilder & addContextInfo( Args && ... args ) + { + ( this->addContextInfoImpl( DiagnosticContext( args ) ), ... ); + return *this; + } + + /** + * @brief Add the dectection location the DiagnosticMsg + * @param detectionLocation The context where the diagnostic happoned + * @return The instance, for builder pattern. + */ + DiagnosticMsgBuilder & addDetectionLocation( string_view detectionLocation ); + + /** + * @brief Add the signal to the DiagnosticMsg. + * - the signal can be one of the main error signals. + * - if the signal is SIGFPE, the nature of floating point error will be interpreted. + * @param sig The signal, from ISO C99 or POSIX standard. + * @param toEnd adds the message to the end if true, at the start otherwise. + * @return The instance, for builder pattern. + */ + DiagnosticMsgBuilder & addSignal( integer sig, bool toEnd = false ); + /** + * @brief Set the source code location values (file and line where the error is detected) + * @param msgFile Name of the source file location to add + * @param msgLine Line of the source file location to add + * @return Reference to the current instance for method chaining. + */ + DiagnosticMsgBuilder & setCodeLocation( std::string_view msgFile, integer msgLine ); + /** + * @brief Set the type of the error + * @param msgType The type can be error, warning or exception + * @return Reference to the current instance for method chaining. + */ + DiagnosticMsgBuilder & setType( MsgType msgType ); + /** + * @brief Set the cause of the error + * @param cause See documentation of m_cause. + * @return Reference to the current instance for method chaining. + */ + DiagnosticMsgBuilder & setCause( std::string_view cause ); + /** + * @brief Add a rank on which the error has been raised + * @param rank The value to add + * @return Reference to the current instance for method chaining. + */ + DiagnosticMsgBuilder & addRank( integer rank ); + /** + * @brief Add stack trace information about the error + * @param ossStackTrace stack trace information to add + * @return Reference to the current instance for method chaining. + */ + DiagnosticMsgBuilder & addCallStackInfo( std::string_view ossStackTrace ); + + /** + * @return Get the DiagnosticMsg + */ + DiagnosticMsg & getDiagnosticMsg(); + +private: + + /** + * @brief Private constructor - use init() or modify() instead + * @param msg Reference to the DiagnosticMsg to build/modify + */ + DiagnosticMsgBuilder( DiagnosticMsg & msg ): + m_errorMsg( msg ){} + + /** + * @brief Add contextual information about the error/warning + * @param ctxInfo rvalue of the DiagnosticContext class + */ + DiagnosticMsgBuilder & addContextInfoImpl( DiagnosticContext && ctxInfo ); + + /// The diagnosticMsg being constructed + DiagnosticMsg & m_errorMsg; +}; +} diff --git a/src/coreComponents/common/logger/ErrorHandling.cpp b/src/coreComponents/common/logger/ErrorHandling.cpp index 6881e11259a..4dcc53081c4 100644 --- a/src/coreComponents/common/logger/ErrorHandling.cpp +++ b/src/coreComponents/common/logger/ErrorHandling.cpp @@ -20,11 +20,6 @@ #include "ErrorHandling.hpp" #include "common/DataTypes.hpp" #include "common/logger/Logger.hpp" -#include "common/format/StringUtilities.hpp" - -#include -#include -#include // signal management #include @@ -45,15 +40,15 @@ ErrorLogger g_errorLogger{}; ErrorLogger & ErrorLogger::global() { return g_errorLogger; } -std::string ErrorContext::attributeToString( ErrorContext::Attribute attribute ) +std::string DiagnosticContext::attributeToString( DiagnosticContext::Attribute attribute ) { switch( attribute ) { - case ErrorContext::Attribute::InputFile: return "inputFile"; - case ErrorContext::Attribute::InputLine: return "inputLine"; - case ErrorContext::Attribute::DataPath: return "dataPath"; - case ErrorContext::Attribute::DetectionLoc: return "detectionLocation"; - case ErrorContext::Attribute::Signal: return "signal"; + case DiagnosticContext::Attribute::InputFile: return "inputFile"; + case DiagnosticContext::Attribute::InputLine: return "inputLine"; + case DiagnosticContext::Attribute::DataPath: return "dataPath"; + case DiagnosticContext::Attribute::DetectionLoc: return "detectionLocation"; + case DiagnosticContext::Attribute::Signal: return "signal"; default: return "unknown"; } } @@ -87,11 +82,11 @@ DiagnosticMsgBuilder DiagnosticMsgBuilder::modify( DiagnosticMsg & errorMsg ) return DiagnosticMsgBuilder( errorMsg ); } -DiagnosticMsgBuilder & DiagnosticMsgBuilder::addContextInfoImpl( ErrorContext && ctxInfo ) +DiagnosticMsgBuilder & DiagnosticMsgBuilder::addContextInfoImpl( DiagnosticContext && ctxInfo ) { auto lowerBoundPos = std::lower_bound( m_errorMsg.m_contextsInfo.begin(), m_errorMsg.m_contextsInfo.end(), ctxInfo.m_priority, - []( ErrorContext const & ctx, integer priority ) + []( DiagnosticContext const & ctx, integer priority ) { return ctx.m_priority >= priority; } ); m_errorMsg.m_contextsInfo.insert( lowerBoundPos, std::move( ctxInfo ) ); return *this; @@ -99,9 +94,9 @@ DiagnosticMsgBuilder & DiagnosticMsgBuilder::addContextInfoImpl( ErrorContext && DiagnosticMsgBuilder & DiagnosticMsgBuilder::addDetectionLocation( string_view detectionLocation ) { - addContextInfo( ErrorContext{ string( detectionLocation ), - { { ErrorContext::Attribute::DetectionLoc, - string( detectionLocation ) } } } ); + addContextInfo( DiagnosticContext{ string( detectionLocation ), + { { DiagnosticContext::Attribute::DetectionLoc, + string( detectionLocation ) } } } ); return *this; } @@ -166,12 +161,12 @@ DiagnosticMsgBuilder & DiagnosticMsgBuilder::addSignal( integer const sig, bool // standard messages addToMsg( errorMsg, toEnd ); - this->addContextInfo( ErrorContext{ "Signal (detected from Signal Handler)", - { { ErrorContext::Attribute::Signal, - std::to_string( sig ) }, - { ErrorContext::Attribute::DetectionLoc, - string( "Signal handler" ) } - } } ); + this->addContextInfo( DiagnosticContext{ "Signal (detected from Signal Handler)", + { { DiagnosticContext::Attribute::Signal, + std::to_string( sig ) }, + { DiagnosticContext::Attribute::DetectionLoc, + string( "Signal handler" ) } + } } ); return *this; } @@ -309,7 +304,7 @@ void ErrorLogger::formatMsgForLog( DiagnosticMsg const & errMsg, std::ostream & } os << PREFIX << "Rank " << stringutilities::join( errMsg.m_ranksInfo, ", " ) << "\n"; // --- ERROR CONTEXT & MESSAGE --- - std::vector< ErrorContext > const & contexts = errMsg.m_contextsInfo; + std::vector< DiagnosticContext > const & contexts = errMsg.m_contextsInfo; if( contexts.empty() || contexts.front().m_formattedContext.empty()) { os << PREFIX << "Message :\n"; @@ -374,15 +369,15 @@ void ErrorLogger::writeToYamlStream( DiagnosticMsg & errMsg ) // context information if( !errMsg.m_contextsInfo.empty() ) { - std::vector< ErrorContext > contextInfo = errMsg.m_contextsInfo; + std::vector< DiagnosticContext > contextInfo = errMsg.m_contextsInfo; // Sort contextual information by decreasing priority std::sort( contextInfo.begin(), contextInfo.end(), - []( const ErrorContext & a, const ErrorContext & b ) { + []( const DiagnosticContext & a, const DiagnosticContext & 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 : contextInfo ) + for( DiagnosticContext const & ctxInfo : contextInfo ) { yamlFile << g_level3Start << "priority: " << ctxInfo.m_priority << "\n"; if( !ctxInfo.m_formattedContext.empty()) @@ -391,7 +386,7 @@ void ErrorLogger::writeToYamlStream( DiagnosticMsg & errMsg ) } for( auto const & [key, value] : ctxInfo.m_attributes ) { - yamlFile << g_level3Next << ErrorContext::attributeToString( key ) << ": " << value << "\n"; + yamlFile << g_level3Next << DiagnosticContext::attributeToString( key ) << ": " << value << "\n"; } } } @@ -435,8 +430,12 @@ void ErrorLogger::writeToYamlStream( DiagnosticMsg & errMsg ) } } + + void ErrorLogger::flushErrorMsg( DiagnosticMsg & errMsg ) { + loggerMsgReportData.notifyMsg( getCurrentLogPart(), + errMsg ); writeToLogStream( errMsg ); if( isOutputFileEnabled() ) { @@ -446,6 +445,9 @@ void ErrorLogger::flushErrorMsg( DiagnosticMsg & errMsg ) void ErrorLogger::flushCurrentExceptionMessage() { + loggerMsgReportData.notifyMsg( getCurrentLogPart(), + m_getCurrentExceptionMsg ); + writeToLogStream( m_getCurrentExceptionMsg ); if( isOutputFileEnabled() ) { diff --git a/src/coreComponents/common/logger/ErrorHandling.hpp b/src/coreComponents/common/logger/ErrorHandling.hpp index 38df2a2566c..9c38d0bb08a 100644 --- a/src/coreComponents/common/logger/ErrorHandling.hpp +++ b/src/coreComponents/common/logger/ErrorHandling.hpp @@ -21,263 +21,13 @@ #define INITIALIZATION_ERROR_LOGGER_HPP #include "common/DataTypes.hpp" -#include "common/format/Format.hpp" -#include "common/format/StringUtilities.hpp" +#include "common/format/LogPart.hpp" +#include "common/logger/LogHistory.hpp" #include namespace geos { -/** - * @struct ErrorContext - * Store contextual information about the error that occurred and assign it a priority - * default is 0 - */ -struct ErrorContext -{ - - /** - * @enum Attribute - * Enumeration used to secure potential map keys - */ - enum class Attribute - { - InputFile, - InputLine, - DataPath, - DetectionLoc, - Signal, - }; - - /// String containing the target object name followed by the the file and line declaring it. - string m_formattedContext; - - /** - * @brief The map contains contextual information about the error - * It could be something like - * "file" = "/path/to/file.xml" - * "line" = "24" - * or something like - * "dataPath" = "/Functions/co2brine_philipsDensityTable - * The key is a field of the Attribute enumeration and is converted to a string for writing in the YAML - */ - map< Attribute, std::string > m_attributes; - - /** - * @brief Priority level assigned to an error context. - * @details Used to prioritize contexts (higher values = more relevant). Default is 0. - */ - integer m_priority = 0; - - /** - * @brief Construct to initialize ErrorContext - * @param formattedContext String containing the target object name followed by the the file and line declaring it. - * @param attributes Map containing contextual information about the error - */ - ErrorContext( string formattedContext, map< Attribute, std::string > attributes ): - m_formattedContext( formattedContext ), - m_attributes( attributes ) {}; - - /** - * @brief Construct to initialize ErrorContext given a string containing the context and his priority - * @param formattedContext String containing the target object name followed by the the file and line declaring it. - * @param attributes Map containing contextual information about the error - * @param priority Priority level assigned to an error context. - */ - ErrorContext( string formattedContext, map< Attribute, std::string > attributes, integer priority ): - m_formattedContext( formattedContext ), - m_attributes( attributes ), - m_priority( priority ) {}; - - /** - * @brief Set the priority value of the current error context information. - * This way the different context information will appear in descending order during the error log output. - * @param priority the new value to asign - * @return the reference to the corresponding error - */ - ErrorContext & setPriority( integer priority ) - { m_priority = priority; return *this; } - - /** - * @brief Convert a value from the Attribute enumeration to a string - * @param attribute the value of the enumeration to be converted - * @return a string representation of the enumeration value - */ - static std::string attributeToString( Attribute attribute ); - -}; - -/** - * @enum MsgType - * Enum listing the different types of possible diagnostics - */ -enum class MsgType -{ - Error, - ExternalError, - Warning, - Exception, - Undefined -}; - -/** - * @brief Struct to construct the diagnostic message object - */ -struct DiagnosticMsg -{ - /// Type of diagnostic (Warning, Error or Exception) - MsgType m_type = MsgType::Undefined; - /// the message that can be completed - std::string m_msg; - /// the cause of the error (erroneous condition, failed assertion...) if identified (optional) - std::string m_cause; - /// the rank(s) on which the diagnostic occured - std::set< int > m_ranksInfo; - /// the source location file - std::string m_file; - /// the source location line (default is 0) - integer m_line = 0; - /// Additional information about the diagnostic in the input file - std::vector< ErrorContext > m_contextsInfo; - /// the stack trace - std::vector< std::string > m_sourceCallStack; - /// Indicates whether the stored call stack trace is valid and usable. - bool m_isValidStackTrace = false; -}; - -/** - * @brief Builder class for constructing DiagnosticMsg objects - */ -class DiagnosticMsgBuilder -{ -public: - -/** - * @brief Initialize a new DiagnosticMsg - * @param msg The DiagnosticMsg being built - * @param msgType Type of the diagnostic - * @param msgContent The message of the diagnostic. It can be completed afterward - * @param rank The rank on which the diagnostic occured - * @return DiagnosticMsgBuilder - */ - static DiagnosticMsgBuilder init( DiagnosticMsg & msg, - MsgType msgType, - std::string_view msgContent, - integer rank ); - - /** - * @brief Modify an existing DiagnosticMsg - * @param errorMsg The existing DiagnosticMsg - * @return DiagnosticMsgBuilder - */ - static DiagnosticMsgBuilder modify( DiagnosticMsg & errorMsg ); - - /** - * @brief Append exception text to the message - * @param e The exception containing text to add - * @param toEnd If true, append at end; otherwise prepend - * @return Reference to the current instance for method chaining. - */ - DiagnosticMsgBuilder & addToMsg( std::exception const & e, bool toEnd = false ); - - /** - * @brief Append text to the message - * @param msg The text to add - * @param toEnd If true, append at end; otherwise prepend - * @return Reference to the current instance for method chaining. - */ - DiagnosticMsgBuilder & addToMsg( std::string_view msg, bool toEnd = false ); - - /** - * @brief Adds one or more context elements to the error - * @tparam Args Variadic pack of compatible types (ErrorContext / DataContext) - * @param args List of context data structures. - * @return Reference to the current instance for method chaining. - */ - template< typename ... Args > - DiagnosticMsgBuilder & addContextInfo( Args && ... args ) - { - ( this->addContextInfoImpl( ErrorContext( args ) ), ... ); - return *this; - } - - /** - * @brief Add where the detection occured - * @param detectionLocation The context where the diagnostic happoned - * @return The instance, for builder pattern. - */ - DiagnosticMsgBuilder & addDetectionLocation( string_view detectionLocation ); - - /** - * @brief Add the signal to the DiagnosticMsg. - * - the signal can be one of the main error signals. - * - if the signal is SIGFPE, the nature of floating point error will be interpreted. - * @param sig The signal, from ISO C99 or POSIX standard. - * @param toEnd adds the message to the end if true, at the start otherwise. - * @return The instance, for builder pattern. - */ - DiagnosticMsgBuilder & addSignal( integer sig, bool toEnd = false ); - - /** - * @brief Set the source code location values (file and line where the error is detected) - * @param msgFile Name of the source file location to add - * @param msgLine Line of the source file location to add - * @return Reference to the current instance for method chaining. - */ - DiagnosticMsgBuilder & setCodeLocation( std::string_view msgFile, integer msgLine ); - - /** - * @brief Set the type of the error, (amoung one of the MsgType) - * @param msgType The type can be error, warning or exception - * @return Reference to the current instance for method chaining. - */ - DiagnosticMsgBuilder & setType( MsgType msgType ); - - /** - * @brief Set the cause of the error - * @param cause See documentation of m_cause. - * @return Reference to the current instance for method chaining. - */ - DiagnosticMsgBuilder & setCause( std::string_view cause ); - - /** - * @brief Add a rank on which the error has been raised - * @param rank The rank value - * @return Reference to the current instance for method chaining. - */ - DiagnosticMsgBuilder & addRank( integer rank ); - - /** - * @brief Add the stack trace information about the error - * @param stacktrace stack trace information to add - * @return Reference to the current instance for method chaining. - */ - DiagnosticMsgBuilder & addCallStackInfo( std::string_view stacktrace ); - - /** - * @return Get the DiagnosticMsg - */ - DiagnosticMsg & getDiagnosticMsg(); - -private: - - /** - * @brief Private constructor - use init() or modify() instead - * @param msg Reference to the DiagnosticMsg to build/modify - */ - DiagnosticMsgBuilder( DiagnosticMsg & msg ): - m_errorMsg( msg ){} - - /** - * @brief Add contextual information about the error/warning - * @param ctxInfo rvalue of the ErrorContext class - */ - DiagnosticMsgBuilder & addContextInfoImpl( ErrorContext && ctxInfo ); - - /// The diagnosticMsg being constructed - DiagnosticMsg & m_errorMsg; -}; - /** * @brief Logger for formatting and outputting diagnostics */ @@ -374,7 +124,7 @@ class ErrorLogger /** * @brief Write all the information retrieved about the diagnostic message into the instance - * outputs (stream specified, std::cout by default + optional yaml file) + * outputs (stream specified + optional yaml file) * @param errMsg a reference to the ErrorMsg to output, and will be re-initialized * @note Used for warnings and non-exception errors */ @@ -393,16 +143,49 @@ class ErrorLogger */ void writeToLogStream( DiagnosticMsg & errMsg ); + /** + * @brief Gets the current logger report data. + * @return The current log part as a string. + */ + LogHistory const & getLoggerReportData() const + {return loggerMsgReportData;} + + /** + * @brief Gets the current logger report data. + * @return The current log part as a string. + */ + LogHistory & getLoggerReportData() + {return loggerMsgReportData;} + + /** + * @brief Gets the current log part. + * @return The current log part as a string. + */ + string_view getCurrentLogPart() const + {return m_currentLogPart;} + +/** + * @brief Sets the current log part. + * @param currentLogPart The new log part to set. + */ + void setCurrentLogPart( string const & currentLogPart ) + { m_currentLogPart = currentLogPart; } + private: /// The error constructed via exceptions DiagnosticMsg m_getCurrentExceptionMsg; + /// The log history associated + LogHistory loggerMsgReportData = {}; + /// Indicate whether the write to YAML command line option is enabled bool m_writeYaml = false; /// YAML file name std::string_view m_filename = "errors.yaml"; /// The stream used for the log output. By default used std::cout std::ostream & m_stream = std::cout; + /// The current log part being executed + string m_currentLogPart; /// Avoid concurrent access between threads for log outputs std::mutex m_errorHandlerAsciiMutex; /// Avoid concurrent access between threads for yaml outputs diff --git a/src/coreComponents/common/logger/GeosExceptions.hpp b/src/coreComponents/common/logger/GeosExceptions.hpp index f3934bebbc3..95a9d4c65f1 100644 --- a/src/coreComponents/common/logger/GeosExceptions.hpp +++ b/src/coreComponents/common/logger/GeosExceptions.hpp @@ -96,8 +96,7 @@ struct LogicError : public geos::Exception }; /** - * @brief Exception class used to report domain errors. - * Generally, the domain of a mathematical function is the subset of values that it is defined for + * @brief Exception class used to report errors in user input. */ struct DomainError : public geos::Exception { @@ -149,7 +148,7 @@ struct InputError : public geos::Exception }; /** - * @brief Exception class used to report errors related to the simulation + * @brief Exception class used to report errors in user input. */ struct SimulationError : public geos::Exception { diff --git a/src/coreComponents/common/logger/LogHistory.cpp b/src/coreComponents/common/logger/LogHistory.cpp new file mode 100644 index 00000000000..3c5d2596de9 --- /dev/null +++ b/src/coreComponents/common/logger/LogHistory.cpp @@ -0,0 +1,224 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * 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 LogHistory.cpp + */ + +#include "LogHistory.hpp" +#include "common/DataTypes.hpp" +#include "common/StdContainerWrappers.hpp" +#include "common/format/EnumStrings.hpp" +#include "common/format/LogPart.hpp" +#include "common/format/table/TableData.hpp" +#include "common/format/table/TableLayout.hpp" +#include "common/format/table/TableTypes.hpp" +#include "common/logger/MsgType.hpp" +#include "common/MpiWrapper.hpp" +#include "dataRepository/BufferOps.hpp" +#include "dataRepository/BufferOps_inline.hpp" +#include +#include +#include +#include + +namespace geos +{ + +string_view extractAfterLastOccurrence( string_view str, char delimiter ) +{ + size_t pos = str.find_last_of( delimiter ); + + if( pos == std::string::npos ) + { + return ""; + } + + return str.substr( pos + 1 ); +} + +void LogHistory::notifyMsg( string_view logPartName, DiagnosticMsg const & msgType ) +{ + string_view fileName = extractAfterLastOccurrence( msgType.m_file, '/' ); + integer lineCount = msgType.m_line; + + auto & stats = m_diagnosticHistory.get_inserted( std::make_tuple( string( logPartName ), msgType.m_type, + string( fileName ), lineCount )); + stats.count++; +} + +std::pair< stdVector< buffer_unit_type >, stdVector< integer > > +gatherTuplesRank0( buffer_unit_type * bufferToSend, localIndex packedSize ) +{ + integer const numRanks = MpiWrapper::commSize(); + integer const numValues = packedSize; + + // Allows to know how much data each rank will send + stdVector< integer > recvCounts; + // Displacments vector for global alloc + stdVector< integer > displs; + stdVector< buffer_unit_type > globalAllocations; + + if( MpiWrapper::commRank() == 0 ) + { + recvCounts.resize( numRanks ); + displs.resize( numRanks ); + } + + + MpiWrapper::gather( &numValues, 1, recvCounts.data(), 1, 0 ); + + if( MpiWrapper::commRank() == 0 ) + { + integer totalSize = 0; + for( integer i = 0; i < numRanks; ++i ) + { + displs[i] = totalSize; + totalSize += recvCounts[i]; + } + globalAllocations.resize( totalSize ); + } + + MpiWrapper::gatherv( bufferToSend, + numValues, + globalAllocations.data(), + recvCounts.data(), + displs.data(), + 0 ); + + return {globalAllocations, recvCounts}; +} + +void LogHistory::diagnosticStatsReport() +{ + LogHistory & history = ErrorLogger::global().getLoggerReportData(); + stdVector< buffer_unit_type > gTuple( 0 ); + integer totalSize = 0; + //1 - dry run for vector size + for( auto const & [key, value] : getDiagnosticHistory() ) + { + auto const & [logPartType, msgType, filename, lineCount] = key; + + buffer_unit_type * dummy = nullptr; + localIndex entrySize = bufferOps::Pack< false >( dummy, logPartType ) + + bufferOps::Pack< false >( dummy, msgType ) + + bufferOps::Pack< false >( dummy, filename ) + + bufferOps::Pack< false >( dummy, lineCount ); + + totalSize += entrySize; + } + gTuple.resize( totalSize ); + + //2 - Packing + buffer_unit_type * tupleBuffer = gTuple.data(); + for( auto const & [key, value] : getDiagnosticHistory() ) + { + auto const & [logPartType, msgType, filename, lineCount] = key; + + bufferOps::Pack< true >( tupleBuffer, logPartType ); + bufferOps::Pack< true >( tupleBuffer, msgType ); + bufferOps::Pack< true >( tupleBuffer, filename ); + bufferOps::Pack< true >( tupleBuffer, lineCount ); + } + + auto [tuplesPerIt, recvCounts] = gatherTuplesRank0( gTuple.data(), gTuple.size() ); + + //3 - Unpacking + if( MpiWrapper::commRank() == 0 ) + { + buffer_unit_type const * rankStart = tuplesPerIt.data(); + for( size_t idxRank = 0; idxRank < (size_t)MpiWrapper::commSize(); ++idxRank ) + { + integer byteFromThisRank = recvCounts[idxRank]; + if( byteFromThisRank != 0 ) + { + buffer_unit_type const * rankEnd= rankStart + byteFromThisRank; + while( rankStart < rankEnd ) + { + string logPartUnpacked; + MsgType MsgTypeUnpacked; + string fileNameUnpacked; + integer lineCountUnpacked; + bufferOps::Unpack( rankStart, logPartUnpacked ); + bufferOps::Unpack( rankStart, MsgTypeUnpacked ); + bufferOps::Unpack( rankStart, fileNameUnpacked ); + bufferOps::Unpack( rankStart, lineCountUnpacked ); + history.insertDiagnosticReport( logPartUnpacked, MsgTypeUnpacked, fileNameUnpacked, lineCountUnpacked ); + } + } + } + } + + //4 - Display + if( MpiWrapper::commRank() == 0 ) + { + TableTextFormatter tableReportFormatter; + GEOS_LOG( tableReportFormatter.toString< LogHistory >( GEOS_GLOBAL_LOGGER.getLoggerReportData())); + } +} + +template<> +string TableTextFormatter::toString< LogHistory >( LogHistory const & messageCounts ) const +{ + TableLayout tableLayout; + tableLayout.addColumn( "Types" ); + + for( size_t msgTypeIdx = (size_t) MsgType::Error; msgTypeIdx != (size_t)MsgType::Undefined; msgTypeIdx++ ) + { + tableLayout.addColumn( EnumStrings< MsgType >::toString( (MsgType) msgTypeIdx ) ); + } + + stdMap< std::pair< string, MsgType >, integer > countPerPartAndType; + using CellRow = stdArray< TableData::CellData, (size_t) MsgType::Undefined >; + CellRow emptyCellRow; + emptyCellRow.fill( TableData::CellData{CellType::Value, "0"} ); + stdMap< string, CellRow > rowByPart; + + + for( const auto & [tupleKey, msgTypes] : messageCounts.getDiagnosticHistory()) + { + auto logPart = std::get< 0 >( tupleKey ); + auto msgType = std::get< 1 >( tupleKey ); + + countPerPartAndType.get_inserted( std::make_pair( logPart, msgType ))++; + + if( rowByPart.find( logPart ) == rowByPart.end()) + rowByPart.get_inserted( logPart ) = emptyCellRow; + } + + for( auto & [keyPair, count] : countPerPartAndType ) + { + auto logPart = std::get< 0 >( keyPair ); + auto msgType = std::get< 1 >( keyPair ); + rowByPart.get_inserted( logPart ).at((size_t)msgType ).value = std::to_string( count ); + } + + TableData data; + for( auto const & [logPart, cells] : rowByPart ) + { + stdVector< TableData::CellData >row ( { + TableData::CellData{ CellType::Value, logPart } + } ); + + row.insert( row.end(), cells.begin(), cells.end()); + data.addRow( row ); + } + + TableTextFormatter textFormatter( tableLayout ); + return textFormatter.toString( data ) + "\n"; +} + + +} diff --git a/src/coreComponents/common/logger/LogHistory.hpp b/src/coreComponents/common/logger/LogHistory.hpp new file mode 100644 index 00000000000..ea350ef5801 --- /dev/null +++ b/src/coreComponents/common/logger/LogHistory.hpp @@ -0,0 +1,139 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * 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 LogHistory.hpp + */ + +#ifndef GEOS_COMMON_LOGGER_MSG_REPORT_DATA_HPP +#define GEOS_COMMON_LOGGER_MSG_REPORT_DATA_HPP + +#include "common/StdContainerWrappers.hpp" +#include "common/format/LogPart.hpp" +#include "common/format/table/TableFormatter.hpp" +#include "DiagnosticMessage.hpp" +#include "common/logger/MsgType.hpp" +#include + + +namespace geos +{ + +/** + * @brief Statistics for a diagnostic message at a specific location + */ +struct MsgStatistics +{ + /// Number of times the same message occured during the simulation + integer count; +}; + + +/** + * @brief Keep track of all diagnostic message occured during the simulation + */ +class LogHistory +{ +public: + + /// Alias for the historical diagnostic unordered_map key + using DiagnosticKey = std::tuple< string, MsgType, string, integer >; + + /** + * @brief Report a diagnostic message + * @param logPartName The logPart where the message occured + * @param diagMsg The DiagnosticMsg to record + */ + void notifyMsg( string_view logPartName, DiagnosticMsg const & diagMsg ); + + /** + * @brief Display the diagnostic statistics to the log + */ + void diagnosticStatsReport(); + + /** + * @return The const historical diagnostic + */ + auto const & getDiagnosticHistory() const + { return m_diagnosticHistory; } + + /** + * @brief Insert an element to the diagnostic history container if an equivalent key doesn't exist. + * @param logPartName The logPart where the diagnostic occured + * @param msgType The diagnostic message type + * @param fileName The filement where the diagnostic occured + * @param lineCount The line where the diagnostic occured + */ + void insertDiagnosticReport( string_view logPartName, MsgType msgType, + string const & fileName, integer lineCount ) + { + m_diagnosticHistory.get_inserted( std::make_tuple( string( logPartName ), msgType, fileName, lineCount )); + } + +private: + + /// @cond DO_NOT_DOCUMENT + struct LocationKeyHash + { + + std::size_t operator()( DiagnosticKey const & key ) const noexcept + { + auto const & [logPartType, msgType, filename, lineCount] = key; + + std::size_t h1 = std::hash< std::string >{} (logPartType); + std::size_t h2 = std::hash< MsgType >{} (msgType); + std::size_t h3 = std::hash< std::string >{} (filename); + std::size_t h4 = std::hash< int >{} (lineCount); + + return h1 ^ (h2 << 1) ^ (h3 << 2) ^ (h4 << 3); + } + + }; + /// @endcond + + /// @cond DO_NOT_DOCUMENT + struct LocationKeyEqual + { + + bool operator()( DiagnosticKey const & lhs, + DiagnosticKey const & rhs ) const + { + return std::get< 0 >( lhs ) == std::get< 0 >( rhs ) && + std::get< 1 >( lhs ) == std::get< 1 >( rhs ) && + std::get< 2 >( lhs ) == std::get< 2 >( rhs ) && + std::get< 3 >( lhs ) == std::get< 3 >( rhs ); + } + }; + /// @endcond + + /** + * @brief Diagnostic history happened during the simulation + */ + stdUnorderedMap< DiagnosticKey, + MsgStatistics, + LocationKeyHash, LocationKeyEqual > m_diagnosticHistory; +}; + +/** + * @brief Template specialisation to convert a LogHistory to a table string. + * @param logHistory The LogHistory object to convert. + * @return The CSV string representation of the logHistory. + */ +template<> +string TableTextFormatter::toString< LogHistory >( LogHistory const & logHistory ) const; + +} + +#endif diff --git a/src/coreComponents/common/logger/MsgType.hpp b/src/coreComponents/common/logger/MsgType.hpp new file mode 100644 index 00000000000..9893da7a6d5 --- /dev/null +++ b/src/coreComponents/common/logger/MsgType.hpp @@ -0,0 +1,51 @@ +/* + * ------------------------------------------------------------------------------------------------------------ + * 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 MsgType.hpp + */ + +#ifndef INITIALIZATION_MSG_TYPE_HPP +#define INITIALIZATION_MSG_TYPE_HPP + +#include "common/format/EnumStrings.hpp" + +namespace geos +{ + +/** + * @enum MsgType + * Enum listing the different types of possible errors + */ +enum class MsgType +{ + Error, + ExternalError, + Warning, + Exception, + Undefined +}; + +/// Declare strings associated with output MsgType values. +ENUM_STRINGS( MsgType, + "Error", + "ExternalError", + "Warning", + "Exception", + "Undefined" ); + +} + +#endif diff --git a/src/coreComponents/common/unitTests/CMakeLists.txt b/src/coreComponents/common/unitTests/CMakeLists.txt index 2f6966bf487..8ef1ba9beaf 100644 --- a/src/coreComponents/common/unitTests/CMakeLists.txt +++ b/src/coreComponents/common/unitTests/CMakeLists.txt @@ -1,7 +1,7 @@ # Specify list of tests set( gtest_geosx_tests - testDataTypes.cpp testFixedSizeDeque.cpp + testDataTypes.cpp testMacros.cpp testMpiWrapper.cpp testTypeDispatch.cpp diff --git a/src/coreComponents/common/unitTests/testDataTypes.cpp b/src/coreComponents/common/unitTests/testDataTypes.cpp index 58ebc681cae..5a47d4f7b63 100644 --- a/src/coreComponents/common/unitTests/testDataTypes.cpp +++ b/src/coreComponents/common/unitTests/testDataTypes.cpp @@ -16,16 +16,19 @@ // Source includes #include "common/DataTypes.hpp" -// TPL includes +#include "common/StdContainerWrappers.hpp" + + +// // TPL includes #include #include +#include using namespace geos; TEST( testDataTypes, testBoundChecking ) { - internal::StdVectorWrapper< std::string, - std::allocator< std::string >, + internal::StdVectorWrapper< std::string, std::allocator< std::string >, true > vectorBoundsChecking = {"test"}; EXPECT_THROW( { try diff --git a/src/coreComponents/constitutive/fluid/multifluid/compositional/parameters/PhaseType.cpp b/src/coreComponents/constitutive/fluid/multifluid/compositional/parameters/PhaseType.cpp index a86de714834..f9dcb183408 100644 --- a/src/coreComponents/constitutive/fluid/multifluid/compositional/parameters/PhaseType.cpp +++ b/src/coreComponents/constitutive/fluid/multifluid/compositional/parameters/PhaseType.cpp @@ -19,6 +19,7 @@ #include "PhaseType.hpp" #include "common/format/StringUtilities.hpp" +#include "common/logger/Logger.hpp" namespace geos { diff --git a/src/coreComponents/dataRepository/DataContext.cpp b/src/coreComponents/dataRepository/DataContext.cpp index 8ce7f1c7b55..c7d1e1bd77b 100644 --- a/src/coreComponents/dataRepository/DataContext.cpp +++ b/src/coreComponents/dataRepository/DataContext.cpp @@ -108,12 +108,12 @@ string DataFileContext::toString() const } } -ErrorContext DataFileContext::getContextInfo() const +DiagnosticContext DataFileContext::getContextInfo() const { - ErrorContext ctxInfo{ + DiagnosticContext ctxInfo{ toString(), - { { ErrorContext::Attribute::InputFile, m_filePath }, - { ErrorContext::Attribute::InputLine, std::to_string( m_line )} } + { { DiagnosticContext::Attribute::InputFile, m_filePath }, + { DiagnosticContext::Attribute::InputLine, std::to_string( m_line )} } }; return ctxInfo; } diff --git a/src/coreComponents/dataRepository/DataContext.hpp b/src/coreComponents/dataRepository/DataContext.hpp index 8a43381b438..7ab4685ed95 100644 --- a/src/coreComponents/dataRepository/DataContext.hpp +++ b/src/coreComponents/dataRepository/DataContext.hpp @@ -63,15 +63,15 @@ class DataContext /** * @brief Returns contextual information, including the file name and the line number - * @return ErrorContext + * @return DiagnosticContext */ - virtual ErrorContext getContextInfo() const = 0; + virtual DiagnosticContext getContextInfo() const = 0; /** - * @brief Conversion operator to ErrorContext - * @return ErrorContext + * @brief Conversion operator to DiagnosticContext + * @return DiagnosticContext */ - explicit operator ErrorContext() const { + explicit operator DiagnosticContext() const { return getContextInfo(); } @@ -172,9 +172,9 @@ class DataFileContext final : public DataContext /** * @brief Return contextual information (file and line of the input file where the error occured) - * @return ErrorContext ErrorLogger instance updated with context information + * @return DiagnosticContext ErrorLogger instance updated with context information */ - ErrorContext getContextInfo() const override; + DiagnosticContext getContextInfo() const override; /** * @return the type name in the source file (XML node tag name / attribute name). diff --git a/src/coreComponents/dataRepository/GroupContext.cpp b/src/coreComponents/dataRepository/GroupContext.cpp index 04e1fa1f2a3..9c3e3dbb6fb 100644 --- a/src/coreComponents/dataRepository/GroupContext.cpp +++ b/src/coreComponents/dataRepository/GroupContext.cpp @@ -54,11 +54,11 @@ string GroupContext::toString() const return path.str(); } -ErrorContext GroupContext::getContextInfo() const +DiagnosticContext GroupContext::getContextInfo() const { - ErrorContext ctxInfo{ + DiagnosticContext ctxInfo{ toString(), - { { ErrorContext::Attribute::DataPath, GEOS_FMT( "{}/{}", m_group.getPath(), m_targetName )} } + { { DiagnosticContext::Attribute::DataPath, GEOS_FMT( "{}/{}", m_group.getPath(), m_targetName )} } }; return ctxInfo; } diff --git a/src/coreComponents/dataRepository/GroupContext.hpp b/src/coreComponents/dataRepository/GroupContext.hpp index abdc1199e7d..698fa02a301 100644 --- a/src/coreComponents/dataRepository/GroupContext.hpp +++ b/src/coreComponents/dataRepository/GroupContext.hpp @@ -71,9 +71,9 @@ class GroupContext : public DataContext /** * @brief Return contextual information here it is a data path - * @return ErrorContext ErrorLogger instance updated with context information + * @return DiagnosticContext ErrorLogger instance updated with context information */ - ErrorContext getContextInfo() const override; + DiagnosticContext getContextInfo() const override; /** * @copydoc DataContext::getToStringInfo() diff --git a/src/coreComponents/dataRepository/WrapperContext.cpp b/src/coreComponents/dataRepository/WrapperContext.cpp index 3d689ade254..323acdc3e83 100644 --- a/src/coreComponents/dataRepository/WrapperContext.cpp +++ b/src/coreComponents/dataRepository/WrapperContext.cpp @@ -38,11 +38,11 @@ string WrapperContext::toString() const GEOS_FMT( "{}/{}", m_group.getDataContext().toString(), m_typeName ); } -ErrorContext WrapperContext::getContextInfo() const +DiagnosticContext WrapperContext::getContextInfo() const { - ErrorContext ctxInfo{ + DiagnosticContext ctxInfo{ toString(), - {{ ErrorContext::Attribute::DataPath, GEOS_FMT( "{}/{}", m_group.getPath(), m_typeName ) } }, + {{ DiagnosticContext::Attribute::DataPath, GEOS_FMT( "{}/{}", m_group.getPath(), m_typeName ) } }, }; return ctxInfo; } diff --git a/src/coreComponents/dataRepository/WrapperContext.hpp b/src/coreComponents/dataRepository/WrapperContext.hpp index b136a66862c..1cab552e581 100644 --- a/src/coreComponents/dataRepository/WrapperContext.hpp +++ b/src/coreComponents/dataRepository/WrapperContext.hpp @@ -56,9 +56,9 @@ class WrapperContext final : public GroupContext /** * @brief Return contextual information here it is a data path - * @return ErrorContext ErrorLogger instance updated with context information + * @return DiagnosticContext ErrorLogger instance updated with context information */ - ErrorContext getContextInfo() const override; + DiagnosticContext getContextInfo() const override; }; diff --git a/src/coreComponents/events/EventManager.cpp b/src/coreComponents/events/EventManager.cpp index 5e24698b008..261542cf52f 100644 --- a/src/coreComponents/events/EventManager.cpp +++ b/src/coreComponents/events/EventManager.cpp @@ -176,7 +176,7 @@ bool EventManager::run( DomainPartition & domain ) m_dt = dt_global; #endif } - LogPart logPart( "TIMESTEP", MpiWrapper::commRank() == 0 ); + LogPart logPart( "Timestep", MpiWrapper::commRank() == 0 ); outputTime( logPart ); logPart.begin(); diff --git a/src/coreComponents/linearAlgebra/multiscale/mesh/coarsening/MetisInterface.cpp b/src/coreComponents/linearAlgebra/multiscale/mesh/coarsening/MetisInterface.cpp index f4d48c82b9a..817bef0c015 100644 --- a/src/coreComponents/linearAlgebra/multiscale/mesh/coarsening/MetisInterface.cpp +++ b/src/coreComponents/linearAlgebra/multiscale/mesh/coarsening/MetisInterface.cpp @@ -19,6 +19,7 @@ #include "MetisInterface.hpp" #include "common/TimingMacros.hpp" +#include "common/logger/Logger.hpp" #include diff --git a/src/coreComponents/mainInterface/GeosxState.cpp b/src/coreComponents/mainInterface/GeosxState.cpp index 1fcb001bc18..daed9d999f4 100644 --- a/src/coreComponents/mainInterface/GeosxState.cpp +++ b/src/coreComponents/mainInterface/GeosxState.cpp @@ -127,7 +127,8 @@ bool GeosxState::initializeDataRepository() Timer timer( m_initTime ); GEOS_THROW_IF_NE( m_state, State::UNINITIALIZED, geos::LogicError ); - + LogPart postProcessiveLog( "Parsing", MpiWrapper::commRank() == 0 ); + postProcessiveLog.begin(); getProblemManager().parseCommandLineInput(); if( !getProblemManager().getSchemaFileName().empty() ) @@ -138,6 +139,7 @@ bool GeosxState::initializeDataRepository() } getProblemManager().parseInputFile(); + postProcessiveLog.end(); getProblemManager().problemSetup(); m_state = State::INITIALIZED; diff --git a/src/coreComponents/mainInterface/ProblemManager.cpp b/src/coreComponents/mainInterface/ProblemManager.cpp index 3c2718b1955..a64ba10c1d7 100644 --- a/src/coreComponents/mainInterface/ProblemManager.cpp +++ b/src/coreComponents/mainInterface/ProblemManager.cpp @@ -172,8 +172,9 @@ void ProblemManager::problemSetup() postInputInitializationRecursive(); - LogPart meshGenerationLog( "Mesh generation", MpiWrapper::commRank() == 0 ); + LogPart meshGenerationLog( "Mesh Generation", MpiWrapper::commRank() == 0 ); meshGenerationLog.begin(); + generateMesh(); meshGenerationLog.end(); @@ -187,7 +188,7 @@ void ProblemManager::problemSetup() initialize(); - LogPart importFieldsLog( "Import fields", MpiWrapper::commRank() == 0 ); + LogPart importFieldsLog( "Import Fields", MpiWrapper::commRank() == 0 ); importFieldsLog.begin(); importFields(); importFieldsLog.end(); diff --git a/src/coreComponents/mesh/ElementType.hpp b/src/coreComponents/mesh/ElementType.hpp index 76df6db0754..056cae6f010 100644 --- a/src/coreComponents/mesh/ElementType.hpp +++ b/src/coreComponents/mesh/ElementType.hpp @@ -21,6 +21,7 @@ #define GEOS_MESH_ELEMENTTYPE_HPP #include "common/format/EnumStrings.hpp" +#include "common/logger/Logger.hpp" namespace geos { diff --git a/src/coreComponents/physicsSolvers/PhysicsSolverBase.cpp b/src/coreComponents/physicsSolvers/PhysicsSolverBase.cpp index 942fa1ed041..920a00c0bcc 100644 --- a/src/coreComponents/physicsSolvers/PhysicsSolverBase.cpp +++ b/src/coreComponents/physicsSolvers/PhysicsSolverBase.cpp @@ -19,6 +19,7 @@ #include "common/MpiWrapper.hpp" #include "codingUtilities/RTTypes.hpp" #include "common/format/EnumStrings.hpp" +#include "common/logger/Logger.hpp" #include "dataRepository/Group.hpp" #include "physicsSolvers/LogLevelsInfo.hpp" #include "common/format/LogPart.hpp" @@ -374,7 +375,7 @@ void PhysicsSolverBase::logEndOfCycleInformation( integer const cycleNumber, integer const numOfSubSteps, stdVector< real64 > const & subStepDts ) const { - LogPart logpart( "TIMESTEP", MpiWrapper::commRank() == 0 ); + LogPart logpart( "Time step", MpiWrapper::commRank() == 0 ); logpart.addEndDescription( "- Cycle ", cycleNumber ); logpart.addEndDescription( "- N substeps ", numOfSubSteps );