diff --git a/CHANGELOG.md b/CHANGELOG.md index 25d41dc1b..0860caf66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,9 +12,11 @@ and this project aspires to adhere to [Semantic Versioning](https://semver.org/s - raja@2024.02.1 - umpire@2024.02.1 - camp@2024.02.1 -- kokkos@3.7.02 +- kokkos@4.4.1 +- mfem@4.7 ### Added +- Added a new unified logging infrastructure. - Added support for unstructured topologies with mixed elements types (for example, hexs and tets). - Added support for `pyramid` and `wedge` elements. - Added `sphere`, `cylinder`, `box`, and `plane` options to the slice filter. diff --git a/src/config/ascent_config.mk.in b/src/config/ascent_config.mk.in index 266e1ec2b..d1cdced9f 100644 --- a/src/config/ascent_config.mk.in +++ b/src/config/ascent_config.mk.in @@ -302,6 +302,7 @@ ASCENT_LIB_FLAGS = $(ASCENT_DEVICE_OBJECT) \ -lascent \ -lascent_flow \ -lascent_lodepng \ + -lascent_logging \ $(ASCENT_ROVER_LIB_FLAGS) $(DRAY_LIB_FLAGS) $(ASCENT_VTKH_LIB_FLAGS) $(ASCENT_VTKM_LIB_FLAGS) $(VTKH_LIB_FLAGS) $(ASCENT_CONDUIT_LIB_FLAGS) $(ASCENT_MFEM_LIB_FLAGS) $(ASCENT_RAJA_LIB_FLAGS) $(ASCENT_UMPIRE_LIB_FLAGS) $(ASCENT_CAMP_LIB_FLAGS) $(ASCENT_OCCA_LIB_FLAGS) $(ASCENT_GENTEN_LIB_FLAGS) $(ASCENT_PYTHON_LIBS) $(ASCENT_CALIPER_LIB_FLAGS) $(ASCENT_ADIAK_LIB_FLAGS) $(ASCENT_OPENMP_LINK_FLAGS) $(ASCENT_CUDA_LIB_FLAGS) # if using Ascent with mpi and/or cuda with a non-GPU sim @@ -310,6 +311,7 @@ ASCENT_MPI_LIB_FLAGS = $(ASCENT_DEVICE_OBJECT_MPI) \ -lascent_mpi \ -lascent_flow \ -lascent_lodepng \ + -lascent_logging \ $(ASCENT_ROVER_MPI_LIB_FLAGS) $(DRAY_MPI_LIB_FLAGS) $(ASCENT_VTKH_MPI_LIB_FLAGS) $(ASCENT_VTKM_LIB_FLAGS) $(VTKH_MPI_LIB_FLAGS) $(ASCENT_CONDUIT_MPI_LIB_FLAGS) $(ASCENT_MFEM_LIB_FLAGS) $(ASCENT_FIDES_LIB_FLAGS) $(ASCENT_ADIOS2_LIB_FLAGS) $(ASCENT_PMT_LIB_FLAGS) $(ASCENT_STREAMSTAT_LIB_FLAGS) $(ASCENT_TOPOFILEPARSER_LIB_FLAGS) $(ASCENT_BABELFLOW_LIB_FLAGS) $(ASCENT_RAJA_LIB_FLAGS) $(ASCENT_UMPIRE_LIB_FLAGS) $(ASCENT_CAMP_LIB_FLAGS) $(ASCENT_OCCA_LIB_FLAGS) $(ASCENT_GENTEN_LIB_FLAGS) $(ASCENT_PYTHON_LIBS) $(ASCENT_CALIPER_LIB_FLAGS) $(ASCENT_OPENMP_LINK_FLAGS) $(ASCENT_CUDA_LIB_FLAGS) @@ -319,5 +321,6 @@ ASCENT_MPI_CUDA_LIB_FLAGS = -L $(ASCENT_DIR)/lib \ -lascent_mpi \ -lascent_flow \ -lascent_lodepng \ + -lascent_logging \ $(ASCENT_ROVER_MPI_LIB_FLAGS) $(DRAY_MPI_LIB_FLAGS) $(ASCENT_VTKH_MPI_LIB_FLAGS) $(ASCENT_VTKM_LIB_FLAGS) $(VTKH_MPI_LIB_FLAGS) $(ASCENT_CONDUIT_MPI_LIB_FLAGS) $(ASCENT_MFEM_LIB_FLAGS) $(ASCENT_OCCA_LIB_FLAGS) $(ASCENT_GENTEN_LIB_FLAGS) $(ASCENT_FIDES_LIB_FLAGS) $(ASCENT_ADIOS2_LIB_FLAGS) $(ASCENT_PMT_LIB_FLAGS) $(ASCENT_STREAMSTAT_LIB_FLAGS) $(ASCENT_TOPOFILEPARSER_LIB_FLAGS) $(ASCENT_BABELFLOW_LIB_FLAGS) $(ASCENT_RAJA_LIB_FLAGS) $(ASCENT_UMPIRE_LIB_FLAGS) $(ASCENT_CAMP_LIB_FLAGS) $(ASCENT_PYTHON_LIBS) $(ASCENT_CALIPER_LIB_FLAGS) $(ASCENT_OPENMP_LINK_FLAGS) $(ASCENT_CUDA_LIB_FLAGS) diff --git a/src/libs/CMakeLists.txt b/src/libs/CMakeLists.txt index e42a92e89..49be02e31 100644 --- a/src/libs/CMakeLists.txt +++ b/src/libs/CMakeLists.txt @@ -2,14 +2,9 @@ # Project developers. See top-level LICENSE AND COPYRIGHT files for dates and # other details. No copyright assignment is required to contribute to Ascent. - -################################ -# Add flow -################################ -add_subdirectory(flow) - - +####################################### # display info about optional features +####################################### if(ENABLE_APCOMP) message(STATUS "Building APComp (ENABLE_APCOMP=ON)") else() @@ -29,10 +24,23 @@ else() endif() +################################ # ascent_png_utils object lib # shared for testing of all libs +################################ add_subdirectory(png_utils) +################################ +# ascent_logging lib +# shared logging for all libs +################################ +add_subdirectory(logging) + +################################ +# Add flow +################################ +add_subdirectory(flow) + ################################ # Add ap comp ################################ diff --git a/src/libs/ascent/CMakeLists.txt b/src/libs/ascent/CMakeLists.txt index 7c41d157a..c170c6dfd 100644 --- a/src/libs/ascent/CMakeLists.txt +++ b/src/libs/ascent/CMakeLists.txt @@ -171,7 +171,7 @@ set(ascent_headers # utils utils/ascent_actions_utils.hpp utils/ascent_data_logger.hpp - utils/ascent_logging.hpp + utils/ascent_logging_old.hpp utils/ascent_block_timer.hpp utils/ascent_mpi_utils.hpp utils/ascent_string_utils.hpp @@ -179,7 +179,6 @@ set(ascent_headers utils/ascent_resources.hpp utils/ascent_resources_cinema_web.hpp utils/ascent_resources_ascent_web.hpp - utils/ascent_annotations.hpp # hola hola/ascent_hola.hpp) @@ -238,12 +237,11 @@ set(ascent_sources utils/ascent_actions_utils.cpp utils/ascent_data_logger.cpp utils/ascent_block_timer.cpp - utils/ascent_logging.cpp + utils/ascent_logging_old.cpp utils/ascent_mpi_utils.cpp utils/ascent_string_utils.cpp utils/ascent_web_interface.cpp utils/ascent_resources.cpp - utils/ascent_annotations.cpp # hola hola/ascent_hola.cpp) @@ -371,7 +369,8 @@ set(ascent_thirdparty_libs conduit::conduit ascent_flow ascent_lodepng - ascent_png_utils) + ascent_png_utils + ascent_logging) ################## # optional libs diff --git a/src/libs/ascent/ascent.cpp b/src/libs/ascent/ascent.cpp index 0b80db005..3f48a52f2 100644 --- a/src/libs/ascent/ascent.cpp +++ b/src/libs/ascent/ascent.cpp @@ -17,14 +17,20 @@ #include #include +#include +#include #include #include #include +#include + #if defined(ASCENT_VTKH_ENABLED) #include #endif + + #ifdef ASCENT_MPI_ENABLED #include #include @@ -36,6 +42,50 @@ using namespace conduit; namespace ascent { +//----------------------------------------------------------------------------- +namespace detail +{ + +//----------------------------------------------------------------------------- +int +ParRank(int comm_id) +{ + int rank = 0; + +#if defined(ASCENT_MPI_ENABLED) + if(comm_id == -1) + { + // do nothing, an error will be thrown later + // so we can respect the exception handling + return 0; + } + MPI_Comm mpi_comm = MPI_Comm_f2c(comm_id); + MPI_Comm_rank(mpi_comm, &rank); +#endif + + return rank; +} + +//----------------------------------------------------------------------------- +int +ParSize(int comm_id) +{ +int comm_size=1; + +#if defined(ASCENT_MPI_ENABLED) + if(comm_id == -1) + { + // do nothing, an error will be thrown later + // so we can respect the exception handling + return 1; + } + MPI_Comm mpi_comm = MPI_Comm_f2c(comm_id); + MPI_Comm_size(mpi_comm, &comm_size); +#endif + + return comm_size; +} + //----------------------------------------------------------------------------- void quiet_handler(const std::string &, @@ -44,6 +94,10 @@ quiet_handler(const std::string &, { } +} + + + //----------------------------------------------------------------------------- Ascent::Ascent() : m_runtime(NULL), @@ -187,6 +241,9 @@ Ascent::open(const conduit::Node &options) comm_id = options["mpi_comm"].to_int32(); } + int par_rank = detail::ParRank(comm_id); + int par_size = detail::ParSize(comm_id); + CheckForSettingsFile(opts_file, processed_opts, true, @@ -201,20 +258,183 @@ Ascent::open(const conduit::Node &options) m_options["mpi_comm"] = options["mpi_comm"]; } - if(m_options.has_path("messages") && - m_options["messages"].dtype().is_string() ) + Node echo_opts; + echo_opts["echo_threshold"] = "info"; + echo_opts["ranks"] = "root"; + + // messages echoed to std out + if(m_options.has_path("messages")) + { + if(m_options["messages"].dtype().is_string()) + { + std::string msgs_opt = m_options["messages"].as_string(); + if( msgs_opt == "verbose") + { + m_verbose_msgs = true; + echo_opts["echo_threshold"] = "all"; + } + else if(msgs_opt == "quiet") + { + m_verbose_msgs = false; + echo_opts["echo_threshold"] = "error"; + } + } + else if(m_options["messages"].dtype().is_object()) + { + const Node &msg_ops = m_options["messages"]; + echo_opts.update(msg_ops); + if(msg_ops.has_child("echo_threshold") && + msg_ops["echo_threshold"].dtype().is_string() ) + { + std::string echo_thresh = msg_ops["echo_threshold"].as_string(); + if(echo_thresh == "none" || + echo_thresh == "error" || + echo_thresh == "warn" ) + { + m_verbose_msgs = false; + } + else + { + m_verbose_msgs = true; + } + } + } + } + + ascent::Logger &logger = ascent::Logger::instance(); + + // setup echo + logger.set_echo_threshold(echo_opts["echo_threshold"].as_string()); + + // controls for mpi ranks + // if ranks == "root" + // rank 0 is what is specified, echo_threshold = "none" for all others + // if ranks == "all" + // echo_threshold = specified option used for all ranks (alreay handled above) + // if ranks == [list of ints] (also accepts single int) + // echo_threshold = specified option used for ranks in the list + + if(echo_opts["ranks"].dtype().is_number()) // list of ints case { - std::string msgs_opt = m_options["messages"].as_string(); - if( msgs_opt == "verbose") + int64_accessor ranks_list = echo_opts["ranks"].value(); + bool active = false; + for(index_t i=0; i < ranks_list.number_of_elements(); i++) { - m_verbose_msgs = true; + if(par_rank == ranks_list[i] ) + { + active = true; + } } - else if(msgs_opt == "quiet") + + if(!active) { - m_verbose_msgs = false; + logger.set_echo_threshold("none"); } } + else // string options case + { + std::string log_ranks_str = echo_opts["ranks"].as_string(); + + if(log_ranks_str == "root") + { + if(par_rank != 0) + { + logger.set_echo_threshold("none"); + } + } + } + + // logging options + // + // logging: true + // + // logging: + // file_pattern: zzzz + // log_threshold: info + // + + Node logging_opts; + logging_opts["enabled"] = 0; + logging_opts["ranks"] = "all"; +#if defined(ASCENT_MPI_ENABLED) + logging_opts["file_pattern"] = "ascent_log_output_rank_{rank:05d}.yaml"; +#else + logging_opts["file_pattern"] = "ascent_log_output.yaml"; +#endif + logging_opts["log_threshold"] = "debug"; + + if(m_options.has_path("logging")) + { + if(m_options["logging"].dtype().is_string() && + m_options["logging"].as_string() == "true") + { + logging_opts["enabled"] = 1; + } + else if(m_options["logging"].dtype().is_object()) + { + logging_opts["enabled"] = 1; + // pull over options + logging_opts.update(m_options["logging"]); + } + } + + // controls for mpi ranks + // if ranks == "root" + // open log on rank 0, do not open on all others + // if ranks == "all" + // open log on all ranks + // if ranks == [list of ints] (also accepts single int) + // open log on ranks specified in the list + + if(logging_opts["ranks"].dtype().is_number()) // list of ints case + { + int64_accessor ranks_list = logging_opts["ranks"].value(); + bool active = false; + for(index_t i=0; i < ranks_list.number_of_elements(); i++) + { + if(par_rank == ranks_list[i] ) + { + active = true; + } + } + + if(!active) + { + logging_opts["enabled"] = 0; + } + } + else // string options case + { + std::string log_ranks_str = logging_opts["ranks"].as_string(); + + if(log_ranks_str == "root") + { + if(par_rank != 0) + { + logging_opts["enabled"] = 0; + } + } + // all already supported if logging is enabled + } + + + if(logging_opts["enabled"].to_int() == 1) + { + logger.set_log_threshold(logging_opts["log_threshold"].as_string()); + std::string file_pattern = logging_opts["file_pattern"].as_string(); + #if defined(ASCENT_MPI_ENABLED) + ASCENT_LOG_OPEN_RANK( file_pattern, par_rank ) // mpi par + ASCENT_LOG_DEBUG(conduit_fmt::format("mpi info: rank={}, size={}", + par_rank, + par_size)); + #else + ASCENT_LOG_OPEN( file_pattern ) // serial + ASCENT_LOG_DEBUG("mpi not enabled"); + #endif + } + + // exception controls if(m_options.has_path("exceptions") && m_options["exceptions"].dtype().is_string() ) { @@ -300,7 +520,7 @@ Ascent::open(const conduit::Node &options) // make sure to do this after. if(!m_verbose_msgs) { - conduit::utils::set_info_handler(quiet_handler); + conduit::utils::set_info_handler(detail::quiet_handler); } set_status("Ascent::open completed"); @@ -549,6 +769,7 @@ Ascent::close() } set_status("Ascent::close completed"); + ASCENT_LOG_CLOSE(); } catch(conduit::Error &e) { @@ -574,6 +795,7 @@ Ascent::close() << e.message() << std::endl; } } + ASCENT_LOG_CLOSE(); } } @@ -585,6 +807,7 @@ Ascent::set_status(const std::string &msg) std::ostringstream oss; oss << msg << " at " << timestamp(); m_status["message"] = oss.str(); + ASCENT_LOG_DEBUG(msg); } //---------------------------------------------------------------------------// @@ -597,6 +820,7 @@ Ascent::set_status(const std::string &msg, oss << msg << " at " << timestamp(); m_status["message"] = oss.str(); m_status["details"] = details; + ASCENT_LOG_DEBUG(msg + " " + details); } //---------------------------------------------------------------------------// diff --git a/src/libs/ascent/ascent.hpp b/src/libs/ascent/ascent.hpp index 765f70651..44757aa17 100644 --- a/src/libs/ascent/ascent.hpp +++ b/src/libs/ascent/ascent.hpp @@ -20,6 +20,7 @@ #include +#include #include #include diff --git a/src/libs/ascent/hola/ascent_hola.cpp b/src/libs/ascent/hola/ascent_hola.cpp index a61d0409b..4934bc1f4 100644 --- a/src/libs/ascent/hola/ascent_hola.cpp +++ b/src/libs/ascent/hola/ascent_hola.cpp @@ -25,6 +25,7 @@ // ascent includes //----------------------------------------------------------------------------- #include +#include #include diff --git a/src/libs/ascent/runtimes/ascent_main_runtime.cpp b/src/libs/ascent/runtimes/ascent_main_runtime.cpp index 0b8332d27..83c1dabc0 100644 --- a/src/libs/ascent/runtimes/ascent_main_runtime.cpp +++ b/src/libs/ascent/runtimes/ascent_main_runtime.cpp @@ -131,6 +131,15 @@ AscentRuntime::~AscentRuntime() void AscentRuntime::Initialize(const conduit::Node &options) { + +// handle logging first +#if defined(ASCENT_MPI_ENABLED) + +#else + +#endif + + #if ASCENT_MPI_ENABLED if(!options.has_child("mpi_comm") || !options["mpi_comm"].dtype().is_integer()) diff --git a/src/libs/ascent/runtimes/ascent_mfem_data_adapter.cpp b/src/libs/ascent/runtimes/ascent_mfem_data_adapter.cpp index 08ae7988a..fec8e11c5 100644 --- a/src/libs/ascent/runtimes/ascent_mfem_data_adapter.cpp +++ b/src/libs/ascent/runtimes/ascent_mfem_data_adapter.cpp @@ -13,6 +13,7 @@ #include "ascent_mfem_data_adapter.hpp" #include +#include // standard lib includes #include diff --git a/src/libs/ascent/runtimes/ascent_transmogrifier.cpp b/src/libs/ascent/runtimes/ascent_transmogrifier.cpp index a9cfc8573..535f05c76 100644 --- a/src/libs/ascent/runtimes/ascent_transmogrifier.cpp +++ b/src/libs/ascent/runtimes/ascent_transmogrifier.cpp @@ -17,6 +17,7 @@ #include "ascent_mfem_data_adapter.hpp" #endif #include "ascent_logging.hpp" +#include "ascent_logging_old.hpp" #include #include diff --git a/src/libs/ascent/runtimes/ascent_vtkh_collection.cpp b/src/libs/ascent/runtimes/ascent_vtkh_collection.cpp index d73abe3af..d24cbac37 100644 --- a/src/libs/ascent/runtimes/ascent_vtkh_collection.cpp +++ b/src/libs/ascent/runtimes/ascent_vtkh_collection.cpp @@ -14,6 +14,7 @@ #include "ascent_vtkh_collection.hpp" #include "ascent_mpi_utils.hpp" #include "ascent_logging.hpp" +#include "ascent_logging_old.hpp" #if defined(ASCENT_MPI_ENABLED) #include diff --git a/src/libs/ascent/runtimes/ascent_vtkh_data_adapter.cpp b/src/libs/ascent/runtimes/ascent_vtkh_data_adapter.cpp index 82caa2ca2..2dae0b825 100644 --- a/src/libs/ascent/runtimes/ascent_vtkh_data_adapter.cpp +++ b/src/libs/ascent/runtimes/ascent_vtkh_data_adapter.cpp @@ -27,6 +27,9 @@ #include #endif +#include +#include + // VTKm includes #define VTKM_USE_DOUBLE_PRECISION #include diff --git a/src/libs/ascent/runtimes/expressions/ascent_array_internals.hpp b/src/libs/ascent/runtimes/expressions/ascent_array_internals.hpp index 24b1b3929..a896d9e37 100644 --- a/src/libs/ascent/runtimes/expressions/ascent_array_internals.hpp +++ b/src/libs/ascent/runtimes/expressions/ascent_array_internals.hpp @@ -14,6 +14,7 @@ #include "ascent_memory_manager.hpp" #include "ascent_logging.hpp" +#include "ascent_logging_old.hpp" #if defined(ASCENT_UMPIRE_ENABLED) #include diff --git a/src/libs/ascent/runtimes/expressions/ascent_blueprint_type_utils.hpp b/src/libs/ascent/runtimes/expressions/ascent_blueprint_type_utils.hpp index 565df5011..ef47a2672 100644 --- a/src/libs/ascent/runtimes/expressions/ascent_blueprint_type_utils.hpp +++ b/src/libs/ascent/runtimes/expressions/ascent_blueprint_type_utils.hpp @@ -9,6 +9,7 @@ #include #include +#include //----------------------------------------------------------------------------- // -- begin ascent:: -- diff --git a/src/libs/ascent/runtimes/expressions/ascent_execution_manager.cpp b/src/libs/ascent/runtimes/expressions/ascent_execution_manager.cpp index d204ea4fe..e2c547a46 100644 --- a/src/libs/ascent/runtimes/expressions/ascent_execution_manager.cpp +++ b/src/libs/ascent/runtimes/expressions/ascent_execution_manager.cpp @@ -1,6 +1,7 @@ #include "ascent_execution_manager.hpp" #include #include +#include namespace ascent { diff --git a/src/libs/ascent/runtimes/expressions/ascent_jit_array.cpp b/src/libs/ascent/runtimes/expressions/ascent_jit_array.cpp index 61ac28a34..7d3245a05 100644 --- a/src/libs/ascent/runtimes/expressions/ascent_jit_array.cpp +++ b/src/libs/ascent/runtimes/expressions/ascent_jit_array.cpp @@ -12,6 +12,7 @@ #include "ascent_jit_array.hpp" #include +#include //----------------------------------------------------------------------------- // -- begin ascent:: -- diff --git a/src/libs/ascent/runtimes/expressions/ascent_jit_field.cpp b/src/libs/ascent/runtimes/expressions/ascent_jit_field.cpp index ae2d082a5..09d3a6fe0 100644 --- a/src/libs/ascent/runtimes/expressions/ascent_jit_field.cpp +++ b/src/libs/ascent/runtimes/expressions/ascent_jit_field.cpp @@ -12,6 +12,7 @@ #include "ascent_jit_field.hpp" #include +#include //----------------------------------------------------------------------------- // -- begin ascent:: -- diff --git a/src/libs/ascent/runtimes/expressions/ascent_jit_math.cpp b/src/libs/ascent/runtimes/expressions/ascent_jit_math.cpp index 9a734e8ec..a3ce2f859 100644 --- a/src/libs/ascent/runtimes/expressions/ascent_jit_math.cpp +++ b/src/libs/ascent/runtimes/expressions/ascent_jit_math.cpp @@ -12,6 +12,7 @@ #include "ascent_jit_math.hpp" #include +#include //----------------------------------------------------------------------------- // -- begin ascent:: -- diff --git a/src/libs/ascent/runtimes/expressions/ascent_memory_manager.cpp b/src/libs/ascent/runtimes/expressions/ascent_memory_manager.cpp index aa988e1d0..e74e7038a 100644 --- a/src/libs/ascent/runtimes/expressions/ascent_memory_manager.cpp +++ b/src/libs/ascent/runtimes/expressions/ascent_memory_manager.cpp @@ -1,5 +1,6 @@ #include "ascent_memory_manager.hpp" #include +#include #include diff --git a/src/libs/ascent/runtimes/flow_filters/ascent_runtime_conduit_to_vtkm_parsing.cpp b/src/libs/ascent/runtimes/flow_filters/ascent_runtime_conduit_to_vtkm_parsing.cpp index fc6e31a91..d4af2066b 100644 --- a/src/libs/ascent/runtimes/flow_filters/ascent_runtime_conduit_to_vtkm_parsing.cpp +++ b/src/libs/ascent/runtimes/flow_filters/ascent_runtime_conduit_to_vtkm_parsing.cpp @@ -14,6 +14,7 @@ #include "ascent_runtime_conduit_to_vtkm_parsing.hpp" #include +#include using namespace conduit; //----------------------------------------------------------------------------- @@ -252,6 +253,7 @@ parse_color_table(const conduit::Node &color_table_node) const Node &peg = itr.next(); if(!peg.has_child("position")) { + // FIXME: This should be an error ASCENT_WARN("Color map control point must have a position"); } diff --git a/src/libs/ascent/runtimes/flow_filters/ascent_runtime_dray_filters.cpp b/src/libs/ascent/runtimes/flow_filters/ascent_runtime_dray_filters.cpp index 08eee01e5..309e0fd7f 100644 --- a/src/libs/ascent/runtimes/flow_filters/ascent_runtime_dray_filters.cpp +++ b/src/libs/ascent/runtimes/flow_filters/ascent_runtime_dray_filters.cpp @@ -451,6 +451,7 @@ parse_color_table(const conduit::Node &color_table_node) const Node &peg = itr.next(); if(!peg.has_child("position")) { + // FIXME: This should be an error ASCENT_WARN("Color map control point must have a position"); } diff --git a/src/libs/ascent/utils/ascent_logging.cpp b/src/libs/ascent/utils/ascent_logging_old.cpp similarity index 94% rename from src/libs/ascent/utils/ascent_logging.cpp rename to src/libs/ascent/utils/ascent_logging_old.cpp index 016a27d20..88ee5330d 100644 --- a/src/libs/ascent/utils/ascent_logging.cpp +++ b/src/libs/ascent/utils/ascent_logging_old.cpp @@ -6,11 +6,11 @@ //----------------------------------------------------------------------------- /// -/// file: ascent_logging.cpp +/// file: ascent_logging_old.cpp /// //----------------------------------------------------------------------------- -#include "ascent_logging.hpp" +#include "ascent_logging_old.hpp" //----------------------------------------------------------------------------- // -- begin ascent:: -- diff --git a/src/libs/ascent/utils/ascent_logging.hpp b/src/libs/ascent/utils/ascent_logging_old.hpp similarity index 98% rename from src/libs/ascent/utils/ascent_logging.hpp rename to src/libs/ascent/utils/ascent_logging_old.hpp index 1e572188b..1df8e7dcb 100644 --- a/src/libs/ascent/utils/ascent_logging.hpp +++ b/src/libs/ascent/utils/ascent_logging_old.hpp @@ -9,8 +9,8 @@ /// file: ascent_logging.hpp /// //----------------------------------------------------------------------------- -#ifndef ASCENT_LOGGING_HPP -#define ASCENT_LOGGING_HPP +#ifndef ASCENT_LOGGING_OLD_HPP +#define ASCENT_LOGGING_OLD_HPP #include #include diff --git a/src/libs/logging/CMakeLists.txt b/src/libs/logging/CMakeLists.txt new file mode 100644 index 000000000..f68951e28 --- /dev/null +++ b/src/libs/logging/CMakeLists.txt @@ -0,0 +1,55 @@ +# Copyright (c) Lawrence Livermore National Security, LLC and other Ascent +# Project developers. See top-level LICENSE AND COPYRIGHT files for dates and +# other details. No copyright assignment is required to contribute to Ascent. + + +# gen config header +set(ASCENT_LOGGING_ENABLE_CALIPER ${CALIPER_FOUND}) +configure_file ("${CMAKE_CURRENT_SOURCE_DIR}/ascent_logging_config.h.in" + "${CMAKE_CURRENT_BINARY_DIR}/ascent_logging_config.h") + +set(ascent_logging_headers + ${CMAKE_CURRENT_BINARY_DIR}/ascent_logging_config.h + ascent_logging.hpp + ascent_logging_timer.hpp + ascent_annotations.hpp + ascent_logging_exports.h + ) + +set(ascent_logging_sources + ascent_logging.cpp + ascent_logging_timer.cpp + ascent_annotations.cpp + ) + + +set(ascent_logging_deps conduit::conduit) + +if(CALIPER_FOUND) + list(APPEND ascent_logging_deps caliper) +endif() + +blt_add_library(NAME ascent_logging + SOURCES ${ascent_logging_sources} + HEADERS ${aascent_logging_headers} + DEPENDS_ON ${ascent_logging_deps}) + +# for generated config header +target_include_directories(ascent_logging PUBLIC $) +target_include_directories(ascent_logging PUBLIC $) + +# extra defs and props +target_compile_definitions(ascent_logging PRIVATE ASCENT_EXPORTS_FLAG) + +if(ENABLE_HIDDEN_VISIBILITY) + set_target_properties(ascent_logging PROPERTIES CXX_VISIBILITY_PRESET hidden) +endif() + +install(FILES ${ascent_logging_headers} DESTINATION include/ascent/) + +install(TARGETS ascent_logging + EXPORT ascent + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + RUNTIME DESTINATION lib + ) diff --git a/src/libs/ascent/utils/ascent_annotations.cpp b/src/libs/logging/ascent_annotations.cpp similarity index 90% rename from src/libs/ascent/utils/ascent_annotations.cpp rename to src/libs/logging/ascent_annotations.cpp index 196cabae4..3ab4ea384 100644 --- a/src/libs/ascent/utils/ascent_annotations.cpp +++ b/src/libs/logging/ascent_annotations.cpp @@ -15,7 +15,7 @@ //----------------------------------------------------------------------------- #include "conduit.hpp" -#if defined(ASCENT_CALIPER_ENABLED) +#if defined(ASCENT_LOGGING_ENABLE_CALIPER) #include "caliper/cali-manager.h" #endif @@ -31,7 +31,7 @@ namespace ascent namespace annotations { -#if defined(ASCENT_CALIPER_ENABLED) +#if defined(ASCENT_LOGGING_ENABLE_CALIPER) static cali::ConfigManager *cali_cfg_manager = NULL; #endif @@ -40,7 +40,7 @@ static cali::ConfigManager *cali_cfg_manager = NULL; bool supported() { -#if defined(ASCENT_CALIPER_ENABLED) +#if defined(ASCENT_LOGGING_ENABLE_CALIPER) return true; #else return false; @@ -51,7 +51,7 @@ supported() void initialize() { -#if defined(ASCENT_CALIPER_ENABLED) +#if defined(ASCENT_LOGGING_ENABLE_CALIPER) conduit::Node opts; initialize(opts); #endif @@ -61,11 +61,11 @@ initialize() void initialize(const conduit::Node &opts) { -#if defined(ASCENT_CALIPER_ENABLED) +#if defined(ASCENT_LOGGING_ENABLE_CALIPER) if(cali_cfg_manager != NULL) { - ASCENT_ERROR("Ascent Caliper Config Manager already initialized.") + ASCENT_LOG_ERROR("Ascent Caliper Config Manager already initialized.") } // check opts @@ -113,7 +113,7 @@ initialize(const conduit::Node &opts) void flush() { -#if defined(ASCENT_CALIPER_ENABLED) +#if defined(ASCENT_LOGGING_ENABLE_CALIPER) if(cali_cfg_manager != NULL) { cali_cfg_manager->flush(); @@ -126,7 +126,7 @@ flush() void finalize() { -#if defined(ASCENT_CALIPER_ENABLED) +#if defined(ASCENT_LOGGING_ENABLE_CALIPER) flush(); if(cali_cfg_manager != NULL) { diff --git a/src/libs/ascent/utils/ascent_annotations.hpp b/src/libs/logging/ascent_annotations.hpp similarity index 96% rename from src/libs/ascent/utils/ascent_annotations.hpp rename to src/libs/logging/ascent_annotations.hpp index 7017f1bad..cac2aa886 100644 --- a/src/libs/ascent/utils/ascent_annotations.hpp +++ b/src/libs/logging/ascent_annotations.hpp @@ -14,12 +14,12 @@ //----------------------------------------------------------------------------- // -- ascent includes -- //----------------------------------------------------------------------------- -#include -#include +#include +#include #include //----------------------------------------------------------------------------- -#if defined(ASCENT_CALIPER_ENABLED) +#if defined(ASCENT_LOGGING_ENABLE_CALIPER) #include #endif @@ -28,7 +28,7 @@ /// ASCENT_ANNOTATE_ZZZ macros are used for caliper performance annotations. // //----------------------------------------------------------------------------- -#if defined(ASCENT_CALIPER_ENABLED) +#if defined(ASCENT_LOGGING_ENABLE_CALIPER) #define ASCENT_ANNOTATE_MARK_BEGIN( name ) CALI_MARK_BEGIN( name ) #define ASCENT_ANNOTATE_MARK_END( name ) CALI_MARK_END( name ) #define ASCENT_ANNOTATE_MARK_FUNCTION CALI_CXX_MARK_FUNCTION diff --git a/src/libs/logging/ascent_logging.cpp b/src/libs/logging/ascent_logging.cpp new file mode 100644 index 000000000..1c1131df6 --- /dev/null +++ b/src/libs/logging/ascent_logging.cpp @@ -0,0 +1,476 @@ +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// +// Copyright (c) Lawrence Livermore National Security, LLC and other Ascent +// Project developers. See top-level LICENSE AND COPYRIGHT files for dates and +// other details. No copyright assignment is required to contribute to Ascent. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// + +//----------------------------------------------------------------------------- +/// +/// file: ascent_logging.cpp +/// +//----------------------------------------------------------------------------- + +#include "ascent_logging.hpp" + +// standard includes +#include + +#include +#include +#include + +// thirdparty includes +#include +#include + +using namespace conduit; + +//----------------------------------------------------------------------------- +// -- begin ascent:: -- +//----------------------------------------------------------------------------- +namespace ascent +{ + +//----------------------------------------------------------------------------- +// main logger instance +//----------------------------------------------------------------------------- +Logger Logger::m_instance; + +//----------------------------------------------------------------------------- +Logger::Scope::Scope(Logger &lgr, const std::string &name) + : m_lgr(lgr), + m_name(name) +{ + m_lgr.log_block_begin(m_name); +} + +//----------------------------------------------------------------------------- +Logger::Scope::~Scope() +{ + m_lgr.log_block_end(m_name); +} + +//----------------------------------------------------------------------------- +Logger::Logger() + : m_log_open(false), + m_indent_level(0), + m_rank(-1), + m_log_threshold(Logger::LOG_INFO_ID), + m_echo_threshold(Logger::LOG_NONE_ID) +{ + m_key_counters.push(std::map()); +} + +//----------------------------------------------------------------------------- +Logger::~Logger() +{ + close(); +} + +//----------------------------------------------------------------------------- +void +Logger::reset() +{ + m_indent_level = 0; + m_log_threshold = Logger::LOG_INFO_ID; + m_echo_threshold = Logger::LOG_NONE_ID; + // reset our stacks + m_timers = std::stack(); + m_key_counters = std::stack>(); + m_key_counters.push(std::map()); +} + +//----------------------------------------------------------------------------- +void +Logger::open(const std::string &ofpattern) +{ + if(is_log_open()) + { + std::string emsg = conduit_fmt::format("[FATAL_ERROR] failed to open log with pattern: {}, logger already has {} open.", + ofpattern, m_log_fname); + throw conduit::Error(emsg, + __FILE__, + __LINE__); + } + + // multi node case, assumes file pattern includes "rank" + if(rank() > -1) + { + m_log_fname = conduit_fmt::format(ofpattern, + conduit_fmt::arg("rank",rank())); + } + else + { + m_log_fname = ofpattern; + } + + // open append (consequtive ascent open use cases) + m_log_stream.open(m_log_fname.c_str(),std::ios_base::app); + + if(!m_log_stream.is_open()) + { + throw conduit::Error(conduit_fmt::format("[FATAL_ERROR] Failed to open log file: {} ", m_log_fname), + __FILE__, + __LINE__); + } + m_log_open = true; + log_message(Logger::LOG_DEBUG_ID,conduit_fmt::format("opened log file: {}", m_log_fname)); +} + +//----------------------------------------------------------------------------- +bool +Logger::is_log_open() +{ + return m_log_open; +} + +//----------------------------------------------------------------------------- +void +Logger::close() +{ + if(is_log_open()) + { + log_message(Logger::LOG_DEBUG_ID,conduit_fmt::format("closing log file: {}", m_log_fname)); + m_log_stream.close(); + m_log_open = false; + m_log_fname = ""; + } + + reset(); +} + +//----------------------------------------------------------------------------- +void +Logger::flush() +{ + if(is_log_open()) + { + log_stream() << std::flush; + } +} + +//----------------------------------------------------------------------------- +void +Logger::log_block_begin(const std::string &name) +{ + // skip if log is not open + if(!is_log_open()) + { + return; + } + + // make sure we have a unique key name + int key_count = m_key_counters.top()[name]++; + + log_stream() << m_indent_string <<"-\n"; + set_indent_level(indent_level()+1); + + if(key_count == 0) + { + log_stream() << m_indent_string << name << ":\n"; + } + else + { + log_stream() << m_indent_string << name << "_" << key_count <<":\n"; + } + set_indent_level(indent_level()+1); + // add timer for new level + m_timers.push(Timer()); + // add key counter for new level + m_key_counters.push(std::map()); +} + +//----------------------------------------------------------------------------- +void +Logger::log_block_end(const std::string &name) +{ + // skip if log is not open + if(!is_log_open()) + { + return; + } + + log_stream() << m_indent_string <<"-\n"; + log_stream() << m_indent_string << " time_elapsed: " << m_timers.top().elapsed() << "\n"; + set_indent_level(indent_level()-2); + m_key_counters.pop(); + m_timers.pop(); +} + +//----------------------------------------------------------------------------- +void +Logger::log_message(int level, + const std::string &msg, + const std::string &file, + int line) +{ + // echo if equal or above echo threshold + if(level >= echo_threshold()) + { + log_message(level, msg, file, line, std::cout, false); + } + + // log if equal or above logging threshold + if(level >= log_threshold()) + { + log_message(level, msg, file, line, log_stream(), true); + } +} + + +//----------------------------------------------------------------------------- +void +Logger::log_message(int level, + const std::string &msg, + const std::string &file, + int line, + std::ostream &os, + bool detailed) +{ + /* + {parent_indent}- + {parent_indent}{indent}level: + {parent_indent}{indent}file: + {parent_indent}{indent}line: + ... msg txt + */ + os << m_indent_string <<"-\n"; + os << m_indent_string << " level: " << level_id_to_string(level) << "\n"; + if(detailed) + { + os << m_indent_string << " file: " << file << "\n"; + os << m_indent_string << " line: " << line << "\n"; + os << m_indent_string << " timestamp: \"" << timestamp() << "\"\n"; + } + log_message_inner(msg, os); +} + +//----------------------------------------------------------------------------- +void +Logger::log_message(int level, + const std::string &msg) +{ + // echo if equal or above echo threshold + if(level >= echo_threshold()) + { + log_message(level, msg, std::cout, false); + } + + // log if equal or above logging threshold + if(level >= log_threshold()) + { + log_message(level, msg, log_stream(), true); + } +} + +//----------------------------------------------------------------------------- +void +Logger::log_message(int level, + const std::string &msg, + std::ostream &os, + bool detailed) +{ + /* + {parent_indent}- + {parent_indent}{indent}level: + ... msg txt + */ + os << m_indent_string <<"-\n"; + os << m_indent_string << " level: " << level_id_to_string(level) << "\n"; + if(detailed) + { + os << m_indent_string << " timestamp: \"" << timestamp() << "\"\n"; + } + log_message_inner(msg, os); +} + + +//----------------------------------------------------------------------------- +void +Logger::log_message_inner(const std::string &msg, + std::ostream &os) +{ + /* + {parent_indent}{indent}msg: | + {parent_indent}{indent}{indent} msg line + ... + {parent_indent}{indent}{indent} msg line + */ + os << m_indent_string << " msg: |\n"; + std::istringstream input; + input.str(msg); + for (std::string line; std::getline(input, line);) + { + os << m_indent_string << " " << line << "\n"; + } +} + +//----------------------------------------------------------------------------- +int +Logger::indent_level() const +{ + return m_indent_level; +} + +//----------------------------------------------------------------------------- +void +Logger::set_indent_level(int level) +{ + m_indent_level = level; + m_indent_string = std::string(m_indent_level*2, ' '); +} + +//----------------------------------------------------------------------------- +int +Logger::rank() const +{ + return m_rank; +} + +//----------------------------------------------------------------------------- +void +Logger::set_rank(int rank) +{ + m_rank = rank; +} + +//----------------------------------------------------------------------------- +void +Logger::set_log_threshold(int level) +{ + m_log_threshold = level; +} + +//----------------------------------------------------------------------------- +void +Logger::set_log_threshold(const std::string &level_str) +{ + set_log_threshold(level_string_to_id(level_str)); +} + +//----------------------------------------------------------------------------- +int +Logger::log_threshold() const +{ + return m_log_threshold; +} + +//----------------------------------------------------------------------------- +void +Logger::set_echo_threshold(int level) +{ + m_echo_threshold = level; +} + +//----------------------------------------------------------------------------- +void +Logger::set_echo_threshold(const std::string &level_str) +{ + set_echo_threshold(level_string_to_id(level_str)); +} + + +//----------------------------------------------------------------------------- +int +Logger::echo_threshold() const +{ + return m_echo_threshold; +} + +//----------------------------------------------------------------------------- +std::ostream & +Logger::log_stream() +{ + return m_log_stream; +} + +//----------------------------------------------------------------------------- +Logger & +Logger::instance() +{ + return m_instance; +} + +//----------------------------------------------------------------------------- +std::string +Logger::level_id_to_string(int level) +{ + if(level < Logger::LOG_ALL_ID ) + { + level = Logger::LOG_ALL_ID; + } + else if(level < Logger::LOG_DEBUG_ID) + { + level = Logger::LOG_DEBUG_ID; + } + else if(level > Logger::LOG_ERROR_ID) + { + level = Logger::LOG_ERROR_ID; + } + switch(level) + { + case Logger::LOG_ALL_ID: return "all"; break; + case Logger::LOG_DEBUG_ID: return "debug"; break; + case Logger::LOG_INFO_ID: return "info"; break; + case Logger::LOG_WARN_ID: return "warn"; break; + case Logger::LOG_ERROR_ID: return "error"; break; + case Logger::LOG_NONE_ID: return "none"; break; + } +} + +//----------------------------------------------------------------------------- +int +Logger::level_string_to_id(const std::string &level_str) +{ + // strip, lower? + if(level_str == "all" ) + { + return Logger::LOG_ALL_ID; + } + else if(level_str == "debug" ) + { + return Logger::LOG_DEBUG_ID; + } + else if(level_str == "info" ) + { + return Logger::LOG_INFO_ID; + } + else if(level_str == "warn" ) + { + return Logger::LOG_WARN_ID; + } + else if(level_str == "error" ) + { + return Logger::LOG_ERROR_ID; + } + else if(level_str == "none" ) + { + return Logger::LOG_NONE_ID; + } + else + { + // Unknown, default to all. + return Logger::LOG_ALL_ID; + } +} + +//----------------------------------------------------------------------------- +std::string +Logger::timestamp() +{ + std::time_t time = std::time(nullptr); + auto tm = *std::localtime(&time); + std::ostringstream oss; + oss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S"); + return oss.str(); +} + +//----------------------------------------------------------------------------- +}; +//----------------------------------------------------------------------------- +// -- end ascent:: -- +//----------------------------------------------------------------------------- + + + + diff --git a/src/libs/logging/ascent_logging.hpp b/src/libs/logging/ascent_logging.hpp new file mode 100644 index 000000000..84cba5263 --- /dev/null +++ b/src/libs/logging/ascent_logging.hpp @@ -0,0 +1,289 @@ +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// +// Copyright (c) Lawrence Livermore National Security, LLC and other Ascent +// Project developers. See top-level LICENSE AND COPYRIGHT files for dates and +// other details. No copyright assignment is required to contribute to Ascent. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// + +//----------------------------------------------------------------------------- +/// +/// file: ascent_logging.hpp +/// +//----------------------------------------------------------------------------- +#ifndef ASCENT_LOGGING_HPP +#define ASCENT_LOGGING_HPP + +#include +#include +#include +#include + +#include +#include +#include + +//----------------------------------------------------------------------------- +/* + +Unified Logging Macros used by all libraries.alignas + +macros: + +ASCENT_LOG_OPEN( output_file_name_pattern ) // serial +ASCENT_LOG_OPEN( output_file_name_pattern, rank ) // mpi par + +ASCENT_LOG_DEBUG( msg ) (w/ line, file) +ASCENT_LOG_INFO( msg ) (w/ line, file) +ASCENT_LOG_WARN( msg ) (w/ line, file) +ASCENT_LOG_ERROR( msg ) (w/ line, file) + +ASCENT_LOG_SCOPE( name ) --> increase indent +ASCENT_LOG_MARK_BEGIN( name ) --> increase indent +ASCENT_LOG_MARK_END( name ) --> decrease indent +ASCENT_LOG_MARK_FUNCTION () + +ASCENT_LOG_FLUSH() +ASCENT_LOG_CLOSE() +*/ +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +#define ASCENT_LOG_OPEN( ofname_pattern ) \ +{ \ + ascent::Logger::instance().open(ofname_pattern); \ +} + +//----------------------------------------------------------------------------- +#define ASCENT_LOG_OPEN_RANK( ofname_pattern , rank ) \ +{ \ + ascent::Logger &lgr = ascent::Logger::instance(); \ + lgr.set_rank(rank); \ + lgr.open(ofname_pattern); \ +} + +//----------------------------------------------------------------------------- +#define ASCENT_LOG_DEBUG( msg ) \ +{ \ + std::ostringstream _ascent_oss_info; \ + _ascent_oss_info << msg; \ + ascent::Logger::instance().log_message(ascent::Logger::LOG_DEBUG_ID, \ + _ascent_oss_info.str(), \ + std::string(__FILE__), \ + __LINE__); \ +} + +//----------------------------------------------------------------------------- +#define ASCENT_LOG_INFO( msg ) \ +{ \ + std::ostringstream _ascent_oss_info; \ + _ascent_oss_info << msg; \ + ascent::Logger::instance().log_message(ascent::Logger::LOG_INFO_ID, \ + _ascent_oss_info.str(), \ + std::string(__FILE__), \ + __LINE__); \ +} + +//----------------------------------------------------------------------------- +#define ASCENT_LOG_WARN( msg ) \ +{ \ + std::ostringstream _ascent_oss_info; \ + _ascent_oss_info << msg; \ + ascent::Logger::instance().log_message(ascent::Logger::LOG_WARN_ID, \ + _ascent_oss_info.str(), \ + std::string(__FILE__), \ + __LINE__); \ +} + +//----------------------------------------------------------------------------- +#define ASCENT_LOG_ERROR( msg ) \ +{ \ + std::ostringstream _ascent_oss_info; \ + _ascent_oss_info << msg; \ + ascent::Logger::instance().log_message(ascent::Logger::LOG_ERROR_ID, \ + _ascent_oss_info.str(), \ + std::string(__FILE__), \ + __LINE__); \ + ascent::Logger::instance().flush(); \ + throw conduit::Error(_ascent_oss_info.str(), \ + std::string(__FILE__), \ + __LINE__); \ +} + +//----------------------------------------------------------------------------- +#define ASCENT_LOG_FLUSH() \ +{ \ + ascent::Logger::instance().flush(); \ +} + +//----------------------------------------------------------------------------- +#define ASCENT_LOG_CLOSE() \ +{ \ + ascent::Logger::instance().close(); \ +} + +//----------------------------------------------------------------------------- +#define ASCENT_MARK_SCOPE( name ) ASCENT_ANNOTATE_MARK_SCOPE; ascent::Logger::Scope _ascent_lgr_scope(ascent::Logger::instance(), name ); + +//----------------------------------------------------------------------------- +#define ASCENT_MARK_FUNCTION( name ) ASCENT_ANNOTATE_MARK_FUNCTION; ascent::Logger::Scope _ascent_lgr_func(ascent::Logger::instance(), std::string(__func__)); + +//----------------------------------------------------------------------------- +#define ASCENT_MARK_BEGIN( name ) ASCENT_ANNOTATE_MARK_BEGIN( name ); \ +{ \ + ascent::Logger::instance().log_block_begin(name); \ +} + +//----------------------------------------------------------------------------- +#define ASCENT_MARK_END( name ) ASCENT_ANNOTATE_MARK_END( name ); \ +{ \ + ascent::Logger::instance().log_block_end(name); \ +} + +//----------------------------------------------------------------------------- +// -- begin ascent:: -- +//----------------------------------------------------------------------------- +namespace ascent +{ + +//----------------------------------------------------------------------------- +class ASCENT_API Logger +{ +public: + + //------------------------------------------------------------------------- + typedef enum + { + LOG_ALL_ID = -1, // lowest + LOG_DEBUG_ID = 1, + LOG_INFO_ID = 2, + LOG_WARN_ID = 3, + LOG_ERROR_ID = 4, + LOG_NONE_ID = 127, // highest + } MessageLevel; + + //------------------------------------------------------------------------- + class ASCENT_API Scope + { + public: + Scope(Logger &lgr, const std::string &name); + ~Scope(); + private: + Logger &m_lgr; + std::string m_name; + }; + + // + // file pattern examples: + // "ascent_log_out.yaml" + // "ascent_log_out_{rank}.yaml" + // "ascent_log_out_{rank:05d}.yaml" + // + void open(const std::string &ofile_pattern); + bool is_log_open(); + void reset(); // reset to defaults + void close(); + void flush(); + + void log_message(int level, + const std::string &msg, + const std::string &file, + int line); + + void log_message(int level, + const std::string &msg); + + void log_block_begin(const std::string &name); + void log_block_end(const std::string &name); + + int rank() const; + void set_rank(int rank); + + int indent_level() const; + void set_indent_level(int level); + + // any msgs >= log_threshold will be logged + void set_log_threshold(int level); + void set_log_threshold(const std::string &level_str); + int log_threshold() const; + + // any msgs >= echo_threshold will sent to std out as well as log + void set_echo_threshold(int level); + void set_echo_threshold(const std::string &level_str); + int echo_threshold() const; + + std::ostream &log_stream(); + static Logger &instance(); + +private: + //------------------------------------------------------------------------- + // constructor + destructor + // ------------------------------------------------------------------------ + Logger(); + ~Logger(); + + // ------------------------------------------------------------------------ + // helpers + // ------------------------------------------------------------------------ + static std::string level_id_to_string(int level); + static int level_string_to_id(const std::string &level_str); + static std::string timestamp(); + + void log_message(int level, + const std::string &msg, + const std::string &file, + int line, + std::ostream &os, + bool detailed); + + void log_message(int level, + const std::string &msg, + std::ostream &os, + bool detailed); + + void log_message_inner(const std::string &msg, + std::ostream &os); + + void log_block_begin(const std::string &name, + std::ostream &os); + + void log_block_end(const std::string &name, + std::ostream &os); + + // ------------------------------------------------------------------------ + // instance vars + // ------------------------------------------------------------------------ + std::ofstream m_log_stream; + bool m_log_open; + std::string m_log_fname; + int m_indent_level; // default = 0 + int m_rank; // default = -1 + int m_log_threshold; // default = INFO + int m_echo_threshold; // default = NONE + std::string m_indent_string; // current indent string + + // ------------------------------------------------------------------------ + // logging state stacks + // ------------------------------------------------------------------------ + // stack of timers + std::stack m_timers; + // stack of block name counters + // used to make sure we have unique keys in our yaml output + std::stack> m_key_counters; + + // ------------------------------------------------------------------------ + // static members + // ------------------------------------------------------------------------ + static Logger m_instance; +}; + +//----------------------------------------------------------------------------- +}; +//----------------------------------------------------------------------------- +// -- end ascent:: -- +//----------------------------------------------------------------------------- + +#endif +//----------------------------------------------------------------------------- +// -- end header ifdef guard +//----------------------------------------------------------------------------- + + diff --git a/src/libs/logging/ascent_logging_config.h.in b/src/libs/logging/ascent_logging_config.h.in new file mode 100644 index 000000000..bb5a9264d --- /dev/null +++ b/src/libs/logging/ascent_logging_config.h.in @@ -0,0 +1,19 @@ +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// +// Copyright (c) Lawrence Livermore National Security, LLC and other Ascent +// Project developers. See top-level LICENSE AND COPYRIGHT files for dates and +// other details. No copyright assignment is required to contribute to Ascent. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// + + +//----------------------------------------------------------------------------- +/// +/// file: ascent_logging_config.h +/// +//----------------------------------------------------------------------------- + +#ifndef ASCENT_LOGGING_CONFIG_H +#define ASCENT_LOGGING_CONFIG_H + +#cmakedefine ASCENT_LOGGING_ENABLE_CALIPER "@CALIPER_FOUND@" + +#endif diff --git a/src/libs/logging/ascent_logging_exports.h b/src/libs/logging/ascent_logging_exports.h new file mode 100644 index 000000000..b157f620d --- /dev/null +++ b/src/libs/logging/ascent_logging_exports.h @@ -0,0 +1,45 @@ +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// +// Copyright (c) Lawrence Livermore National Security, LLC and other Ascent +// Project developers. See top-level LICENSE AND COPYRIGHT files for dates and +// other details. No copyright assignment is required to contribute to Ascent. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// + + +//----------------------------------------------------------------------------- +/// +/// file: ascent_logging_exports.h +/// +//----------------------------------------------------------------------------- + +#ifndef ASCENT_LOGGING_EXPORTS_H +#define ASCENT_LOGGING_EXPORTS_H + +//----------------------------------------------------------------------------- +// -- define proper lib exports for various platforms -- +//----------------------------------------------------------------------------- +#if defined(_WIN32) +#if defined(ASCENT_EXPORTS_FLAG) +#define ASCENT_API __declspec(dllexport) +#else +#define ASCENT_API __declspec(dllimport) +#endif +#if defined(_MSC_VER) +// Turn off warning about lack of DLL interface +#pragma warning(disable:4251) +// Turn off warning non-dll class is base for dll-interface class. +#pragma warning(disable:4275) +// Turn off warning about identifier truncation +#pragma warning(disable:4786) +#endif +#else +# if __GNUC__ >= 4 && defined(ASCENT_EXPORTS_FLAG) +# define ASCENT_API __attribute__ ((visibility("default"))) +# else +# define ASCENT_API /* hidden by default */ +# endif +#endif + +#endif + + + diff --git a/src/libs/logging/ascent_logging_timer.cpp b/src/libs/logging/ascent_logging_timer.cpp new file mode 100644 index 000000000..e67959249 --- /dev/null +++ b/src/libs/logging/ascent_logging_timer.cpp @@ -0,0 +1,61 @@ +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// +// Copyright (c) Lawrence Livermore National Security, LLC and other Ascent +// Project developers. See top-level LICENSE AND COPYRIGHT files for dates and +// other details. No copyright assignment is required to contribute to Ascent. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// + + +//----------------------------------------------------------------------------- +/// +/// file: ascent_logging_timer.cpp +/// +//----------------------------------------------------------------------------- + +#include "ascent_logging_timer.hpp" + + +using namespace std::chrono; + +//----------------------------------------------------------------------------- +// -- begin ascent:: -- +//----------------------------------------------------------------------------- +namespace ascent +{ + + +//----------------------------------------------------------------------------- +Timer::Timer() +{ + reset(); +} + +//----------------------------------------------------------------------------- +Timer::~Timer() +{ + +} + +//----------------------------------------------------------------------------- +void +Timer::reset() +{ + m_start = high_resolution_clock::now(); +} + +//----------------------------------------------------------------------------- +float +Timer::elapsed() const +{ + return duration_cast>(high_resolution_clock::now() - m_start).count(); +} + + + +//----------------------------------------------------------------------------- +}; +//----------------------------------------------------------------------------- +// -- end ascent:: -- +//----------------------------------------------------------------------------- + + + diff --git a/src/libs/logging/ascent_logging_timer.hpp b/src/libs/logging/ascent_logging_timer.hpp new file mode 100644 index 000000000..b0e348371 --- /dev/null +++ b/src/libs/logging/ascent_logging_timer.hpp @@ -0,0 +1,56 @@ +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// +// Copyright (c) Lawrence Livermore National Security, LLC and other Ascent +// Project developers. See top-level LICENSE AND COPYRIGHT files for dates and +// other details. No copyright assignment is required to contribute to Ascent. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// + + +//----------------------------------------------------------------------------- +/// +/// file: ascent_logging_timer.hpp +/// +//----------------------------------------------------------------------------- + +#ifndef ASCENT_LOGGING_TIMER_HPP +#define ASCENT_LOGGING_TIMER_HPP + +#include +#include + +//----------------------------------------------------------------------------- +// -- begin ascent:: -- +//----------------------------------------------------------------------------- +namespace ascent +{ + + +//----------------------------------------------------------------------------- +class ASCENT_API Timer +{ + +public: + + explicit Timer(); + ~Timer(); + void reset(); + float elapsed() const; + +private: + std::chrono::high_resolution_clock::time_point m_start; +}; + + +//----------------------------------------------------------------------------- +}; +//----------------------------------------------------------------------------- +// -- end ascent:: -- +//----------------------------------------------------------------------------- + + + +#endif +//----------------------------------------------------------------------------- +// -- end header ifdef guard +//----------------------------------------------------------------------------- + + diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index a961ce81f..8708e9d5b 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -39,6 +39,9 @@ include_directories("${CMAKE_CURRENT_SOURCE_DIR}/vtkh") # add tpl smoke tests, so they run before we run the ascent tests add_subdirectory("thirdparty") +# add logging tests +add_subdirectory("logging") + # add apcomp tests if(ENABLE_APCOMP) add_subdirectory("apcomp") diff --git a/src/tests/ascent/CMakeLists.txt b/src/tests/ascent/CMakeLists.txt index 7e2664116..c4bd7ce10 100644 --- a/src/tests/ascent/CMakeLists.txt +++ b/src/tests/ascent/CMakeLists.txt @@ -16,6 +16,7 @@ set(BASIC_TESTS t_ascent_smoke t_ascent_runtime_options t_ascent_data_binning t_ascent_utils + t_ascent_logging t_ascent_annotations t_ascent_derived t_ascent_empty_runtime diff --git a/src/tests/ascent/t_ascent_logging.cpp b/src/tests/ascent/t_ascent_logging.cpp new file mode 100644 index 000000000..ba3e73820 --- /dev/null +++ b/src/tests/ascent/t_ascent_logging.cpp @@ -0,0 +1,151 @@ +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// +// Copyright (c) Lawrence Livermore National Security, LLC and other Ascent +// Project developers. See top-level LICENSE AND COPYRIGHT files for dates and +// other details. No copyright assignment is required to contribute to Ascent. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// + +//----------------------------------------------------------------------------- +/// +/// file: t_ascent_logging.cpp +/// +//----------------------------------------------------------------------------- + + +#include "gtest/gtest.h" + +#include + +#include +#include + +#include + +#include "t_config.hpp" +#include "t_utils.hpp" + + + + +using namespace std; +using namespace conduit; +using namespace ascent; + + + +//----------------------------------------------------------------------------- +TEST(ascent_logging, test_logging_simplest) +{ + Node n; + ascent::about(n); + // only run this test if ascent was built with vtkm support + if(n["runtimes/ascent/vtkm/status"].as_string() == "disabled") + { + ASCENT_INFO("Ascent vtkm support disabled, skipping test"); + return; + } + + // + // Create an example mesh. + // + Node data, verify_info; + conduit::blueprint::mesh::examples::braid("hexs", + 5, + 5, + 5, + data); + EXPECT_TRUE(conduit::blueprint::mesh::verify(data,verify_info)); + + + string output_path = prepare_output_dir(); + string output_file = conduit::utils::join_file_path(output_path,"tout_logging_render1"); + + // remove old images before rendering + remove_test_image(output_file); + conduit::utils::remove_path_if_exists("ascent_log_output.yaml"); + EXPECT_FALSE(conduit::utils::is_file("ascent_log_output.yaml")); + + conduit::Node actions; + conduit::Node &add_scenes= actions.append(); + add_scenes["action"] = "add_scenes"; + conduit::Node &scenes = add_scenes["scenes"]; + scenes["s1/plots/p1/type"] = "pseudocolor"; + scenes["s1/plots/p1/field"] = "braid"; + scenes["s1/image_prefix"] = output_file; + + // + // Run Ascent + // + + Ascent ascent; + + Node ascent_opts; + ascent_opts["logging"] = "true"; + ascent.open(ascent_opts); + ascent.publish(data); + ascent.execute(actions); + ascent.close(); + + // check that the log file exists + EXPECT_TRUE(conduit::utils::is_file("ascent_log_output.yaml")); + +} + +//----------------------------------------------------------------------------- +TEST(ascent_logging, test_logging_options) +{ + Node n; + ascent::about(n); + // only run this test if ascent was built with vtkm support + if(n["runtimes/ascent/vtkm/status"].as_string() == "disabled") + { + ASCENT_INFO("Ascent vtkm support disabled, skipping test"); + return; + } + + // + // Create an example mesh. + // + Node data, verify_info; + conduit::blueprint::mesh::examples::braid("hexs", + 5, + 5, + 5, + data); + EXPECT_TRUE(conduit::blueprint::mesh::verify(data,verify_info)); + + + string output_path = prepare_output_dir(); + string output_file = conduit::utils::join_file_path(output_path,"tout_logging_render2"); + string log_file = conduit::utils::join_file_path(output_path,"tout_my_log.yaml"); + + // remove old images before rendering + remove_test_image(output_file); + conduit::utils::remove_path_if_exists(log_file); + EXPECT_FALSE(conduit::utils::is_file(log_file)); + + conduit::Node actions; + conduit::Node &add_scenes= actions.append(); + add_scenes["action"] = "add_scenes"; + conduit::Node &scenes = add_scenes["scenes"]; + scenes["s1/plots/p1/type"] = "pseudocolor"; + scenes["s1/plots/p1/field"] = "braid"; + scenes["s1/image_prefix"] = output_file; + + // + // Run Ascent + // + + Ascent ascent; + + Node ascent_opts; + ascent_opts["logging/file_pattern"] = log_file; + ascent_opts["logging/log_threshold"] = "all"; + ascent.open(ascent_opts); + ascent.publish(data); + ascent.execute(actions); + ascent.close(); + + // check that the log file exists + EXPECT_TRUE(conduit::utils::is_file(log_file)); + +} \ No newline at end of file diff --git a/src/tests/ascent/t_ascent_mpi_ascent_runtime.cpp b/src/tests/ascent/t_ascent_mpi_ascent_runtime.cpp index 3ab6eb5cf..8232b4b1d 100644 --- a/src/tests/ascent/t_ascent_mpi_ascent_runtime.cpp +++ b/src/tests/ascent/t_ascent_mpi_ascent_runtime.cpp @@ -124,7 +124,7 @@ TEST(ascent_mpi_runtime, test_error_for_mpi_vs_non_mpi) Ascent ascent; Node ascent_opts; ascent_opts["exceptions"] = "forward"; - // we throw an error if an mpi_comm is NO provided to a mpi ver of ascent + // we throw an error if an mpi_comm is NOT provided to a mpi ver of ascent EXPECT_THROW(ascent.open(ascent_opts),conduit::Error); } @@ -169,6 +169,99 @@ TEST(ascent_mpi_runtime, test_for_error_reading_actions) } +//----------------------------------------------------------------------------- +TEST(ascent_mpi_runtime, test_mpi_logs) +{ + // + // Set Up MPI + // + int par_rank; + int par_size; + MPI_Comm comm = MPI_COMM_WORLD; + MPI_Comm_rank(comm, &par_rank); + MPI_Comm_size(comm, &par_size); + + // make sure the _output dir exists + string output_path = ""; + if(par_rank == 0) + { + output_path = prepare_output_dir(); + } + else + { + output_path = output_dir(); + } + + string log_base = conduit::utils::join_file_path(output_path,"tout_log_mpi_test"); + + // + // Test cases + // + // case "0" creates 1 log per mpi task default name in cwd + // ascent_log_out_rank_00000.yaml + // ascent_log_out_rank_00001.yaml + // case "a" creates 1 log per mpi + // tout_log_mpi_test_rank_a_00.yaml + // tout_log_mpi_test_rank_a_01.yaml + // + // case "b" creates log only for root (rank 0) + // tout_log_mpi_test_rank_b_00.yaml + // + // case "c" creates log only on rank 1 + // tout_log_mpi_test_rank_c_01.yaml + // + + + if(par_rank == 0) + { + conduit::utils::remove_path_if_exists("ascent_log_output_rank_00000.yaml"); + conduit::utils::remove_path_if_exists("ascent_log_output_rank_00001.yaml"); + conduit::utils::remove_path_if_exists(log_base + "_a_00.yaml"); + conduit::utils::remove_path_if_exists(log_base + "_a_01.yaml"); + conduit::utils::remove_path_if_exists(log_base + "_b_00.yaml"); + conduit::utils::remove_path_if_exists(log_base + "_c_01.yaml"); + } + + Ascent ascent; + // case 0 + Node ascent_opts; + ascent_opts["mpi_comm"] = MPI_Comm_c2f(comm); + ascent_opts["logging"] = "true"; + ascent.open(ascent_opts); + ascent.close(); + + // case a + ascent_opts.reset(); + ascent_opts["mpi_comm"] = MPI_Comm_c2f(comm); + ascent_opts["logging/file_pattern"] = log_base + "_a_{rank:02d}.yaml"; + ascent.open(ascent_opts); + ascent.close(); + + // case b + ascent_opts.reset(); + ascent_opts["mpi_comm"] = MPI_Comm_c2f(comm); + ascent_opts["logging/file_pattern"] = log_base + "_b_{rank:02d}.yaml"; + ascent_opts["logging/ranks"] = "root"; + ascent.open(ascent_opts); + ascent.close(); + + // case c + ascent_opts.reset(); + ascent_opts["mpi_comm"] = MPI_Comm_c2f(comm); + ascent_opts["logging/file_pattern"] = log_base + "_c_{rank:02d}.yaml"; + ascent_opts["logging/ranks"] =1; + ascent.open(ascent_opts); + ascent.close(); + + MPI_Barrier(comm); + EXPECT_TRUE(conduit::utils::is_file("ascent_log_output_rank_00000.yaml")); + EXPECT_TRUE(conduit::utils::is_file("ascent_log_output_rank_00001.yaml")); + EXPECT_TRUE(conduit::utils::is_file(log_base + "_a_00.yaml")); + EXPECT_TRUE(conduit::utils::is_file(log_base + "_a_01.yaml")); + EXPECT_TRUE(conduit::utils::is_file(log_base + "_b_00.yaml")); + EXPECT_TRUE(conduit::utils::is_file(log_base + "_c_01.yaml")); +} + //----------------------------------------------------------------------------- int main(int argc, char* argv[]) diff --git a/src/tests/logging/CMakeLists.txt b/src/tests/logging/CMakeLists.txt new file mode 100644 index 000000000..5ac0b6a22 --- /dev/null +++ b/src/tests/logging/CMakeLists.txt @@ -0,0 +1,27 @@ +############################################################################### +# Copyright (c) Lawrence Livermore National Security, LLC and other Ascent +# Project developers. See top-level LICENSE AND COPYRIGHT files for dates and +# other details. No copyright assignment is required to contribute to Ascent. +############################################################################### + + +################################ +# Unit Tests +################################ +set(BASIC_TESTS t_ascent_logger_basic) +# set(MPI_TESTS t_ascent_logger_mpi) + + +message(STATUS "Adding logger unit tests") +foreach(TEST ${BASIC_TESTS}) + message(STATUS "adding test ${TEST}") + add_cpp_test(TEST ${TEST} DEPENDS_ON ascent_logging) +endforeach() + +# if(MPI_FOUND) +# message(STATUS "Adding logger mpi unit tests") +# foreach(TEST ${MPI_TESTS}) +# message(STATUS "adding MPI test ${TEST}") +# add_cpp_mpi_test(TEST ${TEST} NUM_MPI_TASKS 2 DEPENDS_ON ascent_logging) +# endforeach() +# endif() diff --git a/src/tests/logging/t_ascent_logger_basic.cpp b/src/tests/logging/t_ascent_logger_basic.cpp new file mode 100644 index 000000000..6baa9d665 --- /dev/null +++ b/src/tests/logging/t_ascent_logger_basic.cpp @@ -0,0 +1,235 @@ +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// +// Copyright (c) Lawrence Livermore National Security, LLC and other Ascent +// Project developers. See top-level LICENSE AND COPYRIGHT files for dates and +// other details. No copyright assignment is required to contribute to Ascent. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// + +//----------------------------------------------------------------------------- +/// +/// file: t_ascent_logger_basic.cpp +/// +//----------------------------------------------------------------------------- + +#include "gtest/gtest.h" + +#include + +#include +#include + +#include "t_config.hpp" + +using namespace std; +using namespace conduit; +using namespace ascent; + + +//----------------------------------------------------------------------------- +void my_func_nest_2() +{ + ASCENT_MARK_FUNCTION(); + ASCENT_LOG_INFO("nest 2"); +} + +//----------------------------------------------------------------------------- +void my_func_nest_1() +{ + ASCENT_MARK_FUNCTION(); + ASCENT_LOG_INFO("nest 1"); + my_func_nest_2(); +} + +//----------------------------------------------------------------------------- +void my_func_nest_0() +{ + ASCENT_MARK_FUNCTION(); + ASCENT_LOG_INFO("nest 0"); + my_func_nest_1(); +} + +//----------------------------------------------------------------------------- +void myfunc() +{ + ASCENT_MARK_FUNCTION(); + ASCENT_LOG_INFO("I am here!"); +} + +//----------------------------------------------------------------------------- +TEST(ascent_logging, basic_logging) +{ + // remove file if it exists + std::string lfname = "tout_logging_log_1.yaml"; + conduit::utils::remove_path_if_exists(lfname); + ASCENT_LOG_OPEN(lfname); + // top level entry count + ASCENT_LOG_DEBUG("my debug!"); + ASCENT_LOG_INFO("my info!"); // msg (1) + ASCENT_LOG_WARN("my warning!"); // msg (2) + ASCENT_MARK_BEGIN("blocky"); // block (3) + ASCENT_LOG_INFO("my info!"); + ASCENT_LOG_WARN("my warning!"); + ASCENT_MARK_END("blocky"); + myfunc(); // myfunc (4) + + ASCENT_MARK_BEGIN("blocky"); // block (5) + myfunc(); + ASCENT_MARK_END("blocky"); + + ASCENT_MARK_BEGIN("blocky"); // block (6) + my_func_nest_0(); + ASCENT_MARK_END("blocky"); + ASCENT_LOG_CLOSE(); + + conduit::Node n; + n.load(lfname); + n.print(); + // 7 messages at root level + EXPECT_EQ(n.number_of_children(),6); +} + +//----------------------------------------------------------------------------- +TEST(ascent_logging, basic_logging_echo) +{ + // remove file if it exists + std::string lfname = "tout_logging_log_2.yaml"; + conduit::utils::remove_path_if_exists(lfname); + ascent::Logger::instance().set_echo_threshold(ascent::Logger::LOG_ALL_ID); + std::cout << "[echoed]" << std::endl; + ASCENT_LOG_OPEN(lfname); + ASCENT_LOG_DEBUG("my debug!"); + ASCENT_LOG_INFO("my info!"); + ASCENT_LOG_WARN("my warning!"); + ASCENT_LOG_CLOSE(); + + std::cout << "[loaded]" << std::endl; + conduit::Node n; + n.load(lfname); + n.print(); + // we should have 2 msgs above debug + EXPECT_EQ(n.number_of_children(),2); +} + +//----------------------------------------------------------------------------- +TEST(ascent_logging, basic_logging_threshold) +{ + // remove file if it exists + std::string lfname = "tout_logging_log_3.yaml"; + conduit::utils::remove_path_if_exists(lfname); + ASCENT_LOG_OPEN(lfname); + ASCENT_LOG_INFO("my info!"); + ascent::Logger::instance().set_log_threshold(ascent::Logger::LOG_NONE_ID); + ASCENT_LOG_WARN("my warning!"); + ASCENT_LOG_CLOSE(); + + std::cout << "[loaded]" << std::endl; + conduit::Node n; + n.load(lfname); + n.print(); + // we should have 1 msg above debug + EXPECT_EQ(n.number_of_children(),1); +} + +//----------------------------------------------------------------------------- +TEST(ascent_logging, basic_logging_error) +{ + bool error_occured = false; + try + { + ASCENT_LOG_ERROR("my error!"); + } + catch (conduit::Error &error) + { + std::cout << error.what() << std::endl; + error_occured = true; + } + EXPECT_TRUE(error_occured); + + // now check error inside log file + // remove file if it exists + std::string lfname = "tout_logging_log_4.yaml"; + conduit::utils::remove_path_if_exists(lfname); + ASCENT_LOG_OPEN(lfname); + + error_occured = false; + try + { + ASCENT_LOG_ERROR("my error!"); + } + catch (conduit::Error &error) + { + std::cout << error.what() << std::endl; + error_occured = true; + } + EXPECT_TRUE(error_occured); + + ASCENT_LOG_CLOSE(); + std::cout << "[loaded]" << std::endl; + conduit::Node n; + n.load(lfname); + n.print(); + // we should have 1 msg above debug + EXPECT_EQ(n.number_of_children(),1); +} + +//----------------------------------------------------------------------------- +TEST(ascent_logging, basic_logging_append) +{ + // remove file if it exists + std::string lfname = "tout_logging_log_5.yaml"; + conduit::utils::remove_path_if_exists(lfname); + ascent::Logger::instance().set_log_threshold(ascent::Logger::LOG_ALL_ID); + ASCENT_LOG_OPEN(lfname); + ASCENT_LOG_INFO("my debug 1!"); + ASCENT_LOG_INFO("my info 1!"); + ASCENT_LOG_WARN("my warning 1!"); + ASCENT_LOG_CLOSE(); + + ascent::Logger::instance().set_log_threshold(ascent::Logger::LOG_ALL_ID); + ASCENT_LOG_OPEN(lfname); + ASCENT_LOG_INFO("my debug 2!"); + ASCENT_LOG_INFO("my info 2!"); + ASCENT_LOG_WARN("my warning 2!"); + ASCENT_LOG_CLOSE(); + + std::cout << "[loaded]" << std::endl; + conduit::Node n; + n.load(lfname); + n.print(); + // we should have 5 * 2 (open, close, + 1 debug, + 1 info, + 1 warn) + EXPECT_EQ(n.number_of_children(),10); +} + + +//----------------------------------------------------------------------------- +TEST(ascent_logging, basic_logging_error_bad_log_file) +{ + bool error_occured = false; + try + { + ASCENT_LOG_OPEN("/blargh/totally/bogus/des/path/to/log/file.yaml"); + } + catch (conduit::Error &error) + { + std::cout << error.what() << std::endl; + error_occured = true; + } + EXPECT_TRUE(error_occured); + + // remove file if it exists + std::string lfname = "tout_logging_log_6.yaml"; + conduit::utils::remove_path_if_exists(lfname); + error_occured =false; + try + { + // double open should throw an exception + ASCENT_LOG_OPEN(lfname); + ASCENT_LOG_OPEN(lfname); + } + catch (conduit::Error &error) + { + std::cout << error.what() << std::endl; + error_occured = true; + } + EXPECT_TRUE(error_occured); + ASCENT_LOG_CLOSE(); +}