diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 4ce11b830b..3d121d7357 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -569,6 +569,12 @@ target_compile_definitions(cuopt_objs PUBLIC CUSPARSE_ENABLE_EXPERIMENTAL_API ) +# Lets callers reach routing's logger through init_component_logger_t. Routing is optional, +# so the entry point it declares is only linkable when routing was actually built. +if(NOT SKIP_ROUTING_BUILD) + target_compile_definitions(cuopt_objs PUBLIC CUOPT_HAS_ROUTING) +endif() + target_compile_options(cuopt_objs PRIVATE "$<$:${CUOPT_CXX_FLAGS}>" "$<$:${CUOPT_CUDA_FLAGS}>" diff --git a/cpp/cuopt_cli.cpp b/cpp/cuopt_cli.cpp index e070425eab..539f9f1321 100644 --- a/cpp/cuopt_cli.cpp +++ b/cpp/cuopt_cli.cpp @@ -100,8 +100,15 @@ int run_single_file(const std::string& file_path, cuopt::mathematical_optimization::io::mps_reader_type_t mps_reader, cuopt::mathematical_optimization::solver_settings_t& settings) { - cuopt::init_logger_t log(settings.get_parameter(CUOPT_LOG_FILE), - settings.get_parameter(CUOPT_LOG_TO_CONSOLE)); + // The solver's logger lives in the solver library and is not reachable from here, so + // configure it through its exported entry point. The CLI then configures its own logger + // for the messages it emits itself; it appends rather than truncates so that it does not + // clear the file the solver has just opened. + const auto log_file = settings.get_parameter(CUOPT_LOG_FILE); + const auto log_console = settings.get_parameter(CUOPT_LOG_TO_CONSOLE); + + cuopt::init_component_logger_t solver_log(log_file, log_console); + cuopt::init_logger_t log(log_file, log_console, /*truncate=*/false); std::string base_filename = file_path.substr(file_path.find_last_of("/\\") + 1); diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt index e8737cf6da..db71f8fa4d 100644 --- a/cpp/src/CMakeLists.txt +++ b/cpp/src/CMakeLists.txt @@ -4,7 +4,6 @@ # cmake-format: on set(UTIL_SRC_FILES ${CMAKE_CURRENT_SOURCE_DIR}/utilities/seed_generator.cu - ${CMAKE_CURRENT_SOURCE_DIR}/utilities/logger.cpp ${CMAKE_CURRENT_SOURCE_DIR}/utilities/version_info.cpp ${CMAKE_CURRENT_SOURCE_DIR}/utilities/timestamp_utils.cpp ${CMAKE_CURRENT_SOURCE_DIR}/utilities/work_unit_scheduler.cpp) diff --git a/cpp/src/math_optimization/CMakeLists.txt b/cpp/src/math_optimization/CMakeLists.txt index efa1600c54..25449bc929 100644 --- a/cpp/src/math_optimization/CMakeLists.txt +++ b/cpp/src/math_optimization/CMakeLists.txt @@ -9,6 +9,7 @@ list(PREPEND ${CMAKE_CURRENT_SOURCE_DIR}/solution_reader.cu ${CMAKE_CURRENT_SOURCE_DIR}/solution_writer.cu ${CMAKE_CURRENT_SOURCE_DIR}/tic_toc.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/logger_entry.cpp ) set(CUOPT_SRC_FILES ${CUOPT_SRC_FILES} diff --git a/cpp/src/math_optimization/logger_entry.cpp b/cpp/src/math_optimization/logger_entry.cpp new file mode 100644 index 0000000000..b1ed0907a7 --- /dev/null +++ b/cpp/src/math_optimization/logger_entry.cpp @@ -0,0 +1,24 @@ +/* clang-format off */ +/* + * SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +/* clang-format on */ + +#include + +/* + * The logger itself is header-only and hidden, so it is private to each component library. + * This translation unit is compiled into cuopt_mathopt only, which is what makes the + * functions below reach mathopt's instance and no other. + */ +namespace cuopt::mathematical_optimization { + +void configure_logging(const std::string& log_file, bool log_to_console, bool truncate) +{ + cuopt::configure_logging_impl(log_file, log_to_console, truncate); +} + +void reset_logging() { cuopt::reset_logging_impl(); } + +} // namespace cuopt::mathematical_optimization diff --git a/cpp/src/routing/CMakeLists.txt b/cpp/src/routing/CMakeLists.txt index 452c4806da..abf11bd6d0 100644 --- a/cpp/src/routing/CMakeLists.txt +++ b/cpp/src/routing/CMakeLists.txt @@ -1,9 +1,10 @@ # cmake-format: off -# SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +# SPDX-FileCopyrightText: Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 # cmake-format: on set(ROUTING_SRC_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/logger_entry.cpp ${CMAKE_CURRENT_SOURCE_DIR}/local_search/compute_insertions.cu ${CMAKE_CURRENT_SOURCE_DIR}/ges/squeeze.cu ${CMAKE_CURRENT_SOURCE_DIR}/local_search/sliding_window.cu diff --git a/cpp/src/routing/logger_entry.cpp b/cpp/src/routing/logger_entry.cpp new file mode 100644 index 0000000000..b284623e1f --- /dev/null +++ b/cpp/src/routing/logger_entry.cpp @@ -0,0 +1,24 @@ +/* clang-format off */ +/* + * SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +/* clang-format on */ + +#include + +/* + * The logger itself is header-only and hidden, so it is private to each component library. + * This translation unit is compiled into cuopt_routing only, which is what makes the + * functions below reach routing's instance and no other. + */ +namespace cuopt::routing { + +void configure_logging(const std::string& log_file, bool log_to_console, bool truncate) +{ + cuopt::configure_logging_impl(log_file, log_to_console, truncate); +} + +void reset_logging() { cuopt::reset_logging_impl(); } + +} // namespace cuopt::routing diff --git a/cpp/src/routing/solve.cu b/cpp/src/routing/solve.cu index a7caf88ad9..89c6ed2c59 100644 --- a/cpp/src/routing/solve.cu +++ b/cpp/src/routing/solve.cu @@ -16,6 +16,10 @@ template assignment_t solve(data_model_view_t const& data_model, solver_settings_t const& settings) { + // Routing's logger is private to cuopt_routing and starts out sinking into a buffer, so + // without this the CUOPT_LOG_ERROR calls below are recorded and never emitted anywhere. + init_logger_t log("", settings.get_error_logging_mode()); + try { cuopt::routing::solver_t solver(data_model, settings); return solver.solve(); diff --git a/cpp/src/utilities/logger.cpp b/cpp/src/utilities/logger.cpp deleted file mode 100644 index 217f9c64cb..0000000000 --- a/cpp/src/utilities/logger.cpp +++ /dev/null @@ -1,191 +0,0 @@ -/* clang-format off */ -/* - * SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - */ -/* clang-format on */ - -#include -#include - -namespace cuopt { - -struct buffered_entry { - rapids_logger::level_enum level; - std::string msg; -}; - -// Buffer to store log messages -class log_buffer { - public: - log_buffer() = default; - ~log_buffer() = default; - - void log(rapids_logger::level_enum lvl, const char* msg) - { - std::lock_guard lock(mutex); - if (!msg) return; - std::string str(msg); - - if (!str.empty() && str.back() == '\n') { str.pop_back(); } - messages.push_back({lvl, std::move(str)}); - } - - size_t size() const - { - std::lock_guard lock(mutex); - return messages.size(); - } - - std::vector drain_all() - { - std::lock_guard lock(mutex); - std::vector out; - out.swap(messages); - return out; - } - - std::vector messages; - mutable std::mutex mutex; -}; - -log_buffer& global_log_buffer() -{ - static log_buffer buffer; - return buffer; -} - -// Callback function for the buffer sink -static void buffer_log_callback(int lvl, const char* msg) -{ - // store level with message; actual filtering happens at logger time - global_log_buffer().log(static_cast(lvl), msg); -} - -/** - * @brief Returns the default sink for the global logger. - * - * If the environment variable `CUOPT_DEBUG_LOG_FILE` is defined, the default sink is a sink to that - * file. Otherwise, the default is to dump to stderr. - * - * @return sink_ptr The sink to use - */ -rapids_logger::sink_ptr default_sink() -{ - return std::make_shared(buffer_log_callback); -} - -/** - * @brief Returns the default log pattern for the global logger. - * - * @return std::string The default log pattern. - */ -inline std::string default_pattern() { return "[%Y-%m-%d %H:%M:%S:%f] [%n] [%-6l] %v"; } - -/** - * @brief Returns the default log level for the global logger. - * - * @return rapids_logger::level_enum The default log level. - */ -inline rapids_logger::level_enum default_level() -{ -#if CUOPT_LOG_ACTIVE_LEVEL == RAPIDS_LOGGER_LOG_LEVEL_TRACE - return rapids_logger::level_enum::trace; -#elif CUOPT_LOG_ACTIVE_LEVEL == RAPIDS_LOGGER_LOG_LEVEL_DEBUG - return rapids_logger::level_enum::debug; -#elif CUOPT_LOG_ACTIVE_LEVEL == RAPIDS_LOGGER_LOG_LEVEL_INFO - return rapids_logger::level_enum::info; -#elif CUOPT_LOG_ACTIVE_LEVEL == RAPIDS_LOGGER_LOG_LEVEL_WARN - return rapids_logger::level_enum::warn; -#elif CUOPT_LOG_ACTIVE_LEVEL == RAPIDS_LOGGER_LOG_LEVEL_ERROR - return rapids_logger::level_enum::error; -#elif CUOPT_LOG_ACTIVE_LEVEL == RAPIDS_LOGGER_LOG_LEVEL_CRITICAL - return rapids_logger::level_enum::critical; -#else - return rapids_logger::level_enum::info; -#endif -} - -rapids_logger::logger& default_logger() -{ - static rapids_logger::logger logger_ = [] { - rapids_logger::logger logger_{"CUOPT", {default_sink()}}; -#if CUOPT_LOG_ACTIVE_LEVEL >= RAPIDS_LOGGER_LOG_LEVEL_INFO - logger_.set_pattern("%v"); -#else - logger_.set_pattern(default_pattern()); -#endif - logger_.set_level(default_level()); - logger_.flush_on(rapids_logger::level_enum::debug); - - return logger_; - }(); - - return logger_; -} - -void reset_default_logger() -{ - default_logger().sinks().clear(); - default_logger().sinks().push_back(default_sink()); -#if CUOPT_LOG_ACTIVE_LEVEL >= RAPIDS_LOGGER_LOG_LEVEL_INFO - default_logger().set_pattern("%v"); -#else - default_logger().set_pattern(default_pattern()); -#endif - default_logger().set_level(default_level()); - default_logger().flush_on(rapids_logger::level_enum::debug); -} - -// Guard object whose destructor resets the logger -struct logger_config_guard { - ~logger_config_guard() { cuopt::reset_default_logger(); } -}; - -// Weak reference to detect if any init_logger_t instance is still alive -static std::weak_ptr g_active_guard; -static std::mutex g_guard_mutex; - -init_logger_t::init_logger_t(std::string log_file, bool log_to_console) -{ - std::lock_guard lock(g_guard_mutex); - - auto existing_guard = g_active_guard.lock(); - if (existing_guard) { - // Reuse existing configuration, just hold a reference to keep it alive - guard_ = existing_guard; - return; - } - - cuopt::default_logger().sinks().clear(); - - // re-initialize sinks - if (log_to_console) { - cuopt::default_logger().sinks().push_back( - std::make_shared(std::cout)); - } - if (!log_file.empty()) { - cuopt::default_logger().sinks().push_back( - std::make_shared(log_file, true)); - cuopt::default_logger().flush_on(rapids_logger::level_enum::debug); - } - -#if CUOPT_LOG_ACTIVE_LEVEL >= RAPIDS_LOGGER_LOG_LEVEL_INFO - cuopt::default_logger().set_pattern("%v"); -#else - cuopt::default_logger().set_pattern(cuopt::default_pattern()); -#endif - - // Extract messages from the global buffer and log to the default logger - auto buffered_messages = global_log_buffer().drain_all(); - for (const auto& entry : buffered_messages) { - cuopt::default_logger().log(entry.level, entry.msg.c_str()); - } - - // Create guard and store weak reference for future instances to find - auto guard = std::make_shared(); - g_active_guard = guard; - guard_ = guard; -} - -} // namespace cuopt diff --git a/cpp/src/utilities/logger.hpp b/cpp/src/utilities/logger.hpp index 2f9053b05f..bdc9564319 100644 --- a/cpp/src/utilities/logger.hpp +++ b/cpp/src/utilities/logger.hpp @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -22,32 +23,352 @@ #include #include -namespace CUOPT_EXPORT cuopt { +/* + * The logger and its buffer are defined inline and with hidden visibility, so each library + * that links this header owns its own. cuOpt ships as separate solver libraries and + * rapids_logger provides the logger type rather than a shared instance, so there is no + * single place to host one without a library existing purely to hold it. Each solver + * configures its own logging through its own settings. + * + * Hidden visibility is what does the separating, and it is not optional. The static local + * of an inline function is emitted as an STB_GNU_UNIQUE symbol, which glibc merges across + * the whole process regardless of RTLD_LOCAL, so a header-only logger with default + * visibility would still be one shared instance. Do not mark this namespace CUOPT_EXPORT. + * + * Callers outside the libraries cannot reach a hidden logger, so each component exports a + * configure entry point instead -- see log_target_t and init_component_logger_t below. + */ +namespace cuopt { + +struct buffered_entry { + rapids_logger::level_enum level; + std::string msg; +}; + +// Buffer to store log messages +class log_buffer { + public: + log_buffer() = default; + ~log_buffer() = default; + + void log(rapids_logger::level_enum lvl, const char* msg) + { + std::lock_guard lock(mutex); + if (!msg) return; + std::string str(msg); + + if (!str.empty() && str.back() == '\n') { str.pop_back(); } + messages.push_back({lvl, std::move(str)}); + } + + size_t size() const + { + std::lock_guard lock(mutex); + return messages.size(); + } + + std::vector drain_all() + { + std::lock_guard lock(mutex); + std::vector out; + out.swap(messages); + return out; + } + + std::vector messages; + mutable std::mutex mutex; +}; + +inline log_buffer& global_log_buffer() +{ + static log_buffer buffer; + return buffer; +} + +// Callback function for the buffer sink +inline void buffer_log_callback(int lvl, const char* msg) +{ + // store level with message; actual filtering happens at logger time + global_log_buffer().log(static_cast(lvl), msg); +} /** - * @brief Get the default logger. + * @brief Returns the default sink for the global logger. + * + * If the environment variable `CUOPT_DEBUG_LOG_FILE` is defined, the default sink is a sink to that + * file. Otherwise, the default is to dump to stderr. * - * @return logger& The default logger + * @return sink_ptr The sink to use */ -rapids_logger::logger& default_logger(); +inline rapids_logger::sink_ptr default_sink() +{ + return std::make_shared(buffer_log_callback); +} /** - * @brief Reset the default logger to the default settings. - * This is needed when we are running multiple tests and each test has different logger settings - * and we need to reset the logger to the default settings before each test. + * @brief Returns the default log pattern for the global logger. + * + * @return std::string The default log pattern. */ -void reset_default_logger(); +inline std::string default_pattern() { return "[%Y-%m-%d %H:%M:%S:%f] [%n] [%-6l] %v"; } + +/** + * @brief Returns the default log level for the global logger. + * + * @return rapids_logger::level_enum The default log level. + */ +inline rapids_logger::level_enum default_level() +{ +#if CUOPT_LOG_ACTIVE_LEVEL == RAPIDS_LOGGER_LOG_LEVEL_TRACE + return rapids_logger::level_enum::trace; +#elif CUOPT_LOG_ACTIVE_LEVEL == RAPIDS_LOGGER_LOG_LEVEL_DEBUG + return rapids_logger::level_enum::debug; +#elif CUOPT_LOG_ACTIVE_LEVEL == RAPIDS_LOGGER_LOG_LEVEL_INFO + return rapids_logger::level_enum::info; +#elif CUOPT_LOG_ACTIVE_LEVEL == RAPIDS_LOGGER_LOG_LEVEL_WARN + return rapids_logger::level_enum::warn; +#elif CUOPT_LOG_ACTIVE_LEVEL == RAPIDS_LOGGER_LOG_LEVEL_ERROR + return rapids_logger::level_enum::error; +#elif CUOPT_LOG_ACTIVE_LEVEL == RAPIDS_LOGGER_LOG_LEVEL_CRITICAL + return rapids_logger::level_enum::critical; +#else + return rapids_logger::level_enum::info; +#endif +} + +inline rapids_logger::logger& default_logger() +{ + static rapids_logger::logger logger_ = [] { + rapids_logger::logger logger_{"CUOPT", {default_sink()}}; +#if CUOPT_LOG_ACTIVE_LEVEL >= RAPIDS_LOGGER_LOG_LEVEL_INFO + logger_.set_pattern("%v"); +#else + logger_.set_pattern(default_pattern()); +#endif + logger_.set_level(default_level()); + logger_.flush_on(rapids_logger::level_enum::debug); + + return logger_; + }(); + + return logger_; +} + +inline void reset_default_logger() +{ + default_logger().sinks().clear(); + default_logger().sinks().push_back(default_sink()); +#if CUOPT_LOG_ACTIVE_LEVEL >= RAPIDS_LOGGER_LOG_LEVEL_INFO + default_logger().set_pattern("%v"); +#else + default_logger().set_pattern(default_pattern()); +#endif + default_logger().set_level(default_level()); + default_logger().flush_on(rapids_logger::level_enum::debug); +} + +/** + * @brief Point this image's logger at the given sinks and flush anything buffered so far. + * + * @param log_file File to log to, or empty for none. + * @param log_to_console Whether to also log to stdout. + * @param truncate Whether opening @p log_file clears it. Pass false when another + * image is already logging to the same path and has truncated it. + */ +inline void apply_logger_config(const std::string& log_file, bool log_to_console, bool truncate) +{ + cuopt::default_logger().sinks().clear(); + + // re-initialize sinks + if (log_to_console) { + cuopt::default_logger().sinks().push_back( + std::make_shared(std::cout)); + } + if (!log_file.empty()) { + // Clear the file up front rather than letting the sink truncate. Several loggers in one + // process can share a path -- the CLI has its own and the solver library has another -- + // and a truncating sink writes from offset 0, silently overwriting whatever the other + // one has already appended. Opening every sink in append mode keeps them interleaving. + if (truncate) { std::ofstream(log_file, std::ios::trunc); } + cuopt::default_logger().sinks().push_back( + std::make_shared(log_file, /*truncate=*/false)); + cuopt::default_logger().flush_on(rapids_logger::level_enum::debug); + } + +#if CUOPT_LOG_ACTIVE_LEVEL >= RAPIDS_LOGGER_LOG_LEVEL_INFO + cuopt::default_logger().set_pattern("%v"); +#else + cuopt::default_logger().set_pattern(cuopt::default_pattern()); +#endif + + // Extract messages from the global buffer and log to the default logger + auto buffered_messages = global_log_buffer().drain_all(); + for (const auto& entry : buffered_messages) { + cuopt::default_logger().log(entry.level, entry.msg.c_str()); + } +} -// Ref-counted logger initializer +/** + * @brief Ref-counted initializer for the logger of the image that constructs it. + * + * Library code uses this directly: constructed inside cuopt_routing it configures routing's + * logger, inside cuopt_mathopt it configures mathopt's. Callers outside the libraries get + * their own logger this way and should use init_component_logger_t to reach a library's. + */ class init_logger_t { // Using shared_ptr for ref-counting std::shared_ptr guard_; public: - init_logger_t(std::string log_file, bool log_to_console); + init_logger_t(std::string log_file, bool log_to_console, bool truncate = true); +}; + +// Guard object whose destructor resets the logger +struct logger_config_guard { + ~logger_config_guard() { cuopt::reset_default_logger(); } +}; + +// Weak reference to detect if any init_logger_t instance is still alive +inline std::weak_ptr g_active_guard; +inline std::mutex g_guard_mutex; + +// Holds this library's configuration alive when it was set from outside, since the external +// caller has no object in this image to own it. +inline std::shared_ptr& external_config_guard() +{ + static std::shared_ptr guard; + return guard; +} + +/** + * @brief Body of a component's exported configure entry point. + * + * Takes the same guard that init_logger_t takes, and keeps it alive. Library code that later + * constructs an init_logger_t of its own -- the MIP and PDLP solve paths both do -- then sees + * a live configuration and reuses it. Without that, the solver would reconfigure the logger + * mid-run and, with truncate set, clear a log file the caller had already written to. + */ +inline void configure_logging_impl(const std::string& log_file, bool log_to_console, bool truncate) +{ + std::lock_guard lock(g_guard_mutex); + + apply_logger_config(log_file, log_to_console, truncate); + + auto guard = std::make_shared(); + g_active_guard = guard; + external_config_guard() = guard; +} + +inline void reset_logging_impl() +{ + std::lock_guard lock(g_guard_mutex); + external_config_guard().reset(); +} + +inline init_logger_t::init_logger_t(std::string log_file, bool log_to_console, bool truncate) +{ + std::lock_guard lock(g_guard_mutex); + + auto existing_guard = g_active_guard.lock(); + if (existing_guard) { + // Reuse existing configuration, just hold a reference to keep it alive + guard_ = existing_guard; + return; + } + + apply_logger_config(log_file, log_to_console, truncate); + + // Create guard and store weak reference for future instances to find + auto guard = std::make_shared(); + g_active_guard = guard; + guard_ = guard; +} + +/** + * @brief Which component library's logger to configure. + */ +enum class log_target_t { + mathopt, ///< LP / MILP / QP, in cuopt_mathopt + routing ///< VRP, in cuopt_routing +}; + +} // namespace cuopt + +/* + * Exported per-component entry points. Each is defined in exactly one component library and + * configures that library's own hidden logger. They are the only logging symbols that cross + * a library boundary. + */ +namespace cuopt::mathematical_optimization { +CUOPT_EXPORT void configure_logging(const std::string& log_file, + bool log_to_console, + bool truncate); +CUOPT_EXPORT void reset_logging(); +} // namespace cuopt::mathematical_optimization + +#ifdef CUOPT_HAS_ROUTING +namespace cuopt::routing { +CUOPT_EXPORT void configure_logging(const std::string& log_file, + bool log_to_console, + bool truncate); +CUOPT_EXPORT void reset_logging(); +} // namespace cuopt::routing +#endif + +namespace cuopt { + +/** + * @brief Configures a component library's logger from outside that library. + * + * `init_logger_t` configures the logger of whichever image constructs it, which is what + * library code wants but not what an external caller wants: the CLI, the tests and the + * Python bindings each hold their own logger and need to reach into the solver's. This + * dispatches to the component's exported entry point instead. + * + * Defaults to mathopt because every external caller today is LP or MILP; routing is opted + * into explicitly. + */ +class init_component_logger_t { + log_target_t target_; + + public: + explicit init_component_logger_t(const std::string& log_file, + bool log_to_console, + log_target_t target = log_target_t::mathopt, + bool truncate = true) + : target_(target) + { + switch (target_) { + case log_target_t::routing: +#ifdef CUOPT_HAS_ROUTING + cuopt::routing::configure_logging(log_file, log_to_console, truncate); +#endif + break; + case log_target_t::mathopt: + default: + cuopt::mathematical_optimization::configure_logging(log_file, log_to_console, truncate); + break; + } + } + + ~init_component_logger_t() + { + switch (target_) { + case log_target_t::routing: +#ifdef CUOPT_HAS_ROUTING + cuopt::routing::reset_logging(); +#endif + break; + case log_target_t::mathopt: + default: cuopt::mathematical_optimization::reset_logging(); break; + } + } + + init_component_logger_t(const init_component_logger_t&) = delete; + init_component_logger_t& operator=(const init_component_logger_t&) = delete; }; -} // namespace CUOPT_EXPORT cuopt +} // namespace cuopt namespace cuopt::detail { diff --git a/cpp/tests/dual_simplex/unit_tests/solve.cpp b/cpp/tests/dual_simplex/unit_tests/solve.cpp index 2e44442599..d502ca9292 100644 --- a/cpp/tests/dual_simplex/unit_tests/solve.cpp +++ b/cpp/tests/dual_simplex/unit_tests/solve.cpp @@ -23,7 +23,7 @@ namespace cuopt::mathematical_optimization::simplex::test { TEST(dual_simplex, chess_set) { - cuopt::init_logger_t log("", true); + cuopt::init_component_logger_t log("", true); namespace simplex = cuopt::mathematical_optimization::simplex; raft::handle_t handle{}; simplex::user_problem_t user_problem(&handle); @@ -97,7 +97,7 @@ TEST(dual_simplex, chess_set) TEST(dual_simplex, burglar) { - cuopt::init_logger_t log("", true); + cuopt::init_component_logger_t log("", true); constexpr int num_items = 8; constexpr double max_weight = 102; @@ -173,7 +173,7 @@ TEST(dual_simplex, burglar) TEST(dual_simplex, empty_columns) { - cuopt::init_logger_t log("", true); + cuopt::init_component_logger_t log("", true); // Same as burglar problem above but with an empty column inserted constexpr int num_items = 9; constexpr double max_weight = 102; @@ -262,7 +262,7 @@ TEST(dual_simplex, empty_columns) TEST(dual_simplex, dual_variable_greater_than) { - cuopt::init_logger_t log("", true); + cuopt::init_component_logger_t log("", true); // minimize 3*x0 + 2 * x1 // subject to x0 + x1 >= 1 // x0 + 2x1 >= 3 diff --git a/cpp/tests/dual_simplex/unit_tests/solve_barrier.cu b/cpp/tests/dual_simplex/unit_tests/solve_barrier.cu index 16640c6c60..9f5963acec 100644 --- a/cpp/tests/dual_simplex/unit_tests/solve_barrier.cu +++ b/cpp/tests/dual_simplex/unit_tests/solve_barrier.cu @@ -41,7 +41,7 @@ static void init_handler(const raft::handle_t* handle_ptr) TEST(barrier, chess_set) { - cuopt::init_logger_t log("", true); + cuopt::init_component_logger_t log("", true); namespace simplex = cuopt::mathematical_optimization::simplex; raft::handle_t handle{}; init_handler(&handle); @@ -111,7 +111,7 @@ TEST(barrier, chess_set) TEST(barrier, dual_variable_greater_than) { - cuopt::init_logger_t log("", true); + cuopt::init_component_logger_t log("", true); // minimize 3*x0 + 2 * x1 // subject to x0 + x1 >= 1 // x0 + 2x1 >= 3