From 7a0e172d698583cf3aba141d5e5ade1e6e8dc051 Mon Sep 17 00:00:00 2001 From: billschereriii Date: Wed, 16 Nov 2022 17:05:15 -0600 Subject: [PATCH 01/37] Initial C++ implementation --- include/client.h | 8 +- include/dbnode.h | 2 +- include/logger.h | 175 ++++++++++++++++++++++++++++++++++ include/redisserver.h | 18 ---- include/sr_enums.h | 10 ++ include/srexception.h | 91 +++++++++++++++++- include/utility.h | 62 ++++++++++++ src/c/c_error.cpp | 18 ---- src/cpp/client.cpp | 206 ++++++++++++++++++++++++++++++++++++++-- src/cpp/dataset.cpp | 40 ++++++++ src/cpp/logger.cpp | 144 ++++++++++++++++++++++++++++ src/cpp/redisserver.cpp | 82 ++++------------ src/cpp/threadpool.cpp | 60 +++++------- src/cpp/utility.cpp | 97 +++++++++++++++++++ 14 files changed, 864 insertions(+), 149 deletions(-) create mode 100644 include/logger.h create mode 100644 include/utility.h create mode 100644 src/cpp/logger.cpp create mode 100644 src/cpp/utility.cpp diff --git a/include/client.h b/include/client.h index e93d9f688..8fe583784 100644 --- a/include/client.h +++ b/include/client.h @@ -29,8 +29,8 @@ #ifndef SMARTREDIS_CPP_CLIENT_H #define SMARTREDIS_CPP_CLIENT_H #ifdef __cplusplus -#include "string.h" -#include "stdlib.h" +#include +#include #include #include #include @@ -48,6 +48,7 @@ #include "tensorbase.h" #include "tensor.h" #include "sr_enums.h" +#include "logger.h" ///@file @@ -73,10 +74,11 @@ class Client /*! * \brief Client constructor * \param cluster Flag for if a database cluster is being used + * \param client_id Name to use for this client when logging * \throw SmartRedis::Exception if client connection or * object initialization fails */ - Client(bool cluster); + Client(bool cluster, const std::string& client_id = "anonymous"); /*! * \brief Client copy constructor is not available diff --git a/include/dbnode.h b/include/dbnode.h index f573e4fa4..8bc714393 100644 --- a/include/dbnode.h +++ b/include/dbnode.h @@ -44,7 +44,7 @@ class DBNode; * \brief The DBNode class stores connection and hash slot * information for the database node. */ -class DBNode{ +class DBNode { public: diff --git a/include/logger.h b/include/logger.h new file mode 100644 index 000000000..aad8da018 --- /dev/null +++ b/include/logger.h @@ -0,0 +1,175 @@ +/* + * BSD 2-Clause License + * + * Copyright (c) 2021-2022, Hewlett Packard Enterprise + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SMARTREDIS_LOGGER_H +#define SMARTREDIS_LOGGER_H + +#include +#include +#include "utility.h" +#include "sr_enums.h" + +///@file + +namespace SmartRedis { + +/*! +* \brief The Logger class implements a logging facility for SmartRedis +*/ +class Logger { + + public: + + /*! + * \brief Retrieve the unique Logger instance + * \returns The actual logger instance + */ + static Logger& get_instance() + { + static Logger instance; // instantiated on first acccess + return instance; + } + + /*! + * \brief Set up logging for the current client + * \param _client_id ID to use for the current client + */ + void configure_logging(const std::string& _client_id); + + private: + + /*! + * \brief Logger constructor + */ + Logger() { initialized = false; } + + /*! + * \brief Logger copy constructor unavailable + * \param logger The Logger to copy for construction + */ + Logger(const Logger& logger) = delete; + + /*! + * \brief Logger assignment operator unavailable + * \param logger The Logger to copy for construction + */ + void operator=(const Logger& logger) = delete; + + /*! + * \brief Default Logger destructor + */ + ~Logger() = default; + + public: + + /*! + * \brief Conditionally log data if the logging level is high enough + * \param level Minimum logging level for data to be logged + * \param data Text of data to be logged + */ + void log_data(SRLoggingLevel level, const char* data); + + /*! + * \brief Conditionally log data if the logging level is high enough + * \param level Minimum logging level for data to be logged + * \param data Text of data to be logged + */ + void log_data(SRLoggingLevel level, const std::string& data); + + /*! + * \brief Conditionally log data if the logging level is high enough + * \param level Minimum logging level for data to be logged + * \param data Text of data to be logged + */ + void log_data(SRLoggingLevel level, const std::string_view& data); + + private: + + /*! + * \brief Track whether logging is initialized + */ + bool initialized; + + /*! + * \brief The client ID for this client + */ + std::string client_id; + + /*! + * \brief The file to which to write log data + */ + std::string logfile; + + /*! + * \brief The current logging level + */ + SRLoggingLevel log_level; +}; + +/*! +* \brief The FunctionLogger class logs entry and exit of an API function. +* The intended use is to create an instance of this class on the stack +* inside each API point via the LOG_API_FUNCTION macro, below. +*/ +class FunctionLogger { + public: + /*! + * \brief Logger constructor + * \param function_name The name of the function to track + */ + FunctionLogger(const char* function_name) + : name(function_name) + { + Logger::get_instance().log_data( + LLDebug, "API Function " + name + " called"); + } + + /*! + * \brief Logger destructor + */ + ~FunctionLogger() + { + Logger::get_instance().log_data( + LLDebug, "API Function " + name + " exited"); + } + private: + /*! + * \brief The name of the current function + */ + std::string name; +}; + +/*! +* \brief Instantiate a FunctionLogger for the enclosing API function +*/ +#define LOG_API_FUNCTION() FunctionLogger ___function_logger___(__func__) + + +} //namespace SmartRedis + +#endif //SMARTREDIS_LOGGER_H diff --git a/include/redisserver.h b/include/redisserver.h index a5639b815..c1061f115 100644 --- a/include/redisserver.h +++ b/include/redisserver.h @@ -647,24 +647,6 @@ class RedisServer { */ void _check_ssdb_string(const std::string& env_str); - /*! - * \brief Initialize a variable of type integer from an environment - * variable. If the environment variable is not set, - * the default value is assigned. - * \param value Reference to a integer value which will be assigned - * a default value or environment variable value - * \param env_var std::string of the environment variable name - * \param default_value The default value to assign if the environment - * variable is not set. - * \throw SmartRedis::RuntimeException if environment variable - * retrieval fails, conversion to integer fails, or - * if the value of the environment value contains - * characters other than [0,9] or a negative sign ('-'). - */ - void _init_integer_from_env(int& value, - const std::string& env_var, - const int& default_value); - /*! * \brief This function checks that _connection_timeout, * _connection_interval, _command_timeout, and diff --git a/include/sr_enums.h b/include/sr_enums.h index 62ba98ee8..9705b3fe9 100644 --- a/include/sr_enums.h +++ b/include/sr_enums.h @@ -72,4 +72,14 @@ typedef enum { SRTensorTypeUint16 = 8 // 16-bit unsigned integer tensor type } SRTensorType; +/*! +* \brief Enumeration for logging levels +*/ +typedef enum { + LLInvalid = 0, // Invalid or uninitialized logging level + LLNone = 1, // No logging at all + LLInfo = 2, // Informational logging only + LLDebug = 3 // Verbose logging for debugging purposes +} SRLoggingLevel; + #endif // SMARTREDIS_ENUMS_H diff --git a/include/srexception.h b/include/srexception.h index f782f0d79..7c7ab2b52 100644 --- a/include/srexception.h +++ b/include/srexception.h @@ -89,7 +89,8 @@ class Exception: public std::exception Exception(const char* what_arg, const char* file, int line) : _msg(what_arg), _loc(file + std::string(":") + std::to_string(line)) { - // NOP + Logger::get_instance().log_data( + LLInfo, exception_class() + " at " + _loc + ":" + _msg); } /*! @@ -101,7 +102,8 @@ class Exception: public std::exception Exception(const std::string& what_arg, const char* file, int line) : _msg(what_arg), _loc(file + std::string(":") + std::to_string(line)) { - // NOP + Logger::get_instance().log_data( + LLInfo, exception_class() + " at " + _loc + ":" + _msg); } /*! @@ -155,6 +157,14 @@ class Exception: public std::exception return SRInvalidError; } + /*! + * \brief Get a string representation of the exception class + * \returns Stringified version of the class name + */ + virtual std::string exception_class() { + return std::string("Exception") + } + /*! * \brief Retrieve the message for an exception * \returns String of message data @@ -191,6 +201,19 @@ class Exception: public std::exception class BadAllocException: public Exception { public: + /*! + * \brief BadAllocException constructor with location information + * \param what_arg The message for the exception + * \param file The source file from which the exception was thrown + * \param line The line number from which the exception was thrown + */ + BadAllocException(const std::string& what_arg, const char* file, int line) + : Exception(what_arg, file, line) + { + Logger::get_instance().log_data( + LLInfo, "BadAllocException at " + _loc + ":" + _msg); + } + using Exception::Exception; /*! @@ -200,6 +223,14 @@ class BadAllocException: public Exception SRError to_error_code() const noexcept override { return SRBadAllocError; } + + /*! + * \brief Get a string representation of the exception class + * \returns Stringified version of the class name + */ + virtual std::string exception_class() { + return std::string("BadAllocException") + } }; /*! @@ -223,6 +254,14 @@ class DatabaseException: public Exception SRError to_error_code() const noexcept override { return SRDatabaseError; } + + /*! + * \brief Get a string representation of the exception class + * \returns Stringified version of the class name + */ + virtual std::string exception_class() { + return std::string("DatabaseException") + } }; /*! @@ -246,6 +285,14 @@ class RuntimeException: public Exception SRError to_error_code() const noexcept override { return SRRuntimeError; } + + /*! + * \brief Get a string representation of the exception class + * \returns Stringified version of the class name + */ + virtual std::string exception_class() { + return std::string("RuntimeException") + } }; /*! @@ -269,6 +316,14 @@ class ParameterException: public Exception SRError to_error_code() const noexcept override { return SRParameterError; } + + /*! + * \brief Get a string representation of the exception class + * \returns Stringified version of the class name + */ + virtual std::string exception_class() { + return std::string("ParameterException") + } }; /*! @@ -292,6 +347,14 @@ class TimeoutException: public Exception SRError to_error_code() const noexcept override { return SRTimeoutError; } + + /*! + * \brief Get a string representation of the exception class + * \returns Stringified version of the class name + */ + virtual std::string exception_class() { + return std::string("TimeoutException") + } }; /*! @@ -315,6 +378,14 @@ class InternalException: public Exception SRError to_error_code() const noexcept override { return SRInternalError; } + + /*! + * \brief Get a string representation of the exception class + * \returns Stringified version of the class name + */ + virtual std::string exception_class() { + return std::string("InternalException") + } }; /*! @@ -338,6 +409,14 @@ class KeyException: public Exception SRError to_error_code() const noexcept override { return SRKeyError; } + + /*! + * \brief Get a string representation of the exception class + * \returns Stringified version of the class name + */ + virtual std::string exception_class() { + return std::string("KeyException") + } }; /*! @@ -360,6 +439,14 @@ class TypeException: public Exception SRError to_error_code() const noexcept override { return SRTypeError; } + + /*! + * \brief Get a string representation of the exception class + * \returns Stringified version of the class name + */ + virtual std::string exception_class() { + return std::string("TypeException") + } }; /*! diff --git a/include/utility.h b/include/utility.h new file mode 100644 index 000000000..3e0f5e4fc --- /dev/null +++ b/include/utility.h @@ -0,0 +1,62 @@ +/* + * BSD 2-Clause License + * + * Copyright (c) 2021-2022, Hewlett Packard Enterprise + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SMARTREDIS_UTILITY_H +#define SMARTREDIS_UTILITY_H + +#include +#include +#include "address.h" + +///@file + +namespace SmartRedis { + +/*! +* \brief Initialize an integer from an environment variable +* \param value Receives the value of the environment variable +* \param env_var The name of the environment variable to query +* \param default_value Default if the environment variable is not set +*/ +void get_integer_from_env(int& value, + const std::string& env_var, + int default_value); + +/*! +* \brief Initialize a string from an environment variable +* \param value Receives the value of the environment variable +* \param env_var The name of the environment variable to query +* \param default_value Default if the environment variable is not set +*/ +void get_string_from_env(std::string& value, + const std::string& env_var, + const std::string& default_value); + +} //namespace SmartRedis + +#endif //SMARTREDIS_UTILITY_H diff --git a/src/c/c_error.cpp b/src/c/c_error.cpp index ef1f349a7..af4020c43 100644 --- a/src/c/c_error.cpp +++ b/src/c/c_error.cpp @@ -39,24 +39,6 @@ static Exception __lastError = Exception("no error"); extern "C" void SRSetLastError(const Exception& last_error) { - // Check environment for debug level if we haven't done so yet - static bool __debug_level_verbose = false; - static bool __debug_level_checked = false; - if (!__debug_level_checked) - { - __debug_level_checked = true; - char *dbg_setting = getenv("SMARTREDIS_DEBUG_LEVEL"); - if (dbg_setting != NULL) { - std::string dbgLevel(dbg_setting); - __debug_level_verbose = dbgLevel.compare("VERBOSE") == 0; - } - } - - // Print out the error message if verbose - if (__debug_level_verbose && SRNoError != last_error.to_error_code()) { - printf("%s\n", last_error.what()); - } - // Store the last error __lastError = last_error; } diff --git a/src/cpp/client.cpp b/src/cpp/client.cpp index 9c8ebd276..440468af5 100644 --- a/src/cpp/client.cpp +++ b/src/cpp/client.cpp @@ -29,20 +29,30 @@ #include #include "client.h" #include "srexception.h" +#include "logger.h" +#include "utility.h" using namespace SmartRedis; // Constructor -Client::Client(bool cluster) - : _redis_cluster(cluster ? new RedisCluster() : NULL), - _redis(cluster ? NULL : new Redis()) +Client::Client(bool cluster, const std::string& client_id) { + // Set up logging + Logger& logger = Logger::get_instance(); + logger.configure_logging(client_id); + logger.log_data(LLInfo, "New client created"); + + // Set up Redis server connection // A std::bad_alloc exception on the initializer will be caught // by the call to new for the client + _redis_cluster = (cluster ? new RedisCluster() : NULL); + _redis = (cluster ? NULL : new Redis()); if (cluster) _redis_server = _redis_cluster; else _redis_server = _redis; + + // Initialize key prefixing _set_prefixes_from_env(); _use_tensor_prefix = true; _use_model_prefix = false; @@ -63,11 +73,17 @@ Client::~Client() _redis = NULL; } _redis_server = NULL; + + Logger& logger = Logger::get_instance(); + logger.log_data(LLInfo, "Client destroyed"); } // Put a DataSet object into the database void Client::put_dataset(DataSet& dataset) { + // Track calls to this API function + LOG_API_FUNCTION(); + CommandList cmds; _append_dataset_metadata_commands(cmds, dataset); _append_dataset_tensor_commands(cmds, dataset); @@ -78,6 +94,9 @@ void Client::put_dataset(DataSet& dataset) // Retrieve a DataSet object from the database DataSet Client::get_dataset(const std::string& name) { + // Track calls to this API function + LOG_API_FUNCTION(); + // Get the metadata message and construct DataSet CommandReply reply = _get_dataset_metadata(name); @@ -108,6 +127,9 @@ DataSet Client::get_dataset(const std::string& name) void Client::rename_dataset(const std::string& old_name, const std::string& new_name) { + // Track calls to this API function + LOG_API_FUNCTION(); + copy_dataset(old_name, new_name); delete_dataset(old_name); } @@ -116,6 +138,9 @@ void Client::rename_dataset(const std::string& old_name, void Client::copy_dataset(const std::string& src_name, const std::string& dest_name) { + // Track calls to this API function + LOG_API_FUNCTION(); + // Get the metadata message and construct DataSet CommandReply reply = _get_dataset_metadata(src_name); if (reply.n_elements() == 0) { @@ -149,6 +174,9 @@ void Client::copy_dataset(const std::string& src_name, // All tensors and metdata in the DataSet will be deleted. void Client::delete_dataset(const std::string& name) { + // Track calls to this API function + LOG_API_FUNCTION(); + CommandReply reply = _get_dataset_metadata(name); if (reply.n_elements() == 0) { throw SRRuntimeException("The requested DataSet " + @@ -184,6 +212,9 @@ void Client::put_tensor(const std::string& name, const SRTensorType type, const SRMemoryLayout mem_layout) { + // Track calls to this API function + LOG_API_FUNCTION(); + std::string key = _build_tensor_key(name, false); TensorBase* tensor = NULL; @@ -240,6 +271,9 @@ void Client::get_tensor(const std::string& name, SRTensorType& type, const SRMemoryLayout mem_layout) { + // Track calls to this API function + LOG_API_FUNCTION(); + // Retrieve the TensorBase from the database TensorBase* ptr = _get_tensorbase_obj(name); @@ -263,6 +297,8 @@ void Client::get_tensor(const std::string& name, SRTensorType& type, const SRMemoryLayout mem_layout) { + // Track calls to this API function + LOG_API_FUNCTION(); std::vector dims_vec; get_tensor(name, data, dims_vec, type, mem_layout); @@ -287,6 +323,9 @@ void Client::unpack_tensor(const std::string& name, const SRTensorType type, const SRMemoryLayout mem_layout) { + // Track calls to this API function + LOG_API_FUNCTION(); + if (mem_layout == SRMemLayoutContiguous && dims.size() > 1) { throw SRRuntimeException("The destination memory space "\ "dimension vector should only "\ @@ -405,6 +444,9 @@ void Client::unpack_tensor(const std::string& name, void Client::rename_tensor(const std::string& old_name, const std::string& new_name) { + // Track calls to this API function + LOG_API_FUNCTION(); + std::string old_key = _build_tensor_key(old_name, true); std::string new_key = _build_tensor_key(new_name, false); CommandReply reply = _redis_server->rename_tensor(old_key, new_key); @@ -415,6 +457,9 @@ void Client::rename_tensor(const std::string& old_name, // Delete a tensor from the database void Client::delete_tensor(const std::string& name) { + // Track calls to this API function + LOG_API_FUNCTION(); + std::string key = _build_tensor_key(name, true); CommandReply reply = _redis_server->delete_tensor(key); if (reply.has_error()) @@ -425,6 +470,9 @@ void Client::delete_tensor(const std::string& name) void Client::copy_tensor(const std::string& src_name, const std::string& dest_name) { + // Track calls to this API function + LOG_API_FUNCTION(); + std::string src_key = _build_tensor_key(src_name, true); std::string dest_key = _build_tensor_key(dest_name, false); CommandReply reply = _redis_server->copy_tensor(src_key, dest_key); @@ -443,6 +491,9 @@ void Client::set_model_from_file(const std::string& name, const std::vector& inputs, const std::vector& outputs) { + // Track calls to this API function + LOG_API_FUNCTION(); + if (model_file.size() == 0) { throw SRParameterException("model_file is a required " "parameter of set_model_from_file."); @@ -471,6 +522,9 @@ void Client::set_model_from_file_multigpu(const std::string& name, const std::vector& inputs, const std::vector& outputs) { + // Track calls to this API function + LOG_API_FUNCTION(); + if (model_file.size() == 0) { throw SRParameterException("model_file is a required " "parameter of set_model_from_file_multigpu."); @@ -497,6 +551,9 @@ void Client::set_model(const std::string& name, const std::vector& inputs, const std::vector& outputs) { + // Track calls to this API function + LOG_API_FUNCTION(); + if (name.size() == 0) { throw SRParameterException("name is a required parameter of set_model."); } @@ -551,6 +608,9 @@ void Client::set_model_multigpu(const std::string& name, const std::vector& inputs, const std::vector& outputs) { + // Track calls to this API function + LOG_API_FUNCTION(); + if (name.size() == 0) { throw SRParameterException("name is a required parameter of set_model."); } @@ -596,6 +656,9 @@ void Client::set_model_multigpu(const std::string& name, // Retrieve the model from the database std::string_view Client::get_model(const std::string& name) { + // Track calls to this API function + LOG_API_FUNCTION(); + std::string get_key = _build_model_key(name, true); CommandReply reply = _redis_server->get_model(get_key); if (reply.has_error()) @@ -613,6 +676,9 @@ void Client::set_script_from_file(const std::string& name, const std::string& device, const std::string& script_file) { + // Track calls to this API function + LOG_API_FUNCTION(); + // Read the script from the file std::ifstream fin(script_file); std::ostringstream ostream; @@ -632,6 +698,9 @@ void Client::set_script_from_file_multigpu(const std::string& name, int first_gpu, int num_gpus) { + // Track calls to this API function + LOG_API_FUNCTION(); + // Read the script from the file std::ifstream fin(script_file); std::ostringstream ostream; @@ -649,6 +718,9 @@ void Client::set_script(const std::string& name, const std::string& device, const std::string_view& script) { + // Track calls to this API function + LOG_API_FUNCTION(); + if (device.size() == 0) { throw SRParameterException("device is a required " "parameter of set_script."); @@ -668,6 +740,9 @@ void Client::set_script_multigpu(const std::string& name, int first_gpu, int num_gpus) { + // Track calls to this API function + LOG_API_FUNCTION(); + if (first_gpu < 0) { throw SRParameterException("first_gpu must be a non-negative integer."); } @@ -696,6 +771,9 @@ void Client::run_model(const std::string& name, std::vector inputs, std::vector outputs) { + // Track calls to this API function + LOG_API_FUNCTION(); + std::string key = _build_model_key(name, true); if (_use_tensor_prefix) { @@ -714,6 +792,9 @@ void Client::run_model_multigpu(const std::string& name, int first_gpu, int num_gpus) { + // Track calls to this API function + LOG_API_FUNCTION(); + if (first_gpu < 0) { throw SRParameterException("first_gpu must be a non-negative integer."); } @@ -737,6 +818,9 @@ void Client::run_script(const std::string& name, std::vector inputs, std::vector outputs) { + // Track calls to this API function + LOG_API_FUNCTION(); + std::string key = _build_model_key(name, true); if (_use_tensor_prefix) { @@ -756,6 +840,9 @@ void Client::run_script_multigpu(const std::string& name, int first_gpu, int num_gpus) { + // Track calls to this API function + LOG_API_FUNCTION(); + if (first_gpu < 0) { throw SRParameterException("first_gpu must be a non-negative integer"); } @@ -776,6 +863,9 @@ void Client::run_script_multigpu(const std::string& name, // Delete a model from the database void Client::delete_model(const std::string& name) { + // Track calls to this API function + LOG_API_FUNCTION(); + std::string key = _build_model_key(name, true); CommandReply reply = _redis_server->delete_model(key); @@ -787,6 +877,9 @@ void Client::delete_model(const std::string& name) void Client::delete_model_multigpu( const std::string& name, int first_gpu, int num_gpus) { + // Track calls to this API function + LOG_API_FUNCTION(); + if (first_gpu < 0) { throw SRParameterException("first_gpu must be a non-negative integer"); } @@ -801,6 +894,9 @@ void Client::delete_model_multigpu( // Delete a script from the database void Client::delete_script(const std::string& name) { + // Track calls to this API function + LOG_API_FUNCTION(); + std::string key = _build_model_key(name, true); CommandReply reply = _redis_server->delete_script(key); @@ -812,6 +908,9 @@ void Client::delete_script(const std::string& name) void Client::delete_script_multigpu( const std::string& name, int first_gpu, int num_gpus) { + // Track calls to this API function + LOG_API_FUNCTION(); + if (first_gpu < 0) { throw SRParameterException("first_gpu must be a non-negative integer"); } @@ -826,12 +925,18 @@ void Client::delete_script_multigpu( // Check if the key exists in the database bool Client::key_exists(const std::string& key) { + // Track calls to this API function + LOG_API_FUNCTION(); + return _redis_server->key_exists(key); } // Check if the tensor (or the dataset) exists in the database bool Client::tensor_exists(const std::string& name) { + // Track calls to this API function + LOG_API_FUNCTION(); + std::string key = _build_tensor_key(name, true); return _redis_server->key_exists(key); } @@ -839,6 +944,9 @@ bool Client::tensor_exists(const std::string& name) // Check if the dataset exists in the database bool Client::dataset_exists(const std::string& name) { + // Track calls to this API function + LOG_API_FUNCTION(); + std::string key = _build_dataset_ack_key(name, true); return _redis_server->hash_field_exists(key, _DATASET_ACK_FIELD); } @@ -846,6 +954,9 @@ bool Client::dataset_exists(const std::string& name) // Check if the model (or the script) exists in the database bool Client::model_exists(const std::string& name) { + // Track calls to this API function + LOG_API_FUNCTION(); + std::string key = _build_model_key(name, true); return _redis_server->model_key_exists(key); } @@ -855,6 +966,9 @@ bool Client::poll_key(const std::string& key, int poll_frequency_ms, int num_tries) { + // Track calls to this API function + LOG_API_FUNCTION(); + // Check for the key however many times requested for (int i = 0; i < num_tries; i++) { if (key_exists(key)) @@ -871,6 +985,9 @@ bool Client::poll_model(const std::string& name, int poll_frequency_ms, int num_tries) { + // Track calls to this API function + LOG_API_FUNCTION(); + // Check for the model/script however many times requested for (int i = 0; i < num_tries; i++) { if (model_exists(name)) @@ -887,6 +1004,9 @@ bool Client::poll_tensor(const std::string& name, int poll_frequency_ms, int num_tries) { + // Track calls to this API function + LOG_API_FUNCTION(); + // Check for the tensor however many times requested for (int i = 0; i < num_tries; i++) { if (tensor_exists(name)) @@ -903,6 +1023,9 @@ bool Client::poll_dataset(const std::string& name, int poll_frequency_ms, int num_tries) { + // Track calls to this API function + LOG_API_FUNCTION(); + // Check for the dataset however many times requested for (int i = 0; i < num_tries; i++) { if (dataset_exists(name)) @@ -917,6 +1040,9 @@ bool Client::poll_dataset(const std::string& name, // Establish a datasource void Client::set_data_source(std::string source_id) { + // Track calls to this API function + LOG_API_FUNCTION(); + // Validate the source prefix bool valid_prefix = false; size_t num_prefix = _get_key_prefixes.size(); @@ -948,6 +1074,9 @@ void Client::set_data_source(std::string source_id) // prefix model and script keys. void Client::use_model_ensemble_prefix(bool use_prefix) { + // Track calls to this API function + LOG_API_FUNCTION(); + _use_model_prefix = use_prefix; } @@ -959,6 +1088,9 @@ void Client::use_model_ensemble_prefix(bool use_prefix) // aggregation list keys. void Client::use_list_ensemble_prefix(bool use_prefix) { + // Track calls to this API function + LOG_API_FUNCTION(); + _use_list_prefix = use_prefix; } @@ -972,12 +1104,18 @@ void Client::use_list_ensemble_prefix(bool use_prefix) // environment variables. void Client::use_tensor_ensemble_prefix(bool use_prefix) { + // Track calls to this API function + LOG_API_FUNCTION(); + _use_tensor_prefix = use_prefix; } // Returns information about the given database node parsed_reply_nested_map Client::get_db_node_info(std::string address) { + // Track calls to this API function + LOG_API_FUNCTION(); + // Run an INFO EVERYTHING command to get node info DBInfoCommand cmd; SRAddress db_address(address); @@ -995,6 +1133,9 @@ parsed_reply_nested_map Client::get_db_node_info(std::string address) // Returns the CLUSTER INFO command reply addressed to a single cluster node. parsed_reply_map Client::get_db_cluster_info(std::string address) { + // Track calls to this API function + LOG_API_FUNCTION(); + if (_redis_cluster == NULL) throw SRRuntimeException("Cannot run on non-cluster environment"); @@ -1017,6 +1158,9 @@ parsed_reply_map Client::get_ai_info(const std::string& address, const std::string& key, const bool reset_stat) { + // Track calls to this API function + LOG_API_FUNCTION(); + // Run the command CommandReply reply = _redis_server->get_model_script_ai_info(address, key, reset_stat); @@ -1058,6 +1202,9 @@ parsed_reply_map Client::get_ai_info(const std::string& address, // Delete all the keys of the given database void Client::flush_db(std::string address) { + // Track calls to this API function + LOG_API_FUNCTION(); + AddressAtCommand cmd; SRAddress db_address(address); cmd.set_exec_address(db_address); @@ -1072,6 +1219,9 @@ void Client::flush_db(std::string address) std::unordered_map Client::config_get(std::string expression, std::string address) { + // Track calls to this API function + LOG_API_FUNCTION(); + AddressAtCommand cmd; SRAddress db_address(address); cmd.set_exec_address(db_address); @@ -1094,6 +1244,9 @@ Client::config_get(std::string expression, std::string address) // Reconfigure the server void Client::config_set(std::string config_param, std::string value, std::string address) { + // Track calls to this API function + LOG_API_FUNCTION(); + AddressAtCommand cmd; SRAddress db_address(address); cmd.set_exec_address(db_address); @@ -1106,6 +1259,9 @@ void Client::config_set(std::string config_param, std::string value, std::string void Client::save(std::string address) { + // Track calls to this API function + LOG_API_FUNCTION(); + AddressAtCommand cmd; SRAddress db_address(address); cmd.set_exec_address(db_address); @@ -1120,6 +1276,9 @@ void Client::save(std::string address) void Client::append_to_list(const std::string& list_name, const DataSet& dataset) { + // Track calls to this API function + LOG_API_FUNCTION(); + // Build the list key std::string list_key = _build_list_key(list_name, false); @@ -1140,6 +1299,9 @@ void Client::append_to_list(const std::string& list_name, // Delete an aggregation list void Client::delete_list(const std::string& list_name) { + // Track calls to this API function + LOG_API_FUNCTION(); + // Build the list key std::string list_key = _build_list_key(list_name, true); @@ -1157,6 +1319,9 @@ void Client::delete_list(const std::string& list_name) void Client::copy_list(const std::string& src_name, const std::string& dest_name) { + // Track calls to this API function + LOG_API_FUNCTION(); + // Check for empty string inputs if (src_name.size() == 0) { throw SRParameterException("The src_name parameter cannot "\ @@ -1244,6 +1409,9 @@ void Client::copy_list(const std::string& src_name, void Client::rename_list(const std::string& src_name, const std::string& dest_name) { + // Track calls to this API function + LOG_API_FUNCTION(); + if (src_name.size() == 0) { throw SRParameterException("The src_name parameter cannot "\ "be an empty string."); @@ -1265,6 +1433,9 @@ void Client::rename_list(const std::string& src_name, // Get the length of the list int Client::get_list_length(const std::string& list_name) { + // Track calls to this API function + LOG_API_FUNCTION(); + // Build the list key std::string list_key = _build_list_key(list_name, false); @@ -1297,6 +1468,9 @@ int Client::get_list_length(const std::string& list_name) bool Client::poll_list_length(const std::string& name, int list_length, int poll_frequency_ms, int num_tries) { + // Track calls to this API function + LOG_API_FUNCTION(); + // Enforce positive list length if (list_length < 0) { throw SRParameterException("A positive value for list_length "\ @@ -1311,6 +1485,9 @@ bool Client::poll_list_length(const std::string& name, int list_length, bool Client::poll_list_length_gte(const std::string& name, int list_length, int poll_frequency_ms, int num_tries) { + // Track calls to this API function + LOG_API_FUNCTION(); + // Enforce positive list length if (list_length < 0) { throw SRParameterException("A positive value for list_length "\ @@ -1325,6 +1502,9 @@ bool Client::poll_list_length_gte(const std::string& name, int list_length, bool Client::poll_list_length_lte(const std::string& name, int list_length, int poll_frequency_ms, int num_tries) { + // Track calls to this API function + LOG_API_FUNCTION(); + // Enforce positive list length if (list_length < 0) { throw SRParameterException("A positive value for list_length "\ @@ -1340,6 +1520,9 @@ bool Client::poll_list_length_lte(const std::string& name, int list_length, // Retrieve datasets in aggregation list std::vector Client::get_datasets_from_list(const std::string& list_name) { + // Track calls to this API function + LOG_API_FUNCTION(); + if (list_name.size() == 0) { throw SRParameterException("The list name must have length "\ "greater than zero"); @@ -1353,6 +1536,9 @@ std::vector Client::get_dataset_list_range(const std::string& list_name const int start_index, const int end_index) { + // Track calls to this API function + LOG_API_FUNCTION(); + if (list_name.size() == 0) { throw SRParameterException("The list name must have length "\ "greater than zero"); @@ -1366,16 +1552,18 @@ std::vector Client::get_dataset_list_range(const std::string& list_name void Client::_set_prefixes_from_env() { // Establish set prefix - const char* keyout_p = std::getenv("SSKEYOUT"); - if (keyout_p != NULL) - _put_key_prefix = keyout_p; + std::string put_key_prefix; + get_string_from_env(put_key_prefix, "SSKEYOUT", ""); + if (put_key_prefix.length() > 0) + _put_key_prefix = put_key_prefix; else _put_key_prefix.clear(); // Establish get prefix(es) - char* keyin_p = std::getenv("SSKEYIN"); - if (keyin_p != NULL) { - char* a = keyin_p; + std::string get_key_prefixes; + get_string_from_env(get_key_prefixes, "SSKEYIN", ""); + if (get_key_prefixes.length() > 0) { + char* a = get_key_prefixes.c_str(); char* b = a; char parse_char = ','; while (*b != '\0') { diff --git a/src/cpp/dataset.cpp b/src/cpp/dataset.cpp index b15d06413..51228b61b 100644 --- a/src/cpp/dataset.cpp +++ b/src/cpp/dataset.cpp @@ -29,6 +29,7 @@ #include #include "dataset.h" #include "srexception.h" +#include "logging.h" using namespace SmartRedis; @@ -46,6 +47,9 @@ void DataSet::add_tensor(const std::string& name, const SRTensorType type, SRMemoryLayout mem_layout) { + // Track calls to this API function + LOG_API_FUNCTION(); + _add_to_tensorpack(name, data, dims, type, mem_layout); _metadata.add_string(".tensor_names", name); } @@ -57,6 +61,9 @@ void DataSet::add_meta_scalar(const std::string& name, const void* data, const SRMetaDataType type) { + // Track calls to this API function + LOG_API_FUNCTION(); + _metadata.add_scalar(name, data, type); } @@ -66,6 +73,9 @@ void DataSet::add_meta_scalar(const std::string& name, void DataSet::add_meta_string(const std::string& name, const std::string& data) { + // Track calls to this API function + LOG_API_FUNCTION(); + _metadata.add_string(name, data); } @@ -78,6 +88,9 @@ void DataSet::get_tensor(const std::string& name, SRTensorType& type, SRMemoryLayout mem_layout) { + // Track calls to this API function + LOG_API_FUNCTION(); + // Clone the tensor in the DataSet TensorBase* tensor = _get_tensorbase_obj(name); if (tensor == NULL) { @@ -99,6 +112,9 @@ void DataSet::get_tensor(const std::string& name, SRTensorType& type, SRMemoryLayout mem_layout) { + // Track calls to this API function + LOG_API_FUNCTION(); + std::vector dims_vec; get_tensor(name, data, dims_vec, type, mem_layout); @@ -124,6 +140,9 @@ void DataSet::unpack_tensor(const std::string& name, const SRTensorType type, SRMemoryLayout mem_layout) { + // Track calls to this API function + LOG_API_FUNCTION(); + _enforce_tensor_exists(name); _tensorpack.get_tensor(name)->fill_mem_space(data, dims, mem_layout); } @@ -138,6 +157,9 @@ void DataSet::get_meta_scalars(const std::string& name, size_t& length, SRMetaDataType& type) { + // Track calls to this API function + LOG_API_FUNCTION(); + _metadata.get_scalar_values(name, data, length, type); } @@ -151,24 +173,36 @@ void DataSet::get_meta_strings(const std::string& name, size_t& n_strings, size_t*& lengths) { + // Track calls to this API function + LOG_API_FUNCTION(); + _metadata.get_string_values(name, data, n_strings, lengths); } // Check if the DataSet has a field bool DataSet::has_field(const std::string& field_name) { + // Track calls to this API function + LOG_API_FUNCTION(); + return _metadata.has_field(field_name); } // Clear all entries in a DataSet field. void DataSet::clear_field(const std::string& field_name) { + // Track calls to this API function + LOG_API_FUNCTION(); + _metadata.clear_field(field_name); } // Retrieve the names of the tensors in the DataSet std::vector DataSet::get_tensor_names() { + // Track calls to this API function + LOG_API_FUNCTION(); + if (_metadata.has_field(".tensor_names")) return _metadata.get_string_values(".tensor_names"); else @@ -181,12 +215,18 @@ std::vector DataSet::get_tensor_names() // std::vectorstd::string. std::vector DataSet::get_meta_strings(const std::string& name) { + // Track calls to this API function + LOG_API_FUNCTION(); + return _metadata.get_string_values(name); } // Get the Tensor type of the Tensor SRTensorType DataSet::get_tensor_type(const std::string& name) { + // Track calls to this API function + LOG_API_FUNCTION(); + return _tensorpack.get_tensor(name)->type(); } diff --git a/src/cpp/logger.cpp b/src/cpp/logger.cpp new file mode 100644 index 000000000..2d9d35049 --- /dev/null +++ b/src/cpp/logger.cpp @@ -0,0 +1,144 @@ +/* + * BSD 2-Clause License + * + * Copyright (c) 2021-2022, Hewlett Packard Enterprise + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include "utility.h" +#include "logger.h" +#include "srexception.h" + +using namespace SmartRedis; + +/*! +* \brief Set up logging for the current client +* \param _client_id ID to use for the current client +*/ +void Logger::configure_logging(const std::string& _client_id) +{ + // If we're already initialized, they can set up a client ID + // Useful if they call a Dataset API point before setting up + // a Client object + if (initialized) { + client_id = _client_id; + return; + } + + // Get the logfile + get_string_from_env(logfile, "SS_LOG_FILE", ""); + if (logfile.length() == 0) { + throw SRRuntimeException( + "No file specified for logging"); + } + + // Make sure it can be written to + { // Limit scope of logstream to keep file open for + // minimal time + std::ofstream logstream; + logstream.open(logfile, std::ios_base::app); + if (!logstream.good()) { + throw SRRuntimeException( + "Cannot write to file: " + logfile); + } + } + + // Get the logging level + std::string level; + get_string_from_env(level, "SS_LOG_LEVEL", ""); + if (level.length() == 0) { + throw SRRuntimeException( + "No level specified for logging"); + } + if (level.compare("NONE") == 0) + log_level = LLNone; + else if (level.compare("INFO") == 0) + log_level = LLInfo; + else if (level.compare("DEBUG") == 0) + log_level = LLDebug; + else { + throw SRRuntimeException( + "Unrecognized logging level: " + level); + } + + // Done + initialized = true; +} + +/*! +* \brief Conditionally log data if the logging level is high enough +* \param level Minimum logging level for data to be logged +* \param data Text of data to be logged +*/ +void Logger::log_data(SRLoggingLevel level, const std::string& data) +{ + // If we're not initialized, configure logging as an anonymous + // client. This can happen if a caller invokes a Dataset API point + // without initializing a Client object + if (!initialized) + configure_logging("anonymous"); + + // Silently ignore logging more verbose than requested + if (level > log_level) + return; + + // Get the current timestamp + auto t = std::time(NULL); + auto tm = *std::localtime(&t); + auto timestamp = std::put_time(&tm, "%H-%M-%S"); + + // write the log data + std::ofstream logstream; + logstream.open(logfile, std::ios_base::app); + logstream << client_id << "@" << timestamp << ":" << data; +} + +/*! +* \brief Conditionally log data if the logging level is high enough +* \param level Minimum logging level for data to be logged +* \param data Text of data to be logged +*/ +void Logger::log_data(SRLoggingLevel level, const char* data) +{ + const std::string _data(data); + log_data(level, _data); +} + +/*! +* \brief Conditionally log data if the logging level is high enough +* \param level Minimum logging level for data to be logged +* \param data Text of data to be logged +*/ +void Logger::log_data(SRLoggingLevel level, const std::string_view& data) +{ + const std::string _data(data); + log_data(level, _data); +} diff --git a/src/cpp/redisserver.cpp b/src/cpp/redisserver.cpp index 72430498f..2e09dc398 100644 --- a/src/cpp/redisserver.cpp +++ b/src/cpp/redisserver.cpp @@ -29,6 +29,7 @@ #include #include "redisserver.h" #include "srexception.h" +#include "utility.h" using namespace SmartRedis; @@ -36,16 +37,16 @@ using namespace SmartRedis; RedisServer::RedisServer() : _gen(_rd()) { - _init_integer_from_env(_connection_timeout, _CONN_TIMEOUT_ENV_VAR, - _DEFAULT_CONN_TIMEOUT); - _init_integer_from_env(_connection_interval, _CONN_INTERVAL_ENV_VAR, - _DEFAULT_CONN_INTERVAL); - _init_integer_from_env(_command_timeout, _CMD_TIMEOUT_ENV_VAR, - _DEFAULT_CMD_TIMEOUT); - _init_integer_from_env(_command_interval, _CMD_INTERVAL_ENV_VAR, - _DEFAULT_CMD_INTERVAL); - _init_integer_from_env(_thread_count, _TP_THREAD_COUNT, - _DEFAULT_THREAD_COUNT); + get_integer_from_env(_connection_timeout, _CONN_TIMEOUT_ENV_VAR, + _DEFAULT_CONN_TIMEOUT); + get_integer_from_env(_connection_interval, _CONN_INTERVAL_ENV_VAR, + _DEFAULT_CONN_INTERVAL); + get_integer_from_env(_command_timeout, _CMD_TIMEOUT_ENV_VAR, + _DEFAULT_CMD_TIMEOUT); + get_integer_from_env(_command_interval, _CMD_INTERVAL_ENV_VAR, + _DEFAULT_CMD_INTERVAL); + get_integer_from_env(_thread_count, _TP_THREAD_COUNT, + _DEFAULT_THREAD_COUNT); _check_runtime_variables(); @@ -72,29 +73,29 @@ RedisServer::~RedisServer() SRAddress RedisServer::_get_ssdb() { // Retrieve the environment variable - char* env_char = getenv("SSDB"); - if (env_char == NULL) + std::string db_spec; + get_string_from_env(db_spec, "SSDB", ""); + if (db_spec.length() == 0) throw SRRuntimeException("The environment variable SSDB "\ "must be set to use the client."); - std::string env_str = std::string(env_char); - _check_ssdb_string(env_str); + _check_ssdb_string(db_spec); // Parse the data in it std::vector address_choices; const char delim = ','; size_t i_pos = 0; - size_t j_pos = env_str.find(delim); + size_t j_pos = db_spec.find(delim); while (j_pos != std::string::npos) { - std::string substr = env_str.substr(i_pos, j_pos - i_pos); + std::string substr = db_spec.substr(i_pos, j_pos - i_pos); SRAddress addr_spec(substr); address_choices.push_back(addr_spec); i_pos = j_pos + 1; - j_pos = env_str.find(delim, i_pos); + j_pos = db_spec.find(delim, i_pos); } // Catch the last value that does not have a trailing ',' - if (i_pos < env_str.size()) { - std::string substr = env_str.substr(i_pos, j_pos - i_pos); + if (i_pos < db_spec.size()) { + std::string substr = db_spec.substr(i_pos, j_pos - i_pos); SRAddress addr_spec(substr); address_choices.push_back(addr_spec); } @@ -115,49 +116,6 @@ void RedisServer::_check_ssdb_string(const std::string& env_str) { } } -//Initialize variable of type integer from environment variable -void RedisServer::_init_integer_from_env(int& value, - const std::string& env_var, - const int& default_value) -{ - value = default_value; - - char* env_char = getenv(env_var.c_str()); - - if (env_char != NULL && strlen(env_char) > 0) { - // Enforce that all characters are digits because std::stoi - // will truncate a string like "10xy" to 10. - // We want to guard users from input errors they might have. - char* c = env_char; - while (*c != '\0') { - if (!isdigit(*c) && !(*c == '-' && c == env_char)) { - throw SRParameterException("The value of " + env_var + - " must be a valid number."); - } - c++; - } - - try { - value = std::stoi(env_char); - } - catch (std::invalid_argument& e) { - throw SRParameterException("The value of " + env_var + " could "\ - "not be converted to type integer."); - } - catch (std::out_of_range& e) { - throw SRParameterException("The value of " + env_var + " is too "\ - "large to be stored as an integer "\ - "value."); - } - catch (std::exception& e) { - throw SRInternalException("An unexpected error occurred "\ - "while attempting to convert the "\ - "environment variable " + env_var + - " to an integer."); - } - } -} - // Check that runtime variables are within valid ranges inline void RedisServer::_check_runtime_variables() { diff --git a/src/cpp/threadpool.cpp b/src/cpp/threadpool.cpp index c47c4e287..075039c5a 100644 --- a/src/cpp/threadpool.cpp +++ b/src/cpp/threadpool.cpp @@ -7,16 +7,11 @@ #include "threadpool.h" #include "srexception.h" +#include "logger.h" using namespace SmartRedis; using namespace std::chrono_literals; -// TIME_THREADPOOL -// Enable this flag to display timings for the threadpool activity. -// Currently, this will be to screen, but eventually it will go to -// the SmartRedis log -#undef TIME_THREADPOOL - // Constructor ThreadPool::ThreadPool(unsigned int num_threads) { @@ -30,9 +25,8 @@ ThreadPool::ThreadPool(unsigned int num_threads) // Create worker threads if (num_threads < 1) num_threads = 1; // Force a minimum of 1 thread for (unsigned int i = 0; i < num_threads; i++) { - #ifdef TIME_THREADPOOL - std::cout << "Kicking off thread " + std::to_string(i) << std::endl; - #endif + Logger::get_instance().log_data( + LLDebug, "Kicking off thread " + std::to_string(i)); threads.push_back(std::thread(&ThreadPool::perform_jobs, this, i)); } @@ -58,49 +52,42 @@ void ThreadPool::shutdown() while (!initialization_complete) ; // Spin - #ifdef TIME_THREADPOOL - std::cout << "Shutting down thread pool" << std::endl; - #endif + Logger::get_instance().log_data( + LLDebug, "Shutting down thread pool"); // We're closed for business shutting_down = true; // Wait for worker threads to finish up - #ifdef TIME_THREADPOOL int i = 0; size_t num_threads = threads.size(); - #endif for (std::thread& thr : threads) { cv.notify_all(); // Wake up all the threads - #ifdef TIME_THREADPOOL - std::cout << "Waiting for a thread to terminate (" << std::to_string(i++) << " of " - << std::to_string(num_threads) << ")" << std::endl; - #endif + std::string message = + "Waiting for thread to terminate (" + + std::to_string(i++) + " of " + + std::to_string(num_threads) + ")"; + Logger::get_instance().log_data(LLDebug, message); thr.join(); // Blocks until the thread finishes execution } // Done - #ifdef TIME_THREADPOOL - std::cout << "Shutdown complete" << std::endl; - #endif + Logger::get_instance().log_data(LLDebug, "Shutdown complete"); shutdown_complete = true; } // Worker thread main loop to acquire and perform jobs void ThreadPool::perform_jobs(unsigned int tid) { - #ifdef TIME_THREADPOOL int jobid = 0; - std::cout << "Thread " << std::to_string(tid) << " reporting for duty" << std::endl; - #endif + Logger::get_instance().log_data( + LLDebug, "Thread " + std::to_string(tid) + " reporting for duty"); // Loop forever processing jobs until we get killed std::function job; while (!shutting_down) { - #ifdef TIME_THREADPOOL auto start = std::chrono::steady_clock::now(); - #endif // Get a job, blocking until one appears if none immediately available do { @@ -122,25 +109,26 @@ void ThreadPool::perform_jobs(unsigned int tid) } // End scope and release lock while (!shutting_down); - #ifdef TIME_THREADPOOL auto have_job = std::chrono::steady_clock::now(); - #endif + // Perform the job if (!shutting_down) { job(); - #ifdef TIME_THREADPOOL auto job_done = std::chrono::steady_clock::now(); std::chrono::duration get_job = have_job - start; std::chrono::duration execute_job = job_done - have_job; - std::cout << "Thread " << std::to_string(tid) << " " - << "time to get job " << std::to_string(jobid++) << ": " << get_job.count() << " s; " - << "time to execute job: " << execute_job.count() << " s" << std::endl; - #endif + std::string message = + "Thread " + std::to_string(tid) + + " time to get job " + std::to_string(jobid++) + + ": " + std::to_string(get_job.count()) + " s; " + + "time to execute job: " + + std::to_string(execute_job.count()) + " s"; + Logger::get_instance().log_data(LLDebug, message); } } - #ifdef TIME_THREADPOOL - std::cout << "Thread " << std::to_string(tid) << " shutting down" << std::endl; - #endif + + Logger::get_instance().log_data( + LLDebug, "Thread " + std::to_string(tid) + " shutting down"); } // Submit a job to threadpool for execution diff --git a/src/cpp/utility.cpp b/src/cpp/utility.cpp new file mode 100644 index 000000000..900663d02 --- /dev/null +++ b/src/cpp/utility.cpp @@ -0,0 +1,97 @@ +/* + * BSD 2-Clause License + * + * Copyright (c) 2021-2022, Hewlett Packard Enterprise + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include "utility.h" + +using namespace SmartRedis; + +/*! +* \brief Initialize an integer from an environment variable +* \param value Receives the value of the environment variable +* \param env_var The name of the environment variable to query +* \param default_value Default if the environment variable is not set +*/ +void get_integer_from_env(int& value, + const std::string& env_var, + int default_value) +{ + value = default_value; + + char* env_val = std::getenv(env_var.c_str()); + + if (env_val != NULL && strlen(env_val) > 0) { + // Enforce that all characters are digits because std::stoi + // will truncate a string like "10xy" to 10. + // We want to guard users from input errors they might have. + for (char* c = env_val; *c != '\0'; c++) { + if (!isdigit(*c) && !(*c == '-' && c == env_val)) { + throw SRParameterException("The value of " + env_var + + " must be a valid number."); + } + } + + try { + value = std::stoi(env_val); + } + catch (std::invalid_argument& e) { + throw SRParameterException("The value of " + env_var + " could "\ + "not be converted to type integer."); + } + catch (std::out_of_range& e) { + throw SRParameterException("The value of " + env_var + " is too "\ + "large to be stored as an integer "\ + "value."); + } + catch (std::exception& e) { + throw SRInternalException("An unexpected error occurred "\ + "while attempting to convert the "\ + "environment variable " + env_var + + " to an integer."); + } + } +} + +/*! +* \brief Initialize a string from an environment variable +* \param value Receives the value of the environment variable +* \param env_var The name of the environment variable to query +* \param default_value Default if the environment variable is not set +*/ +void get_string_from_env(std::string& value, + const std::string& env_var, + const std::string& default_value) +{ + value = default_value; + + char* env_val = std::getenv(env_var.c_str()); + + if (env_val != NULL && strlen(env_val) > 0) + value = env_val; +} From 798d305b9e7c65ce73908e7bb8327399e4b31294 Mon Sep 17 00:00:00 2001 From: billschereriii Date: Thu, 17 Nov 2022 14:07:06 -0600 Subject: [PATCH 02/37] Updates from Chris's comments --- include/srexception.h | 12 ------- include/utility.h | 30 +++++++++-------- src/cpp/client.cpp | 4 +-- src/cpp/logger.cpp | 4 +-- src/cpp/redisserver.cpp | 12 +++---- src/cpp/utility.cpp | 71 ++++++++++++++++++++++++++--------------- 6 files changed, 71 insertions(+), 62 deletions(-) diff --git a/include/srexception.h b/include/srexception.h index 7c7ab2b52..477d0e14b 100644 --- a/include/srexception.h +++ b/include/srexception.h @@ -201,18 +201,6 @@ class Exception: public std::exception class BadAllocException: public Exception { public: - /*! - * \brief BadAllocException constructor with location information - * \param what_arg The message for the exception - * \param file The source file from which the exception was thrown - * \param line The line number from which the exception was thrown - */ - BadAllocException(const std::string& what_arg, const char* file, int line) - : Exception(what_arg, file, line) - { - Logger::get_instance().log_data( - LLInfo, "BadAllocException at " + _loc + ":" + _msg); - } using Exception::Exception; diff --git a/include/utility.h b/include/utility.h index 3e0f5e4fc..af7de674c 100644 --- a/include/utility.h +++ b/include/utility.h @@ -38,24 +38,26 @@ namespace SmartRedis { /*! -* \brief Initialize an integer from an environment variable -* \param value Receives the value of the environment variable -* \param env_var The name of the environment variable to query -* \param default_value Default if the environment variable is not set +* \brief Initialize an integer from configuration, such as an +* environment variable +* \param value Receives the configuration value +* \param cfg_key The key to query for the configuration variable +* \param default_value Default if configuration key is not set */ -void get_integer_from_env(int& value, - const std::string& env_var, - int default_value); +void get_config_integer(int& value, + const std::string& cfg_key, + int default_value); /*! -* \brief Initialize a string from an environment variable -* \param value Receives the value of the environment variable -* \param env_var The name of the environment variable to query -* \param default_value Default if the environment variable is not set +* \brief Initialize an string from configuration, such as an +* environment variable +* \param value Receives the configuration value +* \param cfg_key The key to query for the configuration variable +* \param default_value Default if configuration key is not set */ -void get_string_from_env(std::string& value, - const std::string& env_var, - const std::string& default_value); +void get_config_string(std::string& value, + const std::string& cfg_key, + const std::string& default_value); } //namespace SmartRedis diff --git a/src/cpp/client.cpp b/src/cpp/client.cpp index 440468af5..4f9695e36 100644 --- a/src/cpp/client.cpp +++ b/src/cpp/client.cpp @@ -1553,7 +1553,7 @@ void Client::_set_prefixes_from_env() { // Establish set prefix std::string put_key_prefix; - get_string_from_env(put_key_prefix, "SSKEYOUT", ""); + get_config_string(put_key_prefix, "SSKEYOUT", ""); if (put_key_prefix.length() > 0) _put_key_prefix = put_key_prefix; else @@ -1561,7 +1561,7 @@ void Client::_set_prefixes_from_env() // Establish get prefix(es) std::string get_key_prefixes; - get_string_from_env(get_key_prefixes, "SSKEYIN", ""); + get_config_string(get_key_prefixes, "SSKEYIN", ""); if (get_key_prefixes.length() > 0) { char* a = get_key_prefixes.c_str(); char* b = a; diff --git a/src/cpp/logger.cpp b/src/cpp/logger.cpp index 2d9d35049..fa3d46898 100644 --- a/src/cpp/logger.cpp +++ b/src/cpp/logger.cpp @@ -54,7 +54,7 @@ void Logger::configure_logging(const std::string& _client_id) } // Get the logfile - get_string_from_env(logfile, "SS_LOG_FILE", ""); + get_config_string(logfile, "SS_LOG_FILE", ""); if (logfile.length() == 0) { throw SRRuntimeException( "No file specified for logging"); @@ -73,7 +73,7 @@ void Logger::configure_logging(const std::string& _client_id) // Get the logging level std::string level; - get_string_from_env(level, "SS_LOG_LEVEL", ""); + get_config_string(level, "SS_LOG_LEVEL", ""); if (level.length() == 0) { throw SRRuntimeException( "No level specified for logging"); diff --git a/src/cpp/redisserver.cpp b/src/cpp/redisserver.cpp index 2e09dc398..64d28d3e4 100644 --- a/src/cpp/redisserver.cpp +++ b/src/cpp/redisserver.cpp @@ -37,15 +37,15 @@ using namespace SmartRedis; RedisServer::RedisServer() : _gen(_rd()) { - get_integer_from_env(_connection_timeout, _CONN_TIMEOUT_ENV_VAR, + get_config_integer(_connection_timeout, _CONN_TIMEOUT_ENV_VAR, _DEFAULT_CONN_TIMEOUT); - get_integer_from_env(_connection_interval, _CONN_INTERVAL_ENV_VAR, + get_config_integer(_connection_interval, _CONN_INTERVAL_ENV_VAR, _DEFAULT_CONN_INTERVAL); - get_integer_from_env(_command_timeout, _CMD_TIMEOUT_ENV_VAR, + get_config_integer(_command_timeout, _CMD_TIMEOUT_ENV_VAR, _DEFAULT_CMD_TIMEOUT); - get_integer_from_env(_command_interval, _CMD_INTERVAL_ENV_VAR, + get_config_integer(_command_interval, _CMD_INTERVAL_ENV_VAR, _DEFAULT_CMD_INTERVAL); - get_integer_from_env(_thread_count, _TP_THREAD_COUNT, + get_config_integer(_thread_count, _TP_THREAD_COUNT, _DEFAULT_THREAD_COUNT); _check_runtime_variables(); @@ -74,7 +74,7 @@ SRAddress RedisServer::_get_ssdb() { // Retrieve the environment variable std::string db_spec; - get_string_from_env(db_spec, "SSDB", ""); + get_config_string(db_spec, "SSDB", ""); if (db_spec.length() == 0) throw SRRuntimeException("The environment variable SSDB "\ "must be set to use the client."); diff --git a/src/cpp/utility.cpp b/src/cpp/utility.cpp index 900663d02..d8335b5c1 100644 --- a/src/cpp/utility.cpp +++ b/src/cpp/utility.cpp @@ -28,70 +28,89 @@ #include #include +#include +#include +#include +#include "srexception.h" #include "utility.h" +#include "logger.h" using namespace SmartRedis; /*! -* \brief Initialize an integer from an environment variable -* \param value Receives the value of the environment variable -* \param env_var The name of the environment variable to query -* \param default_value Default if the environment variable is not set +* \brief Initialize an integer from configuration, such as an +* environment variable +* \param value Receives the configuration value +* \param cfg_key The key to query for the configuration variable +* \param default_value Default if configuration key is not set */ -void get_integer_from_env(int& value, - const std::string& env_var, - int default_value) +void get_config_integer(int& value, + const std::string& cfg_key, + int default_value) { value = default_value; - char* env_val = std::getenv(env_var.c_str()); + char* cfg_val = std::getenv(cfg_key.c_str()); - if (env_val != NULL && strlen(env_val) > 0) { + if (cfg_val != NULL && std::strlen(cfg_val) > 0) { // Enforce that all characters are digits because std::stoi // will truncate a string like "10xy" to 10. // We want to guard users from input errors they might have. - for (char* c = env_val; *c != '\0'; c++) { - if (!isdigit(*c) && !(*c == '-' && c == env_val)) { - throw SRParameterException("The value of " + env_var + + for (char* c = cfg_val; *c != '\0'; c++) { + if (!isdigit(*c) && !(*c == '-' && c == cfg_val)) { + throw SRParameterException("The value of " + cfg_key + " must be a valid number."); } } try { - value = std::stoi(env_val); + value = std::stoi(cfg_val); } catch (std::invalid_argument& e) { - throw SRParameterException("The value of " + env_var + " could "\ + throw SRParameterException("The value of " + cfg_key + " could "\ "not be converted to type integer."); } catch (std::out_of_range& e) { - throw SRParameterException("The value of " + env_var + " is too "\ + throw SRParameterException("The value of " + cfg_key + " is too "\ "large to be stored as an integer "\ "value."); } catch (std::exception& e) { throw SRInternalException("An unexpected error occurred "\ "while attempting to convert the "\ - "environment variable " + env_var + + "environment variable " + cfg_key + " to an integer."); } } + else { + Logger::get_instance().log_data( + LLDebug, + "Warning: Configuration variable " + cfg_key + " not set" + ); + } } /*! -* \brief Initialize a string from an environment variable -* \param value Receives the value of the environment variable -* \param env_var The name of the environment variable to query -* \param default_value Default if the environment variable is not set +* \brief Initialize an string from configuration, such as an +* environment variable +* \param value Receives the configuration value +* \param cfg_key The key to query for the configuration variable +* \param default_value Default if configuration key is not set */ -void get_string_from_env(std::string& value, - const std::string& env_var, - const std::string& default_value) +void get_config_string(std::string& value, + const std::string& cfg_key, + const std::string& default_value) { value = default_value; - char* env_val = std::getenv(env_var.c_str()); + char* cfg_val = std::getenv(cfg_key.c_str()); - if (env_val != NULL && strlen(env_val) > 0) - value = env_val; + if (cfg_val != NULL && std::strlen(cfg_val) > 0) + value = cfg_val; + else { + Logger::get_instance().log_data( + LLDebug, + "Warning: Configuration variable " + cfg_key + " not set" + ); + } } From 15b17aebed0490d4e76403349ceedb94a783f8d2 Mon Sep 17 00:00:00 2001 From: billschereriii Date: Thu, 17 Nov 2022 17:47:12 -0600 Subject: [PATCH 03/37] 4-client implementation; doc updates --- doc/changelog.rst | 3 +++ doc/runtime.rst | 25 +++++++++++++++++++++++ include/c_client.h | 6 +++++- include/logger.h | 17 ++++++++++++---- include/pyclient.h | 3 ++- include/srexception.h | 6 ++---- src/c/c_client.cpp | 9 +++++--- src/cpp/client.cpp | 3 +-- src/cpp/threadpool.cpp | 17 +++++++--------- src/cpp/utility.cpp | 4 ++-- src/fortran/client.F90 | 26 +++++++++++++++++++----- src/fortran/client/client_interfaces.inc | 11 ++++++---- src/python/module/smartredis/client.py | 6 ++++-- src/python/src/pyclient.cpp | 4 ++-- 14 files changed, 100 insertions(+), 40 deletions(-) diff --git a/doc/changelog.rst b/doc/changelog.rst index f327b4259..9cea71e71 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -15,15 +15,18 @@ Description - This version adds new functionality in the form of support for Unix Domain Sockets. - Fortran client can now be optionally built with the rest of the library - Initial support for dataset conversions, specifically Xarray. +- Added support for logging of client activity. Detailed Notes +- Added client activity and manual logging for developer use (PR281_) - Update library linking instructions and update Fortran tester build process (PR277_) - Added `add_metadata_for_xarray` and `transform_to_xarray` methods in `DatasetConverter` class for initial support with Xarray (PR262_) - Change Dockerfile to use Ubuntu 20.04 LTS image (PR276_) - Implemented support for Unix Domain Sockets, including refactorization of server address code, test cases, and check-in tests. (PR252_) - A new make target `make lib-with-fortran` now compiles the Fortran client and dataset into its own library which applications can link against (PR245_) +.. _PR281: https://github.com/CrayLabs/SmartRedis/pull/281 .. _PR277: https://github.com/CrayLabs/SmartRedis/pull/277 .. _PR262: https://github.com/CrayLabs/SmartRedis/pull/262 .. _PR276: https://github.com/CrayLabs/SmartRedis/pull/276 diff --git a/doc/runtime.rst b/doc/runtime.rst index 37a584c65..38264abea 100644 --- a/doc/runtime.rst +++ b/doc/runtime.rst @@ -42,6 +42,31 @@ location. However, the Python ``Client`` constructor also allows for the database location to be set as an input parameter. In this case, it sets SSDB from the input parameter. +Logging Environment Variables +============================= + +SmartRedis will log events to a file on behalf of a client. There +are two main environment variables that affect logging, ``SR_LOG_FILE`` +and ``SR_LOG_LEVEL``. + +``SR_LOG_FILE`` is the specifier for the location of the file that +receives logging information. Each entry in the file will be prefixed +with a timestamp and the identifier of the client that invoked the logging +message. + +``SR_LOG_LEVEL`` relates to the verbosity of information that wil be logged. +It may be one of three levels: ``NONE`` disables logging altogether. +``INFO`` provides informational logging, such as exception events that +transpire within the SmartRedis library and creation or destruction of a +client object. ``DEBUG`` provides more verbose logging, including information +on the activities of the SmartRedis thread pool and API function entry and exit. +Debug level logging will also log the absence of an expected environment variable, +though this can happen only if the variables to set up logging are in place. + +The runtime impact of log levels NONE or INFO should be minimal on +client performance; however, seting the log level to DEBUG may cause some +degradation. + Ensemble Environment Variables ============================== diff --git a/include/c_client.h b/include/c_client.h index 1e3d8cd23..4ee9af84b 100644 --- a/include/c_client.h +++ b/include/c_client.h @@ -44,9 +44,13 @@ extern "C" { * \brief C-client constructor * \param cluster Flag to indicate if a database cluster is being used * \param new_client Receives the new client +* \param client_id Identifier for the current client +* \param client_id_length Length in characters of the client_id string * \return Returns SRNoError on success or an error code on failure */ -SRError SmartRedisCClient(bool cluster, void **new_client); +SRError SmartRedisCClient( + bool cluster, void **new_client, + const char* client_id, const size_t client_id_length); /*! * \brief C-client destructor diff --git a/include/logger.h b/include/logger.h index aad8da018..c1e64e7d3 100644 --- a/include/logger.h +++ b/include/logger.h @@ -131,6 +131,17 @@ class Logger { SRLoggingLevel log_level; }; +/*! +* \brief Conditionally log data if the logging level is high enough +* \param level Minimum logging level for data to be logged +* \param data Text of data to be logged +*/ +inline void log_data(SRLoggingLevel level, const std::string& data) +{ + Logger::get_instance().log_data(level, data); +} + + /*! * \brief The FunctionLogger class logs entry and exit of an API function. * The intended use is to create an instance of this class on the stack @@ -145,8 +156,7 @@ class FunctionLogger { FunctionLogger(const char* function_name) : name(function_name) { - Logger::get_instance().log_data( - LLDebug, "API Function " + name + " called"); + log_data(LLDebug, "API Function " + name + " called"); } /*! @@ -154,8 +164,7 @@ class FunctionLogger { */ ~FunctionLogger() { - Logger::get_instance().log_data( - LLDebug, "API Function " + name + " exited"); + log_data(LLDebug, "API Function " + name + " exited"); } private: /*! diff --git a/include/pyclient.h b/include/pyclient.h index 18654cb8e..bd91b1a32 100644 --- a/include/pyclient.h +++ b/include/pyclient.h @@ -60,8 +60,9 @@ class PyClient * \brief PyClient constructor * \param cluster Flag to indicate if a database cluster * is being used + * \param client_id Identifier for the current client */ - PyClient(bool cluster); + PyClient(bool cluster, const std::string& client_id = "anonymous"); /*! * \brief PyClient destructor diff --git a/include/srexception.h b/include/srexception.h index 477d0e14b..49ab61d52 100644 --- a/include/srexception.h +++ b/include/srexception.h @@ -89,8 +89,7 @@ class Exception: public std::exception Exception(const char* what_arg, const char* file, int line) : _msg(what_arg), _loc(file + std::string(":") + std::to_string(line)) { - Logger::get_instance().log_data( - LLInfo, exception_class() + " at " + _loc + ":" + _msg); + log_data(LLInfo, exception_class() + " at " + _loc + ":" + _msg); } /*! @@ -102,8 +101,7 @@ class Exception: public std::exception Exception(const std::string& what_arg, const char* file, int line) : _msg(what_arg), _loc(file + std::string(":") + std::to_string(line)) { - Logger::get_instance().log_data( - LLInfo, exception_class() + " at " + _loc + ":" + _msg); + log_data(LLInfo, exception_class() + " at " + _loc + ":" + _msg); } /*! diff --git a/src/c/c_client.cpp b/src/c/c_client.cpp index c5fd68263..fa1c84e53 100644 --- a/src/c/c_client.cpp +++ b/src/c/c_client.cpp @@ -38,14 +38,17 @@ using namespace SmartRedis; // Return a pointer to a new Client. // The caller is responsible for deleting the client via DeleteClient(). extern "C" -SRError SmartRedisCClient(bool cluster, void** new_client) +SRError SmartRedisCClient( + bool cluster, void** new_client, + const char* client_id, const size_t client_id_length) { SRError result = SRNoError; try { // Sanity check params - SR_CHECK_PARAMS(new_client != NULL); + SR_CHECK_PARAMS(new_client != NULL && client_id != NULL); - Client* s = new Client(cluster); + std::string _client_id(client_id, client_id_length); + Client* s = new Client(cluster, _client_id); *new_client = reinterpret_cast(s); } catch (const std::bad_alloc& e) { diff --git a/src/cpp/client.cpp b/src/cpp/client.cpp index 4f9695e36..ac7dfd10b 100644 --- a/src/cpp/client.cpp +++ b/src/cpp/client.cpp @@ -74,8 +74,7 @@ Client::~Client() } _redis_server = NULL; - Logger& logger = Logger::get_instance(); - logger.log_data(LLInfo, "Client destroyed"); + log_data(LLInfo, "Client destroyed"); } // Put a DataSet object into the database diff --git a/src/cpp/threadpool.cpp b/src/cpp/threadpool.cpp index 075039c5a..c7a1299e1 100644 --- a/src/cpp/threadpool.cpp +++ b/src/cpp/threadpool.cpp @@ -25,8 +25,7 @@ ThreadPool::ThreadPool(unsigned int num_threads) // Create worker threads if (num_threads < 1) num_threads = 1; // Force a minimum of 1 thread for (unsigned int i = 0; i < num_threads; i++) { - Logger::get_instance().log_data( - LLDebug, "Kicking off thread " + std::to_string(i)); + log_data(LLDebug, "Kicking off thread " + std::to_string(i)); threads.push_back(std::thread(&ThreadPool::perform_jobs, this, i)); } @@ -52,8 +51,7 @@ void ThreadPool::shutdown() while (!initialization_complete) ; // Spin - Logger::get_instance().log_data( - LLDebug, "Shutting down thread pool"); + log_data(LLDebug, "Shutting down thread pool"); // We're closed for business shutting_down = true; @@ -67,12 +65,12 @@ void ThreadPool::shutdown() "Waiting for thread to terminate (" + std::to_string(i++) + " of " + std::to_string(num_threads) + ")"; - Logger::get_instance().log_data(LLDebug, message); + log_data(LLDebug, message); thr.join(); // Blocks until the thread finishes execution } // Done - Logger::get_instance().log_data(LLDebug, "Shutdown complete"); + log_data(LLDebug, "Shutdown complete"); shutdown_complete = true; } @@ -80,7 +78,7 @@ void ThreadPool::shutdown() void ThreadPool::perform_jobs(unsigned int tid) { int jobid = 0; - Logger::get_instance().log_data( + log_data( LLDebug, "Thread " + std::to_string(tid) + " reporting for duty"); // Loop forever processing jobs until we get killed @@ -123,12 +121,11 @@ void ThreadPool::perform_jobs(unsigned int tid) ": " + std::to_string(get_job.count()) + " s; " + "time to execute job: " + std::to_string(execute_job.count()) + " s"; - Logger::get_instance().log_data(LLDebug, message); + log_data(LLDebug, message); } } - Logger::get_instance().log_data( - LLDebug, "Thread " + std::to_string(tid) + " shutting down"); + log_data(LLDebug, "Thread " + std::to_string(tid) + " shutting down"); } // Submit a job to threadpool for execution diff --git a/src/cpp/utility.cpp b/src/cpp/utility.cpp index d8335b5c1..60b95f337 100644 --- a/src/cpp/utility.cpp +++ b/src/cpp/utility.cpp @@ -83,7 +83,7 @@ void get_config_integer(int& value, } } else { - Logger::get_instance().log_data( + log_data( LLDebug, "Warning: Configuration variable " + cfg_key + " not set" ); @@ -108,7 +108,7 @@ void get_config_string(std::string& value, if (cfg_val != NULL && std::strlen(cfg_val) > 0) value = cfg_val; else { - Logger::get_instance().log_data( + log_data( LLDebug, "Warning: Configuration variable " + cfg_key + " not set" ); diff --git a/src/fortran/client.F90 b/src/fortran/client.F90 index 69d62f283..ebd8d42ac 100644 --- a/src/fortran/client.F90 +++ b/src/fortran/client.F90 @@ -232,14 +232,30 @@ function SR_error_parser(self, response_code) result(is_error) end function SR_error_parser !> Initializes a new instance of a SmartRedis client -function initialize_client(self, cluster) - integer(kind=enum_kind) :: initialize_client - class(client_type), intent(inout) :: self !< Receives the initialized client - logical, optional, intent(in ) :: cluster !< If true, client uses a database cluster (Default: .false.) +function initialize_client(self, cluster, client_id) + integer(kind=enum_kind) :: initialize_client + class(client_type), intent(inout) :: self !< Receives the initialized client + logical, optional, intent(in ) :: cluster !< If true, client uses a database cluster (Default: .false.) + character(len=*), optional, intent(in ) :: client_id !< Identifier for the current client + + ! Local variables + character(kind=c_char, len=:), allocatable :: c_client_id + integer(kind=c_size_t) :: client_id_length + + if (present(client_id)) then + allocate(character(kind=c_char, len=len_trim(client_id)) :: c_client_id) + c_client_id = client_id + client_id_length = len_trim(client_id) + else + allocate(character(kind=c_char, len=10) :: c_client_id) + c_client_id = 'anonymous' + client_id_length = 10 + endif if (present(cluster)) self%cluster = cluster - initialize_client = c_constructor(self%cluster, self%client_ptr) + initialize_client = c_constructor(self%cluster, c_client_id, client_id_length, self%client_ptr) self%is_initialized = initialize_client .eq. SRNoError + if (allocated(c_client_id)) deallocate(c_client_id) end function initialize_client !> Check whether the client has been initialized diff --git a/src/fortran/client/client_interfaces.inc b/src/fortran/client/client_interfaces.inc index 9e7697892..b3462441a 100644 --- a/src/fortran/client/client_interfaces.inc +++ b/src/fortran/client/client_interfaces.inc @@ -25,12 +25,15 @@ ! OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. interface - function c_constructor(cluster, new_client) bind(c, name="SmartRedisCClient") + function c_constructor(cluster, client_id, client_id_length, new_client) bind(c, name="SmartRedisCClient") use iso_c_binding, only : c_ptr, c_bool import :: enum_kind - integer(kind=enum_kind) :: c_constructor - logical(kind=c_bool), value :: cluster !< True if a database cluster is being used - type(c_ptr) :: new_client !< Receives the newly constructed client + integer(kind=enum_kind) :: c_constructor + logical(kind=c_bool), value :: cluster !< True if a database cluster is being used + character(kind=c_char) :: client_id(*) + integer(kind=c_size_t), value :: client_id_length + + type(c_ptr) :: new_client !< Receives the newly constructed client end function c_constructor end interface diff --git a/src/python/module/smartredis/client.py b/src/python/module/smartredis/client.py index 1391eb616..875bba1a1 100644 --- a/src/python/module/smartredis/client.py +++ b/src/python/module/smartredis/client.py @@ -39,7 +39,7 @@ from .smartredisPy import RedisReplyError as PybindRedisReplyError class Client(PyClient): - def __init__(self, address=None, cluster=False): + def __init__(self, address=None, cluster=False, client_id="anonymous"): """Initialize a RedisAI client For clusters, the address can be a single tcp/ip address and port @@ -52,6 +52,8 @@ def __init__(self, address=None, cluster=False): :param address: Address of the database :param cluster: True if connecting to a redis cluster, defaults to False :type cluster: bool, optional + :param client_id: Identifier for the current client + :type client_id: str :raises RedisConnectionError: if connection initialization fails """ if address: @@ -59,7 +61,7 @@ def __init__(self, address=None, cluster=False): if "SSDB" not in os.environ: raise RedisConnectionError("Could not connect to database. $SSDB not set") try: - super().__init__(cluster) + super().__init__(cluster, client_id) except PybindRedisReplyError as e: raise RedisConnectionError(str(e)) from None except RuntimeError as e: diff --git a/src/python/src/pyclient.cpp b/src/python/src/pyclient.cpp index bd971dba8..ad3feed6d 100644 --- a/src/python/src/pyclient.cpp +++ b/src/python/src/pyclient.cpp @@ -35,12 +35,12 @@ using namespace SmartRedis; namespace py = pybind11; -PyClient::PyClient(bool cluster) +PyClient::PyClient(bool cluster, std::string& client_id) { // throw SRRuntimeException("Test"); _client = NULL; try { - _client = new Client(cluster); + _client = new Client(cluster, client_id); } catch (Exception& e) { // exception is already prepared for caller From 6f6a2aa86c2dd3bb3fc2940b5d7facd2230b9946 Mon Sep 17 00:00:00 2001 From: billschereriii Date: Fri, 18 Nov 2022 16:39:57 -0600 Subject: [PATCH 04/37] Address Matt's feedback and eliminate chicken-and-egg logging issues --- include/logger.h | 55 ++++++++++++++++++++---- include/sr_enums.h | 9 ++-- include/srexception.h | 4 +- include/utility.h | 10 ++++- src/cpp/logger.cpp | 98 +++++++++++++++++++++++++++++-------------- src/cpp/utility.cpp | 22 ++++++---- 6 files changed, 144 insertions(+), 54 deletions(-) diff --git a/include/logger.h b/include/logger.h index c1e64e7d3..4ec503930 100644 --- a/include/logger.h +++ b/include/logger.h @@ -51,15 +51,15 @@ class Logger { */ static Logger& get_instance() { - static Logger instance; // instantiated on first acccess - return instance; + static Logger __instance; // instantiated on first acccess + return __instance; } /*! * \brief Set up logging for the current client * \param _client_id ID to use for the current client */ - void configure_logging(const std::string& _client_id); + void configure_logging(const std::string& client_id); private: @@ -108,27 +108,49 @@ class Logger { */ void log_data(SRLoggingLevel level, const std::string_view& data); + /*! + * \brief Conditionally log warning data if the logging level is + * high enough + * \param level Minimum logging level for data to be logged + * \param data Text of data to be logged + */ + void log_warning(SRLoggingLevel level, const std::string& data) + { + log_data(level, "WARNING: " + data); + } + + /*! + * \brief Conditionally log error data if the logging level is + * high enough + * \param level Minimum logging level for data to be logged + * \param data Text of data to be logged + */ + void log_error(SRLoggingLevel level, const std::string& data) + { + log_data(level, "ERROR: " + data); + } + private: /*! * \brief Track whether logging is initialized */ - bool initialized; + bool _initialized; /*! * \brief The client ID for this client */ - std::string client_id; + std::string _client_id; /*! * \brief The file to which to write log data */ - std::string logfile; + std::string _logfile; /*! * \brief The current logging level */ - SRLoggingLevel log_level; + SRLoggingLevel _log_level; }; /*! @@ -141,6 +163,25 @@ inline void log_data(SRLoggingLevel level, const std::string& data) Logger::get_instance().log_data(level, data); } +/*! +* \brief Conditionally log a warning if the logging level is high enough +* \param level Minimum logging level for data to be logged +* \param data Text of data to be logged +*/ +inline void log_warning(SRLoggingLevel level, const std::string& data) +{ + Logger::get_instance().log_warning(level, data); +} + +/*! +* \brief Conditionally log an error if the logging level is high enough +* \param level Minimum logging level for data to be logged +* \param data Text of data to be logged +*/ +inline void log_error(SRLoggingLevel level, const std::string& data) +{ + Logger::get_instance().log_error(level, data); +} /*! * \brief The FunctionLogger class logs entry and exit of an API function. diff --git a/include/sr_enums.h b/include/sr_enums.h index 9705b3fe9..3535a5e82 100644 --- a/include/sr_enums.h +++ b/include/sr_enums.h @@ -76,10 +76,11 @@ typedef enum { * \brief Enumeration for logging levels */ typedef enum { - LLInvalid = 0, // Invalid or uninitialized logging level - LLNone = 1, // No logging at all - LLInfo = 2, // Informational logging only - LLDebug = 3 // Verbose logging for debugging purposes + LLInvalid = 0, // Invalid or uninitialized logging level + LLQuiet = 1, // No logging at all + LLInfo = 2, // Informational logging only + LLDebug = 3, // Verbose logging for debugging purposes + LLDeveloper = 4 // Extra verbose logging for internal use } SRLoggingLevel; #endif // SMARTREDIS_ENUMS_H diff --git a/include/srexception.h b/include/srexception.h index 49ab61d52..8879dc5fe 100644 --- a/include/srexception.h +++ b/include/srexception.h @@ -89,7 +89,7 @@ class Exception: public std::exception Exception(const char* what_arg, const char* file, int line) : _msg(what_arg), _loc(file + std::string(":") + std::to_string(line)) { - log_data(LLInfo, exception_class() + " at " + _loc + ":" + _msg); + log_error(LLInfo, exception_class() + " at " + _loc + ":" + _msg); } /*! @@ -101,7 +101,7 @@ class Exception: public std::exception Exception(const std::string& what_arg, const char* file, int line) : _msg(what_arg), _loc(file + std::string(":") + std::to_string(line)) { - log_data(LLInfo, exception_class() + " at " + _loc + ":" + _msg); + log_error(LLInfo, exception_class() + " at " + _loc + ":" + _msg); } /*! diff --git a/include/utility.h b/include/utility.h index af7de674c..e547f668d 100644 --- a/include/utility.h +++ b/include/utility.h @@ -43,10 +43,13 @@ namespace SmartRedis { * \param value Receives the configuration value * \param cfg_key The key to query for the configuration variable * \param default_value Default if configuration key is not set +* \param suppress_warning Do not issue a warning if the variable +* is not set */ void get_config_integer(int& value, const std::string& cfg_key, - int default_value); + int default_value, + bool suppress_warning = false); /*! * \brief Initialize an string from configuration, such as an @@ -54,10 +57,13 @@ void get_config_integer(int& value, * \param value Receives the configuration value * \param cfg_key The key to query for the configuration variable * \param default_value Default if configuration key is not set +* \param suppress_warning Do not issue a warning if the variable +* is not set */ void get_config_string(std::string& value, const std::string& cfg_key, - const std::string& default_value); + const std::string& default_value, + bool suppress_warning = false); } //namespace SmartRedis diff --git a/src/cpp/logger.cpp b/src/cpp/logger.cpp index fa3d46898..777906a8f 100644 --- a/src/cpp/logger.cpp +++ b/src/cpp/logger.cpp @@ -43,54 +43,85 @@ using namespace SmartRedis; * \brief Set up logging for the current client * \param _client_id ID to use for the current client */ -void Logger::configure_logging(const std::string& _client_id) +void Logger::configure_logging(const std::string& client_id) { // If we're already initialized, they can set up a client ID // Useful if they call a Dataset API point before setting up // a Client object - if (initialized) { - client_id = _client_id; + _client_id = client_id; + if (_initialized) { return; } + _initialized = true; // Get the logfile - get_config_string(logfile, "SS_LOG_FILE", ""); - if (logfile.length() == 0) { - throw SRRuntimeException( - "No file specified for logging"); - } + get_config_string(_logfile, "SS_LOG_FILE", "", true); + std::string requestedLogfile(_logfile); + bool missingLogFile = _logfile.length() == 0; // Make sure it can be written to - { // Limit scope of logstream to keep file open for - // minimal time + bool badLogFile = false; + if (_logfile.length() > 0) { std::ofstream logstream; - logstream.open(logfile, std::ios_base::app); - if (!logstream.good()) { - throw SRRuntimeException( - "Cannot write to file: " + logfile); - } + logstream.open(_logfile, std::ios_base::app); + badLogFile = !logstream.good(); + + // Switch to STDOUT if we can't write to the specified file + if (badLogFile) + _logfile = ""; } // Get the logging level std::string level; - get_config_string(level, "SS_LOG_LEVEL", ""); - if (level.length() == 0) { - throw SRRuntimeException( - "No level specified for logging"); + get_config_string(level, "SS_LOG_LEVEL", "", true); + bool missingLogLevel = level.length() == 0; + bool badLogLevel = false; + if (level.length() > 0) { + if (level.compare("QUIET") == 0) + _log_level = LLQuiet; + else if (level.compare("INFO") == 0) + _log_level = LLInfo; + else if (level.compare("DEBUG") == 0) + _log_level = LLDebug; + else if (level.compare("DEVELOPER") == 0) + _log_level = LLDeveloper; + else { + // Don't recognize the requested level; use default + badLogLevel = true; + _log_level = LLInfo; + } } - if (level.compare("NONE") == 0) - log_level = LLNone; - else if (level.compare("INFO") == 0) - log_level = LLInfo; - else if (level.compare("DEBUG") == 0) - log_level = LLDebug; else { + _log_level = LLInfo; + } + + // Now that everything is configured, issue warning and + // error messages + if (missingLogFile) { + log_warning( + LLInfo, + "Environment variable SS_LOG_FILE is not set. " + "Defaulting to stdout" + ); + } + if (missingLogLevel) { + log_warning( + LLInfo, + "Environment variable SS_LOG_LEVEL is not set. " + "Defaulting to INFO" + ); + } + if (badLogFile) { + throw SRRuntimeException( + "Cannot write to file: " + requestedLogfile); + } + if (badLogLevel) { throw SRRuntimeException( "Unrecognized logging level: " + level); } // Done - initialized = true; + _initialized = true; } /*! @@ -103,11 +134,11 @@ void Logger::log_data(SRLoggingLevel level, const std::string& data) // If we're not initialized, configure logging as an anonymous // client. This can happen if a caller invokes a Dataset API point // without initializing a Client object - if (!initialized) + if (!_initialized) configure_logging("anonymous"); // Silently ignore logging more verbose than requested - if (level > log_level) + if (level > _log_level) return; // Get the current timestamp @@ -116,9 +147,14 @@ void Logger::log_data(SRLoggingLevel level, const std::string& data) auto timestamp = std::put_time(&tm, "%H-%M-%S"); // write the log data - std::ofstream logstream; - logstream.open(logfile, std::ios_base::app); - logstream << client_id << "@" << timestamp << ":" << data; + // (There must be a cleaner way to write this!) + if (_logfile.length() > 0) { + std::ofstream logstream; + logstream.open(_logfile, std::ios_base::app); + logstream << _client_id << "@" << timestamp << ":" << data; + } else { + std::cout << _client_id << "@" << timestamp << ":" << data; + } } /*! diff --git a/src/cpp/utility.cpp b/src/cpp/utility.cpp index 60b95f337..e1a612b4b 100644 --- a/src/cpp/utility.cpp +++ b/src/cpp/utility.cpp @@ -43,10 +43,13 @@ using namespace SmartRedis; * \param value Receives the configuration value * \param cfg_key The key to query for the configuration variable * \param default_value Default if configuration key is not set +* \param suppress_warning Do not issue a warning if the variable +* is not set */ void get_config_integer(int& value, const std::string& cfg_key, - int default_value) + int default_value, + bool suppress_warning /* = false */) { value = default_value; @@ -82,10 +85,10 @@ void get_config_integer(int& value, " to an integer."); } } - else { - log_data( + else if (!suppress_warning) { + log_warning( LLDebug, - "Warning: Configuration variable " + cfg_key + " not set" + "Configuration variable " + cfg_key + " not set" ); } } @@ -96,10 +99,13 @@ void get_config_integer(int& value, * \param value Receives the configuration value * \param cfg_key The key to query for the configuration variable * \param default_value Default if configuration key is not set +* \param suppress_warning Do not issue a warning if the variable +* is not set */ void get_config_string(std::string& value, const std::string& cfg_key, - const std::string& default_value) + const std::string& default_value, + bool suppress_warning /* = false */) { value = default_value; @@ -107,10 +113,10 @@ void get_config_string(std::string& value, if (cfg_val != NULL && std::strlen(cfg_val) > 0) value = cfg_val; - else { - log_data( + else if (!suppress_warning) { + log_warning( LLDebug, - "Warning: Configuration variable " + cfg_key + " not set" + "Configuration variable " + cfg_key + " not set" ); } } From 86b3043851550d5aa46986325f0d6dd9c35345df Mon Sep 17 00:00:00 2001 From: billschereriii Date: Tue, 22 Nov 2022 16:36:08 -0600 Subject: [PATCH 05/37] Fix compile errors --- CMakeLists.txt | 2 + include/logger.h | 57 ++++++++++++++++++++++++++- include/srexception.h | 20 +++++----- include/utility.h | 2 +- src/cpp/client.cpp | 4 +- src/cpp/dataset.cpp | 2 +- src/cpp/logger.cpp | 60 +++++++++++++++++++++++++++++ src/cpp/redis.cpp | 5 ++- src/cpp/rediscluster.cpp | 5 ++- src/cpp/utility.cpp | 2 +- src/python/src/pyclient.cpp | 2 +- tests/cpp/unit-tests/CMakeLists.txt | 2 + 12 files changed, 143 insertions(+), 20 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e59a70a3..9703ed7b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,6 +87,8 @@ set(CLIENT_SRC src/cpp/stringfield.cpp src/cpp/pipelinereply.cpp src/cpp/threadpool.cpp + src/cpp/utility.cpp + src/cpp/logger.cpp ) include_directories(SYSTEM diff --git a/include/logger.h b/include/logger.h index 4ec503930..97cd4cdb8 100644 --- a/include/logger.h +++ b/include/logger.h @@ -36,6 +36,16 @@ ///@file +/* +* Redirect logging functions to exception-free variants for C and Fortran +*/ +#ifndef __cplusplus +#define log_data log_data_noexcept +#define log_warning log_warning_noexcept +#define log_error log_error_noexcept +#endif // __cplusplus + +#ifdef __cplusplus namespace SmartRedis { /*! @@ -66,7 +76,7 @@ class Logger { /*! * \brief Logger constructor */ - Logger() { initialized = false; } + Logger() { _initialized = false; } /*! * \brief Logger copy constructor unavailable @@ -183,6 +193,10 @@ inline void log_error(SRLoggingLevel level, const std::string& data) Logger::get_instance().log_error(level, data); } + +///////////////////////////////////////////////////////// +// Stack-based function logger + /*! * \brief The FunctionLogger class logs entry and exit of an API function. * The intended use is to create an instance of this class on the stack @@ -221,5 +235,46 @@ class FunctionLogger { } //namespace SmartRedis +#endif // __cplusplus + + +///////////////////////////////////////////////////////// +// Prototypes for C and Fortran logging methods + +/*! +* \brief Macro to establish C linkage in both C and C++ +*/ +#ifdef __cplusplus +#define C_API extern "C" +#else +#define C_API +#endif + +/*! +* \brief Conditionally log data if the logging level is high enough +* \param level Minimum logging level for data to be logged +* \param data Text of data to be logged +* \param data_len Length in characters of data to be logged +*/ +C_API void log_data_noexcept( + SRLoggingLevel level, const char* data, size_t data_len); + +/*! +* \brief Conditionally log a warning if the logging level is high enough +* \param level Minimum logging level for data to be logged +* \param data Text of data to be logged +* \param data_len Length in characters of data to be logged +*/ +C_API void log_warning_noexcept( + SRLoggingLevel level, const char* data, size_t data_len); + +/*! +* \brief Conditionally log an error if the logging level is high enough +* \param level Minimum logging level for data to be logged +* \param data Text of data to be logged +* \param data_len Length in characters of data to be logged +*/ +C_API void log_error_noexcept( + SRLoggingLevel level, const char* data, size_t data_len); #endif //SMARTREDIS_LOGGER_H diff --git a/include/srexception.h b/include/srexception.h index 8879dc5fe..7344b1dd4 100644 --- a/include/srexception.h +++ b/include/srexception.h @@ -31,6 +31,8 @@ #include #include +#include "sr_enums.h" +#include "logger.h" ///@file @@ -160,7 +162,7 @@ class Exception: public std::exception * \returns Stringified version of the class name */ virtual std::string exception_class() { - return std::string("Exception") + return std::string("Exception"); } /*! @@ -215,7 +217,7 @@ class BadAllocException: public Exception * \returns Stringified version of the class name */ virtual std::string exception_class() { - return std::string("BadAllocException") + return std::string("BadAllocException"); } }; @@ -246,7 +248,7 @@ class DatabaseException: public Exception * \returns Stringified version of the class name */ virtual std::string exception_class() { - return std::string("DatabaseException") + return std::string("DatabaseException"); } }; @@ -277,7 +279,7 @@ class RuntimeException: public Exception * \returns Stringified version of the class name */ virtual std::string exception_class() { - return std::string("RuntimeException") + return std::string("RuntimeException"); } }; @@ -308,7 +310,7 @@ class ParameterException: public Exception * \returns Stringified version of the class name */ virtual std::string exception_class() { - return std::string("ParameterException") + return std::string("ParameterException"); } }; @@ -339,7 +341,7 @@ class TimeoutException: public Exception * \returns Stringified version of the class name */ virtual std::string exception_class() { - return std::string("TimeoutException") + return std::string("TimeoutException"); } }; @@ -370,7 +372,7 @@ class InternalException: public Exception * \returns Stringified version of the class name */ virtual std::string exception_class() { - return std::string("InternalException") + return std::string("InternalException"); } }; @@ -401,7 +403,7 @@ class KeyException: public Exception * \returns Stringified version of the class name */ virtual std::string exception_class() { - return std::string("KeyException") + return std::string("KeyException"); } }; @@ -431,7 +433,7 @@ class TypeException: public Exception * \returns Stringified version of the class name */ virtual std::string exception_class() { - return std::string("TypeException") + return std::string("TypeException"); } }; diff --git a/include/utility.h b/include/utility.h index e547f668d..0bd8ee64b 100644 --- a/include/utility.h +++ b/include/utility.h @@ -48,7 +48,7 @@ namespace SmartRedis { */ void get_config_integer(int& value, const std::string& cfg_key, - int default_value, + const int default_value, bool suppress_warning = false); /*! diff --git a/src/cpp/client.cpp b/src/cpp/client.cpp index ac7dfd10b..1f46de641 100644 --- a/src/cpp/client.cpp +++ b/src/cpp/client.cpp @@ -1562,8 +1562,8 @@ void Client::_set_prefixes_from_env() std::string get_key_prefixes; get_config_string(get_key_prefixes, "SSKEYIN", ""); if (get_key_prefixes.length() > 0) { - char* a = get_key_prefixes.c_str(); - char* b = a; + const char* a = get_key_prefixes.c_str(); + const char* b = a; char parse_char = ','; while (*b != '\0') { if (*b == parse_char) { diff --git a/src/cpp/dataset.cpp b/src/cpp/dataset.cpp index 51228b61b..9f7b4f9ac 100644 --- a/src/cpp/dataset.cpp +++ b/src/cpp/dataset.cpp @@ -29,7 +29,7 @@ #include #include "dataset.h" #include "srexception.h" -#include "logging.h" +#include "logger.h" using namespace SmartRedis; diff --git a/src/cpp/logger.cpp b/src/cpp/logger.cpp index 777906a8f..3eb6a6e41 100644 --- a/src/cpp/logger.cpp +++ b/src/cpp/logger.cpp @@ -178,3 +178,63 @@ void Logger::log_data(SRLoggingLevel level, const std::string_view& data) const std::string _data(data); log_data(level, _data); } + +/*! +* \brief Conditionally log data if the logging level is high enough +* \param level Minimum logging level for data to be logged +* \param data Text of data to be logged +* \param data_len Length in characters of data to be logged +*/ +extern "C" void log_data_noexcept( + SRLoggingLevel level, const char* data, size_t data_len) +{ + auto &logger = Logger::get_instance(); + try { + std::string strData(data, data_len); + logger.log_data(level, strData); + } + catch (Exception e) { + std::cout << "Logging failure: " << e.where() + << ": " << e.what() << std::endl; + } +} + +/*! +* \brief Conditionally log a warning if the logging level is high enough +* \param level Minimum logging level for data to be logged +* \param data Text of data to be logged +* \param data_len Length in characters of data to be logged +*/ +extern "C" void log_warning_noexcept( + SRLoggingLevel level, const char* data, size_t data_len) +{ + auto &logger = Logger::get_instance(); + try { + std::string strData(data, data_len); + logger.log_warning(level, strData); + } + catch (Exception e) { + std::cout << "Logging failure: " << e.where() + << ": " << e.what() << std::endl; + } +} + +/*! +* \brief Conditionally log an error if the logging level is high enough +* \param level Minimum logging level for data to be logged +* \param data Text of data to be logged +* \param data_len Length in characters of data to be logged +*/ +extern "C" void log_error_noexcept( + SRLoggingLevel level, const char* data, size_t data_len) +{ + auto &logger = Logger::get_instance(); + try { + std::string strData(data, data_len); + logger.log_error(level, strData); + } + catch (Exception e) { + std::cout << "Logging failure: " << e.where() + << ": " << e.what() << std::endl; + } +} diff --git a/src/cpp/redis.cpp b/src/cpp/redis.cpp index 5f6221754..fc7e3a685 100644 --- a/src/cpp/redis.cpp +++ b/src/cpp/redis.cpp @@ -28,6 +28,7 @@ #include "redis.h" #include "srexception.h" +#include "utility.h" using namespace SmartRedis; @@ -387,8 +388,8 @@ CommandReply Redis::run_model(const std::string& key, { // Check for a non-default timeout setting int run_timeout; - _init_integer_from_env(run_timeout, _MODEL_TIMEOUT_ENV_VAR, - _DEFAULT_MODEL_TIMEOUT); + get_config_integer(run_timeout, _MODEL_TIMEOUT_ENV_VAR, + _DEFAULT_MODEL_TIMEOUT); // Build the command CompoundCommand cmd; diff --git a/src/cpp/rediscluster.cpp b/src/cpp/rediscluster.cpp index c9d1c72f4..5f6daa9cd 100644 --- a/src/cpp/rediscluster.cpp +++ b/src/cpp/rediscluster.cpp @@ -30,6 +30,7 @@ #include "nonkeyedcommand.h" #include "keyedcommand.h" #include "srexception.h" +#include "utility.h" using namespace SmartRedis; @@ -615,8 +616,8 @@ CommandReply RedisCluster::run_model(const std::string& model_name, { // Check for a non-default timeout setting int run_timeout; - _init_integer_from_env(run_timeout, _MODEL_TIMEOUT_ENV_VAR, - _DEFAULT_MODEL_TIMEOUT); + get_config_integer(run_timeout, _MODEL_TIMEOUT_ENV_VAR, + _DEFAULT_MODEL_TIMEOUT); /* For this version of run model, we have to copy all input and output tensors, so we will randomly select diff --git a/src/cpp/utility.cpp b/src/cpp/utility.cpp index e1a612b4b..2dd7953b8 100644 --- a/src/cpp/utility.cpp +++ b/src/cpp/utility.cpp @@ -48,7 +48,7 @@ using namespace SmartRedis; */ void get_config_integer(int& value, const std::string& cfg_key, - int default_value, + const int default_value, bool suppress_warning /* = false */) { value = default_value; diff --git a/src/python/src/pyclient.cpp b/src/python/src/pyclient.cpp index ad3feed6d..6d46347dc 100644 --- a/src/python/src/pyclient.cpp +++ b/src/python/src/pyclient.cpp @@ -35,7 +35,7 @@ using namespace SmartRedis; namespace py = pybind11; -PyClient::PyClient(bool cluster, std::string& client_id) +PyClient::PyClient(bool cluster, const std::string& client_id) { // throw SRRuntimeException("Test"); _client = NULL; diff --git a/tests/cpp/unit-tests/CMakeLists.txt b/tests/cpp/unit-tests/CMakeLists.txt index 9add6f647..3f66d4733 100644 --- a/tests/cpp/unit-tests/CMakeLists.txt +++ b/tests/cpp/unit-tests/CMakeLists.txt @@ -73,6 +73,8 @@ set(SOURCES ../../../src/cpp/tensorbase.cpp ../../../src/cpp/tensorpack.cpp ../../../src/cpp/threadpool.cpp + ../../../src/cpp/utility.cpp + ../../../src/cpp/logger.cpp ) # The unit tests to be executed From fb3dd7da9f51f095f26be2cc06649dc53bf442a6 Mon Sep 17 00:00:00 2001 From: billschereriii Date: Tue, 22 Nov 2022 17:52:23 -0600 Subject: [PATCH 06/37] Fix link issue that seems to only affect MacOS --- include/utility.h | 1 - src/cpp/utility.cpp | 8 +++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/utility.h b/include/utility.h index 0bd8ee64b..90caf0df8 100644 --- a/include/utility.h +++ b/include/utility.h @@ -31,7 +31,6 @@ #include #include -#include "address.h" ///@file diff --git a/src/cpp/utility.cpp b/src/cpp/utility.cpp index 2dd7953b8..6f91e07f6 100644 --- a/src/cpp/utility.cpp +++ b/src/cpp/utility.cpp @@ -35,7 +35,7 @@ #include "utility.h" #include "logger.h" -using namespace SmartRedis; +namespace SmartRedis { /*! * \brief Initialize an integer from configuration, such as an @@ -49,7 +49,7 @@ using namespace SmartRedis; void get_config_integer(int& value, const std::string& cfg_key, const int default_value, - bool suppress_warning /* = false */) + bool suppress_warning /*= false*/) { value = default_value; @@ -105,7 +105,7 @@ void get_config_integer(int& value, void get_config_string(std::string& value, const std::string& cfg_key, const std::string& default_value, - bool suppress_warning /* = false */) + bool suppress_warning /*= false*/) { value = default_value; @@ -120,3 +120,5 @@ void get_config_string(std::string& value, ); } } + +} // namespace SmartRedis { From c19ae428850cb2e5c0006b1f88ddb8e79bad6749 Mon Sep 17 00:00:00 2001 From: billschereriii Date: Wed, 23 Nov 2022 12:45:35 -0600 Subject: [PATCH 07/37] It compiles so it must be fine --- CMakeLists.txt | 1 + src/fortran/client/client_interfaces.inc | 2 +- src/fortran/logger.F90 | 99 ++++++++++++++++++++++++ src/fortran/logger/logger_interfaces.inc | 55 +++++++++++++ 4 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 src/fortran/logger.F90 create mode 100644 src/fortran/logger/logger_interfaces.inc diff --git a/CMakeLists.txt b/CMakeLists.txt index 9703ed7b6..448b687f0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -101,6 +101,7 @@ if (BUILD_FORTRAN) src/fortran/fortran_c_interop.F90 src/fortran/dataset.F90 src/fortran/client.F90 + src/fortran/logger.F90 ) include_directories(src/fortran) # Note the following has to be before ANY add_library command) diff --git a/src/fortran/client/client_interfaces.inc b/src/fortran/client/client_interfaces.inc index b3462441a..1c4ffed3d 100644 --- a/src/fortran/client/client_interfaces.inc +++ b/src/fortran/client/client_interfaces.inc @@ -26,7 +26,7 @@ interface function c_constructor(cluster, client_id, client_id_length, new_client) bind(c, name="SmartRedisCClient") - use iso_c_binding, only : c_ptr, c_bool + use iso_c_binding, only : c_ptr, c_bool, c_char, c_size_t import :: enum_kind integer(kind=enum_kind) :: c_constructor logical(kind=c_bool), value :: cluster !< True if a database cluster is being used diff --git a/src/fortran/logger.F90 b/src/fortran/logger.F90 new file mode 100644 index 000000000..b2f508284 --- /dev/null +++ b/src/fortran/logger.F90 @@ -0,0 +1,99 @@ +! BSD 2-Clause License +! +! Copyright (c) 2021-2022, Hewlett Packard Enterprise +! All rights reserved. +! +! Redistribution and use in source and binary forms, with or without +! modification, are permitted provided that the following conditions are met: +! +! 1. Redistributions of source code must retain the above copyright notice, this +! list of conditions and the following disclaimer. +! +! 2. Redistributions in binary form must reproduce the above copyright notice, +! this list of conditions and the following disclaimer in the documentation +! and/or other materials provided with the distribution. +! +! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +! DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +! FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +! DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +! SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +! OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +module smartredis_logger + +use iso_c_binding, only : c_ptr, c_char, c_size_t +use iso_c_binding, only : c_int8_t, c_int16_t, c_int32_t, c_int64_t, c_float, c_double +use iso_c_binding, only : c_loc, c_f_pointer +use fortran_c_interop, only : convert_char_array_to_c, enum_kind, C_MAX_STRING + +use, intrinsic :: iso_fortran_env, only: stderr => error_unit +implicit none; private + +#include "enum_fortran.inc" +#include "logger/logger_interfaces.inc" + +public :: enum_kind !< The kind of integer equivalent to a C enum. According to C an Fortran + !! standards this should be c_int, but is renamed here to ensure that + !! users do not have to import the iso_c_binding module into their + !! programs + +contains + +!> Log data to the SmartRedis log +subroutine log_data(level, data) + integer (kind=enum_kind), intent(in) :: level !< Minimum logging level to log the data at + character(len=*), intent(in) :: data !< Data to be logged + + ! Local variables + character(kind=c_char, len=:), allocatable :: c_data + integer(kind=c_size_t) :: c_data_length + + allocate(character(kind=c_char, len=len_trim(data)) :: c_data) + c_data = data + c_data_length = len_trim(data) + + call c_log_data(level, c_data, c_data_length) + deallocate(c_data) +end subroutine log_data + +!> Log a warning to the SmartRedis log +subroutine log_warning(level, data) + integer (kind=enum_kind), intent(in) :: level !< Minimum logging level to log the data at + character(len=*), intent(in) :: data !< Data to be logged + + ! Local variables + character(kind=c_char, len=:), allocatable :: c_data + integer(kind=c_size_t) :: c_data_length + + allocate(character(kind=c_char, len=len_trim(data)) :: c_data) + c_data = data + c_data_length = len_trim(data) + + call c_log_warning(level, c_data, c_data_length) + deallocate(c_data) +end subroutine log_warning + +!> Log an error to the SmartRedis log +subroutine log_error(level, data) + integer (kind=enum_kind), intent(in) :: level !< Minimum logging level to log the data at + character(len=*), intent(in) :: data !< Data to be logged + + ! Local variables + character(kind=c_char, len=:), allocatable :: c_data + integer(kind=c_size_t) :: c_data_length + + allocate(character(kind=c_char, len=len_trim(data)) :: c_data) + c_data = data + c_data_length = len_trim(data) + + call c_log_error(level, c_data, c_data_length) + deallocate(c_data) +end subroutine log_error + +end module smartredis_logger + diff --git a/src/fortran/logger/logger_interfaces.inc b/src/fortran/logger/logger_interfaces.inc new file mode 100644 index 000000000..1abd8d24f --- /dev/null +++ b/src/fortran/logger/logger_interfaces.inc @@ -0,0 +1,55 @@ +! BSD 2-Clause License +! +! Copyright (c) 2021-2022, Hewlett Packard Enterprise +! All rights reserved. +! +! Redistribution and use in source and binary forms, with or without +! modification, are permitted provided that the following conditions are met: +! +! 1. Redistributions of source code must retain the above copyright notice, this +! list of conditions and the following disclaimer. +! +! 2. Redistributions in binary form must reproduce the above copyright notice, +! this list of conditions and the following disclaimer in the documentation +! and/or other materials provided with the distribution. +! +! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +! DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +! FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +! DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +! SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +! OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +interface + subroutine c_log_data(level, data, data_length) bind(c, name="log_data") + use iso_c_binding, only : c_ptr, c_char, c_size_t + import :: enum_kind + integer(kind=enum_kind) :: level + character(kind=c_char) :: data(*) + integer(kind=c_size_t), value :: data_length + end subroutine c_log_data +end interface + +interface + subroutine c_log_warning(level, data, data_length) bind(c, name="log_warning") + use iso_c_binding, only : c_ptr, c_char, c_size_t + import :: enum_kind + integer(kind=enum_kind) :: level + character(kind=c_char) :: data(*) + integer(kind=c_size_t), value :: data_length + end subroutine c_log_warning +end interface + +interface + subroutine c_log_error(level, data, data_length) bind(c, name="log_error") + use iso_c_binding, only : c_ptr, c_char, c_size_t + import :: enum_kind + integer(kind=enum_kind) :: level + character(kind=c_char) :: data(*) + integer(kind=c_size_t), value :: data_length + end subroutine c_log_error +end interface From fd0a45551f174667b18db89e69abdc3b9ae012df Mon Sep 17 00:00:00 2001 From: billschereriii Date: Wed, 23 Nov 2022 13:42:34 -0600 Subject: [PATCH 08/37] Python logging is code complete --- src/python/bindings/bind.cpp | 6 +++ src/python/module/smartredis/logger.py | 71 ++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 src/python/module/smartredis/logger.py diff --git a/src/python/bindings/bind.cpp b/src/python/bindings/bind.cpp index 598349052..e38402562 100644 --- a/src/python/bindings/bind.cpp +++ b/src/python/bindings/bind.cpp @@ -28,6 +28,7 @@ #include "pyclient.h" #include "srexception.h" +#include "logger.h" using namespace SmartRedis; namespace py = pybind11; @@ -108,6 +109,11 @@ PYBIND11_MODULE(smartredisPy, m) { .def("get_meta_strings", &PyDataset::get_meta_strings) .def("get_name", &PyDataset::get_name); + // Logging functions + m.def("cpp_log_data", &log_data) + .def("cpp_log_warning", &log_warning) + .def("cpp_log_error", &log_error); + // Python exception classes static py::exception exception_handler(m, "RedisReplyError"); static py::exception runtime_exception_handler(m, "RedisRuntimeError", exception_handler.ptr()); diff --git a/src/python/module/smartredis/logger.py b/src/python/module/smartredis/logger.py new file mode 100644 index 000000000..fef6e843d --- /dev/null +++ b/src/python/module/smartredis/logger.py @@ -0,0 +1,71 @@ +# BSD 2-Clause License +# +# Copyright (c) 2021-2022, Hewlett Packard Enterprise +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +from .smartredisPy import cpp_log_data, cpp_log_warning, cpp_log_error +from .util import exception_handler, typecheck + +@exception_handler +def log_data(level, data): + """Log data to the SmartRedis logfile + + :param level: minimum logging level for data to be logged with + :type name: enum + :param data: message data to log + :type data: str + :raises RedisReplyError: if logging fails + """ + typecheck(level, "level", int) + typecheck(data, "data", str) + cpp_log_data(level, data) + +@exception_handler +def log_warning(level, data): + """Log a warning to the SmartRedis logfile + + :param level: minimum logging level for data to be logged with + :type name: enum + :param data: message data to log + :type data: str + :raises RedisReplyError: if logging fails + """ + typecheck(level, "level", int) + typecheck(data, "data", str) + cpp_log_warning(level, data) + +@exception_handler +def log_error(level, data): + """Log an error to the SmartRedis logfile + + :param level: minimum logging level for data to be logged with + :type name: enum + :param data: message data to log + :type data: str + :raises RedisReplyError: if logging fails + """ + typecheck(level, "level", int) + typecheck(data, "data", str) + cpp_log_error(level, data) + From 4e257c83836fe9b2eb3f0d14fd7be3e02efa0f5e Mon Sep 17 00:00:00 2001 From: billschereriii Date: Fri, 25 Nov 2022 13:42:39 -0600 Subject: [PATCH 09/37] All tests pass again --- conftest.py | 5 ++++ examples/serial/c/example_put_get_3D.c | 4 ++- examples/serial/c/example_put_unpack_1D.c | 4 ++- include/c_client.h | 8 +++--- include/enum_fortran.inc | 9 +++++++ include/logger.h | 4 ++- include/pyclient.h | 4 ++- src/c/c_client.cpp | 6 +++-- src/python/bindings/bind.cpp | 2 +- src/python/src/pyclient.cpp | 1 - tests/c/client_test_dataset_aggregation.c | 5 +++- tests/c/client_test_dataset_exists.c | 8 ++++-- tests/c/client_test_put_get_1D.c | 32 +++++++++++++++++------ tests/c/client_test_put_get_2D.c | 32 +++++++++++++++++------ tests/c/client_test_put_get_3D.c | 32 +++++++++++++++++------ tests/c/client_test_put_unpack_1D.c | 4 ++- tests/docker/c/test_docker.c | 4 ++- 17 files changed, 124 insertions(+), 40 deletions(-) diff --git a/conftest.py b/conftest.py index d84d3fbd6..291fb2713 100644 --- a/conftest.py +++ b/conftest.py @@ -32,6 +32,7 @@ import os import random import string +import inspect dtypes = [ np.float64, @@ -65,6 +66,10 @@ def mock_data(): def mock_model(): return MockTestModel +@pytest.fixture +def context(): + return inspect.stack()[1][3] + class MockTestData: @staticmethod diff --git a/examples/serial/c/example_put_get_3D.c b/examples/serial/c/example_put_get_3D.c index e154354a3..d88a74ba3 100644 --- a/examples/serial/c/example_put_get_3D.c +++ b/examples/serial/c/example_put_get_3D.c @@ -38,6 +38,8 @@ int main(int argc, char* argv[]) { values. */ + const char* client_id = "put_get_3d"; + size_t cid_len = strlen(client_id); size_t n_dims = 3; size_t* dims = malloc(n_dims*sizeof(size_t)); dims[0] = 10; @@ -46,7 +48,7 @@ int main(int argc, char* argv[]) { void* client = NULL; bool cluster_mode = true; // Set to false if not using a clustered database - if (SRNoError != SmartRedisCClient(cluster_mode, &client)) { + if (SRNoError != SmartRedisCClient(cluster_mode, client_id, cid_len, &client)) { printf("Client initialization failed!\n"); exit(-1); } diff --git a/examples/serial/c/example_put_unpack_1D.c b/examples/serial/c/example_put_unpack_1D.c index 5f00ef359..113ea8d7b 100644 --- a/examples/serial/c/example_put_unpack_1D.c +++ b/examples/serial/c/example_put_unpack_1D.c @@ -34,6 +34,8 @@ int main(int argc, char* argv[]) { + const char* client_id = "put_unpack_1d"; + size_t cid_len = strlen(client_id); size_t* dims = malloc(sizeof(size_t)); dims[0] = 10; size_t n_dims = 1; @@ -46,7 +48,7 @@ int main(int argc, char* argv[]) { void* client = NULL; bool cluster_mode = true; // Set to false if not using a clustered database - if (SRNoError != SmartRedisCClient(cluster_mode, &client)) { + if (SRNoError != SmartRedisCClient(cluster_mode, client_id, cid_len, &client)) { printf("Client initialization failed!\n"); exit(-1); } diff --git a/include/c_client.h b/include/c_client.h index 4ee9af84b..012cf2e67 100644 --- a/include/c_client.h +++ b/include/c_client.h @@ -43,14 +43,16 @@ extern "C" { /*! * \brief C-client constructor * \param cluster Flag to indicate if a database cluster is being used -* \param new_client Receives the new client * \param client_id Identifier for the current client * \param client_id_length Length in characters of the client_id string +* \param new_client Receives the new client * \return Returns SRNoError on success or an error code on failure */ SRError SmartRedisCClient( - bool cluster, void **new_client, - const char* client_id, const size_t client_id_length); + bool cluster, + const char* client_id, + const size_t client_id_length, + void **new_client); /*! * \brief C-client destructor diff --git a/include/enum_fortran.inc b/include/enum_fortran.inc index d5b38d6dc..e691dc9c9 100644 --- a/include/enum_fortran.inc +++ b/include/enum_fortran.inc @@ -77,3 +77,12 @@ enum, bind(c) enumerator :: SRInvalidError = -1 ! Uninitialized error variable enumerator :: SRTypeError = 9 ! Type mismatch end enum + +! SRLoggingLevel +enum, bind(c) + enumerator :: LLInvalid = -1 ! Invalid or uninitialized logging level + enumerator :: LLQuiet = 1 ! No logging at all + enumerator :: LLInfo = 2 ! Informational logging only + enumerator :: LLDebug = 3 ! Verbose logging for debugging purposes + enumerator :: LLDeveloper = 4 ! Extra verbose logging for internal use +end enum diff --git a/include/logger.h b/include/logger.h index 97cd4cdb8..0591f4ebc 100644 --- a/include/logger.h +++ b/include/logger.h @@ -29,9 +29,11 @@ #ifndef SMARTREDIS_LOGGER_H #define SMARTREDIS_LOGGER_H -#include +#ifdef __cplusplus // Skip C++ headers for C users #include #include "utility.h" +#endif // __cplusplus +#include #include "sr_enums.h" ///@file diff --git a/include/pyclient.h b/include/pyclient.h index bd91b1a32..0e48c10a6 100644 --- a/include/pyclient.h +++ b/include/pyclient.h @@ -62,7 +62,9 @@ class PyClient * is being used * \param client_id Identifier for the current client */ - PyClient(bool cluster, const std::string& client_id = "anonymous"); + PyClient( + bool cluster, + const std::string& client_id = std::string("anonymous")); /*! * \brief PyClient destructor diff --git a/src/c/c_client.cpp b/src/c/c_client.cpp index fa1c84e53..71493f628 100644 --- a/src/c/c_client.cpp +++ b/src/c/c_client.cpp @@ -39,8 +39,10 @@ using namespace SmartRedis; // The caller is responsible for deleting the client via DeleteClient(). extern "C" SRError SmartRedisCClient( - bool cluster, void** new_client, - const char* client_id, const size_t client_id_length) + bool cluster, + const char* client_id, + const size_t client_id_length, + void** new_client) { SRError result = SRNoError; try { diff --git a/src/python/bindings/bind.cpp b/src/python/bindings/bind.cpp index e38402562..d62d6c4ac 100644 --- a/src/python/bindings/bind.cpp +++ b/src/python/bindings/bind.cpp @@ -39,7 +39,7 @@ PYBIND11_MODULE(smartredisPy, m) { // Python client bindings py::class_(m, "PyClient") - .def(py::init()) + .def(py::init()) .def("put_tensor", &PyClient::put_tensor) .def("get_tensor", &PyClient::get_tensor) .def("delete_tensor", &PyClient::delete_tensor) diff --git a/src/python/src/pyclient.cpp b/src/python/src/pyclient.cpp index 6d46347dc..7f51a9ecb 100644 --- a/src/python/src/pyclient.cpp +++ b/src/python/src/pyclient.cpp @@ -37,7 +37,6 @@ namespace py = pybind11; PyClient::PyClient(bool cluster, const std::string& client_id) { -// throw SRRuntimeException("Test"); _client = NULL; try { _client = new Client(cluster, client_id); diff --git a/tests/c/client_test_dataset_aggregation.c b/tests/c/client_test_dataset_aggregation.c index 93ab166dd..a44d62ca6 100644 --- a/tests/c/client_test_dataset_aggregation.c +++ b/tests/c/client_test_dataset_aggregation.c @@ -130,10 +130,13 @@ int main(int argc, char* argv[]) char* dataset_name[] = {"agg_dataset_0", "agg_dataset_1", "agg_dataset_2", "agg_dataset_2", "agg_dataset_3"}; char* list_name = "my_aggregation"; void** datasets = NULL; + const char* client_id = "test_dataset_aggregation"; + size_t cid_len = strlen(client_id); // Initialize client void *client = NULL; - if (SRNoError != SmartRedisCClient(use_cluster(), &client) || NULL == client) { + if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client) || + NULL == client) { printf("Failed to initialize client!\n"); printf("Test passed: NO\n"); return -1; diff --git a/tests/c/client_test_dataset_exists.c b/tests/c/client_test_dataset_exists.c index f1842d554..fecf92b50 100644 --- a/tests/c/client_test_dataset_exists.c +++ b/tests/c/client_test_dataset_exists.c @@ -41,7 +41,9 @@ bool cluster = true; int missing_dataset(char *dataset_name, size_t dataset_name_len) { void *client = NULL; - if (SRNoError != SmartRedisCClient(use_cluster(), &client)) + const char* client_id = "missing_dataset"; + size_t cid_len = strlen(client_id); + if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) return -1; bool exists = false; @@ -67,9 +69,11 @@ int present_dataset(char *dataset_name, size_t dataset_name_len) uint16_t ***tensor = NULL; int i, j, k; bool exists = false; + const char* client_id = "present_dataset"; + size_t cid_len = strlen(client_id); // Initialize client and dataset - if (SRNoError != SmartRedisCClient(use_cluster(), &client) || NULL == client) + if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client) || NULL == client) return -1; if (SRNoError != CDataSet(dataset_name, dataset_name_len, &dataset) || NULL == dataset) return -1; diff --git a/tests/c/client_test_put_get_1D.c b/tests/c/client_test_put_get_1D.c index c67c804c6..e8114e05f 100644 --- a/tests/c/client_test_put_get_1D.c +++ b/tests/c/client_test_put_get_1D.c @@ -117,7 +117,9 @@ int put_get_1D_tensor_double(size_t* dims, size_t n_dims, char* key_suffix, size_t key_suffix_length) { void* client = NULL; - if (SRNoError != SmartRedisCClient(use_cluster(), &client)) + const char* client_id = "put_get_1D_tensor_double"; + size_t cid_len = strlen(client_id); + if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) return -1; double* tensor = (double*)malloc(dims[0]*sizeof(double)); @@ -152,7 +154,9 @@ int put_get_1D_tensor_float(size_t* dims, size_t n_dims, size_t key_suffix_length) { void* client = NULL; - if (SRNoError != SmartRedisCClient(use_cluster(), &client)) + const char* client_id = "put_get_1D_tensor_float"; + size_t cid_len = strlen(client_id); + if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) return -1; float* tensor = (float*)malloc(dims[0]*sizeof(float)); @@ -182,7 +186,9 @@ int put_get_1D_tensor_i8(size_t* dims, size_t n_dims, size_t key_suffix_length) { void* client = NULL; - if (SRNoError != SmartRedisCClient(use_cluster(), &client)) + const char* client_id = "put_get_1D_tensor_i8"; + size_t cid_len = strlen(client_id); + if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) return -1; int8_t* tensor = (int8_t*)malloc(dims[0]*sizeof(int8_t)); @@ -220,7 +226,9 @@ int put_get_1D_tensor_i16(size_t* dims, size_t n_dims, size_t key_suffix_length) { void* client = NULL; - if (SRNoError != SmartRedisCClient(use_cluster(), &client)) + const char* client_id = "put_get_1D_tensor_i16"; + size_t cid_len = strlen(client_id); + if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) return -1; int16_t* tensor = (int16_t*)malloc(dims[0]*sizeof(int16_t)); @@ -258,7 +266,9 @@ int put_get_1D_tensor_i32(size_t* dims, size_t n_dims, size_t key_suffix_length) { void* client = NULL; - if (SRNoError != SmartRedisCClient(use_cluster(), &client)) + const char* client_id = "put_get_1D_tensor_i32"; + size_t cid_len = strlen(client_id); + if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) return -1; int32_t* tensor = (int32_t*)malloc(dims[0]*sizeof(int32_t)); @@ -296,7 +306,9 @@ int put_get_1D_tensor_i64(size_t* dims, size_t n_dims, size_t key_suffix_length) { void* client = NULL; - if (SRNoError != SmartRedisCClient(use_cluster(), &client)) + const char* client_id = "put_get_1D_tensor_i64"; + size_t cid_len = strlen(client_id); + if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) return -1; int64_t* tensor = (int64_t*)malloc(dims[0]*sizeof(int64_t)); @@ -334,7 +346,9 @@ int put_get_1D_tensor_ui8(size_t* dims, size_t n_dims, size_t key_suffix_length) { void* client = NULL; - if (SRNoError != SmartRedisCClient(use_cluster(), &client)) + const char* client_id = "put_get_1D_tensor_ui8"; + size_t cid_len = strlen(client_id); + if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) return -1; uint8_t* tensor = (uint8_t*)malloc(dims[0]*sizeof(uint8_t)); @@ -369,7 +383,9 @@ int put_get_1D_tensor_ui16(size_t* dims, size_t n_dims, size_t key_suffix_length) { void* client = NULL; - if (SRNoError != SmartRedisCClient(use_cluster(), &client)) + const char* client_id = "put_get_1D_tensor_ui16"; + size_t cid_len = strlen(client_id); + if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) return -1; uint16_t* tensor = (uint16_t*)malloc(dims[0]*sizeof(uint16_t)); diff --git a/tests/c/client_test_put_get_2D.c b/tests/c/client_test_put_get_2D.c index 5208bbc10..f707e5bce 100644 --- a/tests/c/client_test_put_get_2D.c +++ b/tests/c/client_test_put_get_2D.c @@ -118,7 +118,9 @@ int put_get_2D_tensor_double(size_t* dims, int n_dims, char* key_suffix, int key_suffix_length) { void* client = NULL; - if (SRNoError != SmartRedisCClient(use_cluster(), &client)) + const char* client_id = "put_get_2D_tensor_double"; + size_t cid_len = strlen(client_id); + if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) return -1; double** tensor = (double**)malloc(dims[0]*sizeof(double*)); @@ -165,7 +167,9 @@ int put_get_2D_tensor_float(size_t* dims, int n_dims, int key_suffix_length) { void* client = NULL; - if (SRNoError != SmartRedisCClient(use_cluster(), &client)) + const char* client_id = "put_get_2D_tensor_float"; + size_t cid_len = strlen(client_id); + if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) return -1; float** tensor = (float**)malloc(dims[0]*sizeof(float*)); @@ -212,7 +216,9 @@ int put_get_2D_tensor_i8(size_t* dims, int n_dims, int key_suffix_length) { void* client = NULL; - if (SRNoError != SmartRedisCClient(use_cluster(), &client)) + const char* client_id = "put_get_2D_tensor_i8"; + size_t cid_len = strlen(client_id); + if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) return -1; int8_t** tensor = (int8_t**)malloc(dims[0]*sizeof(int8_t*)); @@ -263,7 +269,9 @@ int put_get_2D_tensor_i16(size_t* dims, int n_dims, int key_suffix_length) { void* client = NULL; - if (SRNoError != SmartRedisCClient(use_cluster(), &client)) + const char* client_id = "put_get_2D_tensor_i16"; + size_t cid_len = strlen(client_id); + if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) return -1; int16_t** tensor = (int16_t**)malloc(dims[0]*sizeof(int16_t*)); @@ -314,7 +322,9 @@ int put_get_2D_tensor_i32(size_t* dims, int n_dims, int key_suffix_length) { void* client = NULL; - if (SRNoError != SmartRedisCClient(use_cluster(), &client)) + const char* client_id = "put_get_2D_tensor_i32"; + size_t cid_len = strlen(client_id); + if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) return -1; int32_t** tensor = (int32_t**)malloc(dims[0]*sizeof(int32_t*)); @@ -365,7 +375,9 @@ int put_get_2D_tensor_i64(size_t* dims, int n_dims, int key_suffix_length) { void* client = NULL; - if (SRNoError != SmartRedisCClient(use_cluster(), &client)) + const char* client_id = "put_get_2D_tensor_i64"; + size_t cid_len = strlen(client_id); + if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) return -1; int64_t** tensor = (int64_t**)malloc(dims[0]*sizeof(int64_t*)); @@ -416,7 +428,9 @@ int put_get_2D_tensor_ui8(size_t* dims, int n_dims, int key_suffix_length) { void* client = NULL; - if (SRNoError != SmartRedisCClient(use_cluster(), &client)) + const char* client_id = "put_get_2D_tensor_ui8"; + size_t cid_len = strlen(client_id); + if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) return -1; uint8_t** tensor = (uint8_t**)malloc(dims[0]*sizeof(uint8_t*)); @@ -465,7 +479,9 @@ int put_get_2D_tensor_ui16(size_t* dims, int n_dims, int key_suffix_length) { void* client = NULL; - if (SRNoError != SmartRedisCClient(use_cluster(), &client)) + const char* client_id = "put_get_2D_tensor_ui16"; + size_t cid_len = strlen(client_id); + if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) return -1; uint16_t** tensor = (uint16_t**)malloc(dims[0]*sizeof(uint16_t*)); diff --git a/tests/c/client_test_put_get_3D.c b/tests/c/client_test_put_get_3D.c index 7b235899a..771b9252c 100644 --- a/tests/c/client_test_put_get_3D.c +++ b/tests/c/client_test_put_get_3D.c @@ -118,7 +118,9 @@ int put_get_3D_tensor_double(size_t* dims, size_t n_dims, char* key_suffix, size_t key_suffix_length) { void* client = NULL; - if (SRNoError != SmartRedisCClient(use_cluster(), &client)) + const char* client_id = "put_get_3D_tensor_double"; + size_t cid_len = strlen(client_id); + if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) return -1; double*** tensor = (double***)malloc(dims[0]*sizeof(double**)); @@ -175,7 +177,9 @@ int put_get_3D_tensor_float(size_t* dims, size_t n_dims, size_t key_suffix_length) { void* client = NULL; - if (SRNoError != SmartRedisCClient(use_cluster(), &client)) + const char* client_id = "put_get_3D_tensor_float"; + size_t cid_len = strlen(client_id); + if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) return -1; float*** tensor = (float***)malloc(dims[0]*sizeof(float**)); @@ -231,7 +235,9 @@ int put_get_3D_tensor_i8(size_t* dims, size_t n_dims, size_t key_suffix_length) { void* client = NULL; - if (SRNoError != SmartRedisCClient(use_cluster(), &client)) + const char* client_id = "put_get_3D_tensor_i8"; + size_t cid_len = strlen(client_id); + if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) return -1; int8_t*** tensor = (int8_t***)malloc(dims[0]*sizeof(int8_t**)); @@ -291,7 +297,9 @@ int put_get_3D_tensor_i16(size_t* dims, size_t n_dims, size_t key_suffix_length) { void* client = NULL; - if (SRNoError != SmartRedisCClient(use_cluster(), &client)) + const char* client_id = "put_get_3D_tensor_i16"; + size_t cid_len = strlen(client_id); + if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) return -1; int16_t*** tensor = (int16_t***)malloc(dims[0]*sizeof(int16_t**)); @@ -352,7 +360,9 @@ int put_get_3D_tensor_i32(size_t* dims, size_t n_dims, size_t key_suffix_length) { void* client = NULL; - if (SRNoError != SmartRedisCClient(use_cluster(), &client)) + const char* client_id = "put_get_3D_tensor_i32"; + size_t cid_len = strlen(client_id); + if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) return -1; int32_t*** tensor = (int32_t***)malloc(dims[0]*sizeof(int32_t**)); @@ -413,7 +423,9 @@ int put_get_3D_tensor_i64(size_t* dims, size_t n_dims, size_t key_suffix_length) { void* client = NULL; - if (SRNoError != SmartRedisCClient(use_cluster(), &client)) + const char* client_id = "put_get_3D_tensor_i64"; + size_t cid_len = strlen(client_id); + if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) return -1; int64_t*** tensor = (int64_t***)malloc(dims[0]*sizeof(int64_t**)); @@ -474,7 +486,9 @@ int put_get_3D_tensor_ui8(size_t* dims, size_t n_dims, size_t key_suffix_length) { void* client = NULL; - if (SRNoError != SmartRedisCClient(use_cluster(), &client)) + const char* client_id = "put_get_3D_tensor_ui8"; + size_t cid_len = strlen(client_id); + if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) return -1; uint8_t*** tensor = (uint8_t***)malloc(dims[0]*sizeof(uint8_t**)); @@ -535,7 +549,9 @@ int put_get_3D_tensor_ui16(size_t* dims, size_t n_dims, size_t key_suffix_length) { void* client = NULL; - if (SRNoError != SmartRedisCClient(use_cluster(), &client)) + const char* client_id = "put_get_3D_tensor_ui16"; + size_t cid_len = strlen(client_id); + if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) return -1; uint16_t*** tensor = (uint16_t***)malloc(dims[0]*sizeof(uint16_t**)); diff --git a/tests/c/client_test_put_unpack_1D.c b/tests/c/client_test_put_unpack_1D.c index fe83210d0..9ef5e75ad 100644 --- a/tests/c/client_test_put_unpack_1D.c +++ b/tests/c/client_test_put_unpack_1D.c @@ -47,7 +47,9 @@ int put_unpack_1D_tensor(void* tensor, size_t* dims, size_t n_dims, size_t key_suffix_length) { void* client = NULL; - if (SRNoError != SmartRedisCClient(use_cluster(), &client)) + const char* client_id = "put_unpack_1D_tensor"; + size_t cid_len = strlen(client_id); + if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) return -1; char* prefix_str = "1D_tensor_test"; diff --git a/tests/docker/c/test_docker.c b/tests/docker/c/test_docker.c index 0083d092f..b29aa072f 100644 --- a/tests/docker/c/test_docker.c +++ b/tests/docker/c/test_docker.c @@ -36,9 +36,11 @@ int main(int argc, char* argv[]) { void* client = NULL; + const char* client_id = "test_docker"; + size_t cid_len = strlen(client_id); SRError return_code = SRNoError; - return_code = SmartRedisCClient(false, &client); + return_code = SmartRedisCClient(false, client_id, cid_len, &client); if (return_code != SRNoError) { return -1; From 6aa84bb883fb82dc234053d34af5127c6aa7840b Mon Sep 17 00:00:00 2001 From: Andrew Shao Date: Mon, 28 Nov 2022 08:55:49 -0800 Subject: [PATCH 10/37] Lager fortran fixes (#1) Assorted fixes [ Committed by @ashao ] [ Reviewed by @billschereriii ] --- Makefile | 2 +- src/cpp/logger.cpp | 6 +++--- src/fortran/logger.F90 | 2 ++ src/fortran/logger/logger_interfaces.inc | 6 +++--- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 8192b00c2..534cbefb9 100644 --- a/Makefile +++ b/Makefile @@ -93,7 +93,7 @@ build-test-fortran: test-lib-with-fortran # help: build-examples - build all examples (serial, parallel) .PHONY: build-examples -build-examples: lib +build-examples: lib-with-fortran ./build-scripts/build_serial_examples.sh ./build-scripts/build_parallel_examples.sh diff --git a/src/cpp/logger.cpp b/src/cpp/logger.cpp index 3eb6a6e41..f92cb6f39 100644 --- a/src/cpp/logger.cpp +++ b/src/cpp/logger.cpp @@ -193,7 +193,7 @@ extern "C" void log_data_noexcept( std::string strData(data, data_len); logger.log_data(level, strData); } - catch (Exception e) { + catch (Exception& e) { std::cout << "Logging failure: " << e.where() << ": " << e.what() << std::endl; } @@ -213,7 +213,7 @@ extern "C" void log_warning_noexcept( std::string strData(data, data_len); logger.log_warning(level, strData); } - catch (Exception e) { + catch (Exception& e) { std::cout << "Logging failure: " << e.where() << ": " << e.what() << std::endl; } @@ -233,7 +233,7 @@ extern "C" void log_error_noexcept( std::string strData(data, data_len); logger.log_error(level, strData); } - catch (Exception e) { + catch (Exception& e) { std::cout << "Logging failure: " << e.where() << ": " << e.what() << std::endl; } diff --git a/src/fortran/logger.F90 b/src/fortran/logger.F90 index b2f508284..8a7de2e78 100644 --- a/src/fortran/logger.F90 +++ b/src/fortran/logger.F90 @@ -42,6 +42,8 @@ module smartredis_logger !! users do not have to import the iso_c_binding module into their !! programs +public :: log_data, log_warning, log_error + contains !> Log data to the SmartRedis log diff --git a/src/fortran/logger/logger_interfaces.inc b/src/fortran/logger/logger_interfaces.inc index 1abd8d24f..1fe730b21 100644 --- a/src/fortran/logger/logger_interfaces.inc +++ b/src/fortran/logger/logger_interfaces.inc @@ -25,7 +25,7 @@ ! OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. interface - subroutine c_log_data(level, data, data_length) bind(c, name="log_data") + subroutine c_log_data(level, data, data_length) bind(c, name="log_data_noexcept") use iso_c_binding, only : c_ptr, c_char, c_size_t import :: enum_kind integer(kind=enum_kind) :: level @@ -35,7 +35,7 @@ interface end interface interface - subroutine c_log_warning(level, data, data_length) bind(c, name="log_warning") + subroutine c_log_warning(level, data, data_length) bind(c, name="log_warning_noexcept") use iso_c_binding, only : c_ptr, c_char, c_size_t import :: enum_kind integer(kind=enum_kind) :: level @@ -45,7 +45,7 @@ interface end interface interface - subroutine c_log_error(level, data, data_length) bind(c, name="log_error") + subroutine c_log_error(level, data, data_length) bind(c, name="log_error_noexcept") use iso_c_binding, only : c_ptr, c_char, c_size_t import :: enum_kind integer(kind=enum_kind) :: level From 3ee80ee0b587d171eb87d4bf3608cda22f0f690a Mon Sep 17 00:00:00 2001 From: billschereriii Date: Mon, 28 Nov 2022 11:45:15 -0600 Subject: [PATCH 11/37] Add missing newlines to logging --- src/cpp/logger.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/cpp/logger.cpp b/src/cpp/logger.cpp index 3eb6a6e41..b5bcfb940 100644 --- a/src/cpp/logger.cpp +++ b/src/cpp/logger.cpp @@ -151,9 +151,11 @@ void Logger::log_data(SRLoggingLevel level, const std::string& data) if (_logfile.length() > 0) { std::ofstream logstream; logstream.open(_logfile, std::ios_base::app); - logstream << _client_id << "@" << timestamp << ":" << data; + logstream << _client_id << "@" << timestamp << ":" << data + << std::endl; } else { - std::cout << _client_id << "@" << timestamp << ":" << data; + std::cout << _client_id << "@" << timestamp << ":" << data + << std::endl; } } From b9211f16f6be781ede8ffd2f71bcb97cfa81bacd Mon Sep 17 00:00:00 2001 From: billschereriii Date: Mon, 28 Nov 2022 14:48:18 -0600 Subject: [PATCH 12/37] Update test cases to configure logging ID --- tests/cpp/client_test_copy_dataset.cpp | 2 +- tests/cpp/client_test_dataset.cpp | 2 +- tests/cpp/client_test_dataset_aggregation.cpp | 2 +- .../client_test_dataset_copy_assignment.cpp | 2 +- .../client_test_dataset_copy_constructor.cpp | 2 +- tests/cpp/client_test_dataset_empty.cpp | 2 +- .../client_test_dataset_move_assignment.cpp | 2 +- .../client_test_dataset_move_constructor.cpp | 2 +- ...lient_test_dataset_multiple_get_tensor.cpp | 2 +- tests/cpp/client_test_dataset_no_meta.cpp | 2 +- tests/cpp/client_test_dataset_no_tensors.cpp | 2 +- tests/cpp/client_test_delete_dataset.cpp | 2 +- tests/cpp/client_test_ensemble.cpp | 4 +- tests/cpp/client_test_ensemble_dataset.cpp | 4 +- tests/cpp/client_test_mnist.cpp | 2 +- tests/cpp/client_test_mnist_dataset.cpp | 2 +- tests/cpp/client_test_put_get_1D.cpp | 2 +- tests/cpp/client_test_rename_dataset.cpp | 2 +- tests/cpp/dataset_test_utils.h | 3 +- .../cpp/unit-tests/test_aggregation_list.cpp | 2 +- tests/cpp/unit-tests/test_client.cpp | 22 +- tests/cpp/unit-tests/test_client_ensemble.cpp | 4 +- tests/docker/cpp/docker_test.cpp | 2 +- tests/docker/fortran/test_docker.F90 | 2 +- tests/fortran/client_test_dataset.F90 | 2 +- .../client_test_dataset_aggregation.F90 | 2 +- tests/fortran/client_test_ensemble.F90 | 4 +- tests/fortran/client_test_initialized.F90 | 2 +- tests/fortran/client_test_misc_tensor.F90 | 2 +- tests/fortran/client_test_mnist.F90 | 2 +- tests/fortran/client_test_mnist_multigpu.F90 | 3 +- tests/fortran/client_test_put_get_1D.F90 | 2 +- tests/fortran/client_test_put_get_2D.F90 | 2 +- tests/fortran/client_test_put_get_3D.F90 | 2 +- .../client_test_put_get_unpack_dataset.F90 | 3 +- tests/python/test_address.py | 4 +- tests/python/test_dataset_aggregation.py | 4 +- tests/python/test_dataset_ops.py | 24 +- tests/python/test_errors.py | 278 +++++++++--------- tests/python/test_model_methods_torch.py | 12 +- tests/python/test_script_methods.py | 20 +- tests/python/test_tensor_ops.py | 24 +- 42 files changed, 235 insertions(+), 232 deletions(-) diff --git a/tests/cpp/client_test_copy_dataset.cpp b/tests/cpp/client_test_copy_dataset.cpp index 8db2764f6..1a5bfa775 100644 --- a/tests/cpp/client_test_copy_dataset.cpp +++ b/tests/cpp/client_test_copy_dataset.cpp @@ -52,7 +52,7 @@ void put_and_copy_dataset( fill_array(t_send_3, dims[0], dims[1], dims[2]); //Create Client and DataSet - DATASET_TEST_UTILS::DatasetTestClient client(use_cluster()); + DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), __FILE__); SmartRedis::DataSet source_dataset(dataset_name); //Add metadata to the DataSet diff --git a/tests/cpp/client_test_dataset.cpp b/tests/cpp/client_test_dataset.cpp index e19a000a5..46d82afc0 100644 --- a/tests/cpp/client_test_dataset.cpp +++ b/tests/cpp/client_test_dataset.cpp @@ -52,7 +52,7 @@ void put_get_dataset( fill_array(t_send_3, dims[0], dims[1], dims[2]); //Create Client and DataSet - DATASET_TEST_UTILS::DatasetTestClient client(use_cluster()); + DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), __FILE__); SmartRedis::DataSet sent_dataset(dataset_name); //Add metadata to the DataSet diff --git a/tests/cpp/client_test_dataset_aggregation.cpp b/tests/cpp/client_test_dataset_aggregation.cpp index 47a4af46c..6ac37249b 100644 --- a/tests/cpp/client_test_dataset_aggregation.cpp +++ b/tests/cpp/client_test_dataset_aggregation.cpp @@ -112,7 +112,7 @@ void check_dataset(SmartRedis::DataSet& dataset_1, int main(int argc, char* argv[]) { // Create client for dataset and aggregation list actions - SmartRedis::Client client(use_cluster()); + SmartRedis::Client client(use_cluster(), __FILE__); // Set a fill function for dataset creation void (*fill_function)(double***, int, int, int) = diff --git a/tests/cpp/client_test_dataset_copy_assignment.cpp b/tests/cpp/client_test_dataset_copy_assignment.cpp index b35dd009a..aace97bbd 100644 --- a/tests/cpp/client_test_dataset_copy_assignment.cpp +++ b/tests/cpp/client_test_dataset_copy_assignment.cpp @@ -52,7 +52,7 @@ void copy_assignment( fill_array(t_send_3, dims[0], dims[1], dims[2]); //Create Client and DataSets - DATASET_TEST_UTILS::DatasetTestClient client(use_cluster()); + DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), __FILE__); SmartRedis::DataSet* dataset = new SmartRedis::DataSet(dataset_name); //Add tensors to the DataSet diff --git a/tests/cpp/client_test_dataset_copy_constructor.cpp b/tests/cpp/client_test_dataset_copy_constructor.cpp index 638796238..fef9a2423 100644 --- a/tests/cpp/client_test_dataset_copy_constructor.cpp +++ b/tests/cpp/client_test_dataset_copy_constructor.cpp @@ -52,7 +52,7 @@ void copy_constructor( fill_array(t_send_3, dims[0], dims[1], dims[2]); //Create Client and DataSet - DATASET_TEST_UTILS::DatasetTestClient client(use_cluster()); + DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), __FILE__); SmartRedis::DataSet* dataset = new SmartRedis::DataSet(dataset_name); //Add tensors to the DataSet diff --git a/tests/cpp/client_test_dataset_empty.cpp b/tests/cpp/client_test_dataset_empty.cpp index c70002339..570a7f338 100644 --- a/tests/cpp/client_test_dataset_empty.cpp +++ b/tests/cpp/client_test_dataset_empty.cpp @@ -35,7 +35,7 @@ void put_get_empty_dataset(std::string dataset_name) { //Create Client and DataSet - SmartRedis::Client client(use_cluster()); + SmartRedis::Client client(use_cluster(), __FILE__); SmartRedis::DataSet sent_dataset(dataset_name); //Put the DataSet into the database diff --git a/tests/cpp/client_test_dataset_move_assignment.cpp b/tests/cpp/client_test_dataset_move_assignment.cpp index 7e52c213c..4c0697fc3 100644 --- a/tests/cpp/client_test_dataset_move_assignment.cpp +++ b/tests/cpp/client_test_dataset_move_assignment.cpp @@ -52,7 +52,7 @@ void put_get_3D_array( fill_array(t_send_3, dims[0], dims[1], dims[2]); //Create Client and DataSets - DATASET_TEST_UTILS::DatasetTestClient client(use_cluster()); + DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), __FILE__); SmartRedis::DataSet* dataset = new SmartRedis::DataSet(dataset_name); //Add tensors to the DataSet diff --git a/tests/cpp/client_test_dataset_move_constructor.cpp b/tests/cpp/client_test_dataset_move_constructor.cpp index c33b5c06b..e1b70f87b 100644 --- a/tests/cpp/client_test_dataset_move_constructor.cpp +++ b/tests/cpp/client_test_dataset_move_constructor.cpp @@ -52,7 +52,7 @@ void move_constructor( fill_array(t_send_3, dims[0], dims[1], dims[2]); //Create Client and DataSets - DATASET_TEST_UTILS::DatasetTestClient client(use_cluster()); + DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), __FILE__); SmartRedis::DataSet* dataset = new SmartRedis::DataSet(dataset_name); //Add tensors to the DataSet diff --git a/tests/cpp/client_test_dataset_multiple_get_tensor.cpp b/tests/cpp/client_test_dataset_multiple_get_tensor.cpp index bf82e403b..28ec361a9 100644 --- a/tests/cpp/client_test_dataset_multiple_get_tensor.cpp +++ b/tests/cpp/client_test_dataset_multiple_get_tensor.cpp @@ -52,7 +52,7 @@ void get_multiple_tensors( fill_array(t_send_3, dims[0], dims[1], dims[2]); //Create Client and DataSet - DATASET_TEST_UTILS::DatasetTestClient client(use_cluster()); + DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), __FILE__); SmartRedis::DataSet sent_dataset(dataset_name); //Add metadata to the DataSet diff --git a/tests/cpp/client_test_dataset_no_meta.cpp b/tests/cpp/client_test_dataset_no_meta.cpp index 9e28a65b0..7889127c8 100644 --- a/tests/cpp/client_test_dataset_no_meta.cpp +++ b/tests/cpp/client_test_dataset_no_meta.cpp @@ -52,7 +52,7 @@ void put_get_dataset( fill_array(t_send_3, dims[0], dims[1], dims[2]); //Create Client and DataSet - DATASET_TEST_UTILS::DatasetTestClient client(use_cluster()); + DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), __FILE__); SmartRedis::DataSet sent_dataset(dataset_name); //Add tensors to the DataSet diff --git a/tests/cpp/client_test_dataset_no_tensors.cpp b/tests/cpp/client_test_dataset_no_tensors.cpp index 9014e7b55..b4b8fa9f2 100644 --- a/tests/cpp/client_test_dataset_no_tensors.cpp +++ b/tests/cpp/client_test_dataset_no_tensors.cpp @@ -34,7 +34,7 @@ void put_dataset_no_tensors(std::string dataset_name) { //Create Client and DataSet - DATASET_TEST_UTILS::DatasetTestClient client(use_cluster()); + DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), __FILE__); SmartRedis::DataSet sent_dataset(dataset_name); //Add metadata to the DataSet diff --git a/tests/cpp/client_test_delete_dataset.cpp b/tests/cpp/client_test_delete_dataset.cpp index 7e6f3df8c..488929272 100644 --- a/tests/cpp/client_test_delete_dataset.cpp +++ b/tests/cpp/client_test_delete_dataset.cpp @@ -52,7 +52,7 @@ void dataset_delete( fill_array(t_send_3, dims[0], dims[1], dims[2]); //Create Client and DataSets - DATASET_TEST_UTILS::DatasetTestClient client(use_cluster()); + DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), __FILE__); SmartRedis::DataSet* dataset = new SmartRedis::DataSet(dataset_name); //Add tensors to the DataSet diff --git a/tests/cpp/client_test_ensemble.cpp b/tests/cpp/client_test_ensemble.cpp index 2743d203f..2c11e9c24 100644 --- a/tests/cpp/client_test_ensemble.cpp +++ b/tests/cpp/client_test_ensemble.cpp @@ -58,7 +58,7 @@ void produce( std::string keyout="", std::string keyin="") { - SmartRedis::Client client(use_cluster()); + SmartRedis::Client client(use_cluster(), __FILE__ "::producer"); client.use_model_ensemble_prefix(true); // Tensors @@ -128,7 +128,7 @@ void consume(std::vector dims, std::string keyout="", std::string keyin="") { - SmartRedis::Client client(use_cluster()); + SmartRedis::Client client(use_cluster(), __FILE__ "::consumer"); client.use_model_ensemble_prefix(true); // Tensors diff --git a/tests/cpp/client_test_ensemble_dataset.cpp b/tests/cpp/client_test_ensemble_dataset.cpp index fcc02372f..605367fbf 100644 --- a/tests/cpp/client_test_ensemble_dataset.cpp +++ b/tests/cpp/client_test_ensemble_dataset.cpp @@ -35,7 +35,7 @@ void rename_dataset(std::string keyout) { std::vector dims({10,10,2}); - DATASET_TEST_UTILS::DatasetTestClient client(use_cluster()); + DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), __FILE__); client.use_tensor_ensemble_prefix(true); double*** t_send_1 = @@ -137,7 +137,7 @@ void add_to_aggregation_list(std::string keyout) { std::vector dims({10,10,2}); - DATASET_TEST_UTILS::DatasetTestClient client(use_cluster()); + DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), __FILE__); client.use_tensor_ensemble_prefix(true); client.use_list_ensemble_prefix(true); diff --git a/tests/cpp/client_test_mnist.cpp b/tests/cpp/client_test_mnist.cpp index 53c1d29a1..d19445eba 100644 --- a/tests/cpp/client_test_mnist.cpp +++ b/tests/cpp/client_test_mnist.cpp @@ -52,7 +52,7 @@ void load_mnist_image_to_array(float**** img) void run_mnist(const std::string& model_name, const std::string& script_name) { - SmartRedis::Client client(use_cluster()); + SmartRedis::Client client(use_cluster(), __FILE__); float**** array = allocate_4D_array(1,1,28,28); float** result = allocate_2D_array(1, 10); diff --git a/tests/cpp/client_test_mnist_dataset.cpp b/tests/cpp/client_test_mnist_dataset.cpp index 68c48faff..b53db6946 100644 --- a/tests/cpp/client_test_mnist_dataset.cpp +++ b/tests/cpp/client_test_mnist_dataset.cpp @@ -52,7 +52,7 @@ void load_mnist_image_to_array(float**** img) void run_mnist(const std::string& model_name, const std::string& script_name) { - SmartRedis::Client client(use_cluster()); + SmartRedis::Client client(use_cluster(), __FILE__); float**** array = allocate_4D_array(1,1,28,28); float** result = allocate_2D_array(1, 10); diff --git a/tests/cpp/client_test_put_get_1D.cpp b/tests/cpp/client_test_put_get_1D.cpp index 649bf5b0e..c58c7fe86 100644 --- a/tests/cpp/client_test_put_get_1D.cpp +++ b/tests/cpp/client_test_put_get_1D.cpp @@ -38,7 +38,7 @@ void put_get_1D_array( SRTensorType type, std::string key_suffix="") { - SmartRedis::Client client(use_cluster()); + SmartRedis::Client client(use_cluster(), __FILE__); //Allocate and fill arrays T_send* array = (T_send*)malloc(dims[0]*sizeof(T_send)); diff --git a/tests/cpp/client_test_rename_dataset.cpp b/tests/cpp/client_test_rename_dataset.cpp index dc301de57..048b918c9 100644 --- a/tests/cpp/client_test_rename_dataset.cpp +++ b/tests/cpp/client_test_rename_dataset.cpp @@ -52,7 +52,7 @@ void rename_dataset( fill_array(t_send_3, dims[0], dims[1], dims[2]); //Create Client and DataSet - DATASET_TEST_UTILS::DatasetTestClient client(use_cluster()); + DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), __FILE__); SmartRedis::DataSet sent_dataset(dataset_name); //Add metadata to the DataSet diff --git a/tests/cpp/dataset_test_utils.h b/tests/cpp/dataset_test_utils.h index 0fc4b4167..8667c214d 100644 --- a/tests/cpp/dataset_test_utils.h +++ b/tests/cpp/dataset_test_utils.h @@ -43,7 +43,8 @@ namespace DATASET_TEST_UTILS { class DatasetTestClient : public SmartRedis::Client { public: - DatasetTestClient(bool cluster) : Client(cluster) {}; + DatasetTestClient(bool cluster, const std::string& name) + : Client(cluster, name) {}; bool hash_field_exists(const std::string& key, const std::string& field) { diff --git a/tests/cpp/unit-tests/test_aggregation_list.cpp b/tests/cpp/unit-tests/test_aggregation_list.cpp index 119b4a936..7685dcafa 100644 --- a/tests/cpp/unit-tests/test_aggregation_list.cpp +++ b/tests/cpp/unit-tests/test_aggregation_list.cpp @@ -148,7 +148,7 @@ SCENARIO("Testing Dataset aggregation via our client", "[List]") std::cout << std::to_string(get_time_offset()) << ": Testing Dataset aggregation via our client" << std::endl; GIVEN("A Client object and vector of DataSet objects") { - Client client(use_cluster()); + Client client(use_cluster(), __FILE__); std::vector datasets; diff --git a/tests/cpp/unit-tests/test_client.cpp b/tests/cpp/unit-tests/test_client.cpp index 2e936d55c..0e4679c74 100644 --- a/tests/cpp/unit-tests/test_client.cpp +++ b/tests/cpp/unit-tests/test_client.cpp @@ -97,7 +97,7 @@ SCENARIO("Testing Dataset Functions on Client Object", "[Client]") std::cout << std::to_string(get_time_offset()) << ": Testing Dataset Functions on Client Object" << std::endl; GIVEN("A Client object") { - Client client(use_cluster()); + Client client(use_cluster(), __FILE__); THEN("get, rename, and copy DataSet called on " "a nonexistent DataSet throws errors") @@ -193,7 +193,7 @@ SCENARIO("Testing Tensor Functions on Client Object", "[Client]") std::cout << std::to_string(get_time_offset()) << ": Testing Tensor Functions on Client Object" << std::endl; GIVEN("A Client object") { - Client client(use_cluster()); + Client client(use_cluster(), __FILE__); AND_WHEN("Tensors of each type are created and put into the Client") { @@ -473,7 +473,7 @@ SCENARIO("Testing INFO Functions on Client Object", "[Client]") std::cout << std::to_string(get_time_offset()) << ": Testing INFO Functions on Client Object" << std::endl; GIVEN("A Client object") { - Client client(use_cluster()); + Client client(use_cluster(), __FILE__); WHEN("INFO or CLUSTER INFO is called on database with " "an invalid address") @@ -522,7 +522,7 @@ SCENARIO("Testing AI.INFO Functions on Client Object", "[Client]") std::cout << std::to_string(get_time_offset()) << ": Testing AI.INFO Functions on Client Object" << std::endl; GIVEN("A Client object") { - Client client(use_cluster()); + Client client(use_cluster(), __FILE__); WHEN("AI.INFO called on database with an invalid address") { @@ -571,7 +571,7 @@ SCENARIO("Testing FLUSHDB on empty Client Object", "[Client][FLUSHDB]") std::cout << std::to_string(get_time_offset()) << ": Testing FLUSHDB on empty Client Object" << std::endl; GIVEN("An empty non-cluster Client object") { - Client client(use_cluster()); + Client client(use_cluster(), __FILE__); WHEN("FLUSHDB is called on database with " "an invalid address") @@ -611,7 +611,7 @@ SCENARIO("Testing FLUSHDB on Client Object", "[Client][FLUSHDB]") if (use_cluster()) return; - Client client(use_cluster()); + Client client(use_cluster(), __FILE__); std::string dataset_name = "test_dataset_name"; DataSet dataset(dataset_name); dataset.add_meta_string("meta_string_name", "meta_string_val"); @@ -647,7 +647,7 @@ SCENARIO("Testing CONFIG GET and CONFIG SET on Client Object", "[Client]") std::cout << std::to_string(get_time_offset()) << ": Testing CONFIG GET and CONFIG SET on Client Object" << std::endl; GIVEN("A Client object") { - Client client(use_cluster()); + Client client(use_cluster(), __FILE__); WHEN("CONFIG GET or CONFIG SET are called on databases with " "invalid addresses ") @@ -692,7 +692,7 @@ SCENARIO("Test CONFIG GET on an unsupported command", "[Client]") std::cout << std::to_string(get_time_offset()) << ": Test CONFIG GET on an unsupported command" << std::endl; GIVEN("A client object") { - Client client(use_cluster()); + Client client(use_cluster(), __FILE__); std::string address = parse_SSDB(std::getenv("SSDB")); WHEN("CONFIG GET is called with an unsupported command") @@ -713,7 +713,7 @@ SCENARIO("Test CONFIG SET on an unsupported command", "[Client]") std::cout << std::to_string(get_time_offset()) << ": Test CONFIG SET on an unsupported command" << std::endl; GIVEN("A client object") { - Client client(use_cluster()); + Client client(use_cluster(), __FILE__); std::string address = parse_SSDB(std::getenv("SSDB")); WHEN("CONFIG SET is called with an unsupported command") @@ -734,7 +734,7 @@ SCENARIO("Testing SAVE command on Client Object", "[!mayfail][Client][SAVE]") std::cout << std::to_string(get_time_offset()) << ": Testing SAVE command on Client Object" << std::endl; GIVEN("A client object and some data") { - Client client(use_cluster()); + Client client(use_cluster(), __FILE__); std::string dataset_name = "test_save_dataset"; DataSet dataset(dataset_name); dataset.add_meta_string("meta_string_save_name", "meta_string_val"); @@ -813,7 +813,7 @@ SCENARIO("Testing Multi-GPU Function error cases", "[Client]") std::cout << std::to_string(get_time_offset()) << ": Testing Multi-GPU Function error cases" << std::endl; GIVEN("A Client object, a script, and a model") { - Client client(use_cluster()); + Client client(use_cluster(), __FILE__); std::string model_key = "a_model"; std::string model_file = "./../../mnist_data/mnist_cnn.pt"; std::string script_key = "a_script"; diff --git a/tests/cpp/unit-tests/test_client_ensemble.cpp b/tests/cpp/unit-tests/test_client_ensemble.cpp index 5da09beeb..099945b11 100644 --- a/tests/cpp/unit-tests/test_client_ensemble.cpp +++ b/tests/cpp/unit-tests/test_client_ensemble.cpp @@ -137,7 +137,7 @@ SCENARIO("Testing Client ensemble using a producer/consumer paradigm") putenv(keyin_env_put); putenv(keyout_env_put); - Client producer_client(use_cluster()); + Client producer_client(use_cluster(), __FILE__); producer_client.use_model_ensemble_prefix(true); // Tensors @@ -188,7 +188,7 @@ SCENARIO("Testing Client ensemble using a producer/consumer paradigm") putenv(keyin_env_get); putenv(keyout_env_get); - Client consumer_client(use_cluster()); + Client consumer_client(use_cluster(), __FILE__); consumer_client.use_model_ensemble_prefix(true); // Tensors diff --git a/tests/docker/cpp/docker_test.cpp b/tests/docker/cpp/docker_test.cpp index a65b09740..7ab614467 100644 --- a/tests/docker/cpp/docker_test.cpp +++ b/tests/docker/cpp/docker_test.cpp @@ -30,7 +30,7 @@ int main(int argc, char* argv[]) { - SmartRedis::Client client(false); + SmartRedis::Client client(false, __FILE__); std::vector data = {1.0, 2.0, 3.0}; std::vector dims = {3}; diff --git a/tests/docker/fortran/test_docker.F90 b/tests/docker/fortran/test_docker.F90 index 7da5a689c..06baf3f28 100644 --- a/tests/docker/fortran/test_docker.F90 +++ b/tests/docker/fortran/test_docker.F90 @@ -38,7 +38,7 @@ program main real(kind=8), dimension(dim1) :: tensor real(kind=8), dimension(dim1) :: returned - result = client%initialize(.FALSE.) + result = client%initialize(.FALSE., "test_docker.F90") if (result .ne. SRNoError) stop call random_number(tensor) diff --git a/tests/fortran/client_test_dataset.F90 b/tests/fortran/client_test_dataset.F90 index 9cb428188..4433942ce 100644 --- a/tests/fortran/client_test_dataset.F90 +++ b/tests/fortran/client_test_dataset.F90 @@ -164,7 +164,7 @@ program main if (.not. all(meta_int64_recv == meta_int64_vec)) error stop 'meta_int64: FAILED' ! test dataset_existence - result = client%initialize(use_cluster()) + result = client%initialize(use_cluster(), __FILE__) if (result .ne. SRNoError) error stop result = client%dataset_exists("nonexistent", exists) if (result .ne. SRNoError) error stop diff --git a/tests/fortran/client_test_dataset_aggregation.F90 b/tests/fortran/client_test_dataset_aggregation.F90 index 91be63cdb..e05380a84 100644 --- a/tests/fortran/client_test_dataset_aggregation.F90 +++ b/tests/fortran/client_test_dataset_aggregation.F90 @@ -51,7 +51,7 @@ program main character(len=12) :: dataset_name integer :: result - result = client%initialize(use_cluster()) + result = client%initialize(use_cluster(), __FILE__) if (result .ne. SRNoError) error stop call random_number(true_vectors) diff --git a/tests/fortran/client_test_ensemble.F90 b/tests/fortran/client_test_ensemble.F90 index 70c09a47e..939cc7123 100644 --- a/tests/fortran/client_test_ensemble.F90 +++ b/tests/fortran/client_test_ensemble.F90 @@ -49,7 +49,7 @@ program main call setenv("SSKEYIN", "producer_0,producer_1") call setenv("SSKEYOUT", ensemble_keyout) -result = client%initialize(use_cluster()) +result = client%initialize(use_cluster(), __FILE__) if (result .ne. SRNoError) error stop result = client%use_model_ensemble_prefix(.true.) if (result .ne. SRNoError) error stop @@ -103,7 +103,7 @@ program main call setenv("SSKEYIN", "producer_1,producer_0") call setenv("SSKEYOUT", ensemble_keyout) -result = client%initialize(use_cluster()) +result = client%initialize(use_cluster(), __FILE__) if (result .ne. SRNoError) error stop result = client%use_model_ensemble_prefix(.true.) if (result .ne. SRNoError) error stop diff --git a/tests/fortran/client_test_initialized.F90 b/tests/fortran/client_test_initialized.F90 index 48e1d8124..8441660a7 100644 --- a/tests/fortran/client_test_initialized.F90 +++ b/tests/fortran/client_test_initialized.F90 @@ -40,7 +40,7 @@ program main if (client%isinitialized()) error stop 'client not initialized' - result = client%initialize(use_cluster()) + result = client%initialize(use_cluster(), __FILE__) if (result .ne. SRNoError) error stop if (.not. client%isinitialized()) error stop 'client is initialized' diff --git a/tests/fortran/client_test_misc_tensor.F90 b/tests/fortran/client_test_misc_tensor.F90 index 842d488ba..841b9354e 100644 --- a/tests/fortran/client_test_misc_tensor.F90 +++ b/tests/fortran/client_test_misc_tensor.F90 @@ -46,7 +46,7 @@ program main integer :: result logical(kind=c_bool) :: exists - result = client%initialize(use_cluster()) + result = client%initialize(use_cluster(), __FILE__) if (result .ne. SRNoError) error stop print *, "Putting tensor" diff --git a/tests/fortran/client_test_mnist.F90 b/tests/fortran/client_test_mnist.F90 index 85cae2890..9da5e0d15 100644 --- a/tests/fortran/client_test_mnist.F90 +++ b/tests/fortran/client_test_mnist.F90 @@ -44,7 +44,7 @@ program mnist_test character(len=2) :: key_suffix integer :: result - result = client%initialize(use_cluster()) + result = client%initialize(use_cluster(), __FILE__) if (result .ne. SRNoError) error stop result = client%set_model_from_file(model_key, model_file, "TORCH", "CPU") diff --git a/tests/fortran/client_test_mnist_multigpu.F90 b/tests/fortran/client_test_mnist_multigpu.F90 index d62bde5ce..eb567d8cf 100644 --- a/tests/fortran/client_test_mnist_multigpu.F90 +++ b/tests/fortran/client_test_mnist_multigpu.F90 @@ -47,7 +47,8 @@ program mnist_test character(len=2) :: key_suffix integer :: sr_return_code - sr_return_code = client%initialize(use_cluster()) + sr_return_code = client%initialize(use_cluster(), & + __FILE__) if (sr_return_code .ne. SRNoError) error stop sr_return_code = client%set_model_from_file_multigpu(model_key, model_file, "TORCH", first_gpu, num_gpus) diff --git a/tests/fortran/client_test_put_get_1D.F90 b/tests/fortran/client_test_put_get_1D.F90 index eac4739e8..97655ed73 100644 --- a/tests/fortran/client_test_put_get_1D.F90 +++ b/tests/fortran/client_test_put_get_1D.F90 @@ -73,7 +73,7 @@ program main recv_array_integer_64(i) = irand() enddo - result = client%initialize(use_cluster()) + result = client%initialize(use_cluster(), __FILE__) if (result .ne. SRNoError) error stop result = client%put_tensor("true_array_real_32", true_array_real_32, shape(true_array_real_32)) diff --git a/tests/fortran/client_test_put_get_2D.F90 b/tests/fortran/client_test_put_get_2D.F90 index 9326fb0df..85e547af3 100644 --- a/tests/fortran/client_test_put_get_2D.F90 +++ b/tests/fortran/client_test_put_get_2D.F90 @@ -74,7 +74,7 @@ program main recv_array_integer_64(i,j) = irand() enddo; enddo - result = client%initialize(use_cluster()) + result = client%initialize(use_cluster(), __FILE__) if (result .ne. SRNoError) error stop result = client%put_tensor("true_array_real_32", true_array_real_32, shape(true_array_real_32)) diff --git a/tests/fortran/client_test_put_get_3D.F90 b/tests/fortran/client_test_put_get_3D.F90 index 3f2e970a7..7f143a8fa 100644 --- a/tests/fortran/client_test_put_get_3D.F90 +++ b/tests/fortran/client_test_put_get_3D.F90 @@ -76,7 +76,7 @@ program main recv_array_integer_64(i,j,k) = irand() enddo; enddo; enddo - result = client%initialize(use_cluster()) + result = client%initialize(use_cluster(), __FILE__) if (result .ne. SRNoError) error stop result = client%put_tensor("true_array_real_32", true_array_real_32, shape(true_array_real_32)) diff --git a/tests/fortran/client_test_put_get_unpack_dataset.F90 b/tests/fortran/client_test_put_get_unpack_dataset.F90 index 7ee155751..d6661bd05 100644 --- a/tests/fortran/client_test_put_get_unpack_dataset.F90 +++ b/tests/fortran/client_test_put_get_unpack_dataset.F90 @@ -61,7 +61,8 @@ program main integer :: err_code - result = client%initialize(use_cluster()) + result = client%initialize(use_cluster(), & + __FILE__) if (result .ne. SRNoError) error stop call random_number(true_array_real_32) diff --git a/tests/python/test_address.py b/tests/python/test_address.py index c26693ab6..deced09d3 100644 --- a/tests/python/test_address.py +++ b/tests/python/test_address.py @@ -29,13 +29,13 @@ from smartredis import Client -def test_address(use_cluster): +def test_address(use_cluster, context): # get env var to set through client init ssdb = os.environ["SSDB"] del os.environ["SSDB"] # client init should fail if SSDB not set - c = Client(address=ssdb, cluster=use_cluster) + c = Client(address=ssdb, cluster=use_cluster, client_id=context) # check if SSDB was set anyway assert os.environ["SSDB"] == ssdb diff --git a/tests/python/test_dataset_aggregation.py b/tests/python/test_dataset_aggregation.py index 4477fbcd0..ad7aa403b 100644 --- a/tests/python/test_dataset_aggregation.py +++ b/tests/python/test_dataset_aggregation.py @@ -31,9 +31,9 @@ from smartredis.error import * -def test_aggregation(use_cluster): +def test_aggregation(use_cluster, context): num_datasets = 4 - client = Client(None, use_cluster) + client = Client(None, use_cluster, client_id=context) # Build datasets original_datasets = [create_dataset(f"dataset_{i}") for i in range(num_datasets)] diff --git a/tests/python/test_dataset_ops.py b/tests/python/test_dataset_ops.py index 474bd18b5..dd0676942 100644 --- a/tests/python/test_dataset_ops.py +++ b/tests/python/test_dataset_ops.py @@ -31,12 +31,12 @@ from smartredis.error import * -def test_copy_dataset(use_cluster): +def test_copy_dataset(use_cluster, context): # test copying dataset from one key to another dataset = create_dataset("test_dataset_copy") - client = Client(None, use_cluster) + client = Client(None, use_cluster, client_id=context) client.put_dataset(dataset) client.copy_dataset("test_dataset_copy", "test_dataset_copied") @@ -67,12 +67,12 @@ def test_copy_dataset(use_cluster): ) -def test_rename_dataset(use_cluster): +def test_rename_dataset(use_cluster, context): # test renaming a dataset in the database dataset = create_dataset("dataset_rename") - client = Client(None, use_cluster) + client = Client(None, use_cluster, client_id=context) client.put_dataset(dataset) client.rename_dataset("dataset_rename", "dataset_renamed") @@ -105,12 +105,12 @@ def test_rename_dataset(use_cluster): ) -def test_delete_dataset(use_cluster): +def test_delete_dataset(use_cluster, context): # test renaming a dataset in the database dataset = create_dataset("dataset_delete") - client = Client(None, use_cluster) + client = Client(None, use_cluster, client_id=context) client.put_dataset(dataset) client.delete_dataset( @@ -123,25 +123,25 @@ def test_delete_dataset(use_cluster): # ----------- Error handling ------------------------------------ -def test_rename_nonexisting_dataset(use_cluster): +def test_rename_nonexisting_dataset(use_cluster, context): - client = Client(None, use_cluster) + client = Client(None, use_cluster, client_id=context) with pytest.raises(RedisReplyError): client.rename_dataset("not-a-tensor", "still-not-a-tensor") -def test_copy_nonexistant_dataset(use_cluster): +def test_copy_nonexistant_dataset(use_cluster, context): - client = Client(None, use_cluster) + client = Client(None, use_cluster, client_id=context) with pytest.raises(RedisReplyError): client.copy_dataset("not-a-tensor", "still-not-a-tensor") -def test_copy_not_dataset(use_cluster): +def test_copy_not_dataset(use_cluster, context): def test_func(param): print(param) - client = Client(None, use_cluster) + client = Client(None, use_cluster, client_id=context) client.set_function("test_func_dataset", test_func) with pytest.raises(RedisReplyError): client.copy_dataset("test_func_dataset", "test_fork_dataset") diff --git a/tests/python/test_errors.py b/tests/python/test_errors.py index 16f798274..5ec5d8005 100644 --- a/tests/python/test_errors.py +++ b/tests/python/test_errors.py @@ -32,51 +32,51 @@ from smartredis.error import * -def test_SSDB_not_set(use_cluster): +def test_SSDB_not_set(use_cluster, context): ssdb = os.environ["SSDB"] del os.environ["SSDB"] with pytest.raises(RedisConnectionError): - c = Client(None, use_cluster) + c = Client(None, use_cluster, client_id=context) os.environ["SSDB"] = ssdb -def test_bad_SSDB(use_cluster): +def test_bad_SSDB(use_cluster, context): ssdb = os.environ["SSDB"] del os.environ["SSDB"] os.environ["SSDB"] = "not-an-address:6379;" with pytest.raises(RedisConnectionError): - c = Client(None, use_cluster) + c = Client(None, use_cluster, client_id=context) os.environ["SSDB"] = ssdb -def test_bad_get_tensor(use_cluster): - c = Client(None, use_cluster) +def test_bad_get_tensor(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(RedisReplyError): c.get_tensor("not-a-key") -def test_bad_get_dataset(use_cluster): - c = Client(None, use_cluster) +def test_bad_get_dataset(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(RedisKeyError): c.get_dataset("not-a-key") -def test_bad_script_file(use_cluster): - c = Client(None, use_cluster) +def test_bad_script_file(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(FileNotFoundError): c.set_script_from_file("key", "not-a-file") -def test_get_non_existant_script(use_cluster): - c = Client(None, use_cluster) +def test_get_non_existant_script(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(RedisReplyError): script = c.get_script("not-a-script") -def test_bad_function_execution(use_cluster): +def test_bad_function_execution(use_cluster, context): """Error raised inside function""" - c = Client(None, use_cluster) + c = Client(None, use_cluster, client_id=context) c.set_function("bad-function", bad_function) data = np.array([1, 2, 3, 4]) c.put_tensor("bad-func-tensor", data) @@ -84,10 +84,10 @@ def test_bad_function_execution(use_cluster): c.run_script("bad-function", "bad_function", ["bad-func-tensor"], ["output"]) -def test_missing_script_function(use_cluster): +def test_missing_script_function(use_cluster, context): """User requests to run a function not in the script""" - c = Client(None, use_cluster) + c = Client(None, use_cluster, client_id=context) c.set_function("bad-function", bad_function) with pytest.raises(RedisReplyError): c.run_script( @@ -95,27 +95,27 @@ def test_missing_script_function(use_cluster): ) -def test_wrong_model_name(mock_data, mock_model, use_cluster): +def test_wrong_model_name(mock_data, mock_model, use_cluster, context): """User requests to run a model that is not there""" data = mock_data.create_data(1) model = mock_model.create_torch_cnn() - c = Client(None, use_cluster) + c = Client(None, use_cluster, client_id=context) c.set_model("simple_cnn", model, "TORCH", "CPU") c.put_tensor("input", data[0]) with pytest.raises(RedisReplyError): c.run_model("wrong_cnn", ["input"], ["output"]) -def test_wrong_model_name_from_file(mock_data, mock_model, use_cluster): +def test_wrong_model_name_from_file(mock_data, mock_model, use_cluster, context): """User requests to run a model that is not there that was loaded from file.""" try: data = mock_data.create_data(1) mock_model.create_torch_cnn(filepath="./torch_cnn.pt") - c = Client(None, use_cluster) + c = Client(None, use_cluster, client_id=context) c.set_model_from_file("simple_cnn_from_file", "./torch_cnn.pt", "TORCH", "CPU") c.put_tensor("input", data[0]) with pytest.raises(RedisReplyError): @@ -124,16 +124,16 @@ def test_wrong_model_name_from_file(mock_data, mock_model, use_cluster): os.remove("torch_cnn.pt") -def test_bad_device(use_cluster): - c = Client(None, use_cluster) +def test_bad_device(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.set_script("key", "some_script", device="not-a-gpu") ##### # Test type errors from bad parameter types to Client API calls -def test_bad_type_put_tensor(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_put_tensor(use_cluster, context): + c = Client(None, use_cluster, client_id=context) array = np.array([1, 2, 3, 4]) with pytest.raises(TypeError): c.put_tensor(42, array) @@ -141,79 +141,79 @@ def test_bad_type_put_tensor(use_cluster): c.put_tensor("key", [1, 2, 3, 4]) -def test_unsupported_type_put_tensor(use_cluster): +def test_unsupported_type_put_tensor(use_cluster, context): """test an unsupported numpy type""" - c = Client(None, use_cluster) + c = Client(None, use_cluster, client_id=context) data = np.array([1, 2, 3, 4]).astype(np.uint64) with pytest.raises(TypeError): c.put_tensor("key", data) -def test_bad_type_get_tensor(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_get_tensor(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.get_tensor(42) -def test_bad_type_delete_tensor(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_delete_tensor(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.delete_tensor(42) -def test_bad_type_copy_tensor(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_copy_tensor(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.copy_tensor(42, "newname") with pytest.raises(TypeError): c.copy_tensor("oldname", 42) -def test_bad_type_rename_tensor(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_rename_tensor(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.rename_tensor(42, "newname") with pytest.raises(TypeError): c.rename_tensor("oldname", 42) -def test_bad_type_put_dataset(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_put_dataset(use_cluster, context): + c = Client(None, use_cluster, client_id=context) array = np.array([1, 2, 3, 4]) with pytest.raises(TypeError): c.put_dataset(array) -def test_bad_type_get_dataset(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_get_dataset(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.get_dataset(42) -def test_bad_type_delete_dataset(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_delete_dataset(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.delete_dataset(42) -def test_bad_type_copy_dataset(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_copy_dataset(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.copy_dataset(42, "dest") with pytest.raises(TypeError): c.copy_dataset("src", 42) -def test_bad_type_rename_dataset(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_rename_dataset(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.rename_dataset(42, "oldkey") with pytest.raises(TypeError): c.rename_dataset("newkey", 42) -def test_bad_type_set_function(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_set_function(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.set_function(42, bad_function) with pytest.raises(TypeError): @@ -221,8 +221,8 @@ def test_bad_type_set_function(use_cluster): with pytest.raises(TypeError): c.set_function("key", bad_function, 42) -def test_bad_type_set_function_multigpu(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_set_function_multigpu(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.set_function_multigpu(42, bad_function, 0, 1) with pytest.raises(TypeError): @@ -236,8 +236,8 @@ def test_bad_type_set_function_multigpu(use_cluster): with pytest.raises(ValueError): c.set_function_multigpu("key", bad_function, 0, 0) # invalid num GPUs -def test_bad_type_set_script(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_set_script(use_cluster, context): + c = Client(None, use_cluster, client_id=context) key = "key_for_script" script = "bad script but correct parameter type" device = "CPU" @@ -248,8 +248,8 @@ def test_bad_type_set_script(use_cluster): with pytest.raises(TypeError): c.set_script(key, script, 42) -def test_bad_type_set_script_multigpu(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_set_script_multigpu(use_cluster, context): + c = Client(None, use_cluster, client_id=context) key = "key_for_script" script = "bad script but correct parameter type" first_gpu = 0 @@ -267,8 +267,8 @@ def test_bad_type_set_script_multigpu(use_cluster): with pytest.raises(ValueError): c.set_script_multigpu(key, script, first_gpu, 0) -def test_bad_type_set_script_from_file(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_set_script_from_file(use_cluster, context): + c = Client(None, use_cluster, client_id=context) key = "key_for_script" scriptfile = "bad filename but correct parameter type" device = "CPU" @@ -279,8 +279,8 @@ def test_bad_type_set_script_from_file(use_cluster): with pytest.raises(TypeError): c.set_script_from_file(key, scriptfile, 42) -def test_bad_type_set_script_from_file_multigpu(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_set_script_from_file_multigpu(use_cluster, context): + c = Client(None, use_cluster, client_id=context) key = "key_for_script" scriptfile = "bad filename but correct parameter type" first_gpu = 0 @@ -294,14 +294,14 @@ def test_bad_type_set_script_from_file_multigpu(use_cluster): with pytest.raises(TypeError): c.set_script_from_file_multigpu(key, scriptfile, first_gpu, "not an integer") -def test_bad_type_get_script(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_get_script(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.get_script(42) -def test_bad_type_run_script(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_run_script(use_cluster, context): + c = Client(None, use_cluster, client_id=context) key = "my_script" fn_name = "phred" inputs = ["list", "of", "strings"] @@ -316,8 +316,8 @@ def test_bad_type_run_script(use_cluster): c.run_script(key, fn_name, inputs, 42) -def test_bad_type_run_script_multigpu(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_run_script_multigpu(use_cluster, context): + c = Client(None, use_cluster, client_id=context) key = "my_script" fn_name = "phred" inputs = ["list", "of", "strings"] @@ -345,15 +345,15 @@ def test_bad_type_run_script_multigpu(use_cluster): c.run_script_multigpu(key, fn_name, inputs, outputs, offset, first_gpu, 0) -def test_bad_type_get_model(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_get_model(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.get_model(42) -def test_bad_type_set_model(mock_model, use_cluster): +def test_bad_type_set_model(mock_model, use_cluster, context): model = mock_model.create_torch_cnn() - c = Client(None, use_cluster) + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.set_model(42, model, "TORCH", "CPU") with pytest.raises(TypeError): @@ -371,10 +371,10 @@ def test_bad_type_set_model(mock_model, use_cluster): with pytest.raises(TypeError): c.set_model("simple_cnn", model, "TORCH", "CPU", tag=42) -def test_bad_type_set_model_multigpu(mock_model, use_cluster): - c = Client(None, use_cluster) +def test_bad_type_set_model_multigpu(mock_model, use_cluster, context): + c = Client(None, use_cluster, client_id=context) model = mock_model.create_torch_cnn() - c = Client(None, use_cluster) + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.set_model_multigpu(42, model, "TORCH", 0, 1) with pytest.raises(TypeError): @@ -397,9 +397,9 @@ def test_bad_type_set_model_multigpu(mock_model, use_cluster): c.set_model_multigpu("simple_cnn", model, "TORCH", 0, 1, tag=42) -def test_bad_type_set_model_from_file(use_cluster): +def test_bad_type_set_model_from_file(use_cluster, context): modelfile = "bad filename but right parameter type" - c = Client(None, use_cluster) + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.set_model_from_file(42, modelfile, "TORCH", "CPU") with pytest.raises(TypeError): @@ -419,9 +419,9 @@ def test_bad_type_set_model_from_file(use_cluster): with pytest.raises(TypeError): c.set_model_from_file("simple_cnn", modelfile, "TORCH", "CPU", tag=42) -def test_bad_type_set_model_from_file_multigpu(use_cluster): +def test_bad_type_set_model_from_file_multigpu(use_cluster, context): modelfile = "bad filename but right parameter type" - c = Client(None, use_cluster) + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.set_model_from_file_multigpu(42, modelfile, "TORCH", 0, 1) with pytest.raises(TypeError): @@ -441,14 +441,14 @@ def test_bad_type_set_model_from_file_multigpu(use_cluster): with pytest.raises(TypeError): c.set_model_from_file_multigpu("simple_cnn", modelfile, "TORCH", 0, 1, tag=42) -def test_bad_type_run_model(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_run_model(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.run_model(42) -def test_bad_type_run_model_multigpu(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_run_model_multigpu(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.run_model_multigpu(42, 0, 0, 1) with pytest.raises(TypeError): @@ -462,8 +462,8 @@ def test_bad_type_run_model_multigpu(use_cluster): with pytest.raises(ValueError): c.run_model_multigpu("simple_cnn", 0, 0, 0) -def test_bad_type_delete_model_multigpu(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_delete_model_multigpu(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.delete_model_multigpu(42, 0, 1) with pytest.raises(TypeError): @@ -475,8 +475,8 @@ def test_bad_type_delete_model_multigpu(use_cluster): with pytest.raises(ValueError): c.delete_model_multigpu("simple_cnn", 0, 0) -def test_bad_type_delete_script_multigpu(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_delete_script_multigpu(use_cluster, context): + c = Client(None, use_cluster, client_id=context) script_name = "my_script" with pytest.raises(TypeError): c.delete_script_multigpu(42, 0, 1) @@ -489,32 +489,32 @@ def test_bad_type_delete_script_multigpu(use_cluster): with pytest.raises(ValueError): c.delete_script_multigpu(script_name, 0, 0) -def test_bad_type_tensor_exists(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_tensor_exists(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.tensor_exists(42) -def test_bad_type_dataset_exists(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_dataset_exists(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.dataset_exists(42) -def test_bad_type_model_exists(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_model_exists(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.model_exists(42) -def test_bad_type_key_exists(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_key_exists(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.key_exists(42) -def test_bad_type_poll_key(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_poll_key(use_cluster, context): + c = Client(None, use_cluster, client_id=context) name = "some_key" freq = 42 num_tries = 42 @@ -527,8 +527,8 @@ def test_bad_type_poll_key(use_cluster): c.poll_key(name, freq, bogus) -def test_bad_type_poll_tensor(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_poll_tensor(use_cluster, context): + c = Client(None, use_cluster, client_id=context) name = "some_key" freq = 42 num_tries = 42 @@ -541,8 +541,8 @@ def test_bad_type_poll_tensor(use_cluster): c.poll_tensor(name, freq, bogus) -def test_bad_type_poll_dataset(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_poll_dataset(use_cluster, context): + c = Client(None, use_cluster, client_id=context) name = "some_key" freq = 42 num_tries = 42 @@ -555,8 +555,8 @@ def test_bad_type_poll_dataset(use_cluster): c.poll_dataset(name, freq, bogus) -def test_bad_type_poll_model(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_poll_model(use_cluster, context): + c = Client(None, use_cluster, client_id=context) name = "some_key" freq = 42 num_tries = 42 @@ -569,44 +569,44 @@ def test_bad_type_poll_model(use_cluster): c.poll_model(name, freq, bogus) -def test_bad_type_set_data_source(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_set_data_source(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.set_data_source(42) -def test_bad_type_use_model_ensemble_prefix(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_use_model_ensemble_prefix(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.use_model_ensemble_prefix("not a boolean") -def test_bad_type_use_list_ensemble_prefix(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_use_list_ensemble_prefix(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.use_list_ensemble_prefix("not a boolean") -def test_bad_type_use_tensor_ensemble_prefix(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_use_tensor_ensemble_prefix(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.use_tensor_ensemble_prefix("not a boolean") -def test_bad_type_get_db_node_info(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_get_db_node_info(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.get_db_node_info("not a list") -def test_bad_type_get_db_cluster_info(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_get_db_cluster_info(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.get_db_cluster_info("not a list") -def test_bad_type_get_ai_info(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_get_ai_info(use_cluster, context): + c = Client(None, use_cluster, client_id=context) address = ["list", "of", "str"] key = "ai.info.key" with pytest.raises(TypeError): @@ -617,22 +617,22 @@ def test_bad_type_get_ai_info(use_cluster): c.get_ai_info(address, key, "not a boolean") -def test_bad_type_flush_db(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_flush_db(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.flush_db("not a list") -def test_bad_type_config_get(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_config_get(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.config_get("timeout", 42) with pytest.raises(TypeError): c.config_get(42, "address") -def test_bad_type_config_set(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_config_set(use_cluster, context): + c = Client(None, use_cluster, client_id=context) param = "timeout" value = "never" address = "127.0.0.1:6379" @@ -644,42 +644,42 @@ def test_bad_type_config_set(use_cluster): c.config_set(param, value, 42) -def test_bad_type_save(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_save(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.save("not a list") -def test_bad_type_append_to_list(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_append_to_list(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.append_to_list(42, 42) -def test_bad_type_delete_list(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_delete_list(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.delete_list(42) -def test_bad_type_copy_list(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_copy_list(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.copy_list(42, "dest") with pytest.raises(TypeError): c.copy_list("src", 42) -def test_bad_type_rename_list(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_rename_list(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.rename_list(42, "dest") with pytest.raises(TypeError): c.rename_list("src", 42) -def test_bad_type_get_list_length(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_get_list_length(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.get_list_length(42) -def test_bad_type_poll_list_length(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_poll_list_length(use_cluster, context): + c = Client(None, use_cluster, client_id=context) name = "mylist" len = 42 pollfreq = 42 @@ -693,8 +693,8 @@ def test_bad_type_poll_list_length(use_cluster): with pytest.raises(TypeError): c.poll_list_length(name, len, pollfreq, "not an integer") -def test_bad_type_poll_list_length_gte(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_poll_list_length_gte(use_cluster, context): + c = Client(None, use_cluster, client_id=context) name = "mylist" len = 42 pollfreq = 42 @@ -708,8 +708,8 @@ def test_bad_type_poll_list_length_gte(use_cluster): with pytest.raises(TypeError): c.poll_list_length_gte(name, len, pollfreq, "not an integer") -def test_bad_type_poll_list_length_lte(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_poll_list_length_lte(use_cluster, context): + c = Client(None, use_cluster, client_id=context) name = "mylist" len = 42 pollfreq = 42 @@ -723,13 +723,13 @@ def test_bad_type_poll_list_length_lte(use_cluster): with pytest.raises(TypeError): c.poll_list_length_lte(name, len, pollfreq, "not an integer") -def test_bad_type_get_datasets_from_list(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_get_datasets_from_list(use_cluster, context): + c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): c.get_datasets_from_list(42) -def test_bad_type_get_dataset_list_range(use_cluster): - c = Client(None, use_cluster) +def test_bad_type_get_dataset_list_range(use_cluster, context): + c = Client(None, use_cluster, client_id=context) listname = "my_list" start_index = 0 end_index = 42 diff --git a/tests/python/test_model_methods_torch.py b/tests/python/test_model_methods_torch.py index 6a6d65c73..b71b521db 100644 --- a/tests/python/test_model_methods_torch.py +++ b/tests/python/test_model_methods_torch.py @@ -30,18 +30,18 @@ from smartredis import Client -def test_set_model(mock_model, use_cluster): +def test_set_model(mock_model, use_cluster, context): model = mock_model.create_torch_cnn() - c = Client(None, use_cluster) + c = Client(None, use_cluster, client_id=context) c.set_model("simple_cnn", model, "TORCH", "CPU") returned_model = c.get_model("simple_cnn") assert model == returned_model -def test_set_model_from_file(mock_model, use_cluster): +def test_set_model_from_file(mock_model, use_cluster, context): try: mock_model.create_torch_cnn(filepath="./torch_cnn.pt") - c = Client(None, use_cluster) + c = Client(None, use_cluster, client_id=context) c.set_model_from_file("file_cnn", "./torch_cnn.pt", "TORCH", "CPU") assert c.model_exists("file_cnn") returned_model = c.get_model("file_cnn") @@ -54,10 +54,10 @@ def test_set_model_from_file(mock_model, use_cluster): os.remove("torch_cnn.pt") -def test_torch_inference(mock_model, use_cluster): +def test_torch_inference(mock_model, use_cluster, context): # get model and set into database model = mock_model.create_torch_cnn() - c = Client(None, use_cluster) + c = Client(None, use_cluster, client_id=context) c.set_model("torch_cnn", model, "TORCH") # setup input tensor diff --git a/tests/python/test_script_methods.py b/tests/python/test_script_methods.py index e021240c7..2d09e6d38 100644 --- a/tests/python/test_script_methods.py +++ b/tests/python/test_script_methods.py @@ -34,25 +34,25 @@ file_path = osp.dirname(osp.abspath(__file__)) -def test_set_get_function(use_cluster): - c = Client(None, use_cluster) +def test_set_get_function(use_cluster, context): + c = Client(None, use_cluster, client_id=context) c.set_function("test-set-function", one_to_one) script = c.get_script("test-set-function") sent_script = inspect.getsource(one_to_one) assert script == sent_script -def test_set_get_script(use_cluster): - c = Client(None, use_cluster) +def test_set_get_script(use_cluster, context): + c = Client(None, use_cluster, client_id=context) sent_script = read_script_from_file() c.set_script("test-set-script", sent_script) script = c.get_script("test-set-script") assert sent_script == script -def test_set_script_from_file(use_cluster): +def test_set_script_from_file(use_cluster, context): sent_script = read_script_from_file() - c = Client(None, use_cluster) + c = Client(None, use_cluster, client_id=context) c.set_script_from_file( "test-script-file", osp.join(file_path, "./data_processing_script.txt") ) @@ -63,10 +63,10 @@ def test_set_script_from_file(use_cluster): assert not c.model_exists("test-script-file") -def test_run_script(use_cluster): +def test_run_script(use_cluster, context): data = np.array([[1, 2, 3, 4, 5]]) - c = Client(None, use_cluster) + c = Client(None, use_cluster, client_id=context) c.put_tensor("script-test-data", data) c.set_function("one-to-one", one_to_one) c.run_script("one-to-one", "one_to_one", ["script-test-data"], ["script-test-out"]) @@ -74,11 +74,11 @@ def test_run_script(use_cluster): assert out == 5 -def test_run_script_multi(use_cluster): +def test_run_script_multi(use_cluster, context): data = np.array([[1, 2, 3, 4]]) data_2 = np.array([[5, 6, 7, 8]]) - c = Client(None, use_cluster) + c = Client(None, use_cluster, client_id=context) c.put_tensor("srpt-multi-out-data-1", data) c.put_tensor("srpt-multi-out-data-2", data_2) c.set_function("two-to-one", two_to_one) diff --git a/tests/python/test_tensor_ops.py b/tests/python/test_tensor_ops.py index bea38cdb2..d0befa5bb 100644 --- a/tests/python/test_tensor_ops.py +++ b/tests/python/test_tensor_ops.py @@ -31,10 +31,10 @@ from smartredis.error import RedisReplyError -def test_copy_tensor(use_cluster): +def test_copy_tensor(use_cluster, context): # test copying tensor - client = Client(None, use_cluster) + client = Client(None, use_cluster, client_id=context) tensor = np.array([1, 2]) client.put_tensor("test_copy", tensor) @@ -46,10 +46,10 @@ def test_copy_tensor(use_cluster): assert np.array_equal(tensor, returned) -def test_rename_tensor(use_cluster): +def test_rename_tensor(use_cluster, context): # test renaming tensor - client = Client(None, use_cluster) + client = Client(None, use_cluster, client_id=context) tensor = np.array([1, 2]) client.put_tensor("test_rename", tensor) @@ -61,10 +61,10 @@ def test_rename_tensor(use_cluster): assert np.array_equal(tensor, returned) -def test_delete_tensor(use_cluster): +def test_delete_tensor(use_cluster, context): # test renaming tensor - client = Client(None, use_cluster) + client = Client(None, use_cluster, client_id=context) tensor = np.array([1, 2]) client.put_tensor("test_delete", tensor) @@ -76,25 +76,25 @@ def test_delete_tensor(use_cluster): # --------------- Error handling ---------------------- -def test_rename_nonexisting_key(use_cluster): +def test_rename_nonexisting_key(use_cluster, context): - client = Client(None, use_cluster) + client = Client(None, use_cluster, client_id=context) with pytest.raises(RedisReplyError): client.rename_tensor("not-a-tensor", "still-not-a-tensor") -def test_copy_nonexistant_key(use_cluster): +def test_copy_nonexistant_key(use_cluster, context): - client = Client(None, use_cluster) + client = Client(None, use_cluster, client_id=context) with pytest.raises(RedisReplyError): client.copy_tensor("not-a-tensor", "still-not-a-tensor") -def test_copy_not_tensor(use_cluster): +def test_copy_not_tensor(use_cluster, context): def test_func(param): print(param) - client = Client(None, use_cluster) + client = Client(None, use_cluster, client_id=context) client.set_function("test_func", test_func) with pytest.raises(RedisReplyError): client.copy_tensor("test_func", "test_fork") From 38f41d39bb27398aa429fcb91284c55fed2f1e8a Mon Sep 17 00:00:00 2001 From: billschereriii Date: Mon, 28 Nov 2022 15:02:20 -0600 Subject: [PATCH 13/37] Update examples to register client for logging --- examples/parallel/cpp/smartredis_mnist.cpp | 4 +++- examples/parallel/cpp/smartredis_put_get_3D.cpp | 10 +++++++--- examples/parallel/fortran/smartredis_dataset.F90 | 2 +- examples/parallel/fortran/smartredis_mnist.F90 | 2 +- examples/parallel/fortran/smartredis_put_get_3D.F90 | 2 +- examples/serial/cpp/smartredis_dataset.cpp | 2 +- examples/serial/cpp/smartredis_mnist.cpp | 2 +- examples/serial/cpp/smartredis_model.cpp | 2 +- examples/serial/cpp/smartredis_put_get_3D.cpp | 2 +- examples/serial/fortran/smartredis_dataset.F90 | 2 +- examples/serial/fortran/smartredis_put_get_3D.F90 | 2 +- examples/serial/python/example_model_file_torch.py | 2 +- examples/serial/python/example_model_torch.py | 2 +- examples/serial/python/example_put_get_dataset.py | 2 +- examples/serial/python/example_put_get_tensor.py | 2 +- examples/serial/python/example_script.py | 2 +- examples/serial/python/example_script_file.py | 2 +- 17 files changed, 25 insertions(+), 19 deletions(-) diff --git a/examples/parallel/cpp/smartredis_mnist.cpp b/examples/parallel/cpp/smartredis_mnist.cpp index e24a9b41e..ac1cfc561 100644 --- a/examples/parallel/cpp/smartredis_mnist.cpp +++ b/examples/parallel/cpp/smartredis_mnist.cpp @@ -100,10 +100,12 @@ int main(int argc, char* argv[]) { // Retrieve the MPI rank int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); + std::string client_id("Client "); + client_id += std::to_string(rank); // Initialize a Client object bool cluster_mode = true; // Set to false if not using a clustered database - SmartRedis::Client client(cluster_mode); + SmartRedis::Client client(cluster_mode, client_id); // Set the model and script that will be used by all ranks // from MPI rank 0. diff --git a/examples/parallel/cpp/smartredis_put_get_3D.cpp b/examples/parallel/cpp/smartredis_put_get_3D.cpp index 8304401b1..5f419960d 100644 --- a/examples/parallel/cpp/smartredis_put_get_3D.cpp +++ b/examples/parallel/cpp/smartredis_put_get_3D.cpp @@ -50,13 +50,17 @@ int main(int argc, char* argv[]) { for(size_t i=0; i Date: Mon, 28 Nov 2022 15:20:36 -0600 Subject: [PATCH 14/37] Tweak CI/CD YAML files to set up logging environment variables --- .github/workflows/run_post_merge_tests.yml | 2 ++ .github/workflows/run_tests.yml | 4 ++++ .github/workflows/run_tests_uds.yml | 2 ++ src/cpp/logger.cpp | 4 ++-- 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/run_post_merge_tests.yml b/.github/workflows/run_post_merge_tests.yml index 121d22821..21dbfed5a 100644 --- a/.github/workflows/run_post_merge_tests.yml +++ b/.github/workflows/run_post_merge_tests.yml @@ -140,5 +140,7 @@ jobs: if: contains(matrix.os, 'ubuntu') && !contains(matrix.compiler, 'intel') run: | export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/install/lib && + export SR_LOG_FILE=smartredis_examples_log.txt && + export SR_LOG_LEVEL=DEBUG && make test-examples diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index 6538ed963..25bdc8a05 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -107,6 +107,8 @@ jobs: bash ../build-scripts/build-catch.sh && cd ../ && export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/install/lib && + export SR_LOG_FILE=smartredis_cicd_tests_log.txt && + export SR_LOG_LEVEL=DEBUG && make test-verbose - name: Run Python coverage tests @@ -163,5 +165,7 @@ jobs: - name: Run testing with redis cluster run: | export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/install/lib && + export SR_LOG_FILE=smartredis_cicd_tests_log.txt && + export SR_LOG_LEVEL=DEBUG && make test-verbose diff --git a/.github/workflows/run_tests_uds.yml b/.github/workflows/run_tests_uds.yml index 206266c9b..cae816852 100644 --- a/.github/workflows/run_tests_uds.yml +++ b/.github/workflows/run_tests_uds.yml @@ -145,5 +145,7 @@ jobs: - name: Run testing with UDS redis run: | export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/install/lib && + export SR_LOG_FILE=smartredis_uds_tests_log.txt && + export SR_LOG_LEVEL=DEBUG && make test-verbose diff --git a/src/cpp/logger.cpp b/src/cpp/logger.cpp index 495ef66ff..188e78adb 100644 --- a/src/cpp/logger.cpp +++ b/src/cpp/logger.cpp @@ -55,7 +55,7 @@ void Logger::configure_logging(const std::string& client_id) _initialized = true; // Get the logfile - get_config_string(_logfile, "SS_LOG_FILE", "", true); + get_config_string(_logfile, "SR_LOG_FILE", "", true); std::string requestedLogfile(_logfile); bool missingLogFile = _logfile.length() == 0; @@ -73,7 +73,7 @@ void Logger::configure_logging(const std::string& client_id) // Get the logging level std::string level; - get_config_string(level, "SS_LOG_LEVEL", "", true); + get_config_string(level, "SR_LOG_LEVEL", "", true); bool missingLogLevel = level.length() == 0; bool badLogLevel = false; if (level.length() > 0) { From e31a122b1a6b815eed1f9ef86a9ef140f22bd85c Mon Sep 17 00:00:00 2001 From: billschereriii Date: Mon, 28 Nov 2022 15:39:18 -0600 Subject: [PATCH 15/37] __FILE__ is too unpredictable to use in Fortran --- examples/parallel/fortran/smartredis_dataset.F90 | 2 +- examples/parallel/fortran/smartredis_mnist.F90 | 2 +- examples/parallel/fortran/smartredis_put_get_3D.F90 | 2 +- examples/serial/fortran/smartredis_dataset.F90 | 2 +- examples/serial/fortran/smartredis_put_get_3D.F90 | 2 +- tests/fortran/client_test_dataset.F90 | 2 +- tests/fortran/client_test_dataset_aggregation.F90 | 3 ++- tests/fortran/client_test_ensemble.F90 | 2 +- tests/fortran/client_test_initialized.F90 | 2 +- tests/fortran/client_test_misc_tensor.F90 | 2 +- tests/fortran/client_test_mnist.F90 | 2 +- tests/fortran/client_test_mnist_multigpu.F90 | 2 +- tests/fortran/client_test_put_get_1D.F90 | 2 +- tests/fortran/client_test_put_get_2D.F90 | 2 +- tests/fortran/client_test_put_get_3D.F90 | 2 +- tests/fortran/client_test_put_get_unpack_dataset.F90 | 2 +- 16 files changed, 17 insertions(+), 16 deletions(-) diff --git a/examples/parallel/fortran/smartredis_dataset.F90 b/examples/parallel/fortran/smartredis_dataset.F90 index 1192a134e..feec26f5a 100644 --- a/examples/parallel/fortran/smartredis_dataset.F90 +++ b/examples/parallel/fortran/smartredis_dataset.F90 @@ -85,7 +85,7 @@ program main if (result .ne. SRNoError) error stop 'dataset%get_meta_scalars failed' ! Initialize a client - result = client%initialize(.true., __FILE__) ! Change .false. to .true. if not using a clustered database + result = client%initialize(.true., "smartredis_dataset") ! Change .false. to .true. if not using a clustered database if (result .ne. SRNoError) error stop 'client%initialize failed' ! Send the dataset to the database via the client diff --git a/examples/parallel/fortran/smartredis_mnist.F90 b/examples/parallel/fortran/smartredis_mnist.F90 index 6d1906cb9..26fea3db5 100644 --- a/examples/parallel/fortran/smartredis_mnist.F90 +++ b/examples/parallel/fortran/smartredis_mnist.F90 @@ -51,7 +51,7 @@ program mnist_example write(key_suffix, "(A,I1.1)") "_",pe_id ! Initialize a client - result = client%initialize(.true., __FILE__) ! Change .false. to .true. if not using a clustered database + result = client%initialize(.true., "smartredis_mnist") ! Change .false. to .true. if not using a clustered database if (result .ne. SRNoError) error stop 'client%initialize failed' ! Set up model and script for the computation diff --git a/examples/parallel/fortran/smartredis_put_get_3D.F90 b/examples/parallel/fortran/smartredis_put_get_3D.F90 index e584f39fe..953104c51 100644 --- a/examples/parallel/fortran/smartredis_put_get_3D.F90 +++ b/examples/parallel/fortran/smartredis_put_get_3D.F90 @@ -57,7 +57,7 @@ program main call random_number(recv_array_real_64) ! Initialize a client - result = client%initialize(.true., __FILE__) ! Change .false. to .true. if not using a clustered database + result = client%initialize(.true., "smartredis_put_get_3D") ! Change .false. to .true. if not using a clustered database if (result .ne. SRNoError) error stop 'client%initialize failed' ! Add a tensor to the database and verify that we can retrieve it diff --git a/examples/serial/fortran/smartredis_dataset.F90 b/examples/serial/fortran/smartredis_dataset.F90 index 305a2fccd..a2c1b8dbc 100644 --- a/examples/serial/fortran/smartredis_dataset.F90 +++ b/examples/serial/fortran/smartredis_dataset.F90 @@ -75,7 +75,7 @@ program main if (result .ne. SRNoError) error stop 'dataset%get_meta_scalars failed' ! Initialize a client - result = client%initialize(.true., __FILE__) ! Change .false. to .true. if not using a clustered database + result = client%initialize(.true., "smartredis_dataset") ! Change .false. to .true. if not using a clustered database if (result .ne. SRNoError) error stop 'client%initialize failed' ! Send the dataset to the database via the client diff --git a/examples/serial/fortran/smartredis_put_get_3D.F90 b/examples/serial/fortran/smartredis_put_get_3D.F90 index 3f1dc89f7..5c537b2f3 100644 --- a/examples/serial/fortran/smartredis_put_get_3D.F90 +++ b/examples/serial/fortran/smartredis_put_get_3D.F90 @@ -46,7 +46,7 @@ program main call random_number(send_array_real_64) ! Initialize a client - result = client%initialize(.true., __FILE__) ! Change .false. to .true. if not using a clustered database + result = client%initialize(.true., "smartredis_put_get_3D") ! Change .false. to .true. if not using a clustered database if (result .ne. SRNoError) error stop 'client%initialize failed' ! Send a tensor to the database via the client and verify that we can retrieve it diff --git a/tests/fortran/client_test_dataset.F90 b/tests/fortran/client_test_dataset.F90 index 4433942ce..b6c259c90 100644 --- a/tests/fortran/client_test_dataset.F90 +++ b/tests/fortran/client_test_dataset.F90 @@ -164,7 +164,7 @@ program main if (.not. all(meta_int64_recv == meta_int64_vec)) error stop 'meta_int64: FAILED' ! test dataset_existence - result = client%initialize(use_cluster(), __FILE__) + result = client%initialize(use_cluster(), "client_test_dataset") if (result .ne. SRNoError) error stop result = client%dataset_exists("nonexistent", exists) if (result .ne. SRNoError) error stop diff --git a/tests/fortran/client_test_dataset_aggregation.F90 b/tests/fortran/client_test_dataset_aggregation.F90 index e05380a84..38bf1bedb 100644 --- a/tests/fortran/client_test_dataset_aggregation.F90 +++ b/tests/fortran/client_test_dataset_aggregation.F90 @@ -51,7 +51,8 @@ program main character(len=12) :: dataset_name integer :: result - result = client%initialize(use_cluster(), __FILE__) + result = client%initialize(use_cluster(), & + "client_test_dataset_aggregation") if (result .ne. SRNoError) error stop call random_number(true_vectors) diff --git a/tests/fortran/client_test_ensemble.F90 b/tests/fortran/client_test_ensemble.F90 index 939cc7123..991ddb398 100644 --- a/tests/fortran/client_test_ensemble.F90 +++ b/tests/fortran/client_test_ensemble.F90 @@ -103,7 +103,7 @@ program main call setenv("SSKEYIN", "producer_1,producer_0") call setenv("SSKEYOUT", ensemble_keyout) -result = client%initialize(use_cluster(), __FILE__) +result = client%initialize(use_cluster(), "client_test_ensemble") if (result .ne. SRNoError) error stop result = client%use_model_ensemble_prefix(.true.) if (result .ne. SRNoError) error stop diff --git a/tests/fortran/client_test_initialized.F90 b/tests/fortran/client_test_initialized.F90 index 8441660a7..caec3be22 100644 --- a/tests/fortran/client_test_initialized.F90 +++ b/tests/fortran/client_test_initialized.F90 @@ -40,7 +40,7 @@ program main if (client%isinitialized()) error stop 'client not initialized' - result = client%initialize(use_cluster(), __FILE__) + result = client%initialize(use_cluster(), "client_test_initialized") if (result .ne. SRNoError) error stop if (.not. client%isinitialized()) error stop 'client is initialized' diff --git a/tests/fortran/client_test_misc_tensor.F90 b/tests/fortran/client_test_misc_tensor.F90 index 841b9354e..23ce54af0 100644 --- a/tests/fortran/client_test_misc_tensor.F90 +++ b/tests/fortran/client_test_misc_tensor.F90 @@ -46,7 +46,7 @@ program main integer :: result logical(kind=c_bool) :: exists - result = client%initialize(use_cluster(), __FILE__) + result = client%initialize(use_cluster(), "client_test_misc_tensor") if (result .ne. SRNoError) error stop print *, "Putting tensor" diff --git a/tests/fortran/client_test_mnist.F90 b/tests/fortran/client_test_mnist.F90 index 9da5e0d15..c42aba28c 100644 --- a/tests/fortran/client_test_mnist.F90 +++ b/tests/fortran/client_test_mnist.F90 @@ -44,7 +44,7 @@ program mnist_test character(len=2) :: key_suffix integer :: result - result = client%initialize(use_cluster(), __FILE__) + result = client%initialize(use_cluster(), "client_test_mnist") if (result .ne. SRNoError) error stop result = client%set_model_from_file(model_key, model_file, "TORCH", "CPU") diff --git a/tests/fortran/client_test_mnist_multigpu.F90 b/tests/fortran/client_test_mnist_multigpu.F90 index eb567d8cf..e0e2b47e0 100644 --- a/tests/fortran/client_test_mnist_multigpu.F90 +++ b/tests/fortran/client_test_mnist_multigpu.F90 @@ -48,7 +48,7 @@ program mnist_test integer :: sr_return_code sr_return_code = client%initialize(use_cluster(), & - __FILE__) + "client_test_mnist_multigpu") if (sr_return_code .ne. SRNoError) error stop sr_return_code = client%set_model_from_file_multigpu(model_key, model_file, "TORCH", first_gpu, num_gpus) diff --git a/tests/fortran/client_test_put_get_1D.F90 b/tests/fortran/client_test_put_get_1D.F90 index 97655ed73..f54fc583e 100644 --- a/tests/fortran/client_test_put_get_1D.F90 +++ b/tests/fortran/client_test_put_get_1D.F90 @@ -73,7 +73,7 @@ program main recv_array_integer_64(i) = irand() enddo - result = client%initialize(use_cluster(), __FILE__) + result = client%initialize(use_cluster(), "client_test_put_get_1D") if (result .ne. SRNoError) error stop result = client%put_tensor("true_array_real_32", true_array_real_32, shape(true_array_real_32)) diff --git a/tests/fortran/client_test_put_get_2D.F90 b/tests/fortran/client_test_put_get_2D.F90 index 85e547af3..d52d9b9e3 100644 --- a/tests/fortran/client_test_put_get_2D.F90 +++ b/tests/fortran/client_test_put_get_2D.F90 @@ -74,7 +74,7 @@ program main recv_array_integer_64(i,j) = irand() enddo; enddo - result = client%initialize(use_cluster(), __FILE__) + result = client%initialize(use_cluster(), "client_test_put_get_2D") if (result .ne. SRNoError) error stop result = client%put_tensor("true_array_real_32", true_array_real_32, shape(true_array_real_32)) diff --git a/tests/fortran/client_test_put_get_3D.F90 b/tests/fortran/client_test_put_get_3D.F90 index 7f143a8fa..c5407074f 100644 --- a/tests/fortran/client_test_put_get_3D.F90 +++ b/tests/fortran/client_test_put_get_3D.F90 @@ -76,7 +76,7 @@ program main recv_array_integer_64(i,j,k) = irand() enddo; enddo; enddo - result = client%initialize(use_cluster(), __FILE__) + result = client%initialize(use_cluster(), "client_test_put_get_3D") if (result .ne. SRNoError) error stop result = client%put_tensor("true_array_real_32", true_array_real_32, shape(true_array_real_32)) diff --git a/tests/fortran/client_test_put_get_unpack_dataset.F90 b/tests/fortran/client_test_put_get_unpack_dataset.F90 index d6661bd05..c86a9f430 100644 --- a/tests/fortran/client_test_put_get_unpack_dataset.F90 +++ b/tests/fortran/client_test_put_get_unpack_dataset.F90 @@ -62,7 +62,7 @@ program main integer :: err_code result = client%initialize(use_cluster(), & - __FILE__) + "client_test_put_get_unpack_dataset") if (result .ne. SRNoError) error stop call random_number(true_array_real_32) From 46457e3a83a68f41e0e0fbacb84e42edd7a0d443 Mon Sep 17 00:00:00 2001 From: billschereriii Date: Mon, 28 Nov 2022 16:33:19 -0600 Subject: [PATCH 16/37] Move client create/destroy to debug level to reduce contention on startup of large jobs --- src/cpp/client.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cpp/client.cpp b/src/cpp/client.cpp index 1f46de641..9e17805f6 100644 --- a/src/cpp/client.cpp +++ b/src/cpp/client.cpp @@ -40,7 +40,7 @@ Client::Client(bool cluster, const std::string& client_id) // Set up logging Logger& logger = Logger::get_instance(); logger.configure_logging(client_id); - logger.log_data(LLInfo, "New client created"); + logger.log_data(LLDebug, "New client created"); // Set up Redis server connection // A std::bad_alloc exception on the initializer will be caught @@ -74,7 +74,7 @@ Client::~Client() } _redis_server = NULL; - log_data(LLInfo, "Client destroyed"); + log_data(LLDebug, "Client destroyed"); } // Put a DataSet object into the database From 02ca7453247b28fd1d025a4d4ee88dab6a51af10 Mon Sep 17 00:00:00 2001 From: billschereriii Date: Mon, 28 Nov 2022 18:15:51 -0600 Subject: [PATCH 17/37] Fix context fixture; catch a few more anonymous tests --- conftest.py | 4 +-- .../client_test_dataset_move_constructor.cpp | 8 ++--- tests/cpp/client_test_mnist.cpp | 2 +- tests/cpp/client_test_mnist_dataset.cpp | 2 +- tests/cpp/client_test_put_get_2D.cpp | 2 +- tests/cpp/client_test_put_get_3D.cpp | 2 +- .../client_test_put_get_3D_static_values.cpp | 2 +- .../cpp/client_test_put_get_contiguous_3D.cpp | 2 +- .../cpp/client_test_put_get_transpose_3D.cpp | 2 +- tests/fortran/client_test_ensemble.F90 | 2 +- tests/python/test_nonkeyed_cmd.py | 30 +++++++++---------- tests/python/test_put_get_dataset.py | 8 ++--- tests/python/test_put_get_tensor.py | 12 ++++---- 13 files changed, 39 insertions(+), 39 deletions(-) diff --git a/conftest.py b/conftest.py index 291fb2713..637b154ba 100644 --- a/conftest.py +++ b/conftest.py @@ -67,8 +67,8 @@ def mock_model(): return MockTestModel @pytest.fixture -def context(): - return inspect.stack()[1][3] +def context(request): + return request.node.name class MockTestData: diff --git a/tests/cpp/client_test_dataset_move_constructor.cpp b/tests/cpp/client_test_dataset_move_constructor.cpp index e1b70f87b..3e4b54a66 100644 --- a/tests/cpp/client_test_dataset_move_constructor.cpp +++ b/tests/cpp/client_test_dataset_move_constructor.cpp @@ -125,11 +125,11 @@ void move_constructor( &DATASET_TEST_UTILS::ui32_meta_1, SRMetadataTypeUint32); - //Move the DataSet half way through metadata additions to - //test that we can continue adding new fields to the old fields - SmartRedis::DataSet moved_dataset = SmartRedis::DataSet(std::move(*dataset)); + //Move the DataSet half way through metadata additions to + //test that we can continue adding new fields to the old fields + SmartRedis::DataSet moved_dataset = SmartRedis::DataSet(std::move(*dataset)); - moved_dataset.add_meta_scalar("ui32_field_1", + moved_dataset.add_meta_scalar("ui32_field_1", &DATASET_TEST_UTILS::ui32_meta_2, SRMetadataTypeUint32); moved_dataset.add_meta_scalar("ui32_field_2", diff --git a/tests/cpp/client_test_mnist.cpp b/tests/cpp/client_test_mnist.cpp index d19445eba..00c416ed8 100644 --- a/tests/cpp/client_test_mnist.cpp +++ b/tests/cpp/client_test_mnist.cpp @@ -78,7 +78,7 @@ void run_mnist(const std::string& model_name, int main(int argc, char* argv[]) { - SmartRedis::Client client(use_cluster()); + SmartRedis::Client client(use_cluster(), __FILE__); std::string model_key = "mnist_model"; std::string model_file = "./../mnist_data/mnist_cnn.pt"; client.set_model_from_file(model_key, model_file, "TORCH", "CPU"); diff --git a/tests/cpp/client_test_mnist_dataset.cpp b/tests/cpp/client_test_mnist_dataset.cpp index b53db6946..3f24f8799 100644 --- a/tests/cpp/client_test_mnist_dataset.cpp +++ b/tests/cpp/client_test_mnist_dataset.cpp @@ -82,7 +82,7 @@ void run_mnist(const std::string& model_name, int main(int argc, char* argv[]) { - SmartRedis::Client client(use_cluster()); + SmartRedis::Client client(use_cluster(), __FILE__); std::string model_key = "mnist_model"; std::string model_file = "./../mnist_data/mnist_cnn.pt"; client.set_model_from_file(model_key, model_file, "TORCH", "CPU"); diff --git a/tests/cpp/client_test_put_get_2D.cpp b/tests/cpp/client_test_put_get_2D.cpp index 38fd33bbb..95e157f26 100644 --- a/tests/cpp/client_test_put_get_2D.cpp +++ b/tests/cpp/client_test_put_get_2D.cpp @@ -39,7 +39,7 @@ void put_get_2D_array( std::string key_suffix="") { - SmartRedis::Client client(use_cluster()); + SmartRedis::Client client(use_cluster(), __FILE__); //Allocate and fill arrays T_send** array = allocate_2D_array(dims[0], dims[1]); diff --git a/tests/cpp/client_test_put_get_3D.cpp b/tests/cpp/client_test_put_get_3D.cpp index 11ab5be0a..dc544a150 100644 --- a/tests/cpp/client_test_put_get_3D.cpp +++ b/tests/cpp/client_test_put_get_3D.cpp @@ -38,7 +38,7 @@ void put_get_3D_array( SRTensorType type, std::string key_suffix="") { - SmartRedis::Client client(use_cluster()); + SmartRedis::Client client(use_cluster(), __FILE__); //Allocate and fill arrays T_send*** array = allocate_3D_array(dims[0], dims[1], dims[2]); diff --git a/tests/cpp/client_test_put_get_3D_static_values.cpp b/tests/cpp/client_test_put_get_3D_static_values.cpp index 9e2af64d9..d632307cc 100644 --- a/tests/cpp/client_test_put_get_3D_static_values.cpp +++ b/tests/cpp/client_test_put_get_3D_static_values.cpp @@ -37,7 +37,7 @@ void put_get_3D_array( SRTensorType type, std::string key_suffix="") { - SmartRedis::Client client(use_cluster()); + SmartRedis::Client client(use_cluster(), __FILE__); //Allocate and fill arrays T_send*** array = allocate_3D_array(dims[0], dims[1], dims[2]); diff --git a/tests/cpp/client_test_put_get_contiguous_3D.cpp b/tests/cpp/client_test_put_get_contiguous_3D.cpp index 242c62e56..e2bcd5d13 100644 --- a/tests/cpp/client_test_put_get_contiguous_3D.cpp +++ b/tests/cpp/client_test_put_get_contiguous_3D.cpp @@ -38,7 +38,7 @@ void put_get_3D_array( SRTensorType type, std::string key_suffix="") { - SmartRedis::Client client(use_cluster()); + SmartRedis::Client client(use_cluster(), __FILE__); //Allocate and fill arrays T_send* array = diff --git a/tests/cpp/client_test_put_get_transpose_3D.cpp b/tests/cpp/client_test_put_get_transpose_3D.cpp index 9ef5435b8..b0600986e 100644 --- a/tests/cpp/client_test_put_get_transpose_3D.cpp +++ b/tests/cpp/client_test_put_get_transpose_3D.cpp @@ -60,7 +60,7 @@ void put_get_3D_array( SRMemoryLayout send_direction = SRMemLayoutContiguous, SRMemoryLayout recv_direction = SRMemLayoutContiguous) { - SmartRedis::Client client(use_cluster()); + SmartRedis::Client client(use_cluster(), __FILE__); //Allocate and fill arrays T_send* array = (T_send*)malloc(dims[0]*dims[1]*dims[2]*sizeof(T_send)); diff --git a/tests/fortran/client_test_ensemble.F90 b/tests/fortran/client_test_ensemble.F90 index 991ddb398..290682c99 100644 --- a/tests/fortran/client_test_ensemble.F90 +++ b/tests/fortran/client_test_ensemble.F90 @@ -49,7 +49,7 @@ program main call setenv("SSKEYIN", "producer_0,producer_1") call setenv("SSKEYOUT", ensemble_keyout) -result = client%initialize(use_cluster(), __FILE__) +result = client%initialize(use_cluster(), "client_test_ensemble") if (result .ne. SRNoError) error stop result = client%use_model_ensemble_prefix(.true.) if (result .ne. SRNoError) error stop diff --git a/tests/python/test_nonkeyed_cmd.py b/tests/python/test_nonkeyed_cmd.py index 54d2bce4c..28e89bb84 100644 --- a/tests/python/test_nonkeyed_cmd.py +++ b/tests/python/test_nonkeyed_cmd.py @@ -32,26 +32,26 @@ from smartredis.error import * -def test_dbnode_info_command(use_cluster): +def test_dbnode_info_command(use_cluster, context): # get env var to set through client init ssdb = os.environ["SSDB"] db_info_addr = [ssdb] del os.environ["SSDB"] - client = Client(address=ssdb, cluster=use_cluster) + client = Client(address=ssdb, cluster=use_cluster, client_id=context) info = client.get_db_node_info(db_info_addr) assert len(info) > 0 -def test_dbcluster_info_command(mock_model, use_cluster): +def test_dbcluster_info_command(mock_model, use_cluster, context): # get env var to set through client init ssdb = os.environ["SSDB"] address = [ssdb] del os.environ["SSDB"] - client = Client(address=ssdb, cluster=use_cluster) + client = Client(address=ssdb, cluster=use_cluster, client_id=context) if use_cluster: info = client.get_db_cluster_info(address) @@ -67,7 +67,7 @@ def test_dbcluster_info_command(mock_model, use_cluster): del os.environ["SSDB"] # Init client - client = Client(address=ssdb, cluster=use_cluster) + client = Client(address=ssdb, cluster=use_cluster, client_id=context) # Get a mock model model = mock_model.create_torch_cnn() @@ -87,7 +87,7 @@ def test_dbcluster_info_command(mock_model, use_cluster): with pytest.raises(RedisRuntimeError): client.get_ai_info(address, "bad_key") -def test_flushdb_command(use_cluster): +def test_flushdb_command(use_cluster, context): # from within the testing framework, there is no way # of knowing each db node that is being used, so skip # if on cluster @@ -98,7 +98,7 @@ def test_flushdb_command(use_cluster): address = [ssdb] del os.environ["SSDB"] - client = Client(address=ssdb, cluster=use_cluster) + client = Client(address=ssdb, cluster=use_cluster, client_id=context) # add key to client via put_tensor tensor = np.array([1, 2]) @@ -109,13 +109,13 @@ def test_flushdb_command(use_cluster): assert not client.tensor_exists("test_copy") -def test_config_set_get_command(use_cluster): +def test_config_set_get_command(use_cluster, context): # get env var to set through client init ssdb = os.environ["SSDB"] del os.environ["SSDB"] - client = Client(address=ssdb, cluster=use_cluster) + client = Client(address=ssdb, cluster=use_cluster, client_id=context) value = "6000" client.config_set("lua-time-limit", value, ssdb) @@ -125,33 +125,33 @@ def test_config_set_get_command(use_cluster): assert get_reply["lua-time-limit"] == value -def test_config_set_command_DNE(use_cluster): +def test_config_set_command_DNE(use_cluster, context): # get env var to set through client init ssdb = os.environ["SSDB"] del os.environ["SSDB"] - client = Client(address=ssdb, cluster=use_cluster) + client = Client(address=ssdb, cluster=use_cluster, client_id=context) # The CONFIG parameter "config_param_DNE" is unsupported with pytest.raises(RedisReplyError): client.config_set("config_param_DNE", "10", ssdb) -def test_config_get_command_DNE(use_cluster): +def test_config_get_command_DNE(use_cluster, context): # get env var to set through client init ssdb = os.environ["SSDB"] del os.environ["SSDB"] - client = Client(address=ssdb, cluster=use_cluster) + client = Client(address=ssdb, cluster=use_cluster, client_id=context) # CONFIG GET returns an empty dictionary if the config_param is unsupported get_reply = client.config_get("config_param_DNE", ssdb) assert get_reply == dict() -def test_save_command(use_cluster, mock_data): +def test_save_command(use_cluster, mock_data, context): # get env var to set through client init ssdb = os.environ["SSDB"] if use_cluster: @@ -161,7 +161,7 @@ def test_save_command(use_cluster, mock_data): del os.environ["SSDB"] # client init should fail if SSDB not set - client = Client(address=ssdb, cluster=use_cluster) + client = Client(address=ssdb, cluster=use_cluster, client_id=context) # for each address, check that the timestamp of the last SAVE increases after calling Client::save for address in addresses: diff --git a/tests/python/test_put_get_dataset.py b/tests/python/test_put_get_dataset.py index 0e0ad6bcd..e481c0563 100644 --- a/tests/python/test_put_get_dataset.py +++ b/tests/python/test_put_get_dataset.py @@ -30,7 +30,7 @@ from smartredis import Client, Dataset -def test_put_get_dataset(mock_data, use_cluster): +def test_put_get_dataset(mock_data, use_cluster, context): """test sending and recieving a dataset with 2D tensors of every datatype """ @@ -43,7 +43,7 @@ def test_put_get_dataset(mock_data, use_cluster): key = f"tensor_{str(index)}" dataset.add_tensor(key, tensor) - client = Client(None, use_cluster) + client = Client(None, use_cluster, client_id=context) assert not client.dataset_exists( "nonexistent-dataset" @@ -64,7 +64,7 @@ def test_put_get_dataset(mock_data, use_cluster): ) -def test_augment_dataset(mock_data, use_cluster): +def test_augment_dataset(mock_data, use_cluster, context): """Test sending, receiving, altering, and sending a Dataset. """ @@ -75,7 +75,7 @@ def test_augment_dataset(mock_data, use_cluster): dataset_name = "augment-dataset" # Initialize a client - client = Client(None, use_cluster) + client = Client(None, use_cluster, client_id=context) # Create a dataset to put into the database dataset = Dataset(dataset_name) diff --git a/tests/python/test_put_get_tensor.py b/tests/python/test_put_get_tensor.py index 4f6416dd4..98146a99f 100644 --- a/tests/python/test_put_get_tensor.py +++ b/tests/python/test_put_get_tensor.py @@ -31,28 +31,28 @@ # ----- Tests ----------------------------------------------------------- -def test_1D_put_get(mock_data, use_cluster): +def test_1D_put_get(mock_data, use_cluster, context): """Test put/get_tensor for 1D numpy arrays""" - client = Client(None, use_cluster) + client = Client(None, use_cluster, client_id=context) data = mock_data.create_data(10) send_get_arrays(client, data) -def test_2D_put_get(mock_data, use_cluster): +def test_2D_put_get(mock_data, use_cluster, context): """Test put/get_tensor for 2D numpy arrays""" - client = Client(None, use_cluster) + client = Client(None, use_cluster, client_id=context) data = mock_data.create_data((10, 10)) send_get_arrays(client, data) -def test_3D_put_get(mock_data, use_cluster): +def test_3D_put_get(mock_data, use_cluster, context): """Test put/get_tensor for 3D numpy arrays""" - client = Client(None, use_cluster) + client = Client(None, use_cluster, client_id=context) data = mock_data.create_data((10, 10, 10)) send_get_arrays(client, data) From a97d7da3a6fdbdf94d9e771436f8311466d463b7 Mon Sep 17 00:00:00 2001 From: billschereriii Date: Mon, 28 Nov 2022 18:59:36 -0600 Subject: [PATCH 18/37] Use INFO-level logging for CI/CD; __FILE__ is too long for C++ client ID --- .github/workflows/run_post_merge_tests.yml | 2 +- .github/workflows/run_tests.yml | 4 ++-- .github/workflows/run_tests_uds.yml | 2 +- tests/cpp/client_test_copy_dataset.cpp | 2 +- tests/cpp/client_test_dataset.cpp | 2 +- tests/cpp/client_test_dataset_aggregation.cpp | 2 +- .../client_test_dataset_copy_assignment.cpp | 2 +- .../client_test_dataset_copy_constructor.cpp | 2 +- tests/cpp/client_test_dataset_empty.cpp | 2 +- .../client_test_dataset_move_assignment.cpp | 2 +- .../client_test_dataset_move_constructor.cpp | 2 +- ...lient_test_dataset_multiple_get_tensor.cpp | 2 +- tests/cpp/client_test_dataset_no_meta.cpp | 2 +- tests/cpp/client_test_dataset_no_tensors.cpp | 2 +- tests/cpp/client_test_delete_dataset.cpp | 2 +- tests/cpp/client_test_ensemble.cpp | 4 ++-- tests/cpp/client_test_ensemble_dataset.cpp | 4 ++-- tests/cpp/client_test_mnist.cpp | 4 ++-- tests/cpp/client_test_mnist_dataset.cpp | 4 ++-- tests/cpp/client_test_put_get_1D.cpp | 2 +- tests/cpp/client_test_put_get_2D.cpp | 2 +- tests/cpp/client_test_put_get_3D.cpp | 2 +- .../client_test_put_get_3D_static_values.cpp | 2 +- .../cpp/client_test_put_get_contiguous_3D.cpp | 2 +- .../cpp/client_test_put_get_transpose_3D.cpp | 2 +- tests/cpp/client_test_rename_dataset.cpp | 2 +- .../cpp/unit-tests/test_aggregation_list.cpp | 2 +- tests/cpp/unit-tests/test_client.cpp | 22 +++++++++---------- tests/cpp/unit-tests/test_client_ensemble.cpp | 4 ++-- tests/cpp/unit-tests/test_ssdb.cpp | 2 +- 30 files changed, 46 insertions(+), 46 deletions(-) diff --git a/.github/workflows/run_post_merge_tests.yml b/.github/workflows/run_post_merge_tests.yml index 21dbfed5a..d63e72ef2 100644 --- a/.github/workflows/run_post_merge_tests.yml +++ b/.github/workflows/run_post_merge_tests.yml @@ -141,6 +141,6 @@ jobs: run: | export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/install/lib && export SR_LOG_FILE=smartredis_examples_log.txt && - export SR_LOG_LEVEL=DEBUG && + export SR_LOG_LEVEL=INFO && make test-examples diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index 25bdc8a05..0de02fc55 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -108,7 +108,7 @@ jobs: cd ../ && export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/install/lib && export SR_LOG_FILE=smartredis_cicd_tests_log.txt && - export SR_LOG_LEVEL=DEBUG && + export SR_LOG_LEVEL=INFO && make test-verbose - name: Run Python coverage tests @@ -166,6 +166,6 @@ jobs: run: | export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/install/lib && export SR_LOG_FILE=smartredis_cicd_tests_log.txt && - export SR_LOG_LEVEL=DEBUG && + export SR_LOG_LEVEL=INFO && make test-verbose diff --git a/.github/workflows/run_tests_uds.yml b/.github/workflows/run_tests_uds.yml index cae816852..2119a5d4d 100644 --- a/.github/workflows/run_tests_uds.yml +++ b/.github/workflows/run_tests_uds.yml @@ -146,6 +146,6 @@ jobs: run: | export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD/install/lib && export SR_LOG_FILE=smartredis_uds_tests_log.txt && - export SR_LOG_LEVEL=DEBUG && + export SR_LOG_LEVEL=INFO && make test-verbose diff --git a/tests/cpp/client_test_copy_dataset.cpp b/tests/cpp/client_test_copy_dataset.cpp index 1a5bfa775..91a82c109 100644 --- a/tests/cpp/client_test_copy_dataset.cpp +++ b/tests/cpp/client_test_copy_dataset.cpp @@ -52,7 +52,7 @@ void put_and_copy_dataset( fill_array(t_send_3, dims[0], dims[1], dims[2]); //Create Client and DataSet - DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), __FILE__); + DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), "client_test_copy_dataset"); SmartRedis::DataSet source_dataset(dataset_name); //Add metadata to the DataSet diff --git a/tests/cpp/client_test_dataset.cpp b/tests/cpp/client_test_dataset.cpp index 46d82afc0..9927998f7 100644 --- a/tests/cpp/client_test_dataset.cpp +++ b/tests/cpp/client_test_dataset.cpp @@ -52,7 +52,7 @@ void put_get_dataset( fill_array(t_send_3, dims[0], dims[1], dims[2]); //Create Client and DataSet - DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), __FILE__); + DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), "client_test_dataset"); SmartRedis::DataSet sent_dataset(dataset_name); //Add metadata to the DataSet diff --git a/tests/cpp/client_test_dataset_aggregation.cpp b/tests/cpp/client_test_dataset_aggregation.cpp index 6ac37249b..91bca8b09 100644 --- a/tests/cpp/client_test_dataset_aggregation.cpp +++ b/tests/cpp/client_test_dataset_aggregation.cpp @@ -112,7 +112,7 @@ void check_dataset(SmartRedis::DataSet& dataset_1, int main(int argc, char* argv[]) { // Create client for dataset and aggregation list actions - SmartRedis::Client client(use_cluster(), __FILE__); + SmartRedis::Client client(use_cluster(), "client_test_dataset_aggregation"); // Set a fill function for dataset creation void (*fill_function)(double***, int, int, int) = diff --git a/tests/cpp/client_test_dataset_copy_assignment.cpp b/tests/cpp/client_test_dataset_copy_assignment.cpp index aace97bbd..a3df18150 100644 --- a/tests/cpp/client_test_dataset_copy_assignment.cpp +++ b/tests/cpp/client_test_dataset_copy_assignment.cpp @@ -52,7 +52,7 @@ void copy_assignment( fill_array(t_send_3, dims[0], dims[1], dims[2]); //Create Client and DataSets - DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), __FILE__); + DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), "client_test_dataset_copy_assignment"); SmartRedis::DataSet* dataset = new SmartRedis::DataSet(dataset_name); //Add tensors to the DataSet diff --git a/tests/cpp/client_test_dataset_copy_constructor.cpp b/tests/cpp/client_test_dataset_copy_constructor.cpp index fef9a2423..8e62d675d 100644 --- a/tests/cpp/client_test_dataset_copy_constructor.cpp +++ b/tests/cpp/client_test_dataset_copy_constructor.cpp @@ -52,7 +52,7 @@ void copy_constructor( fill_array(t_send_3, dims[0], dims[1], dims[2]); //Create Client and DataSet - DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), __FILE__); + DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), "client_test_dataset_copy_constructor"); SmartRedis::DataSet* dataset = new SmartRedis::DataSet(dataset_name); //Add tensors to the DataSet diff --git a/tests/cpp/client_test_dataset_empty.cpp b/tests/cpp/client_test_dataset_empty.cpp index 570a7f338..a096a2508 100644 --- a/tests/cpp/client_test_dataset_empty.cpp +++ b/tests/cpp/client_test_dataset_empty.cpp @@ -35,7 +35,7 @@ void put_get_empty_dataset(std::string dataset_name) { //Create Client and DataSet - SmartRedis::Client client(use_cluster(), __FILE__); + SmartRedis::Client client(use_cluster(), "client_test_dataset_empty"); SmartRedis::DataSet sent_dataset(dataset_name); //Put the DataSet into the database diff --git a/tests/cpp/client_test_dataset_move_assignment.cpp b/tests/cpp/client_test_dataset_move_assignment.cpp index 4c0697fc3..c5c68a4af 100644 --- a/tests/cpp/client_test_dataset_move_assignment.cpp +++ b/tests/cpp/client_test_dataset_move_assignment.cpp @@ -52,7 +52,7 @@ void put_get_3D_array( fill_array(t_send_3, dims[0], dims[1], dims[2]); //Create Client and DataSets - DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), __FILE__); + DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), "client_test_dataset_move_assignment"); SmartRedis::DataSet* dataset = new SmartRedis::DataSet(dataset_name); //Add tensors to the DataSet diff --git a/tests/cpp/client_test_dataset_move_constructor.cpp b/tests/cpp/client_test_dataset_move_constructor.cpp index 3e4b54a66..22119702e 100644 --- a/tests/cpp/client_test_dataset_move_constructor.cpp +++ b/tests/cpp/client_test_dataset_move_constructor.cpp @@ -52,7 +52,7 @@ void move_constructor( fill_array(t_send_3, dims[0], dims[1], dims[2]); //Create Client and DataSets - DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), __FILE__); + DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), "client_test_dataet_move_constructor"); SmartRedis::DataSet* dataset = new SmartRedis::DataSet(dataset_name); //Add tensors to the DataSet diff --git a/tests/cpp/client_test_dataset_multiple_get_tensor.cpp b/tests/cpp/client_test_dataset_multiple_get_tensor.cpp index 28ec361a9..148c6dca8 100644 --- a/tests/cpp/client_test_dataset_multiple_get_tensor.cpp +++ b/tests/cpp/client_test_dataset_multiple_get_tensor.cpp @@ -52,7 +52,7 @@ void get_multiple_tensors( fill_array(t_send_3, dims[0], dims[1], dims[2]); //Create Client and DataSet - DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), __FILE__); + DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), "client_test_dataset_multiple_get_tensor"); SmartRedis::DataSet sent_dataset(dataset_name); //Add metadata to the DataSet diff --git a/tests/cpp/client_test_dataset_no_meta.cpp b/tests/cpp/client_test_dataset_no_meta.cpp index 7889127c8..573164380 100644 --- a/tests/cpp/client_test_dataset_no_meta.cpp +++ b/tests/cpp/client_test_dataset_no_meta.cpp @@ -52,7 +52,7 @@ void put_get_dataset( fill_array(t_send_3, dims[0], dims[1], dims[2]); //Create Client and DataSet - DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), __FILE__); + DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), "client_test_dataset_no_meta"); SmartRedis::DataSet sent_dataset(dataset_name); //Add tensors to the DataSet diff --git a/tests/cpp/client_test_dataset_no_tensors.cpp b/tests/cpp/client_test_dataset_no_tensors.cpp index b4b8fa9f2..7b726d6fb 100644 --- a/tests/cpp/client_test_dataset_no_tensors.cpp +++ b/tests/cpp/client_test_dataset_no_tensors.cpp @@ -34,7 +34,7 @@ void put_dataset_no_tensors(std::string dataset_name) { //Create Client and DataSet - DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), __FILE__); + DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), "client_test_dataset_no_tensors"); SmartRedis::DataSet sent_dataset(dataset_name); //Add metadata to the DataSet diff --git a/tests/cpp/client_test_delete_dataset.cpp b/tests/cpp/client_test_delete_dataset.cpp index 488929272..dd5c00109 100644 --- a/tests/cpp/client_test_delete_dataset.cpp +++ b/tests/cpp/client_test_delete_dataset.cpp @@ -52,7 +52,7 @@ void dataset_delete( fill_array(t_send_3, dims[0], dims[1], dims[2]); //Create Client and DataSets - DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), __FILE__); + DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), "client_test_delete_dataset"); SmartRedis::DataSet* dataset = new SmartRedis::DataSet(dataset_name); //Add tensors to the DataSet diff --git a/tests/cpp/client_test_ensemble.cpp b/tests/cpp/client_test_ensemble.cpp index 2c11e9c24..fa6c881b7 100644 --- a/tests/cpp/client_test_ensemble.cpp +++ b/tests/cpp/client_test_ensemble.cpp @@ -58,7 +58,7 @@ void produce( std::string keyout="", std::string keyin="") { - SmartRedis::Client client(use_cluster(), __FILE__ "::producer"); + SmartRedis::Client client(use_cluster(), "client_test_ensemble::producer"); client.use_model_ensemble_prefix(true); // Tensors @@ -128,7 +128,7 @@ void consume(std::vector dims, std::string keyout="", std::string keyin="") { - SmartRedis::Client client(use_cluster(), __FILE__ "::consumer"); + SmartRedis::Client client(use_cluster(), "client_test_ensemble::consumer"); client.use_model_ensemble_prefix(true); // Tensors diff --git a/tests/cpp/client_test_ensemble_dataset.cpp b/tests/cpp/client_test_ensemble_dataset.cpp index 605367fbf..1a3197c83 100644 --- a/tests/cpp/client_test_ensemble_dataset.cpp +++ b/tests/cpp/client_test_ensemble_dataset.cpp @@ -35,7 +35,7 @@ void rename_dataset(std::string keyout) { std::vector dims({10,10,2}); - DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), __FILE__); + DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), "client_test_ensemble_dataset"); client.use_tensor_ensemble_prefix(true); double*** t_send_1 = @@ -137,7 +137,7 @@ void add_to_aggregation_list(std::string keyout) { std::vector dims({10,10,2}); - DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), __FILE__); + DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), "client_test_ensemble_dataset"); client.use_tensor_ensemble_prefix(true); client.use_list_ensemble_prefix(true); diff --git a/tests/cpp/client_test_mnist.cpp b/tests/cpp/client_test_mnist.cpp index 00c416ed8..1778bed6e 100644 --- a/tests/cpp/client_test_mnist.cpp +++ b/tests/cpp/client_test_mnist.cpp @@ -52,7 +52,7 @@ void load_mnist_image_to_array(float**** img) void run_mnist(const std::string& model_name, const std::string& script_name) { - SmartRedis::Client client(use_cluster(), __FILE__); + SmartRedis::Client client(use_cluster(), "client_test_mnist"); float**** array = allocate_4D_array(1,1,28,28); float** result = allocate_2D_array(1, 10); @@ -78,7 +78,7 @@ void run_mnist(const std::string& model_name, int main(int argc, char* argv[]) { - SmartRedis::Client client(use_cluster(), __FILE__); + SmartRedis::Client client(use_cluster(), "client_test_mnist"); std::string model_key = "mnist_model"; std::string model_file = "./../mnist_data/mnist_cnn.pt"; client.set_model_from_file(model_key, model_file, "TORCH", "CPU"); diff --git a/tests/cpp/client_test_mnist_dataset.cpp b/tests/cpp/client_test_mnist_dataset.cpp index 3f24f8799..6cbbdd204 100644 --- a/tests/cpp/client_test_mnist_dataset.cpp +++ b/tests/cpp/client_test_mnist_dataset.cpp @@ -52,7 +52,7 @@ void load_mnist_image_to_array(float**** img) void run_mnist(const std::string& model_name, const std::string& script_name) { - SmartRedis::Client client(use_cluster(), __FILE__); + SmartRedis::Client client(use_cluster(), "client_test_mnist_dataset"); float**** array = allocate_4D_array(1,1,28,28); float** result = allocate_2D_array(1, 10); @@ -82,7 +82,7 @@ void run_mnist(const std::string& model_name, int main(int argc, char* argv[]) { - SmartRedis::Client client(use_cluster(), __FILE__); + SmartRedis::Client client(use_cluster(), "client_test_mnist_dataset"); std::string model_key = "mnist_model"; std::string model_file = "./../mnist_data/mnist_cnn.pt"; client.set_model_from_file(model_key, model_file, "TORCH", "CPU"); diff --git a/tests/cpp/client_test_put_get_1D.cpp b/tests/cpp/client_test_put_get_1D.cpp index c58c7fe86..5815016ff 100644 --- a/tests/cpp/client_test_put_get_1D.cpp +++ b/tests/cpp/client_test_put_get_1D.cpp @@ -38,7 +38,7 @@ void put_get_1D_array( SRTensorType type, std::string key_suffix="") { - SmartRedis::Client client(use_cluster(), __FILE__); + SmartRedis::Client client(use_cluster(), "client_test_put_get_1D"); //Allocate and fill arrays T_send* array = (T_send*)malloc(dims[0]*sizeof(T_send)); diff --git a/tests/cpp/client_test_put_get_2D.cpp b/tests/cpp/client_test_put_get_2D.cpp index 95e157f26..5d4abc583 100644 --- a/tests/cpp/client_test_put_get_2D.cpp +++ b/tests/cpp/client_test_put_get_2D.cpp @@ -39,7 +39,7 @@ void put_get_2D_array( std::string key_suffix="") { - SmartRedis::Client client(use_cluster(), __FILE__); + SmartRedis::Client client(use_cluster(), "client_test_put_get_2D"); //Allocate and fill arrays T_send** array = allocate_2D_array(dims[0], dims[1]); diff --git a/tests/cpp/client_test_put_get_3D.cpp b/tests/cpp/client_test_put_get_3D.cpp index dc544a150..12cc913ef 100644 --- a/tests/cpp/client_test_put_get_3D.cpp +++ b/tests/cpp/client_test_put_get_3D.cpp @@ -38,7 +38,7 @@ void put_get_3D_array( SRTensorType type, std::string key_suffix="") { - SmartRedis::Client client(use_cluster(), __FILE__); + SmartRedis::Client client(use_cluster(), "client_test_put_get_3D"); //Allocate and fill arrays T_send*** array = allocate_3D_array(dims[0], dims[1], dims[2]); diff --git a/tests/cpp/client_test_put_get_3D_static_values.cpp b/tests/cpp/client_test_put_get_3D_static_values.cpp index d632307cc..4c89a2420 100644 --- a/tests/cpp/client_test_put_get_3D_static_values.cpp +++ b/tests/cpp/client_test_put_get_3D_static_values.cpp @@ -37,7 +37,7 @@ void put_get_3D_array( SRTensorType type, std::string key_suffix="") { - SmartRedis::Client client(use_cluster(), __FILE__); + SmartRedis::Client client(use_cluster(), "client_test_put_get_3D_static_values"); //Allocate and fill arrays T_send*** array = allocate_3D_array(dims[0], dims[1], dims[2]); diff --git a/tests/cpp/client_test_put_get_contiguous_3D.cpp b/tests/cpp/client_test_put_get_contiguous_3D.cpp index e2bcd5d13..e800b813f 100644 --- a/tests/cpp/client_test_put_get_contiguous_3D.cpp +++ b/tests/cpp/client_test_put_get_contiguous_3D.cpp @@ -38,7 +38,7 @@ void put_get_3D_array( SRTensorType type, std::string key_suffix="") { - SmartRedis::Client client(use_cluster(), __FILE__); + SmartRedis::Client client(use_cluster(), "client_test_put_get_contiguous_3D"); //Allocate and fill arrays T_send* array = diff --git a/tests/cpp/client_test_put_get_transpose_3D.cpp b/tests/cpp/client_test_put_get_transpose_3D.cpp index b0600986e..4344ebcfb 100644 --- a/tests/cpp/client_test_put_get_transpose_3D.cpp +++ b/tests/cpp/client_test_put_get_transpose_3D.cpp @@ -60,7 +60,7 @@ void put_get_3D_array( SRMemoryLayout send_direction = SRMemLayoutContiguous, SRMemoryLayout recv_direction = SRMemLayoutContiguous) { - SmartRedis::Client client(use_cluster(), __FILE__); + SmartRedis::Client client(use_cluster(), "client_test_put_get_transpose_3D"); //Allocate and fill arrays T_send* array = (T_send*)malloc(dims[0]*dims[1]*dims[2]*sizeof(T_send)); diff --git a/tests/cpp/client_test_rename_dataset.cpp b/tests/cpp/client_test_rename_dataset.cpp index 048b918c9..4a6eba2b9 100644 --- a/tests/cpp/client_test_rename_dataset.cpp +++ b/tests/cpp/client_test_rename_dataset.cpp @@ -52,7 +52,7 @@ void rename_dataset( fill_array(t_send_3, dims[0], dims[1], dims[2]); //Create Client and DataSet - DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), __FILE__); + DATASET_TEST_UTILS::DatasetTestClient client(use_cluster(), "client_test_rename_dataset"); SmartRedis::DataSet sent_dataset(dataset_name); //Add metadata to the DataSet diff --git a/tests/cpp/unit-tests/test_aggregation_list.cpp b/tests/cpp/unit-tests/test_aggregation_list.cpp index 7685dcafa..af3afeb12 100644 --- a/tests/cpp/unit-tests/test_aggregation_list.cpp +++ b/tests/cpp/unit-tests/test_aggregation_list.cpp @@ -148,7 +148,7 @@ SCENARIO("Testing Dataset aggregation via our client", "[List]") std::cout << std::to_string(get_time_offset()) << ": Testing Dataset aggregation via our client" << std::endl; GIVEN("A Client object and vector of DataSet objects") { - Client client(use_cluster(), __FILE__); + Client client(use_cluster(), "test_aggregation_list"); std::vector datasets; diff --git a/tests/cpp/unit-tests/test_client.cpp b/tests/cpp/unit-tests/test_client.cpp index 0e4679c74..fe260560c 100644 --- a/tests/cpp/unit-tests/test_client.cpp +++ b/tests/cpp/unit-tests/test_client.cpp @@ -97,7 +97,7 @@ SCENARIO("Testing Dataset Functions on Client Object", "[Client]") std::cout << std::to_string(get_time_offset()) << ": Testing Dataset Functions on Client Object" << std::endl; GIVEN("A Client object") { - Client client(use_cluster(), __FILE__); + Client client(use_cluster(), "test_client"); THEN("get, rename, and copy DataSet called on " "a nonexistent DataSet throws errors") @@ -193,7 +193,7 @@ SCENARIO("Testing Tensor Functions on Client Object", "[Client]") std::cout << std::to_string(get_time_offset()) << ": Testing Tensor Functions on Client Object" << std::endl; GIVEN("A Client object") { - Client client(use_cluster(), __FILE__); + Client client(use_cluster(), "test_client"); AND_WHEN("Tensors of each type are created and put into the Client") { @@ -473,7 +473,7 @@ SCENARIO("Testing INFO Functions on Client Object", "[Client]") std::cout << std::to_string(get_time_offset()) << ": Testing INFO Functions on Client Object" << std::endl; GIVEN("A Client object") { - Client client(use_cluster(), __FILE__); + Client client(use_cluster(), "test_client"); WHEN("INFO or CLUSTER INFO is called on database with " "an invalid address") @@ -522,7 +522,7 @@ SCENARIO("Testing AI.INFO Functions on Client Object", "[Client]") std::cout << std::to_string(get_time_offset()) << ": Testing AI.INFO Functions on Client Object" << std::endl; GIVEN("A Client object") { - Client client(use_cluster(), __FILE__); + Client client(use_cluster(), "test_client"); WHEN("AI.INFO called on database with an invalid address") { @@ -571,7 +571,7 @@ SCENARIO("Testing FLUSHDB on empty Client Object", "[Client][FLUSHDB]") std::cout << std::to_string(get_time_offset()) << ": Testing FLUSHDB on empty Client Object" << std::endl; GIVEN("An empty non-cluster Client object") { - Client client(use_cluster(), __FILE__); + Client client(use_cluster(), "test_client"); WHEN("FLUSHDB is called on database with " "an invalid address") @@ -611,7 +611,7 @@ SCENARIO("Testing FLUSHDB on Client Object", "[Client][FLUSHDB]") if (use_cluster()) return; - Client client(use_cluster(), __FILE__); + Client client(use_cluster(), "test_client"); std::string dataset_name = "test_dataset_name"; DataSet dataset(dataset_name); dataset.add_meta_string("meta_string_name", "meta_string_val"); @@ -647,7 +647,7 @@ SCENARIO("Testing CONFIG GET and CONFIG SET on Client Object", "[Client]") std::cout << std::to_string(get_time_offset()) << ": Testing CONFIG GET and CONFIG SET on Client Object" << std::endl; GIVEN("A Client object") { - Client client(use_cluster(), __FILE__); + Client client(use_cluster(), "test_client"); WHEN("CONFIG GET or CONFIG SET are called on databases with " "invalid addresses ") @@ -692,7 +692,7 @@ SCENARIO("Test CONFIG GET on an unsupported command", "[Client]") std::cout << std::to_string(get_time_offset()) << ": Test CONFIG GET on an unsupported command" << std::endl; GIVEN("A client object") { - Client client(use_cluster(), __FILE__); + Client client(use_cluster(), "test_client"); std::string address = parse_SSDB(std::getenv("SSDB")); WHEN("CONFIG GET is called with an unsupported command") @@ -713,7 +713,7 @@ SCENARIO("Test CONFIG SET on an unsupported command", "[Client]") std::cout << std::to_string(get_time_offset()) << ": Test CONFIG SET on an unsupported command" << std::endl; GIVEN("A client object") { - Client client(use_cluster(), __FILE__); + Client client(use_cluster(), "test_client"); std::string address = parse_SSDB(std::getenv("SSDB")); WHEN("CONFIG SET is called with an unsupported command") @@ -734,7 +734,7 @@ SCENARIO("Testing SAVE command on Client Object", "[!mayfail][Client][SAVE]") std::cout << std::to_string(get_time_offset()) << ": Testing SAVE command on Client Object" << std::endl; GIVEN("A client object and some data") { - Client client(use_cluster(), __FILE__); + Client client(use_cluster(), "test_client"); std::string dataset_name = "test_save_dataset"; DataSet dataset(dataset_name); dataset.add_meta_string("meta_string_save_name", "meta_string_val"); @@ -813,7 +813,7 @@ SCENARIO("Testing Multi-GPU Function error cases", "[Client]") std::cout << std::to_string(get_time_offset()) << ": Testing Multi-GPU Function error cases" << std::endl; GIVEN("A Client object, a script, and a model") { - Client client(use_cluster(), __FILE__); + Client client(use_cluster(), "test_client"); std::string model_key = "a_model"; std::string model_file = "./../../mnist_data/mnist_cnn.pt"; std::string script_key = "a_script"; diff --git a/tests/cpp/unit-tests/test_client_ensemble.cpp b/tests/cpp/unit-tests/test_client_ensemble.cpp index 099945b11..724c8d96f 100644 --- a/tests/cpp/unit-tests/test_client_ensemble.cpp +++ b/tests/cpp/unit-tests/test_client_ensemble.cpp @@ -137,7 +137,7 @@ SCENARIO("Testing Client ensemble using a producer/consumer paradigm") putenv(keyin_env_put); putenv(keyout_env_put); - Client producer_client(use_cluster(), __FILE__); + Client producer_client(use_cluster(), "test_client_ensemble"); producer_client.use_model_ensemble_prefix(true); // Tensors @@ -188,7 +188,7 @@ SCENARIO("Testing Client ensemble using a producer/consumer paradigm") putenv(keyin_env_get); putenv(keyout_env_get); - Client consumer_client(use_cluster(), __FILE__); + Client consumer_client(use_cluster(), "test_client_ensemble"); consumer_client.use_model_ensemble_prefix(true); // Tensors diff --git a/tests/cpp/unit-tests/test_ssdb.cpp b/tests/cpp/unit-tests/test_ssdb.cpp index 4ce96d05a..ebcd305fd 100644 --- a/tests/cpp/unit-tests/test_ssdb.cpp +++ b/tests/cpp/unit-tests/test_ssdb.cpp @@ -87,7 +87,7 @@ SCENARIO("Additional Testing for various SSDBs", "[SSDB]") // SSDB points to a unix domain socket and we're using clustered Redis setenv_ssdb ("unix://127.0.0.1:6349"); - CHECK_THROWS_AS(c = new Client(true), SmartRedis::RuntimeException); + CHECK_THROWS_AS(c = new Client(true, "test_ssdb"), SmartRedis::RuntimeException); setenv_ssdb(old_ssdb); } From 92a459052dfcc0258980bccc51646e8930b4319f Mon Sep 17 00:00:00 2001 From: billschereriii Date: Mon, 28 Nov 2022 19:12:23 -0600 Subject: [PATCH 19/37] Make log methods accessible in Python --- src/python/module/smartredis/__init__.py | 3 ++- tests/python/test_errors.py | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/python/module/smartredis/__init__.py b/src/python/module/smartredis/__init__.py index 0ec061281..f8aded556 100644 --- a/src/python/module/smartredis/__init__.py +++ b/src/python/module/smartredis/__init__.py @@ -26,4 +26,5 @@ from .client import Client from .dataset import Dataset -from .dataset_utils import DatasetConverter \ No newline at end of file +from .dataset_utils import DatasetConverter +from .logger import log_data, log_warning, log_error \ No newline at end of file diff --git a/tests/python/test_errors.py b/tests/python/test_errors.py index 5ec5d8005..745bf012b 100644 --- a/tests/python/test_errors.py +++ b/tests/python/test_errors.py @@ -28,7 +28,7 @@ import numpy as np import pytest -from smartredis import Client, Dataset +from smartredis import Client, Dataset, log_data, log_warning, log_error from smartredis.error import * @@ -740,6 +740,21 @@ def test_bad_type_get_dataset_list_range(use_cluster, context): with pytest.raises(TypeError): c.get_dataset_list_range(listname, start_index, "not an integer") +def test_bad_type_log_data(use_cluster, context): + c = Client(None, use_cluster, client_id=context) + with pytest.raises(TypeError): + log_data(42) + +def test_bad_type_log_warning(use_cluster, context): + c = Client(None, use_cluster, client_id=context) + with pytest.raises(TypeError): + log_warning(42) + +def test_bad_type_log_error(use_cluster, context): + c = Client(None, use_cluster, client_id=context) + with pytest.raises(TypeError): + log_error(42) + ##### # Test type errors from bad parameter types to Dataset API calls From e49b3fbee39411f4170910e48b3a9579596db274 Mon Sep 17 00:00:00 2001 From: billschereriii Date: Mon, 28 Nov 2022 20:40:10 -0600 Subject: [PATCH 20/37] Python logger tests --- src/python/bindings/bind.cpp | 8 ++++ src/python/module/smartredis/__init__.py | 20 +++++++++- src/python/module/smartredis/dataset.py | 2 +- src/python/module/smartredis/logger.py | 14 +++++-- tests/python/test_errors.py | 14 +++++-- tests/python/test_logging.py | 49 ++++++++++++++++++++++++ 6 files changed, 97 insertions(+), 10 deletions(-) create mode 100644 tests/python/test_logging.py diff --git a/src/python/bindings/bind.cpp b/src/python/bindings/bind.cpp index d62d6c4ac..d3d82f0a6 100644 --- a/src/python/bindings/bind.cpp +++ b/src/python/bindings/bind.cpp @@ -114,6 +114,14 @@ PYBIND11_MODULE(smartredisPy, m) { .def("cpp_log_warning", &log_warning) .def("cpp_log_error", &log_error); + // Logging levels + py::enum_(m, "SRLoggingLevel") + .value("LLQuiet", LLQuiet) + .value("LLInfo", LLInfo) + .value("LLDebug", LLDebug) + .value("LLDeveloper", LLDeveloper) + .export_values(); + // Python exception classes static py::exception exception_handler(m, "RedisReplyError"); static py::exception runtime_exception_handler(m, "RedisRuntimeError", exception_handler.ptr()); diff --git a/src/python/module/smartredis/__init__.py b/src/python/module/smartredis/__init__.py index f8aded556..63e2b8c59 100644 --- a/src/python/module/smartredis/__init__.py +++ b/src/python/module/smartredis/__init__.py @@ -24,7 +24,25 @@ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +__all__ = [ + "Client", + "Dataset", + "DatasetConverter", + "log_data", + "log_warning", + "log_error", + "LLQuiet", + "LLInfo", + "LLDebug", + "LLDeveloper", +] + from .client import Client from .dataset import Dataset from .dataset_utils import DatasetConverter -from .logger import log_data, log_warning, log_error \ No newline at end of file +from .logger import ( + log_data, log_warning, log_error +) +from .smartredisPy import ( + LLQuiet, LLInfo, LLDebug, LLDeveloper +) diff --git a/src/python/module/smartredis/dataset.py b/src/python/module/smartredis/dataset.py index 096eafc46..c98086f02 100644 --- a/src/python/module/smartredis/dataset.py +++ b/src/python/module/smartredis/dataset.py @@ -42,7 +42,7 @@ def __init__(self, name): """ typecheck(name, "name", str) self._data = PyDataset(name) - + @staticmethod def from_pybind(dataset): diff --git a/src/python/module/smartredis/logger.py b/src/python/module/smartredis/logger.py index fef6e843d..83e004637 100644 --- a/src/python/module/smartredis/logger.py +++ b/src/python/module/smartredis/logger.py @@ -24,9 +24,15 @@ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -from .smartredisPy import cpp_log_data, cpp_log_warning, cpp_log_error +from .smartredisPy import cpp_log_data, cpp_log_warning, cpp_log_error, SRLoggingLevel from .util import exception_handler, typecheck +# Logging levels +#LLQuiet = 1 # No logging at all +#LLInfo = 2 # Informational logging only +#LLDebug = 3 # Verbose logging for debugging purposes +#LLDeveloper = 4 # Extra verbose logging for internal use + @exception_handler def log_data(level, data): """Log data to the SmartRedis logfile @@ -37,7 +43,7 @@ def log_data(level, data): :type data: str :raises RedisReplyError: if logging fails """ - typecheck(level, "level", int) + typecheck(level, "level", SRLoggingLevel) typecheck(data, "data", str) cpp_log_data(level, data) @@ -51,7 +57,7 @@ def log_warning(level, data): :type data: str :raises RedisReplyError: if logging fails """ - typecheck(level, "level", int) + typecheck(level, "level", SRLoggingLevel) typecheck(data, "data", str) cpp_log_warning(level, data) @@ -65,7 +71,7 @@ def log_error(level, data): :type data: str :raises RedisReplyError: if logging fails """ - typecheck(level, "level", int) + typecheck(level, "level", SRLoggingLevel) typecheck(data, "data", str) cpp_log_error(level, data) diff --git a/tests/python/test_errors.py b/tests/python/test_errors.py index 745bf012b..c339a857e 100644 --- a/tests/python/test_errors.py +++ b/tests/python/test_errors.py @@ -28,7 +28,7 @@ import numpy as np import pytest -from smartredis import Client, Dataset, log_data, log_warning, log_error +from smartredis import * from smartredis.error import * @@ -743,17 +743,23 @@ def test_bad_type_get_dataset_list_range(use_cluster, context): def test_bad_type_log_data(use_cluster, context): c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): - log_data(42) + log_data("Not a logging level", "Data to be logged") + with pytest.raises(TypeError): + log_data(LLInfo, 42) def test_bad_type_log_warning(use_cluster, context): c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): - log_warning(42) + log_warning("Not a logging level", "Data to be logged") + with pytest.raises(TypeError): + log_warning(LLInfo, 42) def test_bad_type_log_error(use_cluster, context): c = Client(None, use_cluster, client_id=context) with pytest.raises(TypeError): - log_error(42) + log_error("Not a logging level", "Data to be logged") + with pytest.raises(TypeError): + log_error(LLInfo, 42) ##### # Test type errors from bad parameter types to Dataset API calls diff --git a/tests/python/test_logging.py b/tests/python/test_logging.py new file mode 100644 index 000000000..77918410e --- /dev/null +++ b/tests/python/test_logging.py @@ -0,0 +1,49 @@ +# BSD 2-Clause License +# +# Copyright (c) 2021-2022, Hewlett Packard Enterprise +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import os + +import numpy as np +import pytest +from smartredis import * +from smartredis.error import * + + +def test_logging(use_cluster, context): + c = Client(None, use_cluster, client_id=context) + log_data(LLQuiet, "This is data logging (LLQuiet)") + log_warning(LLQuiet, "This is a warning (LLQuiet)") + log_error(LLQuiet, "This is an error (LLQuiet)") + log_data(LLInfo, "This is data logging (LLInfo)") + log_warning(LLInfo, "This is a warning (LLInfo)") + log_error(LLInfo, "This is an error (LLInfo)") + log_data(LLDebug, "This is data logging (LLDebug)") + log_warning(LLDebug, "This is a warning (LLDebug)") + log_error(LLDebug, "This is an error (LLDebug)") + log_data(LLDeveloper, "This is data logging (LLDeveloper)") + log_warning(LLDeveloper, "This is a warning (LLDeveloper)") + log_error(LLDeveloper, "This is an error (LLDeveloper)") + From fb6dc82f6d37dbe85ec53585e44e608da510aa68 Mon Sep 17 00:00:00 2001 From: billschereriii Date: Tue, 29 Nov 2022 16:01:02 -0600 Subject: [PATCH 21/37] Add CPP unit tests; fix environment corruption in existing unit tests; add CPP interface for client renaming --- include/logger.h | 6 ++ src/cpp/logger.cpp | 10 +++ src/cpp/redisserver.cpp | 6 +- src/cpp/utility.cpp | 22 +++++++ tests/cpp/client_test_ensemble.cpp | 41 ++++-------- tests/cpp/client_test_ensemble_dataset.cpp | 24 ++----- tests/cpp/unit-tests/CMakeLists.txt | 5 +- .../cpp/unit-tests/test_addressanycommand.cpp | 4 ++ .../cpp/unit-tests/test_addressatcommand.cpp | 7 +++ .../cpp/unit-tests/test_aggregation_list.cpp | 5 ++ tests/cpp/unit-tests/test_client.cpp | 4 ++ tests/cpp/unit-tests/test_client_ensemble.cpp | 48 +++++++------- .../unit-tests/test_clusterinfocommand.cpp | 5 ++ tests/cpp/unit-tests/test_commandlist.cpp | 4 ++ tests/cpp/unit-tests/test_commandreply.cpp | 29 ++++++++- tests/cpp/unit-tests/test_compoundcommand.cpp | 5 ++ tests/cpp/unit-tests/test_dataset.cpp | 7 ++- tests/cpp/unit-tests/test_dbinfocommand.cpp | 5 ++ tests/cpp/unit-tests/test_dbnode.cpp | 5 ++ tests/cpp/unit-tests/test_logger.cpp | 63 +++++++++++++++++++ tests/cpp/unit-tests/test_metadata.cpp | 4 ++ tests/cpp/unit-tests/test_multikeycommand.cpp | 5 ++ tests/cpp/unit-tests/test_redisserver.cpp | 50 +++++++++++++++ .../cpp/unit-tests/test_singlekeycommand.cpp | 9 ++- tests/cpp/unit-tests/test_ssdb.cpp | 11 +++- tests/cpp/unit-tests/test_stringfield.cpp | 5 ++ tests/cpp/unit-tests/test_tensor.cpp | 5 ++ tests/cpp/unit-tests/test_tensorbase.cpp | 4 ++ 28 files changed, 316 insertions(+), 82 deletions(-) create mode 100644 tests/cpp/unit-tests/test_logger.cpp diff --git a/include/logger.h b/include/logger.h index 0591f4ebc..cd3abdd7c 100644 --- a/include/logger.h +++ b/include/logger.h @@ -73,6 +73,12 @@ class Logger { */ void configure_logging(const std::string& client_id); + /*! + * \brief Rename the current client + * \param _client_id new ID to use for the current client + */ + void rename_client(const std::string& client_id); + private: /*! diff --git a/src/cpp/logger.cpp b/src/cpp/logger.cpp index 188e78adb..75073e7ea 100644 --- a/src/cpp/logger.cpp +++ b/src/cpp/logger.cpp @@ -39,6 +39,16 @@ using namespace SmartRedis; +/*! +* \brief Rename the current client +* \param _client_id new ID to use for the current client +*/ +void Logger::rename_client(const std::string& client_id) +{ + _client_id = client_id; +} + + /*! * \brief Set up logging for the current client * \param _client_id ID to use for the current client diff --git a/src/cpp/redisserver.cpp b/src/cpp/redisserver.cpp index 64d28d3e4..2be130958 100644 --- a/src/cpp/redisserver.cpp +++ b/src/cpp/redisserver.cpp @@ -130,7 +130,8 @@ inline void RedisServer::_check_runtime_variables() } if (_command_timeout <= 0) { - throw SRParameterException(_CMD_TIMEOUT_ENV_VAR + + throw SRParameterException(_CMD_TIMEOUT_ENV_VAR + " " + + std::to_string(_command_timeout) + " must be greater than 0."); } @@ -146,7 +147,8 @@ inline void RedisServer::_check_runtime_variables() } if (_command_timeout > (INT_MAX / 1000)) { - throw SRParameterException(_CMD_TIMEOUT_ENV_VAR + + throw SRParameterException(_CMD_TIMEOUT_ENV_VAR + " " + + std::to_string(_command_timeout) + " must be less than " + std::to_string(INT_MAX / 1000)); } diff --git a/src/cpp/utility.cpp b/src/cpp/utility.cpp index 6f91e07f6..67e4e4465 100644 --- a/src/cpp/utility.cpp +++ b/src/cpp/utility.cpp @@ -52,8 +52,16 @@ void get_config_integer(int& value, bool suppress_warning /*= false*/) { value = default_value; + std::string message = "Getting value for " + cfg_key; + log_data(LLDebug, message); char* cfg_val = std::getenv(cfg_key.c_str()); + message = "Retrieved value \""; + message += cfg_val == NULL ? "" : cfg_val; + message += "\""; + if (NULL == cfg_val) + message += ". Using default value of " + std::to_string(default_value); + log_data(LLDebug, message); if (cfg_val != NULL && std::strlen(cfg_val) > 0) { // Enforce that all characters are digits because std::stoi @@ -91,6 +99,9 @@ void get_config_integer(int& value, "Configuration variable " + cfg_key + " not set" ); } + + message = "Exiting with value \"" + std::to_string(value) + "\""; + log_data(LLDebug, message); } /*! @@ -108,8 +119,16 @@ void get_config_string(std::string& value, bool suppress_warning /*= false*/) { value = default_value; + std::string message = "Getting value for " + cfg_key; + log_data(LLDebug, message); char* cfg_val = std::getenv(cfg_key.c_str()); + message = "Retrieved value \""; + message += cfg_val == NULL ? "" : cfg_val; + message += "\""; + if (NULL == cfg_val) + message += ". Using default value of \"" + default_value + "\""; + log_data(LLDebug, message); if (cfg_val != NULL && std::strlen(cfg_val) > 0) value = cfg_val; @@ -119,6 +138,9 @@ void get_config_string(std::string& value, "Configuration variable " + cfg_key + " not set" ); } + + message = "Exiting with value \"" + value + "\""; + log_data(LLDebug, message); } } // namespace SmartRedis { diff --git a/tests/cpp/client_test_ensemble.cpp b/tests/cpp/client_test_ensemble.cpp index fa6c881b7..c5c6ddc42 100644 --- a/tests/cpp/client_test_ensemble.cpp +++ b/tests/cpp/client_test_ensemble.cpp @@ -216,50 +216,35 @@ int main(int argc, char* argv[]) { const char* old_keyin = std::getenv("SSKEYIN"); const char* old_keyout = std::getenv("SSKEYOUT"); - char keyin_env_put[] = "SSKEYIN=producer_0,producer_1"; - char keyout_env_put[] = "SSKEYOUT=producer_0"; - putenv( keyin_env_put ); - putenv( keyout_env_put ); + char keyin_env_put[] = "producer_0,producer_1"; + char keyout_env_put[] = "producer_0"; + setenv("SSKEYIN", keyin_env_put, (NULL != old_keyin)); + setenv("SSKEYOUT", keyout_env_put, (NULL != old_keyout)); size_t dim1 = 10; std::vector dims = {dim1}; - produce(dims, - std::string("producer_0"), - std::string("producer_0")); + produce(dims, std::string("producer_0"), std::string("producer_0")); - char keyin_env_get[] = "SSKEYIN=producer_1,producer_0"; - char keyout_env_get[] = "SSKEYOUT=producer_1"; - putenv(keyin_env_get); - putenv(keyout_env_get); - consume(dims, - std::string("producer_1"), - std::string("producer_0")); + char keyin_env_get[] = "producer_1,producer_0"; + char keyout_env_get[] = "producer_1"; + setenv("SSKEYIN", keyin_env_get, 1); + setenv("SSKEYOUT", keyout_env_get, 1); + + consume(dims, std::string("producer_1"), std::string("producer_0")); if (old_keyin != nullptr) { - std::string reset_keyin = std::string("SSKEYIN=") + std::string(old_keyin); - char* reset_keyin_c = new char[reset_keyin.size() + 1]; - std::copy(reset_keyin.begin(), reset_keyin.end(), reset_keyin_c); - reset_keyin_c[reset_keyin.size()] = '\0'; - putenv( reset_keyin_c); - delete[] reset_keyin_c; + setenv("SSKEYIN", old_keyin, 1); } else { unsetenv("SSKEYIN"); } if (old_keyout != nullptr) { - std::string reset_keyout = std::string("SSKEYOUT=") + std::string(old_keyout); - char* reset_keyout_c = new char[reset_keyout.size() + 1]; - std::copy(reset_keyout.begin(), reset_keyout.end(), reset_keyout_c); - reset_keyout_c[reset_keyout.size()] = '\0'; - putenv( reset_keyout_c); - delete[] reset_keyout_c; + setenv("SSKEYOUT", old_keyout, 1); } else { unsetenv("SSKEYOUT"); } - std::cout<<"Ensemble test complete"< +#include "logger.h" unsigned long get_time_offset(); @@ -146,6 +147,9 @@ bool is_same_dataset(DataSet& dataset_1, DataSet& dataset_2) SCENARIO("Testing Dataset aggregation via our client", "[List]") { std::cout << std::to_string(get_time_offset()) << ": Testing Dataset aggregation via our client" << std::endl; + Logger::get_instance().rename_client("test_aggregation_list"); + log_data(LLDebug, "***Beginning DataSet Aggregation testing***"); + GIVEN("A Client object and vector of DataSet objects") { Client client(use_cluster(), "test_aggregation_list"); @@ -500,4 +504,5 @@ SCENARIO("Testing Dataset aggregation via our client", "[List]") } } } + log_data(LLDebug, "***End DataSet Aggregation testing***"); } diff --git a/tests/cpp/unit-tests/test_client.cpp b/tests/cpp/unit-tests/test_client.cpp index fe260560c..40655530a 100644 --- a/tests/cpp/unit-tests/test_client.cpp +++ b/tests/cpp/unit-tests/test_client.cpp @@ -32,6 +32,7 @@ #include "../client_test_utils.h" #include "srexception.h" #include +#include "logger.h" unsigned long get_time_offset(); @@ -95,6 +96,8 @@ void check_all_data(size_t length, std::vector& original_datas, SCENARIO("Testing Dataset Functions on Client Object", "[Client]") { std::cout << std::to_string(get_time_offset()) << ": Testing Dataset Functions on Client Object" << std::endl; + Logger::get_instance().rename_client("test_client"); + log_data(LLDebug, "***Beginning Client testing***"); GIVEN("A Client object") { Client client(use_cluster(), "test_client"); @@ -953,4 +956,5 @@ SCENARIO("Testing Multi-GPU Function error cases", "[Client]") } } } + log_data(LLDebug, "***End Client testing***"); } diff --git a/tests/cpp/unit-tests/test_client_ensemble.cpp b/tests/cpp/unit-tests/test_client_ensemble.cpp index 724c8d96f..cde438554 100644 --- a/tests/cpp/unit-tests/test_client_ensemble.cpp +++ b/tests/cpp/unit-tests/test_client_ensemble.cpp @@ -29,6 +29,7 @@ #include "../../../third-party/catch/single_include/catch2/catch.hpp" #include "client.h" #include "dataset.h" +#include "logger.h" #include "../client_test_utils.h" unsigned long get_time_offset(); @@ -39,26 +40,15 @@ using namespace SmartRedis; // variables to their original state void reset_env_vars(const char* old_keyin, const char* old_keyout) { + log_data(LLDebug, "Resetting SSKEYIN and SSKEYOUT"); if (old_keyin != nullptr) { - std::string reset_keyin = - std::string("SSKEYIN=") + std::string(old_keyin); - char* reset_keyin_c = new char[reset_keyin.size() + 1]; - std::copy(reset_keyin.begin(), reset_keyin.end(), reset_keyin_c); - reset_keyin_c[reset_keyin.size()] = '\0'; - putenv( reset_keyin_c); - delete [] reset_keyin_c; + setenv("SSKEYIN", old_keyin, 1); } else { unsetenv("SSKEYIN"); } if (old_keyout != nullptr) { - std::string reset_keyout = - std::string("SSKEYOUT=") + std::string(old_keyout); - char* reset_keyout_c = new char[reset_keyout.size() + 1]; - std::copy(reset_keyout.begin(), reset_keyout.end(), reset_keyout_c); - reset_keyout_c[reset_keyout.size()] = '\0'; - putenv( reset_keyout_c); - delete [] reset_keyout_c; + setenv("SSKEYOUT", old_keyout, 1); } else { unsetenv("SSKEYOUT"); @@ -90,14 +80,17 @@ void load_mnist_image_to_array(float**** img) SCENARIO("Testing Client ensemble using a producer/consumer paradigm") { std::cout << std::to_string(get_time_offset()) << ": Testing Client ensemble using a producer/consumer paradigm" << std::endl; + Logger::get_instance().rename_client("test_client_ensemble"); + log_data(LLDebug, "***Beginning Client Ensemble testing***"); + GIVEN("Variables that will be used by the producer and consumer") { const char* old_keyin = std::getenv("SSKEYIN"); const char* old_keyout = std::getenv("SSKEYOUT"); - char keyin_env_put[] = "SSKEYIN=producer_0,producer_1"; - char keyout_env_put[] = "SSKEYOUT=producer_0"; - char keyin_env_get[] = "SSKEYIN=producer_1,producer_0"; - char keyout_env_get[] = "SSKEYOUT=producer_1"; + char keyin_env_put[] = "producer_0,producer_1"; + char keyout_env_put[] = "producer_0"; + char keyin_env_get[] = "producer_1,producer_0"; + char keyout_env_get[] = "producer_1"; size_t dim1 = 10; std::vector dims = {dim1}; std::string producer_keyout = "producer_0"; @@ -133,11 +126,13 @@ SCENARIO("Testing Client ensemble using a producer/consumer paradigm") THEN("The Client ensemble can be tested with " "a producer/consumer relationship") { + //////////////////////////////////////////////////////////// // do producer stuff - putenv(keyin_env_put); - putenv(keyout_env_put); + log_data(LLDebug, "***Beginning producer operations***"); + setenv("SSKEYIN", keyin_env_put, (old_keyin != NULL)); + setenv("SSKEYOUT", keyout_env_put, (old_keyout != NULL)); - Client producer_client(use_cluster(), "test_client_ensemble"); + Client producer_client(use_cluster(), "test_client_ensemble::producer"); producer_client.use_model_ensemble_prefix(true); // Tensors @@ -182,13 +177,15 @@ SCENARIO("Testing Client ensemble using a producer/consumer paradigm") producer_client.run_model(model_name, {script_out_key_ds}, {out_key_ds}); free_4D_array(mnist_array, 1, 1, 28); + log_data(LLDebug, "***End producer operations***"); - + //////////////////////////////////////////////////////////// // do consumer stuff - putenv(keyin_env_get); - putenv(keyout_env_get); + log_data(LLDebug, "***Beginning consumer operations***"); + setenv("SSKEYIN", keyin_env_get, 1); + setenv("SSKEYOUT", keyout_env_get, 1); - Client consumer_client(use_cluster(), "test_client_ensemble"); + Client consumer_client(use_cluster(), "test_client_ensemble::consumer"); consumer_client.use_model_ensemble_prefix(true); // Tensors @@ -253,4 +250,5 @@ SCENARIO("Testing Client ensemble using a producer/consumer paradigm") reset_env_vars(old_keyin, old_keyout); } } + log_data(LLDebug, "***End Client Ensemble testing***"); } \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_clusterinfocommand.cpp b/tests/cpp/unit-tests/test_clusterinfocommand.cpp index 565b37b0a..08071afc0 100644 --- a/tests/cpp/unit-tests/test_clusterinfocommand.cpp +++ b/tests/cpp/unit-tests/test_clusterinfocommand.cpp @@ -28,6 +28,7 @@ #include "../../../third-party/catch/single_include/catch2/catch.hpp" #include "clusterinfocommand.h" +#include "logger.h" unsigned long get_time_offset(); @@ -36,6 +37,9 @@ using namespace SmartRedis; SCENARIO("Parsing an empty string for cluster info") { std::cout << std::to_string(get_time_offset()) << ": Parsing an empty string for cluster info" << std::endl; + Logger::get_instance().rename_client("test_clusterinfocommand"); + log_data(LLDebug, "***Beginning ClusterInfoCommand testing***"); + GIVEN("A ClusterInfoCommand and an empty string") { ClusterInfoCommand cmd; @@ -49,4 +53,5 @@ SCENARIO("Parsing an empty string for cluster info") } } } + log_data(LLDebug, "***End ClusterInfoCommand testing***"); } \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_commandlist.cpp b/tests/cpp/unit-tests/test_commandlist.cpp index 9d785c3ff..1156c818c 100644 --- a/tests/cpp/unit-tests/test_commandlist.cpp +++ b/tests/cpp/unit-tests/test_commandlist.cpp @@ -34,6 +34,7 @@ #include "addressatcommand.h" #include "addressanycommand.h" #include "client.h" +#include "logger.h" unsigned long get_time_offset(); @@ -42,6 +43,8 @@ using namespace SmartRedis; SCENARIO("Testing CommandList object", "[CommandList]") { std::cout << std::to_string(get_time_offset()) << ": Testing CommandList objectinfo" << std::endl; + Logger::get_instance().rename_client("test_commandlist"); + log_data(LLDebug, "***Beginning CommandList testing***"); GIVEN("A CommandList object") { CommandList cmd_lst; @@ -334,4 +337,5 @@ SCENARIO("Testing CommandList object on heap", "[CommandList]") } } } + log_data(LLDebug, "***End CommandList testing***"); } \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_commandreply.cpp b/tests/cpp/unit-tests/test_commandreply.cpp index 7bc932c2d..0cf432ad8 100644 --- a/tests/cpp/unit-tests/test_commandreply.cpp +++ b/tests/cpp/unit-tests/test_commandreply.cpp @@ -29,6 +29,7 @@ #include "../../../third-party/catch/single_include/catch2/catch.hpp" #include "commandreply.h" #include "srexception.h" +#include "logger.h" unsigned long get_time_offset(); @@ -104,6 +105,9 @@ void fill_reply_array(redisReply*& reply, int num_of_children) SCENARIO("Testing CommandReply object", "[CommandReply]") { std::cout << std::to_string(get_time_offset()) << ": Testing CommandReply object" << std::endl; + Logger::get_instance().rename_client("test_commandreply"); + log_data(LLDebug, "***Beginning CommandReply object testing***"); + GIVEN("A CommandReply object with type REDIS_REPLY_INTEGER") { redisReply* reply = new redisReply; @@ -159,12 +163,15 @@ SCENARIO("Testing CommandReply object", "[CommandReply]") CHECK_THROWS_AS(cmd_reply.redis_reply_type(), RuntimeException); } } + log_data(LLDebug, "***End CommandReply object testing***"); } SCENARIO("Test CommandReply copy assignment operator and copy " "constructor on simple REDIS_REPLY_TYPES", "[CommandReply]") { std::cout << std::to_string(get_time_offset()) << ": Test CommandReply copy assignment operator and copy" << std::endl; + log_data(LLDebug, "***Beginning CommandReply copy testing***"); + GIVEN("A CommandReply") { redisReply* reply = new redisReply; @@ -205,11 +212,14 @@ SCENARIO("Test CommandReply copy assignment operator and copy " } } } + log_data(LLDebug, "***End CommandReply copy testing***"); } SCENARIO("Test CommandReply::has_error", "[CommandReply]") { std::cout << std::to_string(get_time_offset()) << ": Test CommandReply::has_error" << std::endl; + log_data(LLDebug, "***Beginning CommandReply has_error testing***"); + GIVEN("A parent and child redisReply") { char const* str = "ERR"; @@ -230,13 +240,15 @@ SCENARIO("Test CommandReply::has_error", "[CommandReply]") } } } - + log_data(LLDebug, "***End CommandReply has_error testing***"); } SCENARIO("CommandReply copy assignment operator preserves the state of the " "rvalue and the lvalue when one of the objects are deleted", "[CommandReply]") { std::cout << std::to_string(get_time_offset()) << ": CommandReply copy assignment operator preserves the state of the" << std::endl; + log_data(LLDebug, "***Beginning CommandReply delete testing***"); + GIVEN("Two dynamically allocated CommandReply. One with a complex " "redisReply, and the other with a simple redisReply") { @@ -320,11 +332,14 @@ SCENARIO("CommandReply copy assignment operator preserves the state of the " } } } + log_data(LLDebug, "***End CommandReply delete testing***"); } SCENARIO("Simple tests on CommandReply constructors that use redisReply*", "[CommandReply]") { std::cout << std::to_string(get_time_offset()) << ": Simple tests on CommandReply constructors that use redisReply*" << std::endl; + log_data(LLDebug, "***Beginning CommandReply redisReply testing***"); + GIVEN("A redisReply") { char const* str = "100.0"; @@ -366,11 +381,14 @@ SCENARIO("Simple tests on CommandReply constructors that use redisReply*", "[Com } } } + log_data(LLDebug, "***End CommandReply redisReply testing***"); } SCENARIO("Test CommandReply copy constructor with an inconsistent redisReply", "[CommandReply]") { std::cout << std::to_string(get_time_offset()) << ": Test CommandReply copy constructor with an inconsistent redisReply" << std::endl; + log_data(LLDebug, "***Beginning CommandReply inconsistent redisReply testing***"); + GIVEN("An inconsistent redisReply where its 'elements' doesn't "\ "correspond to its 'element'") { @@ -392,11 +410,13 @@ SCENARIO("Test CommandReply copy constructor with an inconsistent redisReply", " } } } + log_data(LLDebug, "***End CommandReply inconsistent redisReply testing***"); } SCENARIO("Test CommandReply's redisReply deep copy on a shallow copy", "[CommandReply]") { std::cout << std::to_string(get_time_offset()) << ": Test CommandReply's redisReply deep copy on a shallow copy" << std::endl; + log_data(LLDebug, "***Beginning CommandReply deep copy testing***"); GIVEN("A CommandReply with redisReply type REDIS_REPLY_ARRAY") { char const* strs[] = {"zero", "one"}; @@ -431,11 +451,14 @@ SCENARIO("Test CommandReply's redisReply deep copy on a shallow copy", "[Command } } } + log_data(LLDebug, "***End CommandReply deep copy testing***"); } SCENARIO("Test CommandReply string retrieval for non REDIS_REPLY_STRING", "[CommandReply]") { std::cout << std::to_string(get_time_offset()) << ": Test CommandReply string retrieval for non REDIS_REPLY_STRING" << std::endl; + log_data(LLDebug, "***Beginning CommandReply string retrieval testing***"); + char const* strs[] = {"OK", "42.5", "99999999999999999999", "Verbatim string"}; int lens[] = {3, 5, 21, 16}; int types[] = {REDIS_REPLY_STATUS, REDIS_REPLY_DOUBLE, REDIS_REPLY_BIGNUM, REDIS_REPLY_VERB}; @@ -469,12 +492,15 @@ SCENARIO("Test CommandReply string retrieval for non REDIS_REPLY_STRING", "[Comm } delete cmd_reply; } + log_data(LLDebug, "***End CommandReply string retrieval testing***"); } SCENARIO("Test REDIS_REPLY_ERROR retrieval from a CommandReply", "[CommandReply]") { std::cout << std::to_string(get_time_offset()) << ": Test REDIS_REPLY_ERROR retrieval from a CommandReply" << std::endl; + log_data(LLDebug, "***Beginning CommandReply REDIS_REPLY_ERROR retrieval testing***"); + /* CommanReply (ARRAY) LEVEL 0 / | \ @@ -517,4 +543,5 @@ SCENARIO("Test REDIS_REPLY_ERROR retrieval from a CommandReply", "[CommandReply] } } } + log_data(LLDebug, "***End CommandReply REDIS_REPLY_ERROR retrieval testing***"); } \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_compoundcommand.cpp b/tests/cpp/unit-tests/test_compoundcommand.cpp index cbc5d417f..28702ef05 100644 --- a/tests/cpp/unit-tests/test_compoundcommand.cpp +++ b/tests/cpp/unit-tests/test_compoundcommand.cpp @@ -28,6 +28,7 @@ #include "../../../third-party/catch/single_include/catch2/catch.hpp" #include "compoundcommand.h" +#include "logger.h" unsigned long get_time_offset(); @@ -36,6 +37,9 @@ using namespace SmartRedis; SCENARIO("Testing copy constructor and deep copy operator for CompoundCommand", "[CompoundCommand]") { std::cout << std::to_string(get_time_offset()) << ": Testing copy constructor and deep copy operator for CompoundCommand" << std::endl; + Logger::get_instance().rename_client("test_compoundcommand"); + log_data(LLDebug, "***Beginning CompoundCommand testing***"); + GIVEN("A CompoundCommand object") { CompoundCommand cmd; @@ -133,4 +137,5 @@ SCENARIO("Testing copy constructor and deep copy operator for CompoundCommand", } } } + log_data(LLDebug, "***End CompoundCommand testing***"); } \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_dataset.cpp b/tests/cpp/unit-tests/test_dataset.cpp index e4e16c209..22a67a538 100644 --- a/tests/cpp/unit-tests/test_dataset.cpp +++ b/tests/cpp/unit-tests/test_dataset.cpp @@ -30,20 +30,22 @@ #include "dataset.h" #include "srexception.h" #include +#include "logger.h" unsigned long get_time_offset(); using namespace SmartRedis; const char *currentExceptionTypeName() { - int status; -// return abi::__cxa_demangle(abi::__cxa_current_exception_type()->name(), 0, 0, &status); return abi::__cxa_current_exception_type()->name(); } SCENARIO("Testing DataSet object", "[DataSet]") { std::cout << std::to_string(get_time_offset()) << ": Testing DataSet object" << std::endl; + Logger::get_instance().rename_client("test_dataset"); + log_data(LLDebug, "***Beginning DataSet testing***"); + GIVEN("A DataSet object") { std::string dataset_name; @@ -208,4 +210,5 @@ SCENARIO("Testing DataSet object", "[DataSet]") } } } + log_data(LLDebug, "***End DataSet testing***"); } \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_dbinfocommand.cpp b/tests/cpp/unit-tests/test_dbinfocommand.cpp index 736fcd6ab..f80eb2066 100644 --- a/tests/cpp/unit-tests/test_dbinfocommand.cpp +++ b/tests/cpp/unit-tests/test_dbinfocommand.cpp @@ -28,6 +28,7 @@ #include "../../../third-party/catch/single_include/catch2/catch.hpp" #include "dbinfocommand.h" +#include "logger.h" unsigned long get_time_offset(); @@ -36,6 +37,9 @@ using namespace SmartRedis; SCENARIO("Parsing an empty string for db info") { std::cout << std::to_string(get_time_offset()) << ": Parsing an empty string for db info" << std::endl; + Logger::get_instance().rename_client("test_dbinfocommand"); + log_data(LLDebug, "***Beginning DBInfoCommand testing***"); + GIVEN("A DBInfoCommand and an empty string") { DBInfoCommand cmd; @@ -49,4 +53,5 @@ SCENARIO("Parsing an empty string for db info") } } } + log_data(LLDebug, "***End DBInfoCommand testing***"); } \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_dbnode.cpp b/tests/cpp/unit-tests/test_dbnode.cpp index c78093c99..cd0fe750b 100644 --- a/tests/cpp/unit-tests/test_dbnode.cpp +++ b/tests/cpp/unit-tests/test_dbnode.cpp @@ -29,6 +29,7 @@ #include #include "../../../third-party/catch/single_include/catch2/catch.hpp" #include "dbnode.h" +#include "logger.h" unsigned long get_time_offset(); @@ -37,6 +38,9 @@ using namespace SmartRedis; SCENARIO("Testing DBNode object", "[DBNode]") { std::cout << std::to_string(get_time_offset()) << ": Testing DBNode object" << std::endl; + Logger::get_instance().rename_client("test_dbnode"); + log_data(LLDebug, "***Beginning DBNode testing***"); + GIVEN("Two DBNode objects created with the default contructor") { DBNode node_1; @@ -92,4 +96,5 @@ SCENARIO("Testing DBNode object", "[DBNode]") CHECK(node_1 < node_2); } } + log_data(LLDebug, "***End DBNode testing***"); } \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_logger.cpp b/tests/cpp/unit-tests/test_logger.cpp new file mode 100644 index 000000000..5aeb657d9 --- /dev/null +++ b/tests/cpp/unit-tests/test_logger.cpp @@ -0,0 +1,63 @@ +/* + * BSD 2-Clause License + * + * Copyright (c) 2021-2022, Hewlett Packard Enterprise + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "../../../third-party/catch/single_include/catch2/catch.hpp" +#include "../client_test_utils.h" +#include "redis.h" +#include "client.h" +#include "address.h" +#include "logger.h" + +unsigned long get_time_offset(); + +using namespace SmartRedis; + +SCENARIO("Additional Testing for logging", "[LOG]") +{ + std::cout << std::to_string(get_time_offset()) << ": Additional Testing for logging" << std::endl; + Logger::get_instance().rename_client("test_logger"); + log_data(LLDebug, "***Beginning Logger testing***"); + + GIVEN("A Client object") + { + Client client(use_cluster(), "test_logger"); + + THEN("Logging should be able to be done") + { + // log_data() + log_data(LLInfo, "This is data logged at the Info level"); + + // log_warning() + log_warning(LLInfo, "This is a warning logged at the Info level"); + + // log_error() + log_error(LLInfo, "This is an error logged at the Info level"); + } + } + log_data(LLDebug, "***End Logger testing***"); +} \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_metadata.cpp b/tests/cpp/unit-tests/test_metadata.cpp index 8b710b133..998645763 100644 --- a/tests/cpp/unit-tests/test_metadata.cpp +++ b/tests/cpp/unit-tests/test_metadata.cpp @@ -29,6 +29,7 @@ #include "../../../third-party/catch/single_include/catch2/catch.hpp" #include "metadata.h" #include "srexception.h" +#include "logger.h" unsigned long get_time_offset(); @@ -131,6 +132,8 @@ void check_metadata_copied_correctly(MetaData metadata, MetaData metadata_cpy) SCENARIO("Test MetaData", "[MetaData]") { std::cout << std::to_string(get_time_offset()) << ": Test MetaData" << std::endl; + Logger::get_instance().rename_client("test_metadata"); + log_data(LLDebug, "***Beginning Metadata testing***"); GIVEN("A MetaData object") { MetaData metadata; @@ -357,4 +360,5 @@ SCENARIO("Test MetaData", "[MetaData]") } } } + log_data(LLDebug, "***End DBNode testing***"); } \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_multikeycommand.cpp b/tests/cpp/unit-tests/test_multikeycommand.cpp index 7d0d15e45..8fc5987a7 100644 --- a/tests/cpp/unit-tests/test_multikeycommand.cpp +++ b/tests/cpp/unit-tests/test_multikeycommand.cpp @@ -28,6 +28,7 @@ #include "../../../third-party/catch/single_include/catch2/catch.hpp" #include "multikeycommand.h" +#include "logger.h" unsigned long get_time_offset(); @@ -36,6 +37,9 @@ using namespace SmartRedis; SCENARIO("Adding fields of different types", "[MultiKeyCommand]") { std::cout << std::to_string(get_time_offset()) << ": Adding fields of different types" << std::endl; + Logger::get_instance().rename_client("test_multikeycommand"); + log_data(LLDebug, "***Beginning MultiKeyCommand testing***"); + GIVEN("A MultiKeyCommand object") { MultiKeyCommand cmd; @@ -74,4 +78,5 @@ SCENARIO("Adding fields of different types", "[MultiKeyCommand]") } } } + log_data(LLDebug, "***End MultiKeyCommand testing***"); } \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_redisserver.cpp b/tests/cpp/unit-tests/test_redisserver.cpp index 1b269a5e0..e21776492 100644 --- a/tests/cpp/unit-tests/test_redisserver.cpp +++ b/tests/cpp/unit-tests/test_redisserver.cpp @@ -35,6 +35,7 @@ #include "rediscluster.h" #include "redis.h" #include "srexception.h" +#include "logger.h" unsigned long get_time_offset(); @@ -110,6 +111,44 @@ void unset_all_env_vars() unsetenv(CMD_INTERVAL_ENV_VAR); } +// Helper function to retrieve original versions of environment vars +void save_env_vars( + char** conn_timeout, + char** conn_interval, + char** cmd_timeout, + char** cmd_interval) +{ + *conn_timeout = getenv(CONN_TIMEOUT_ENV_VAR); + *conn_interval = getenv(CONN_INTERVAL_ENV_VAR); + *cmd_timeout = getenv(CMD_TIMEOUT_ENV_VAR); + *cmd_interval = getenv(CMD_INTERVAL_ENV_VAR); +} + +// Helper function to restore environment vars +void restore_env_vars( + char* conn_timeout, + char* conn_interval, + char* cmd_timeout, + char* cmd_interval) +{ + if (conn_timeout != NULL) + setenv(CONN_TIMEOUT_ENV_VAR, conn_timeout, 1); + else + unsetenv(CONN_TIMEOUT_ENV_VAR); + if (conn_interval != NULL) + setenv(CONN_INTERVAL_ENV_VAR, conn_interval, 1); + else + unsetenv(CONN_INTERVAL_ENV_VAR); + if (cmd_timeout != NULL) + setenv(CMD_TIMEOUT_ENV_VAR, cmd_timeout, 1); + else + unsetenv(CMD_TIMEOUT_ENV_VAR); + if (cmd_interval != NULL) + setenv(CMD_INTERVAL_ENV_VAR, cmd_interval, 1); + else + unsetenv(CMD_INTERVAL_ENV_VAR); +} + // Helper function to check that all default values being used template void check_all_defaults(T& server) @@ -130,6 +169,15 @@ void check_all_defaults(T& server) SCENARIO("Test runtime settings are initialized correctly", "[RedisServer]") { std::cout << std::to_string(get_time_offset()) << ": Test runtime settings are initialized correctly" << std::endl; + Logger::get_instance().rename_client("test_redisserver"); + log_data(LLDebug, "***Beginning RedisServer testing***"); + + char* __conn_timeout; + char* __conn_interval; + char* __cmd_timeout; + char* __cmd_interval; + save_env_vars(&__conn_timeout, &__conn_interval, &__cmd_timeout, &__cmd_interval); + GIVEN("A Redis derived object created with all environment variables unset") { unset_all_env_vars(); @@ -305,4 +353,6 @@ SCENARIO("Test runtime settings are initialized correctly", "[RedisServer]") CHECK_THROWS_AS(invoke_constructor(), ParameterException); } } + restore_env_vars(__conn_timeout, __conn_interval, __cmd_timeout, __cmd_interval); + log_data(LLDebug, "***End RedisServer testing***"); } \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_singlekeycommand.cpp b/tests/cpp/unit-tests/test_singlekeycommand.cpp index 98738936a..fb70fee29 100644 --- a/tests/cpp/unit-tests/test_singlekeycommand.cpp +++ b/tests/cpp/unit-tests/test_singlekeycommand.cpp @@ -29,6 +29,7 @@ #include "../../../third-party/catch/single_include/catch2/catch.hpp" #include "singlekeycommand.h" #include "srexception.h" +#include "logger.h" unsigned long get_time_offset(); @@ -37,6 +38,9 @@ using namespace SmartRedis; SCENARIO("Retrieve field to empty SingleKeyCommand", "[SingleKeyCommand]") { std::cout << std::to_string(get_time_offset()) << ": Retrieve field to empty SingleKeyCommand" << std::endl; + Logger::get_instance().rename_client("test_singlekeycommand"); + log_data(LLDebug, "***Beginning SingleKeyCommand empty testing***"); + GIVEN("An empty SingleKeyCommand object") { SingleKeyCommand cmd; @@ -50,12 +54,14 @@ SCENARIO("Retrieve field to empty SingleKeyCommand", "[SingleKeyCommand]") } } } - + log_data(LLDebug, "***End SingleKeyCommand empty testing***"); } SCENARIO("Testing copy constructor for SingleKeyCommand on heap", "[SingleKeyCommand]") { std::cout << std::to_string(get_time_offset()) << ": Testing copy constructor for SingleKeyCommand on heap" << std::endl; + log_data(LLDebug, "***Beginning SingleKeyCommand copy testing***"); + GIVEN("A SingleKeyCommand object on the heap") { SingleKeyCommand* cmd = new SingleKeyCommand; @@ -120,4 +126,5 @@ SCENARIO("Testing copy constructor for SingleKeyCommand on heap", "[SingleKeyCom delete cmd_cpy; } } + log_data(LLDebug, "***End SingleKeyCommand copy testing***"); } \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_ssdb.cpp b/tests/cpp/unit-tests/test_ssdb.cpp index ebcd305fd..6c4c6bada 100644 --- a/tests/cpp/unit-tests/test_ssdb.cpp +++ b/tests/cpp/unit-tests/test_ssdb.cpp @@ -30,6 +30,7 @@ #include "redis.h" #include "client.h" #include "address.h" +#include "logger.h" unsigned long get_time_offset(); @@ -59,13 +60,16 @@ void setenv_ssdb(const char* ssdb) SCENARIO("Additional Testing for various SSDBs", "[SSDB]") { std::cout << std::to_string(get_time_offset()) << ": Additional Testing for various SSDBs" << std::endl; + Logger::get_instance().rename_client("test_ssdb"); + log_data(LLDebug, "***Beginning SSDB testing***"); + GIVEN("A TestSSDB object") { const char* old_ssdb = std::getenv("SSDB"); - INFO("SSDB must be set to a valid host and "\ - "port before running this test."); - REQUIRE(old_ssdb != NULL); + INFO("SSDB must be set to a valid host and "\ + "port before running this test."); + REQUIRE(old_ssdb != NULL); TestSSDB test_ssdb; Client* c = NULL; @@ -92,4 +96,5 @@ SCENARIO("Additional Testing for various SSDBs", "[SSDB]") setenv_ssdb(old_ssdb); } } + log_data(LLDebug, "***End SSDB testing***"); } \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_stringfield.cpp b/tests/cpp/unit-tests/test_stringfield.cpp index 6ba3c9766..df729699b 100644 --- a/tests/cpp/unit-tests/test_stringfield.cpp +++ b/tests/cpp/unit-tests/test_stringfield.cpp @@ -28,12 +28,16 @@ #include "../../../third-party/catch/single_include/catch2/catch.hpp" #include "stringfield.h" +#include "logger.h" unsigned long get_time_offset(); SCENARIO("Test StringField", "[StringField]") { std::cout << std::to_string(get_time_offset()) << ": Test StringField" << std::endl; + Logger::get_instance().rename_client("test_stringfield"); + log_data(LLDebug, "***Beginning StringField testing***"); + GIVEN("A StringField object constructed with the string field name") { std::string name_1 = "stringfield_name_1"; @@ -95,4 +99,5 @@ SCENARIO("Test StringField", "[StringField]") } // TODO: Test serializing the StringField } + log_data(LLDebug, "***End StringField testing***"); } \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_tensor.cpp b/tests/cpp/unit-tests/test_tensor.cpp index 19f7749be..6aff47f4b 100644 --- a/tests/cpp/unit-tests/test_tensor.cpp +++ b/tests/cpp/unit-tests/test_tensor.cpp @@ -29,6 +29,7 @@ #include #include "../../../third-party/catch/single_include/catch2/catch.hpp" #include "tensor.h" +#include "logger.h" unsigned long get_time_offset(); @@ -37,6 +38,9 @@ using namespace SmartRedis; SCENARIO("Testing Tensor", "[Tensor]") { std::cout << std::to_string(get_time_offset()) << ": Testing Tensor" << std::endl; + Logger::get_instance().rename_client("test_tensor"); + log_data(LLDebug, "***Beginning Tensor testing***"); + GIVEN("Two Tensors") { // Create first tensor @@ -135,4 +139,5 @@ SCENARIO("Testing Tensor", "[Tensor]") } } } + log_data(LLDebug, "***End Tensor testing***"); } \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_tensorbase.cpp b/tests/cpp/unit-tests/test_tensorbase.cpp index 411f5f503..3f1f62b93 100644 --- a/tests/cpp/unit-tests/test_tensorbase.cpp +++ b/tests/cpp/unit-tests/test_tensorbase.cpp @@ -39,6 +39,9 @@ using namespace SmartRedis; SCENARIO("Testing TensorBase through TensorPack", "[TensorBase]") { std::cout << std::to_string(get_time_offset()) << ": Testing TensorBase through TensorPack" << std::endl; + Logger::get_instance().rename_client("test_tensorbase"); + log_data(LLDebug, "***Beginning TensorBase testing***"); + SRTensorType tensor_type = GENERATE(SRTensorTypeDouble, SRTensorTypeFloat, SRTensorTypeInt64, SRTensorTypeInt32, SRTensorTypeInt16, SRTensorTypeInt8, @@ -234,4 +237,5 @@ SCENARIO("Testing TensorBase through TensorPack", "[TensorBase]") } } } + log_data(LLDebug, "***End TensorBase testing***"); } \ No newline at end of file From 4a321cdeb0134d67180ab53b16e922a9c98589fa Mon Sep 17 00:00:00 2001 From: billschereriii Date: Tue, 29 Nov 2022 16:38:00 -0600 Subject: [PATCH 22/37] Fortran unit test --- src/fortran/logger/logger_interfaces.inc | 18 +++---- tests/fortran/CMakeLists.txt | 1 + tests/fortran/client_test_logging.F90 | 63 ++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 9 deletions(-) create mode 100644 tests/fortran/client_test_logging.F90 diff --git a/src/fortran/logger/logger_interfaces.inc b/src/fortran/logger/logger_interfaces.inc index 1fe730b21..04dfd29de 100644 --- a/src/fortran/logger/logger_interfaces.inc +++ b/src/fortran/logger/logger_interfaces.inc @@ -28,9 +28,9 @@ interface subroutine c_log_data(level, data, data_length) bind(c, name="log_data_noexcept") use iso_c_binding, only : c_ptr, c_char, c_size_t import :: enum_kind - integer(kind=enum_kind) :: level - character(kind=c_char) :: data(*) - integer(kind=c_size_t), value :: data_length + integer(kind=enum_kind), value :: level + character(kind=c_char) :: data(*) + integer(kind=c_size_t), value :: data_length end subroutine c_log_data end interface @@ -38,9 +38,9 @@ interface subroutine c_log_warning(level, data, data_length) bind(c, name="log_warning_noexcept") use iso_c_binding, only : c_ptr, c_char, c_size_t import :: enum_kind - integer(kind=enum_kind) :: level - character(kind=c_char) :: data(*) - integer(kind=c_size_t), value :: data_length + integer(kind=enum_kind), value :: level + character(kind=c_char) :: data(*) + integer(kind=c_size_t), value :: data_length end subroutine c_log_warning end interface @@ -48,8 +48,8 @@ interface subroutine c_log_error(level, data, data_length) bind(c, name="log_error_noexcept") use iso_c_binding, only : c_ptr, c_char, c_size_t import :: enum_kind - integer(kind=enum_kind) :: level - character(kind=c_char) :: data(*) - integer(kind=c_size_t), value :: data_length + integer(kind=enum_kind), value :: level + character(kind=c_char) :: data(*) + integer(kind=c_size_t), value :: data_length end subroutine c_log_error end interface diff --git a/tests/fortran/CMakeLists.txt b/tests/fortran/CMakeLists.txt index 107fb35ea..18627df27 100644 --- a/tests/fortran/CMakeLists.txt +++ b/tests/fortran/CMakeLists.txt @@ -69,6 +69,7 @@ list(APPEND EXECUTABLES client_test_put_get_2D client_test_put_get_3D client_test_put_get_unpack_dataset + client_test_logging ) foreach(EXECUTABLE ${EXECUTABLES}) diff --git a/tests/fortran/client_test_logging.F90 b/tests/fortran/client_test_logging.F90 new file mode 100644 index 000000000..d80608079 --- /dev/null +++ b/tests/fortran/client_test_logging.F90 @@ -0,0 +1,63 @@ +! BSD 2-Clause License +! +! Copyright (c) 2021-2022, Hewlett Packard Enterprise +! All rights reserved. +! +! Redistribution and use in source and binary forms, with or without +! modification, are permitted provided that the following conditions are met: +! +! 1. Redistributions of source code must retain the above copyright notice, this +! list of conditions and the following disclaimer. +! +! 2. Redistributions in binary form must reproduce the above copyright notice, +! this list of conditions and the following disclaimer in the documentation +! and/or other materials provided with the distribution. +! +! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +! DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +! FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +! DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +! SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +! OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +program main + use smartredis_client, only : client_type + use smartredis_logger, only : log_data, log_warning, log_error + use test_utils, only : use_cluster + use iso_fortran_env, only : STDERR => error_unit + use iso_c_binding, only : c_ptr, c_bool, c_null_ptr, c_char, c_int + use iso_c_binding, only : c_int8_t, c_int16_t, c_int32_t, c_int64_t, c_float, c_double, c_size_t + + implicit none + +#include "enum_fortran.inc" + + type(client_type) :: client + integer :: result + + result = client%initialize(use_cluster(), "client_test_logging") + if (result .ne. SRNoError) error stop + + call log_data(LLQuiet, "This is data logged at the Quiet level") + call log_data(LLInfo, "This is data logged at the Info level") + call log_data(LLDebug, "This is data logged at the Debug level") + call log_data(LLDeveloper, & + "This is data logged at the Developer level") + + call log_warning(LLQuiet, "This is a warning logged at the Quiet level") + call log_warning(LLInfo, "This is a warning logged at the Info level") + call log_warning(LLDebug, "This is a warning logged at the Debug level") + call log_warning(LLDeveloper, & + "This is a warning logged at the Developer level") + write(*,*) "client logging: passed" + + call log_error(LLQuiet, "This is an error logged at the Quiet level") + call log_error(LLInfo, "This is an error logged at the Info level") + call log_error(LLDebug, "This is an error logged at the Debug level") + call log_error(LLDeveloper, & + "This is an error logged at the Developer level") +end program main From 50881ba5d5f667fb4c9bdb033e24db138fa6e916 Mon Sep 17 00:00:00 2001 From: billschereriii Date: Tue, 29 Nov 2022 16:55:30 -0600 Subject: [PATCH 23/37] C unit test --- tests/c/CMakeLists.txt | 8 ++++ tests/c/client_test_logging.c | 74 +++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 tests/c/client_test_logging.c diff --git a/tests/c/CMakeLists.txt b/tests/c/CMakeLists.txt index db284d93e..180670ac7 100644 --- a/tests/c/CMakeLists.txt +++ b/tests/c/CMakeLists.txt @@ -56,6 +56,14 @@ target_link_libraries(client_test_dataset_exists ${SR_LIB} ) +add_executable(client_test_logging + client_test_logging.c +) + +target_link_libraries(client_test_logging + ${SR_LIB} +) + add_executable(client_test_put_unpack_1D client_test_put_unpack_1D.c ) diff --git a/tests/c/client_test_logging.c b/tests/c/client_test_logging.c new file mode 100644 index 000000000..c182dd2cf --- /dev/null +++ b/tests/c/client_test_logging.c @@ -0,0 +1,74 @@ +/* + * BSD 2-Clause License + * + * Copyright (c) 2021-2022, Hewlett Packard Enterprise + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "c_client.h" +#include "c_dataset.h" +#include "c_client_test_utils.h" +#include +#include +#include +#include "stdint.h" +#include "srexception.h" +#include "logger.h" + +bool cluster = true; + +#define TEST_LOG(logtype, loglevel, logmessage) \ +log_##logtype(loglevel, logmessage, strlen(logmessage)) + +int main(int argc, char* argv[]) +{ + int result = 0; + void *client = NULL; + const char* client_id = "client_test_logging"; + size_t cid_len = strlen(client_id); + + // Initialize client + if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client) || NULL == client) + return -1; + + // Log stuff + TEST_LOG(data, LLQuiet, "This is data logged at the Quiet level"); + TEST_LOG(data, LLInfo, "This is data logged at the Info level"); + TEST_LOG(data, LLDebug, "This is data logged at the Debug level"); + TEST_LOG(data, LLDeveloper, "This is data logged at the Developer level"); + + TEST_LOG(warning, LLQuiet, "This is a warning logged at the Quiet level"); + TEST_LOG(warning, LLInfo, "This is a warning logged at the Info level"); + TEST_LOG(warning, LLDebug, "This is a warning logged at the Debug level"); + TEST_LOG(warning, LLDeveloper, "This is a warning logged at the Developer level"); + + TEST_LOG(error, LLQuiet, "This is an error logged at the Quiet level"); + TEST_LOG(error, LLInfo, "This is an error logged at the Info level"); + TEST_LOG(error, LLDebug, "This is an error logged at the Debug level"); + TEST_LOG(error, LLDeveloper, "This is an error logged at the Developer level"); + + // Done + printf("Test passed: %s\n", result == 0 ? "YES" : "NO"); + return result; +} From 012112f5bbcd32af4e07fc37c6b792d420202793 Mon Sep 17 00:00:00 2001 From: billschereriii Date: Tue, 6 Dec 2022 16:06:59 -0600 Subject: [PATCH 24/37] Easy parts of the review feedback --- doc/changelog.rst | 1 - doc/runtime.rst | 11 +- examples/parallel/cpp/smartredis_mnist.cpp | 6 +- .../parallel/cpp/smartredis_put_get_3D.cpp | 6 +- examples/serial/c/example_put_get_3D.c | 6 +- examples/serial/c/example_put_unpack_1D.c | 6 +- .../serial/python/example_model_file_torch.py | 2 +- examples/serial/python/example_model_torch.py | 2 +- .../serial/python/example_put_get_dataset.py | 2 +- .../serial/python/example_put_get_tensor.py | 2 +- examples/serial/python/example_script.py | 2 +- examples/serial/python/example_script_file.py | 2 +- include/c_client.h | 8 +- include/client.h | 4 +- include/logger.h | 26 ++-- include/pyclient.h | 4 +- src/c/c_client.cpp | 10 +- src/cpp/client.cpp | 4 +- src/cpp/logger.cpp | 107 ++++++------- src/cpp/threadpool.cpp | 12 +- src/fortran/client.F90 | 26 ++-- src/fortran/client/client_interfaces.inc | 6 +- src/python/module/smartredis/client.py | 8 +- src/python/src/pyclient.cpp | 4 +- tests/c/client_test_dataset_aggregation.c | 6 +- tests/c/client_test_dataset_exists.c | 12 +- tests/c/client_test_logging.c | 6 +- tests/c/client_test_put_get_1D.c | 48 +++--- tests/c/client_test_put_get_2D.c | 48 +++--- tests/c/client_test_put_get_3D.c | 48 +++--- tests/c/client_test_put_unpack_1D.c | 6 +- tests/cpp/unit-tests/CMakeLists.txt | 4 +- tests/docker/c/test_docker.c | 6 +- tests/python/test_address.py | 2 +- tests/python/test_dataset_aggregation.py | 2 +- tests/python/test_dataset_ops.py | 12 +- tests/python/test_errors.py | 146 +++++++++--------- tests/python/test_logging.py | 2 +- tests/python/test_model_methods_torch.py | 6 +- tests/python/test_nonkeyed_cmd.py | 16 +- tests/python/test_put_get_dataset.py | 4 +- tests/python/test_put_get_tensor.py | 6 +- tests/python/test_script_methods.py | 10 +- tests/python/test_tensor_ops.py | 12 +- 44 files changed, 335 insertions(+), 334 deletions(-) diff --git a/doc/changelog.rst b/doc/changelog.rst index 90418044d..4c9ee434d 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -19,7 +19,6 @@ Description - This version adds new functionality in the form of support for Unix Domain Sockets. - Fortran client can now be optionally built with the rest of the library - Initial support for dataset conversions, specifically Xarray. -- Added support for logging of client activity. Detailed Notes diff --git a/doc/runtime.rst b/doc/runtime.rst index 38264abea..896faf23e 100644 --- a/doc/runtime.rst +++ b/doc/runtime.rst @@ -52,16 +52,21 @@ and ``SR_LOG_LEVEL``. ``SR_LOG_FILE`` is the specifier for the location of the file that receives logging information. Each entry in the file will be prefixed with a timestamp and the identifier of the client that invoked the logging -message. +message. The path may be relative or absolute, though a relative path risks +creation of multiple log files if the executables that instantiate SmartRedis +clients are run from different directories. If this variable is not set, +logging information will be sent to standard console output (STDOUT in C and +C++; output_unit in Fortran). ``SR_LOG_LEVEL`` relates to the verbosity of information that wil be logged. -It may be one of three levels: ``NONE`` disables logging altogether. +It may be one of three levels: ``QUIET`` disables logging altogether. ``INFO`` provides informational logging, such as exception events that transpire within the SmartRedis library and creation or destruction of a client object. ``DEBUG`` provides more verbose logging, including information on the activities of the SmartRedis thread pool and API function entry and exit. Debug level logging will also log the absence of an expected environment variable, -though this can happen only if the variables to set up logging are in place. +though this can happen only if the variables to set up logging are in place. If +this parameter is not set, a default logging level of ``INFO`` will be adopted. The runtime impact of log levels NONE or INFO should be minimal on client performance; however, seting the log level to DEBUG may cause some diff --git a/examples/parallel/cpp/smartredis_mnist.cpp b/examples/parallel/cpp/smartredis_mnist.cpp index ac1cfc561..3e348ef8f 100644 --- a/examples/parallel/cpp/smartredis_mnist.cpp +++ b/examples/parallel/cpp/smartredis_mnist.cpp @@ -100,12 +100,12 @@ int main(int argc, char* argv[]) { // Retrieve the MPI rank int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); - std::string client_id("Client "); - client_id += std::to_string(rank); + std::string logger_name("Client "); + logger_name += std::to_string(rank); // Initialize a Client object bool cluster_mode = true; // Set to false if not using a clustered database - SmartRedis::Client client(cluster_mode, client_id); + SmartRedis::Client client(cluster_mode, logger_name); // Set the model and script that will be used by all ranks // from MPI rank 0. diff --git a/examples/parallel/cpp/smartredis_put_get_3D.cpp b/examples/parallel/cpp/smartredis_put_get_3D.cpp index 5f419960d..3dfe5991f 100644 --- a/examples/parallel/cpp/smartredis_put_get_3D.cpp +++ b/examples/parallel/cpp/smartredis_put_get_3D.cpp @@ -53,12 +53,12 @@ int main(int argc, char* argv[]) { // Get our rank int rank = 0; MPI_Comm_rank(MPI_COMM_WORLD, &rank); - std::string client_id("Client "); - client_id += std::to_string(rank); + std::string logger_name("Client "); + logger_name += std::to_string(rank); // Initialize a SmartRedis client bool cluster_mode = true; // Set to false if not using a clustered database - SmartRedis::Client client(cluster_mode, client_id); + SmartRedis::Client client(cluster_mode, logger_name); // Put the tensor in the database std::string key = "3d_tensor_" + std::to_string(rank); diff --git a/examples/serial/c/example_put_get_3D.c b/examples/serial/c/example_put_get_3D.c index d88a74ba3..0eb6041a5 100644 --- a/examples/serial/c/example_put_get_3D.c +++ b/examples/serial/c/example_put_get_3D.c @@ -38,8 +38,8 @@ int main(int argc, char* argv[]) { values. */ - const char* client_id = "put_get_3d"; - size_t cid_len = strlen(client_id); + const char* logger_name = "put_get_3d"; + size_t cid_len = strlen(logger_name); size_t n_dims = 3; size_t* dims = malloc(n_dims*sizeof(size_t)); dims[0] = 10; @@ -48,7 +48,7 @@ int main(int argc, char* argv[]) { void* client = NULL; bool cluster_mode = true; // Set to false if not using a clustered database - if (SRNoError != SmartRedisCClient(cluster_mode, client_id, cid_len, &client)) { + if (SRNoError != SmartRedisCClient(cluster_mode, logger_name, cid_len, &client)) { printf("Client initialization failed!\n"); exit(-1); } diff --git a/examples/serial/c/example_put_unpack_1D.c b/examples/serial/c/example_put_unpack_1D.c index 113ea8d7b..838b94996 100644 --- a/examples/serial/c/example_put_unpack_1D.c +++ b/examples/serial/c/example_put_unpack_1D.c @@ -34,8 +34,8 @@ int main(int argc, char* argv[]) { - const char* client_id = "put_unpack_1d"; - size_t cid_len = strlen(client_id); + const char* logger_name = "put_unpack_1d"; + size_t cid_len = strlen(logger_name); size_t* dims = malloc(sizeof(size_t)); dims[0] = 10; size_t n_dims = 1; @@ -48,7 +48,7 @@ int main(int argc, char* argv[]) { void* client = NULL; bool cluster_mode = true; // Set to false if not using a clustered database - if (SRNoError != SmartRedisCClient(cluster_mode, client_id, cid_len, &client)) { + if (SRNoError != SmartRedisCClient(cluster_mode, logger_name, cid_len, &client)) { printf("Client initialization failed!\n"); exit(-1); } diff --git a/examples/serial/python/example_model_file_torch.py b/examples/serial/python/example_model_file_torch.py index 0a195eec0..008d6c6ed 100644 --- a/examples/serial/python/example_model_file_torch.py +++ b/examples/serial/python/example_model_file_torch.py @@ -43,7 +43,7 @@ def forward(self, x): # Connect a SmartRedis client db_address = "127.0.0.1:6379" -client = Client(address=db_address, cluster=True, client_id="example_model_file_torch.py") +client = Client(address=db_address, cluster=True, logger_name="example_model_file_torch.py") try: net = Net() diff --git a/examples/serial/python/example_model_torch.py b/examples/serial/python/example_model_torch.py index 7b2bdeb74..2b4b21d6f 100644 --- a/examples/serial/python/example_model_torch.py +++ b/examples/serial/python/example_model_torch.py @@ -54,7 +54,7 @@ def forward(self, x): # Connect a SmartRedis client and set the model in the database db_address = "127.0.0.1:6379" -client = Client(address=db_address, cluster=True, client_id="example_model_torch.py") +client = Client(address=db_address, cluster=True, logger_name="example_model_torch.py") client.set_model("torch_cnn", model, "TORCH", "CPU") # Retrieve the model and verify that the retrieved diff --git a/examples/serial/python/example_put_get_dataset.py b/examples/serial/python/example_put_get_dataset.py index 478b8034a..a6f86f620 100644 --- a/examples/serial/python/example_put_get_dataset.py +++ b/examples/serial/python/example_put_get_dataset.py @@ -39,7 +39,7 @@ # Connect SmartRedis client to Redis database db_address = "127.0.0.1:6379" -client = Client(address=db_address, cluster=True, client_id="example_put_get_dataset.py") +client = Client(address=db_address, cluster=True, logger_name="example_put_get_dataset.py") # Place the DataSet into the database client.put_dataset(dataset) diff --git a/examples/serial/python/example_put_get_tensor.py b/examples/serial/python/example_put_get_tensor.py index 153fe7d73..d3856ea1f 100644 --- a/examples/serial/python/example_put_get_tensor.py +++ b/examples/serial/python/example_put_get_tensor.py @@ -29,7 +29,7 @@ # Connect a SmartRedis client to Redis database db_address = "127.0.0.1:6379" -client = Client(address=db_address, cluster=True, client_id="example_put_get_tensor.py") +client = Client(address=db_address, cluster=True, logger_name="example_put_get_tensor.py") # Send a 2D tensor to the database key = "2D_array" diff --git a/examples/serial/python/example_script.py b/examples/serial/python/example_script.py index e46682f4b..5b419ef08 100644 --- a/examples/serial/python/example_script.py +++ b/examples/serial/python/example_script.py @@ -41,7 +41,7 @@ def two_to_one(data, data_2): # Connect a SmartRedis client to the Redis database db_address = "127.0.0.1:6379" -client = Client(address=db_address, cluster=True, client_id="example_script.py") +client = Client(address=db_address, cluster=True, logger_name="example_script.py") # Generate some test data to feed to the two_to_one function data = np.array([[1, 2, 3, 4]]) diff --git a/examples/serial/python/example_script_file.py b/examples/serial/python/example_script_file.py index 3adee6128..cb1ee9f06 100644 --- a/examples/serial/python/example_script_file.py +++ b/examples/serial/python/example_script_file.py @@ -33,7 +33,7 @@ # Connect to the Redis database db_address = "127.0.0.1:6379" -client = Client(address=db_address, cluster=True, client_id="example_script_file.py") +client = Client(address=db_address, cluster=True, logger_name="example_script_file.py") # Place the script in the database client.set_script_from_file( diff --git a/include/c_client.h b/include/c_client.h index 012cf2e67..1e2594757 100644 --- a/include/c_client.h +++ b/include/c_client.h @@ -43,15 +43,15 @@ extern "C" { /*! * \brief C-client constructor * \param cluster Flag to indicate if a database cluster is being used -* \param client_id Identifier for the current client -* \param client_id_length Length in characters of the client_id string +* \param logger_name Identifier for the current client +* \param logger_name_length Length in characters of the logger_name string * \param new_client Receives the new client * \return Returns SRNoError on success or an error code on failure */ SRError SmartRedisCClient( bool cluster, - const char* client_id, - const size_t client_id_length, + const char* logger_name, + const size_t logger_name_length, void **new_client); /*! diff --git a/include/client.h b/include/client.h index 8fe583784..ea2396f5a 100644 --- a/include/client.h +++ b/include/client.h @@ -74,11 +74,11 @@ class Client /*! * \brief Client constructor * \param cluster Flag for if a database cluster is being used - * \param client_id Name to use for this client when logging + * \param logger_name Name to use for this client when logging * \throw SmartRedis::Exception if client connection or * object initialization fails */ - Client(bool cluster, const std::string& client_id = "anonymous"); + Client(bool cluster, const std::string& logger_name = "default"); /*! * \brief Client copy constructor is not available diff --git a/include/logger.h b/include/logger.h index cd3abdd7c..0b6deb61e 100644 --- a/include/logger.h +++ b/include/logger.h @@ -69,15 +69,15 @@ class Logger { /*! * \brief Set up logging for the current client - * \param _client_id ID to use for the current client + * \param logger_name ID to use for the current client */ - void configure_logging(const std::string& client_id); + void configure_logging(const std::string& logger_name); /*! * \brief Rename the current client - * \param _client_id new ID to use for the current client + * \param new_name new ID to use for the current client */ - void rename_client(const std::string& client_id); + void rename_client(const std::string& new_name); private: @@ -94,10 +94,16 @@ class Logger { /*! * \brief Logger assignment operator unavailable - * \param logger The Logger to copy for construction + * \param logger The Logger to assign */ void operator=(const Logger& logger) = delete; + /*! + * \brief Logger move assignment operator unavailable + * \param logger The Logger to move + */ + void operator=(Logger&& logger) = delete; + /*! * \brief Default Logger destructor */ @@ -158,7 +164,7 @@ class Logger { /*! * \brief The client ID for this client */ - std::string _client_id; + std::string _logger_name; /*! * \brief The file to which to write log data @@ -217,9 +223,9 @@ class FunctionLogger { * \param function_name The name of the function to track */ FunctionLogger(const char* function_name) - : name(function_name) + : _name(function_name) { - log_data(LLDebug, "API Function " + name + " called"); + log_data(LLDebug, "API Function " + _name + " called"); } /*! @@ -227,13 +233,13 @@ class FunctionLogger { */ ~FunctionLogger() { - log_data(LLDebug, "API Function " + name + " exited"); + log_data(LLDebug, "API Function " + _name + " exited"); } private: /*! * \brief The name of the current function */ - std::string name; + std::string _name; }; /*! diff --git a/include/pyclient.h b/include/pyclient.h index 0e48c10a6..853206ffc 100644 --- a/include/pyclient.h +++ b/include/pyclient.h @@ -60,11 +60,11 @@ class PyClient * \brief PyClient constructor * \param cluster Flag to indicate if a database cluster * is being used - * \param client_id Identifier for the current client + * \param logger_name Identifier for the current client */ PyClient( bool cluster, - const std::string& client_id = std::string("anonymous")); + const std::string& logger_name = std::string("default")); /*! * \brief PyClient destructor diff --git a/src/c/c_client.cpp b/src/c/c_client.cpp index 71493f628..61a65cd7c 100644 --- a/src/c/c_client.cpp +++ b/src/c/c_client.cpp @@ -40,17 +40,17 @@ using namespace SmartRedis; extern "C" SRError SmartRedisCClient( bool cluster, - const char* client_id, - const size_t client_id_length, + const char* logger_name, + const size_t logger_name_length, void** new_client) { SRError result = SRNoError; try { // Sanity check params - SR_CHECK_PARAMS(new_client != NULL && client_id != NULL); + SR_CHECK_PARAMS(new_client != NULL && logger_name != NULL); - std::string _client_id(client_id, client_id_length); - Client* s = new Client(cluster, _client_id); + std::string _logger_name(logger_name, logger_name_length); + Client* s = new Client(cluster, _logger_name); *new_client = reinterpret_cast(s); } catch (const std::bad_alloc& e) { diff --git a/src/cpp/client.cpp b/src/cpp/client.cpp index 9e17805f6..59229b537 100644 --- a/src/cpp/client.cpp +++ b/src/cpp/client.cpp @@ -35,11 +35,11 @@ using namespace SmartRedis; // Constructor -Client::Client(bool cluster, const std::string& client_id) +Client::Client(bool cluster, const std::string& logger_name) { // Set up logging Logger& logger = Logger::get_instance(); - logger.configure_logging(client_id); + logger.configure_logging(logger_name); logger.log_data(LLDebug, "New client created"); // Set up Redis server connection diff --git a/src/cpp/logger.cpp b/src/cpp/logger.cpp index 75073e7ea..dde0de7c9 100644 --- a/src/cpp/logger.cpp +++ b/src/cpp/logger.cpp @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include "utility.h" #include "logger.h" @@ -39,26 +41,29 @@ using namespace SmartRedis; -/*! -* \brief Rename the current client -* \param _client_id new ID to use for the current client -*/ -void Logger::rename_client(const std::string& client_id) +// Convert a std::string to lower case +void str_to_lower(std::string& str) { - _client_id = client_id; + std::transform( + str.begin(), str.end(), str.begin(), + [](unsigned char c) { return std::tolower(c); } + ); +} + +// Rename the current client +void Logger::rename_client(const std::string& new_name) +{ + _logger_name = new_name; } -/*! -* \brief Set up logging for the current client -* \param _client_id ID to use for the current client -*/ -void Logger::configure_logging(const std::string& client_id) +// Set up logging for the current client +void Logger::configure_logging(const std::string& logger_name) { // If we're already initialized, they can set up a client ID // Useful if they call a Dataset API point before setting up // a Client object - _client_id = client_id; + _logger_name = logger_name; if (_initialized) { return; } @@ -87,13 +92,14 @@ void Logger::configure_logging(const std::string& client_id) bool missingLogLevel = level.length() == 0; bool badLogLevel = false; if (level.length() > 0) { - if (level.compare("QUIET") == 0) + str_to_lower(level); + if (level.compare("quiet") == 0) _log_level = LLQuiet; - else if (level.compare("INFO") == 0) + else if (level.compare("info") == 0) _log_level = LLInfo; - else if (level.compare("DEBUG") == 0) + else if (level.compare("debug") == 0) _log_level = LLDebug; - else if (level.compare("DEVELOPER") == 0) + else if (level.compare("developer") == 0) _log_level = LLDeveloper; else { // Don't recognize the requested level; use default @@ -134,18 +140,14 @@ void Logger::configure_logging(const std::string& client_id) _initialized = true; } -/*! -* \brief Conditionally log data if the logging level is high enough -* \param level Minimum logging level for data to be logged -* \param data Text of data to be logged -*/ +// Conditionally log data if the logging level is high enough void Logger::log_data(SRLoggingLevel level, const std::string& data) { - // If we're not initialized, configure logging as an anonymous + // If we're not initialized, configure logging as a default // client. This can happen if a caller invokes a Dataset API point // without initializing a Client object if (!_initialized) - configure_logging("anonymous"); + configure_logging("default"); // Silently ignore logging more verbose than requested if (level > _log_level) @@ -157,46 +159,43 @@ void Logger::log_data(SRLoggingLevel level, const std::string& data) auto timestamp = std::put_time(&tm, "%H-%M-%S"); // write the log data - // (There must be a cleaner way to write this!) + bool writingFile = (_logfile.length() > 0); + std::ofstream logstream; + std::ostream& log_target(writingFile ? logstream : std::cout); if (_logfile.length() > 0) { - std::ofstream logstream; logstream.open(_logfile, std::ios_base::app); - logstream << _client_id << "@" << timestamp << ":" << data - << std::endl; - } else { - std::cout << _client_id << "@" << timestamp << ":" << data - << std::endl; + if (!logstream.good()) { + // The logfile is no longer writable! + // Switch to console and emit an error + _logfile = ""; + log_error( + LLInfo, "Logfile no longer writeable. Switching to console logging"); + // Re-log this message since the current attempt has failed + log_data(level, data); + // Bail -- we're done here + return; + } } + log_target << _logger_name << "@" << timestamp << ":" << data + << std::endl; } -/*! -* \brief Conditionally log data if the logging level is high enough -* \param level Minimum logging level for data to be logged -* \param data Text of data to be logged -*/ +// Conditionally log data if the logging level is high enough void Logger::log_data(SRLoggingLevel level, const char* data) { const std::string _data(data); log_data(level, _data); } -/*! -* \brief Conditionally log data if the logging level is high enough -* \param level Minimum logging level for data to be logged -* \param data Text of data to be logged -*/ +// Conditionally log data if the logging level is high enough void Logger::log_data(SRLoggingLevel level, const std::string_view& data) { const std::string _data(data); log_data(level, _data); } -/*! -* \brief Conditionally log data if the logging level is high enough -* \param level Minimum logging level for data to be logged -* \param data Text of data to be logged -* \param data_len Length in characters of data to be logged -*/ +// Conditionally log data if the logging level is high enough +// (exception-free variant) extern "C" void log_data_noexcept( SRLoggingLevel level, const char* data, size_t data_len) { @@ -211,12 +210,8 @@ extern "C" void log_data_noexcept( } } -/*! -* \brief Conditionally log a warning if the logging level is high enough -* \param level Minimum logging level for data to be logged -* \param data Text of data to be logged -* \param data_len Length in characters of data to be logged -*/ +// Conditionally log a warning if the logging level is high enough +// (exception-free variant) extern "C" void log_warning_noexcept( SRLoggingLevel level, const char* data, size_t data_len) { @@ -231,12 +226,8 @@ extern "C" void log_warning_noexcept( } } -/*! -* \brief Conditionally log an error if the logging level is high enough -* \param level Minimum logging level for data to be logged -* \param data Text of data to be logged -* \param data_len Length in characters of data to be logged -*/ +// Conditionally log an error if the logging level is high enough +// (exception-free variant) extern "C" void log_error_noexcept( SRLoggingLevel level, const char* data, size_t data_len) { diff --git a/src/cpp/threadpool.cpp b/src/cpp/threadpool.cpp index 672ef8fc2..90a421ba0 100644 --- a/src/cpp/threadpool.cpp +++ b/src/cpp/threadpool.cpp @@ -26,7 +26,7 @@ ThreadPool::ThreadPool(unsigned int num_threads) // Create worker threads if (num_threads < 1) num_threads = 1; // Force a minimum of 1 thread for (unsigned int i = 0; i < num_threads; i++) { - log_data(LLDebug, "Kicking off thread " + std::to_string(i)); + log_data(LLDeveloper, "Kicking off thread " + std::to_string(i)); threads.push_back(std::thread(&ThreadPool::perform_jobs, this, i)); } @@ -51,7 +51,7 @@ void ThreadPool::shutdown() while (!initialization_complete) ; // Spin - log_data(LLDebug, "Shutting down thread pool"); + log_data(LLDeveloper, "Shutting down thread pool"); // We're closed for business shutting_down = true; @@ -65,12 +65,12 @@ void ThreadPool::shutdown() "Waiting for thread to terminate (" + std::to_string(i++) + " of " + std::to_string(num_threads) + ")"; - log_data(LLDebug, message); + log_data(LLDeveloper, message); thr.join(); // Blocks until the thread finishes execution } // Done - log_data(LLDebug, "Shutdown complete"); + log_data(LLDeveloper, "Shutdown complete"); shutdown_complete = true; } @@ -121,11 +121,11 @@ void ThreadPool::perform_jobs(unsigned int tid) ": " + std::to_string(get_job.count()) + " s; " + "time to execute job: " + std::to_string(execute_job.count()) + " s"; - log_data(LLDebug, message); + log_data(LLDeveloper, message); } } - log_data(LLDebug, "Thread " + std::to_string(tid) + " shutting down"); + log_data(LLDeveloper, "Thread " + std::to_string(tid) + " shutting down"); } // Submit a job to threadpool for execution diff --git a/src/fortran/client.F90 b/src/fortran/client.F90 index ebd8d42ac..62ccea93c 100644 --- a/src/fortran/client.F90 +++ b/src/fortran/client.F90 @@ -232,30 +232,30 @@ function SR_error_parser(self, response_code) result(is_error) end function SR_error_parser !> Initializes a new instance of a SmartRedis client -function initialize_client(self, cluster, client_id) +function initialize_client(self, cluster, logger_name) integer(kind=enum_kind) :: initialize_client class(client_type), intent(inout) :: self !< Receives the initialized client logical, optional, intent(in ) :: cluster !< If true, client uses a database cluster (Default: .false.) - character(len=*), optional, intent(in ) :: client_id !< Identifier for the current client + character(len=*), optional, intent(in ) :: logger_name !< Identifier for the current client ! Local variables - character(kind=c_char, len=:), allocatable :: c_client_id - integer(kind=c_size_t) :: client_id_length + character(kind=c_char, len=:), allocatable :: c_logger_name + integer(kind=c_size_t) :: logger_name_length - if (present(client_id)) then - allocate(character(kind=c_char, len=len_trim(client_id)) :: c_client_id) - c_client_id = client_id - client_id_length = len_trim(client_id) + if (present(logger_name)) then + allocate(character(kind=c_char, len=len_trim(logger_name)) :: c_logger_name) + c_logger_name = logger_name + logger_name_length = len_trim(logger_name) else - allocate(character(kind=c_char, len=10) :: c_client_id) - c_client_id = 'anonymous' - client_id_length = 10 + allocate(character(kind=c_char, len=10) :: c_logger_name) + c_logger_name = 'default' + logger_name_length = 8 endif if (present(cluster)) self%cluster = cluster - initialize_client = c_constructor(self%cluster, c_client_id, client_id_length, self%client_ptr) + initialize_client = c_constructor(self%cluster, c_logger_name, logger_name_length, self%client_ptr) self%is_initialized = initialize_client .eq. SRNoError - if (allocated(c_client_id)) deallocate(c_client_id) + if (allocated(c_logger_name)) deallocate(c_logger_name) end function initialize_client !> Check whether the client has been initialized diff --git a/src/fortran/client/client_interfaces.inc b/src/fortran/client/client_interfaces.inc index 1c4ffed3d..35318ce37 100644 --- a/src/fortran/client/client_interfaces.inc +++ b/src/fortran/client/client_interfaces.inc @@ -25,13 +25,13 @@ ! OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. interface - function c_constructor(cluster, client_id, client_id_length, new_client) bind(c, name="SmartRedisCClient") + function c_constructor(cluster, logger_name, logger_name_length, new_client) bind(c, name="SmartRedisCClient") use iso_c_binding, only : c_ptr, c_bool, c_char, c_size_t import :: enum_kind integer(kind=enum_kind) :: c_constructor logical(kind=c_bool), value :: cluster !< True if a database cluster is being used - character(kind=c_char) :: client_id(*) - integer(kind=c_size_t), value :: client_id_length + character(kind=c_char) :: logger_name(*) + integer(kind=c_size_t), value :: logger_name_length type(c_ptr) :: new_client !< Receives the newly constructed client end function c_constructor diff --git a/src/python/module/smartredis/client.py b/src/python/module/smartredis/client.py index 875bba1a1..a7b5cfd0e 100644 --- a/src/python/module/smartredis/client.py +++ b/src/python/module/smartredis/client.py @@ -39,7 +39,7 @@ from .smartredisPy import RedisReplyError as PybindRedisReplyError class Client(PyClient): - def __init__(self, address=None, cluster=False, client_id="anonymous"): + def __init__(self, address=None, cluster=False, logger_name="default"): """Initialize a RedisAI client For clusters, the address can be a single tcp/ip address and port @@ -52,8 +52,8 @@ def __init__(self, address=None, cluster=False, client_id="anonymous"): :param address: Address of the database :param cluster: True if connecting to a redis cluster, defaults to False :type cluster: bool, optional - :param client_id: Identifier for the current client - :type client_id: str + :param logger_name: Identifier for the current client + :type logger_name: str :raises RedisConnectionError: if connection initialization fails """ if address: @@ -61,7 +61,7 @@ def __init__(self, address=None, cluster=False, client_id="anonymous"): if "SSDB" not in os.environ: raise RedisConnectionError("Could not connect to database. $SSDB not set") try: - super().__init__(cluster, client_id) + super().__init__(cluster, logger_name) except PybindRedisReplyError as e: raise RedisConnectionError(str(e)) from None except RuntimeError as e: diff --git a/src/python/src/pyclient.cpp b/src/python/src/pyclient.cpp index 7f51a9ecb..fa24ca750 100644 --- a/src/python/src/pyclient.cpp +++ b/src/python/src/pyclient.cpp @@ -35,11 +35,11 @@ using namespace SmartRedis; namespace py = pybind11; -PyClient::PyClient(bool cluster, const std::string& client_id) +PyClient::PyClient(bool cluster, const std::string& logger_name) { _client = NULL; try { - _client = new Client(cluster, client_id); + _client = new Client(cluster, logger_name); } catch (Exception& e) { // exception is already prepared for caller diff --git a/tests/c/client_test_dataset_aggregation.c b/tests/c/client_test_dataset_aggregation.c index a44d62ca6..e650c6afb 100644 --- a/tests/c/client_test_dataset_aggregation.c +++ b/tests/c/client_test_dataset_aggregation.c @@ -130,12 +130,12 @@ int main(int argc, char* argv[]) char* dataset_name[] = {"agg_dataset_0", "agg_dataset_1", "agg_dataset_2", "agg_dataset_2", "agg_dataset_3"}; char* list_name = "my_aggregation"; void** datasets = NULL; - const char* client_id = "test_dataset_aggregation"; - size_t cid_len = strlen(client_id); + const char* logger_name = "test_dataset_aggregation"; + size_t cid_len = strlen(logger_name); // Initialize client void *client = NULL; - if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client) || + if (SRNoError != SmartRedisCClient(use_cluster(), logger_name, cid_len, &client) || NULL == client) { printf("Failed to initialize client!\n"); printf("Test passed: NO\n"); diff --git a/tests/c/client_test_dataset_exists.c b/tests/c/client_test_dataset_exists.c index fecf92b50..11bfba6ce 100644 --- a/tests/c/client_test_dataset_exists.c +++ b/tests/c/client_test_dataset_exists.c @@ -41,9 +41,9 @@ bool cluster = true; int missing_dataset(char *dataset_name, size_t dataset_name_len) { void *client = NULL; - const char* client_id = "missing_dataset"; - size_t cid_len = strlen(client_id); - if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) + const char* logger_name = "missing_dataset"; + size_t cid_len = strlen(logger_name); + if (SRNoError != SmartRedisCClient(use_cluster(), logger_name, cid_len, &client)) return -1; bool exists = false; @@ -69,11 +69,11 @@ int present_dataset(char *dataset_name, size_t dataset_name_len) uint16_t ***tensor = NULL; int i, j, k; bool exists = false; - const char* client_id = "present_dataset"; - size_t cid_len = strlen(client_id); + const char* logger_name = "present_dataset"; + size_t cid_len = strlen(logger_name); // Initialize client and dataset - if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client) || NULL == client) + if (SRNoError != SmartRedisCClient(use_cluster(), logger_name, cid_len, &client) || NULL == client) return -1; if (SRNoError != CDataSet(dataset_name, dataset_name_len, &dataset) || NULL == dataset) return -1; diff --git a/tests/c/client_test_logging.c b/tests/c/client_test_logging.c index c182dd2cf..79651616d 100644 --- a/tests/c/client_test_logging.c +++ b/tests/c/client_test_logging.c @@ -45,11 +45,11 @@ int main(int argc, char* argv[]) { int result = 0; void *client = NULL; - const char* client_id = "client_test_logging"; - size_t cid_len = strlen(client_id); + const char* logger_name = "client_test_logging"; + size_t cid_len = strlen(logger_name); // Initialize client - if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client) || NULL == client) + if (SRNoError != SmartRedisCClient(use_cluster(), logger_name, cid_len, &client) || NULL == client) return -1; // Log stuff diff --git a/tests/c/client_test_put_get_1D.c b/tests/c/client_test_put_get_1D.c index e8114e05f..f2b7759af 100644 --- a/tests/c/client_test_put_get_1D.c +++ b/tests/c/client_test_put_get_1D.c @@ -117,9 +117,9 @@ int put_get_1D_tensor_double(size_t* dims, size_t n_dims, char* key_suffix, size_t key_suffix_length) { void* client = NULL; - const char* client_id = "put_get_1D_tensor_double"; - size_t cid_len = strlen(client_id); - if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) + const char* logger_name = "put_get_1D_tensor_double"; + size_t cid_len = strlen(logger_name); + if (SRNoError != SmartRedisCClient(use_cluster(), logger_name, cid_len, &client)) return -1; double* tensor = (double*)malloc(dims[0]*sizeof(double)); @@ -154,9 +154,9 @@ int put_get_1D_tensor_float(size_t* dims, size_t n_dims, size_t key_suffix_length) { void* client = NULL; - const char* client_id = "put_get_1D_tensor_float"; - size_t cid_len = strlen(client_id); - if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) + const char* logger_name = "put_get_1D_tensor_float"; + size_t cid_len = strlen(logger_name); + if (SRNoError != SmartRedisCClient(use_cluster(), logger_name, cid_len, &client)) return -1; float* tensor = (float*)malloc(dims[0]*sizeof(float)); @@ -186,9 +186,9 @@ int put_get_1D_tensor_i8(size_t* dims, size_t n_dims, size_t key_suffix_length) { void* client = NULL; - const char* client_id = "put_get_1D_tensor_i8"; - size_t cid_len = strlen(client_id); - if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) + const char* logger_name = "put_get_1D_tensor_i8"; + size_t cid_len = strlen(logger_name); + if (SRNoError != SmartRedisCClient(use_cluster(), logger_name, cid_len, &client)) return -1; int8_t* tensor = (int8_t*)malloc(dims[0]*sizeof(int8_t)); @@ -226,9 +226,9 @@ int put_get_1D_tensor_i16(size_t* dims, size_t n_dims, size_t key_suffix_length) { void* client = NULL; - const char* client_id = "put_get_1D_tensor_i16"; - size_t cid_len = strlen(client_id); - if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) + const char* logger_name = "put_get_1D_tensor_i16"; + size_t cid_len = strlen(logger_name); + if (SRNoError != SmartRedisCClient(use_cluster(), logger_name, cid_len, &client)) return -1; int16_t* tensor = (int16_t*)malloc(dims[0]*sizeof(int16_t)); @@ -266,9 +266,9 @@ int put_get_1D_tensor_i32(size_t* dims, size_t n_dims, size_t key_suffix_length) { void* client = NULL; - const char* client_id = "put_get_1D_tensor_i32"; - size_t cid_len = strlen(client_id); - if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) + const char* logger_name = "put_get_1D_tensor_i32"; + size_t cid_len = strlen(logger_name); + if (SRNoError != SmartRedisCClient(use_cluster(), logger_name, cid_len, &client)) return -1; int32_t* tensor = (int32_t*)malloc(dims[0]*sizeof(int32_t)); @@ -306,9 +306,9 @@ int put_get_1D_tensor_i64(size_t* dims, size_t n_dims, size_t key_suffix_length) { void* client = NULL; - const char* client_id = "put_get_1D_tensor_i64"; - size_t cid_len = strlen(client_id); - if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) + const char* logger_name = "put_get_1D_tensor_i64"; + size_t cid_len = strlen(logger_name); + if (SRNoError != SmartRedisCClient(use_cluster(), logger_name, cid_len, &client)) return -1; int64_t* tensor = (int64_t*)malloc(dims[0]*sizeof(int64_t)); @@ -346,9 +346,9 @@ int put_get_1D_tensor_ui8(size_t* dims, size_t n_dims, size_t key_suffix_length) { void* client = NULL; - const char* client_id = "put_get_1D_tensor_ui8"; - size_t cid_len = strlen(client_id); - if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) + const char* logger_name = "put_get_1D_tensor_ui8"; + size_t cid_len = strlen(logger_name); + if (SRNoError != SmartRedisCClient(use_cluster(), logger_name, cid_len, &client)) return -1; uint8_t* tensor = (uint8_t*)malloc(dims[0]*sizeof(uint8_t)); @@ -383,9 +383,9 @@ int put_get_1D_tensor_ui16(size_t* dims, size_t n_dims, size_t key_suffix_length) { void* client = NULL; - const char* client_id = "put_get_1D_tensor_ui16"; - size_t cid_len = strlen(client_id); - if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) + const char* logger_name = "put_get_1D_tensor_ui16"; + size_t cid_len = strlen(logger_name); + if (SRNoError != SmartRedisCClient(use_cluster(), logger_name, cid_len, &client)) return -1; uint16_t* tensor = (uint16_t*)malloc(dims[0]*sizeof(uint16_t)); diff --git a/tests/c/client_test_put_get_2D.c b/tests/c/client_test_put_get_2D.c index f707e5bce..f3a752cbc 100644 --- a/tests/c/client_test_put_get_2D.c +++ b/tests/c/client_test_put_get_2D.c @@ -118,9 +118,9 @@ int put_get_2D_tensor_double(size_t* dims, int n_dims, char* key_suffix, int key_suffix_length) { void* client = NULL; - const char* client_id = "put_get_2D_tensor_double"; - size_t cid_len = strlen(client_id); - if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) + const char* logger_name = "put_get_2D_tensor_double"; + size_t cid_len = strlen(logger_name); + if (SRNoError != SmartRedisCClient(use_cluster(), logger_name, cid_len, &client)) return -1; double** tensor = (double**)malloc(dims[0]*sizeof(double*)); @@ -167,9 +167,9 @@ int put_get_2D_tensor_float(size_t* dims, int n_dims, int key_suffix_length) { void* client = NULL; - const char* client_id = "put_get_2D_tensor_float"; - size_t cid_len = strlen(client_id); - if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) + const char* logger_name = "put_get_2D_tensor_float"; + size_t cid_len = strlen(logger_name); + if (SRNoError != SmartRedisCClient(use_cluster(), logger_name, cid_len, &client)) return -1; float** tensor = (float**)malloc(dims[0]*sizeof(float*)); @@ -216,9 +216,9 @@ int put_get_2D_tensor_i8(size_t* dims, int n_dims, int key_suffix_length) { void* client = NULL; - const char* client_id = "put_get_2D_tensor_i8"; - size_t cid_len = strlen(client_id); - if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) + const char* logger_name = "put_get_2D_tensor_i8"; + size_t cid_len = strlen(logger_name); + if (SRNoError != SmartRedisCClient(use_cluster(), logger_name, cid_len, &client)) return -1; int8_t** tensor = (int8_t**)malloc(dims[0]*sizeof(int8_t*)); @@ -269,9 +269,9 @@ int put_get_2D_tensor_i16(size_t* dims, int n_dims, int key_suffix_length) { void* client = NULL; - const char* client_id = "put_get_2D_tensor_i16"; - size_t cid_len = strlen(client_id); - if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) + const char* logger_name = "put_get_2D_tensor_i16"; + size_t cid_len = strlen(logger_name); + if (SRNoError != SmartRedisCClient(use_cluster(), logger_name, cid_len, &client)) return -1; int16_t** tensor = (int16_t**)malloc(dims[0]*sizeof(int16_t*)); @@ -322,9 +322,9 @@ int put_get_2D_tensor_i32(size_t* dims, int n_dims, int key_suffix_length) { void* client = NULL; - const char* client_id = "put_get_2D_tensor_i32"; - size_t cid_len = strlen(client_id); - if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) + const char* logger_name = "put_get_2D_tensor_i32"; + size_t cid_len = strlen(logger_name); + if (SRNoError != SmartRedisCClient(use_cluster(), logger_name, cid_len, &client)) return -1; int32_t** tensor = (int32_t**)malloc(dims[0]*sizeof(int32_t*)); @@ -375,9 +375,9 @@ int put_get_2D_tensor_i64(size_t* dims, int n_dims, int key_suffix_length) { void* client = NULL; - const char* client_id = "put_get_2D_tensor_i64"; - size_t cid_len = strlen(client_id); - if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) + const char* logger_name = "put_get_2D_tensor_i64"; + size_t cid_len = strlen(logger_name); + if (SRNoError != SmartRedisCClient(use_cluster(), logger_name, cid_len, &client)) return -1; int64_t** tensor = (int64_t**)malloc(dims[0]*sizeof(int64_t*)); @@ -428,9 +428,9 @@ int put_get_2D_tensor_ui8(size_t* dims, int n_dims, int key_suffix_length) { void* client = NULL; - const char* client_id = "put_get_2D_tensor_ui8"; - size_t cid_len = strlen(client_id); - if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) + const char* logger_name = "put_get_2D_tensor_ui8"; + size_t cid_len = strlen(logger_name); + if (SRNoError != SmartRedisCClient(use_cluster(), logger_name, cid_len, &client)) return -1; uint8_t** tensor = (uint8_t**)malloc(dims[0]*sizeof(uint8_t*)); @@ -479,9 +479,9 @@ int put_get_2D_tensor_ui16(size_t* dims, int n_dims, int key_suffix_length) { void* client = NULL; - const char* client_id = "put_get_2D_tensor_ui16"; - size_t cid_len = strlen(client_id); - if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) + const char* logger_name = "put_get_2D_tensor_ui16"; + size_t cid_len = strlen(logger_name); + if (SRNoError != SmartRedisCClient(use_cluster(), logger_name, cid_len, &client)) return -1; uint16_t** tensor = (uint16_t**)malloc(dims[0]*sizeof(uint16_t*)); diff --git a/tests/c/client_test_put_get_3D.c b/tests/c/client_test_put_get_3D.c index 771b9252c..4f5e1888e 100644 --- a/tests/c/client_test_put_get_3D.c +++ b/tests/c/client_test_put_get_3D.c @@ -118,9 +118,9 @@ int put_get_3D_tensor_double(size_t* dims, size_t n_dims, char* key_suffix, size_t key_suffix_length) { void* client = NULL; - const char* client_id = "put_get_3D_tensor_double"; - size_t cid_len = strlen(client_id); - if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) + const char* logger_name = "put_get_3D_tensor_double"; + size_t cid_len = strlen(logger_name); + if (SRNoError != SmartRedisCClient(use_cluster(), logger_name, cid_len, &client)) return -1; double*** tensor = (double***)malloc(dims[0]*sizeof(double**)); @@ -177,9 +177,9 @@ int put_get_3D_tensor_float(size_t* dims, size_t n_dims, size_t key_suffix_length) { void* client = NULL; - const char* client_id = "put_get_3D_tensor_float"; - size_t cid_len = strlen(client_id); - if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) + const char* logger_name = "put_get_3D_tensor_float"; + size_t cid_len = strlen(logger_name); + if (SRNoError != SmartRedisCClient(use_cluster(), logger_name, cid_len, &client)) return -1; float*** tensor = (float***)malloc(dims[0]*sizeof(float**)); @@ -235,9 +235,9 @@ int put_get_3D_tensor_i8(size_t* dims, size_t n_dims, size_t key_suffix_length) { void* client = NULL; - const char* client_id = "put_get_3D_tensor_i8"; - size_t cid_len = strlen(client_id); - if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) + const char* logger_name = "put_get_3D_tensor_i8"; + size_t cid_len = strlen(logger_name); + if (SRNoError != SmartRedisCClient(use_cluster(), logger_name, cid_len, &client)) return -1; int8_t*** tensor = (int8_t***)malloc(dims[0]*sizeof(int8_t**)); @@ -297,9 +297,9 @@ int put_get_3D_tensor_i16(size_t* dims, size_t n_dims, size_t key_suffix_length) { void* client = NULL; - const char* client_id = "put_get_3D_tensor_i16"; - size_t cid_len = strlen(client_id); - if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) + const char* logger_name = "put_get_3D_tensor_i16"; + size_t cid_len = strlen(logger_name); + if (SRNoError != SmartRedisCClient(use_cluster(), logger_name, cid_len, &client)) return -1; int16_t*** tensor = (int16_t***)malloc(dims[0]*sizeof(int16_t**)); @@ -360,9 +360,9 @@ int put_get_3D_tensor_i32(size_t* dims, size_t n_dims, size_t key_suffix_length) { void* client = NULL; - const char* client_id = "put_get_3D_tensor_i32"; - size_t cid_len = strlen(client_id); - if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) + const char* logger_name = "put_get_3D_tensor_i32"; + size_t cid_len = strlen(logger_name); + if (SRNoError != SmartRedisCClient(use_cluster(), logger_name, cid_len, &client)) return -1; int32_t*** tensor = (int32_t***)malloc(dims[0]*sizeof(int32_t**)); @@ -423,9 +423,9 @@ int put_get_3D_tensor_i64(size_t* dims, size_t n_dims, size_t key_suffix_length) { void* client = NULL; - const char* client_id = "put_get_3D_tensor_i64"; - size_t cid_len = strlen(client_id); - if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) + const char* logger_name = "put_get_3D_tensor_i64"; + size_t cid_len = strlen(logger_name); + if (SRNoError != SmartRedisCClient(use_cluster(), logger_name, cid_len, &client)) return -1; int64_t*** tensor = (int64_t***)malloc(dims[0]*sizeof(int64_t**)); @@ -486,9 +486,9 @@ int put_get_3D_tensor_ui8(size_t* dims, size_t n_dims, size_t key_suffix_length) { void* client = NULL; - const char* client_id = "put_get_3D_tensor_ui8"; - size_t cid_len = strlen(client_id); - if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) + const char* logger_name = "put_get_3D_tensor_ui8"; + size_t cid_len = strlen(logger_name); + if (SRNoError != SmartRedisCClient(use_cluster(), logger_name, cid_len, &client)) return -1; uint8_t*** tensor = (uint8_t***)malloc(dims[0]*sizeof(uint8_t**)); @@ -549,9 +549,9 @@ int put_get_3D_tensor_ui16(size_t* dims, size_t n_dims, size_t key_suffix_length) { void* client = NULL; - const char* client_id = "put_get_3D_tensor_ui16"; - size_t cid_len = strlen(client_id); - if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) + const char* logger_name = "put_get_3D_tensor_ui16"; + size_t cid_len = strlen(logger_name); + if (SRNoError != SmartRedisCClient(use_cluster(), logger_name, cid_len, &client)) return -1; uint16_t*** tensor = (uint16_t***)malloc(dims[0]*sizeof(uint16_t**)); diff --git a/tests/c/client_test_put_unpack_1D.c b/tests/c/client_test_put_unpack_1D.c index 9ef5e75ad..2aa4ff5a9 100644 --- a/tests/c/client_test_put_unpack_1D.c +++ b/tests/c/client_test_put_unpack_1D.c @@ -47,9 +47,9 @@ int put_unpack_1D_tensor(void* tensor, size_t* dims, size_t n_dims, size_t key_suffix_length) { void* client = NULL; - const char* client_id = "put_unpack_1D_tensor"; - size_t cid_len = strlen(client_id); - if (SRNoError != SmartRedisCClient(use_cluster(), client_id, cid_len, &client)) + const char* logger_name = "put_unpack_1D_tensor"; + size_t cid_len = strlen(logger_name); + if (SRNoError != SmartRedisCClient(use_cluster(), logger_name, cid_len, &client)) return -1; char* prefix_str = "1D_tensor_test"; diff --git a/tests/cpp/unit-tests/CMakeLists.txt b/tests/cpp/unit-tests/CMakeLists.txt index cd7da6447..64b1e65fe 100644 --- a/tests/cpp/unit-tests/CMakeLists.txt +++ b/tests/cpp/unit-tests/CMakeLists.txt @@ -80,7 +80,7 @@ set(SOURCES # The unit tests to be executed set(UNIT_TESTS main.cpp - test_aggregation_list.cpp + test_aggregation_list.cpp test_client.cpp test_client_ensemble.cpp test_dataset.cpp @@ -98,7 +98,7 @@ set(UNIT_TESTS test_addressanycommand.cpp test_dbinfocommand.cpp test_clusterinfocommand.cpp - test_redisserver.cpp + test_redisserver.cpp test_logger.cpp test_ssdb.cpp ) diff --git a/tests/docker/c/test_docker.c b/tests/docker/c/test_docker.c index b29aa072f..2f4b35085 100644 --- a/tests/docker/c/test_docker.c +++ b/tests/docker/c/test_docker.c @@ -36,11 +36,11 @@ int main(int argc, char* argv[]) { void* client = NULL; - const char* client_id = "test_docker"; - size_t cid_len = strlen(client_id); + const char* logger_name = "test_docker"; + size_t cid_len = strlen(logger_name); SRError return_code = SRNoError; - return_code = SmartRedisCClient(false, client_id, cid_len, &client); + return_code = SmartRedisCClient(false, logger_name, cid_len, &client); if (return_code != SRNoError) { return -1; diff --git a/tests/python/test_address.py b/tests/python/test_address.py index deced09d3..764ef230c 100644 --- a/tests/python/test_address.py +++ b/tests/python/test_address.py @@ -35,7 +35,7 @@ def test_address(use_cluster, context): del os.environ["SSDB"] # client init should fail if SSDB not set - c = Client(address=ssdb, cluster=use_cluster, client_id=context) + c = Client(address=ssdb, cluster=use_cluster, logger_name=context) # check if SSDB was set anyway assert os.environ["SSDB"] == ssdb diff --git a/tests/python/test_dataset_aggregation.py b/tests/python/test_dataset_aggregation.py index ad7aa403b..d71ab8711 100644 --- a/tests/python/test_dataset_aggregation.py +++ b/tests/python/test_dataset_aggregation.py @@ -33,7 +33,7 @@ def test_aggregation(use_cluster, context): num_datasets = 4 - client = Client(None, use_cluster, client_id=context) + client = Client(None, use_cluster, logger_name=context) # Build datasets original_datasets = [create_dataset(f"dataset_{i}") for i in range(num_datasets)] diff --git a/tests/python/test_dataset_ops.py b/tests/python/test_dataset_ops.py index dd0676942..8abf868fb 100644 --- a/tests/python/test_dataset_ops.py +++ b/tests/python/test_dataset_ops.py @@ -36,7 +36,7 @@ def test_copy_dataset(use_cluster, context): dataset = create_dataset("test_dataset_copy") - client = Client(None, use_cluster, client_id=context) + client = Client(None, use_cluster, logger_name=context) client.put_dataset(dataset) client.copy_dataset("test_dataset_copy", "test_dataset_copied") @@ -72,7 +72,7 @@ def test_rename_dataset(use_cluster, context): dataset = create_dataset("dataset_rename") - client = Client(None, use_cluster, client_id=context) + client = Client(None, use_cluster, logger_name=context) client.put_dataset(dataset) client.rename_dataset("dataset_rename", "dataset_renamed") @@ -110,7 +110,7 @@ def test_delete_dataset(use_cluster, context): dataset = create_dataset("dataset_delete") - client = Client(None, use_cluster, client_id=context) + client = Client(None, use_cluster, logger_name=context) client.put_dataset(dataset) client.delete_dataset( @@ -125,14 +125,14 @@ def test_delete_dataset(use_cluster, context): def test_rename_nonexisting_dataset(use_cluster, context): - client = Client(None, use_cluster, client_id=context) + client = Client(None, use_cluster, logger_name=context) with pytest.raises(RedisReplyError): client.rename_dataset("not-a-tensor", "still-not-a-tensor") def test_copy_nonexistant_dataset(use_cluster, context): - client = Client(None, use_cluster, client_id=context) + client = Client(None, use_cluster, logger_name=context) with pytest.raises(RedisReplyError): client.copy_dataset("not-a-tensor", "still-not-a-tensor") @@ -141,7 +141,7 @@ def test_copy_not_dataset(use_cluster, context): def test_func(param): print(param) - client = Client(None, use_cluster, client_id=context) + client = Client(None, use_cluster, logger_name=context) client.set_function("test_func_dataset", test_func) with pytest.raises(RedisReplyError): client.copy_dataset("test_func_dataset", "test_fork_dataset") diff --git a/tests/python/test_errors.py b/tests/python/test_errors.py index c339a857e..5619b2206 100644 --- a/tests/python/test_errors.py +++ b/tests/python/test_errors.py @@ -36,7 +36,7 @@ def test_SSDB_not_set(use_cluster, context): ssdb = os.environ["SSDB"] del os.environ["SSDB"] with pytest.raises(RedisConnectionError): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) os.environ["SSDB"] = ssdb @@ -45,30 +45,30 @@ def test_bad_SSDB(use_cluster, context): del os.environ["SSDB"] os.environ["SSDB"] = "not-an-address:6379;" with pytest.raises(RedisConnectionError): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) os.environ["SSDB"] = ssdb def test_bad_get_tensor(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(RedisReplyError): c.get_tensor("not-a-key") def test_bad_get_dataset(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(RedisKeyError): c.get_dataset("not-a-key") def test_bad_script_file(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(FileNotFoundError): c.set_script_from_file("key", "not-a-file") def test_get_non_existant_script(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(RedisReplyError): script = c.get_script("not-a-script") @@ -76,7 +76,7 @@ def test_get_non_existant_script(use_cluster, context): def test_bad_function_execution(use_cluster, context): """Error raised inside function""" - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) c.set_function("bad-function", bad_function) data = np.array([1, 2, 3, 4]) c.put_tensor("bad-func-tensor", data) @@ -87,7 +87,7 @@ def test_bad_function_execution(use_cluster, context): def test_missing_script_function(use_cluster, context): """User requests to run a function not in the script""" - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) c.set_function("bad-function", bad_function) with pytest.raises(RedisReplyError): c.run_script( @@ -101,7 +101,7 @@ def test_wrong_model_name(mock_data, mock_model, use_cluster, context): data = mock_data.create_data(1) model = mock_model.create_torch_cnn() - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) c.set_model("simple_cnn", model, "TORCH", "CPU") c.put_tensor("input", data[0]) with pytest.raises(RedisReplyError): @@ -115,7 +115,7 @@ def test_wrong_model_name_from_file(mock_data, mock_model, use_cluster, context) try: data = mock_data.create_data(1) mock_model.create_torch_cnn(filepath="./torch_cnn.pt") - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) c.set_model_from_file("simple_cnn_from_file", "./torch_cnn.pt", "TORCH", "CPU") c.put_tensor("input", data[0]) with pytest.raises(RedisReplyError): @@ -125,7 +125,7 @@ def test_wrong_model_name_from_file(mock_data, mock_model, use_cluster, context) def test_bad_device(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.set_script("key", "some_script", device="not-a-gpu") @@ -133,7 +133,7 @@ def test_bad_device(use_cluster, context): # Test type errors from bad parameter types to Client API calls def test_bad_type_put_tensor(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) array = np.array([1, 2, 3, 4]) with pytest.raises(TypeError): c.put_tensor(42, array) @@ -143,26 +143,26 @@ def test_bad_type_put_tensor(use_cluster, context): def test_unsupported_type_put_tensor(use_cluster, context): """test an unsupported numpy type""" - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) data = np.array([1, 2, 3, 4]).astype(np.uint64) with pytest.raises(TypeError): c.put_tensor("key", data) def test_bad_type_get_tensor(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.get_tensor(42) def test_bad_type_delete_tensor(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.delete_tensor(42) def test_bad_type_copy_tensor(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.copy_tensor(42, "newname") with pytest.raises(TypeError): @@ -170,7 +170,7 @@ def test_bad_type_copy_tensor(use_cluster, context): def test_bad_type_rename_tensor(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.rename_tensor(42, "newname") with pytest.raises(TypeError): @@ -178,26 +178,26 @@ def test_bad_type_rename_tensor(use_cluster, context): def test_bad_type_put_dataset(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) array = np.array([1, 2, 3, 4]) with pytest.raises(TypeError): c.put_dataset(array) def test_bad_type_get_dataset(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.get_dataset(42) def test_bad_type_delete_dataset(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.delete_dataset(42) def test_bad_type_copy_dataset(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.copy_dataset(42, "dest") with pytest.raises(TypeError): @@ -205,7 +205,7 @@ def test_bad_type_copy_dataset(use_cluster, context): def test_bad_type_rename_dataset(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.rename_dataset(42, "oldkey") with pytest.raises(TypeError): @@ -213,7 +213,7 @@ def test_bad_type_rename_dataset(use_cluster, context): def test_bad_type_set_function(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.set_function(42, bad_function) with pytest.raises(TypeError): @@ -222,7 +222,7 @@ def test_bad_type_set_function(use_cluster, context): c.set_function("key", bad_function, 42) def test_bad_type_set_function_multigpu(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.set_function_multigpu(42, bad_function, 0, 1) with pytest.raises(TypeError): @@ -237,7 +237,7 @@ def test_bad_type_set_function_multigpu(use_cluster, context): c.set_function_multigpu("key", bad_function, 0, 0) # invalid num GPUs def test_bad_type_set_script(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) key = "key_for_script" script = "bad script but correct parameter type" device = "CPU" @@ -249,7 +249,7 @@ def test_bad_type_set_script(use_cluster, context): c.set_script(key, script, 42) def test_bad_type_set_script_multigpu(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) key = "key_for_script" script = "bad script but correct parameter type" first_gpu = 0 @@ -268,7 +268,7 @@ def test_bad_type_set_script_multigpu(use_cluster, context): c.set_script_multigpu(key, script, first_gpu, 0) def test_bad_type_set_script_from_file(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) key = "key_for_script" scriptfile = "bad filename but correct parameter type" device = "CPU" @@ -280,7 +280,7 @@ def test_bad_type_set_script_from_file(use_cluster, context): c.set_script_from_file(key, scriptfile, 42) def test_bad_type_set_script_from_file_multigpu(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) key = "key_for_script" scriptfile = "bad filename but correct parameter type" first_gpu = 0 @@ -295,13 +295,13 @@ def test_bad_type_set_script_from_file_multigpu(use_cluster, context): c.set_script_from_file_multigpu(key, scriptfile, first_gpu, "not an integer") def test_bad_type_get_script(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.get_script(42) def test_bad_type_run_script(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) key = "my_script" fn_name = "phred" inputs = ["list", "of", "strings"] @@ -317,7 +317,7 @@ def test_bad_type_run_script(use_cluster, context): def test_bad_type_run_script_multigpu(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) key = "my_script" fn_name = "phred" inputs = ["list", "of", "strings"] @@ -346,14 +346,14 @@ def test_bad_type_run_script_multigpu(use_cluster, context): def test_bad_type_get_model(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.get_model(42) def test_bad_type_set_model(mock_model, use_cluster, context): model = mock_model.create_torch_cnn() - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.set_model(42, model, "TORCH", "CPU") with pytest.raises(TypeError): @@ -372,9 +372,9 @@ def test_bad_type_set_model(mock_model, use_cluster, context): c.set_model("simple_cnn", model, "TORCH", "CPU", tag=42) def test_bad_type_set_model_multigpu(mock_model, use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) model = mock_model.create_torch_cnn() - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.set_model_multigpu(42, model, "TORCH", 0, 1) with pytest.raises(TypeError): @@ -399,7 +399,7 @@ def test_bad_type_set_model_multigpu(mock_model, use_cluster, context): def test_bad_type_set_model_from_file(use_cluster, context): modelfile = "bad filename but right parameter type" - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.set_model_from_file(42, modelfile, "TORCH", "CPU") with pytest.raises(TypeError): @@ -421,7 +421,7 @@ def test_bad_type_set_model_from_file(use_cluster, context): def test_bad_type_set_model_from_file_multigpu(use_cluster, context): modelfile = "bad filename but right parameter type" - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.set_model_from_file_multigpu(42, modelfile, "TORCH", 0, 1) with pytest.raises(TypeError): @@ -442,13 +442,13 @@ def test_bad_type_set_model_from_file_multigpu(use_cluster, context): c.set_model_from_file_multigpu("simple_cnn", modelfile, "TORCH", 0, 1, tag=42) def test_bad_type_run_model(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.run_model(42) def test_bad_type_run_model_multigpu(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.run_model_multigpu(42, 0, 0, 1) with pytest.raises(TypeError): @@ -463,7 +463,7 @@ def test_bad_type_run_model_multigpu(use_cluster, context): c.run_model_multigpu("simple_cnn", 0, 0, 0) def test_bad_type_delete_model_multigpu(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.delete_model_multigpu(42, 0, 1) with pytest.raises(TypeError): @@ -476,7 +476,7 @@ def test_bad_type_delete_model_multigpu(use_cluster, context): c.delete_model_multigpu("simple_cnn", 0, 0) def test_bad_type_delete_script_multigpu(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) script_name = "my_script" with pytest.raises(TypeError): c.delete_script_multigpu(42, 0, 1) @@ -490,31 +490,31 @@ def test_bad_type_delete_script_multigpu(use_cluster, context): c.delete_script_multigpu(script_name, 0, 0) def test_bad_type_tensor_exists(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.tensor_exists(42) def test_bad_type_dataset_exists(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.dataset_exists(42) def test_bad_type_model_exists(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.model_exists(42) def test_bad_type_key_exists(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.key_exists(42) def test_bad_type_poll_key(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) name = "some_key" freq = 42 num_tries = 42 @@ -528,7 +528,7 @@ def test_bad_type_poll_key(use_cluster, context): def test_bad_type_poll_tensor(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) name = "some_key" freq = 42 num_tries = 42 @@ -542,7 +542,7 @@ def test_bad_type_poll_tensor(use_cluster, context): def test_bad_type_poll_dataset(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) name = "some_key" freq = 42 num_tries = 42 @@ -556,7 +556,7 @@ def test_bad_type_poll_dataset(use_cluster, context): def test_bad_type_poll_model(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) name = "some_key" freq = 42 num_tries = 42 @@ -570,43 +570,43 @@ def test_bad_type_poll_model(use_cluster, context): def test_bad_type_set_data_source(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.set_data_source(42) def test_bad_type_use_model_ensemble_prefix(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.use_model_ensemble_prefix("not a boolean") def test_bad_type_use_list_ensemble_prefix(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.use_list_ensemble_prefix("not a boolean") def test_bad_type_use_tensor_ensemble_prefix(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.use_tensor_ensemble_prefix("not a boolean") def test_bad_type_get_db_node_info(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.get_db_node_info("not a list") def test_bad_type_get_db_cluster_info(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.get_db_cluster_info("not a list") def test_bad_type_get_ai_info(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) address = ["list", "of", "str"] key = "ai.info.key" with pytest.raises(TypeError): @@ -618,13 +618,13 @@ def test_bad_type_get_ai_info(use_cluster, context): def test_bad_type_flush_db(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.flush_db("not a list") def test_bad_type_config_get(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.config_get("timeout", 42) with pytest.raises(TypeError): @@ -632,7 +632,7 @@ def test_bad_type_config_get(use_cluster, context): def test_bad_type_config_set(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) param = "timeout" value = "never" address = "127.0.0.1:6379" @@ -645,41 +645,41 @@ def test_bad_type_config_set(use_cluster, context): def test_bad_type_save(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.save("not a list") def test_bad_type_append_to_list(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.append_to_list(42, 42) def test_bad_type_delete_list(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.delete_list(42) def test_bad_type_copy_list(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.copy_list(42, "dest") with pytest.raises(TypeError): c.copy_list("src", 42) def test_bad_type_rename_list(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.rename_list(42, "dest") with pytest.raises(TypeError): c.rename_list("src", 42) def test_bad_type_get_list_length(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.get_list_length(42) def test_bad_type_poll_list_length(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) name = "mylist" len = 42 pollfreq = 42 @@ -694,7 +694,7 @@ def test_bad_type_poll_list_length(use_cluster, context): c.poll_list_length(name, len, pollfreq, "not an integer") def test_bad_type_poll_list_length_gte(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) name = "mylist" len = 42 pollfreq = 42 @@ -709,7 +709,7 @@ def test_bad_type_poll_list_length_gte(use_cluster, context): c.poll_list_length_gte(name, len, pollfreq, "not an integer") def test_bad_type_poll_list_length_lte(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) name = "mylist" len = 42 pollfreq = 42 @@ -724,12 +724,12 @@ def test_bad_type_poll_list_length_lte(use_cluster, context): c.poll_list_length_lte(name, len, pollfreq, "not an integer") def test_bad_type_get_datasets_from_list(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): c.get_datasets_from_list(42) def test_bad_type_get_dataset_list_range(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) listname = "my_list" start_index = 0 end_index = 42 @@ -741,21 +741,21 @@ def test_bad_type_get_dataset_list_range(use_cluster, context): c.get_dataset_list_range(listname, start_index, "not an integer") def test_bad_type_log_data(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): log_data("Not a logging level", "Data to be logged") with pytest.raises(TypeError): log_data(LLInfo, 42) def test_bad_type_log_warning(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): log_warning("Not a logging level", "Data to be logged") with pytest.raises(TypeError): log_warning(LLInfo, 42) def test_bad_type_log_error(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): log_error("Not a logging level", "Data to be logged") with pytest.raises(TypeError): diff --git a/tests/python/test_logging.py b/tests/python/test_logging.py index 77918410e..973dbfdc2 100644 --- a/tests/python/test_logging.py +++ b/tests/python/test_logging.py @@ -33,7 +33,7 @@ def test_logging(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) log_data(LLQuiet, "This is data logging (LLQuiet)") log_warning(LLQuiet, "This is a warning (LLQuiet)") log_error(LLQuiet, "This is an error (LLQuiet)") diff --git a/tests/python/test_model_methods_torch.py b/tests/python/test_model_methods_torch.py index b71b521db..78445b71f 100644 --- a/tests/python/test_model_methods_torch.py +++ b/tests/python/test_model_methods_torch.py @@ -32,7 +32,7 @@ def test_set_model(mock_model, use_cluster, context): model = mock_model.create_torch_cnn() - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) c.set_model("simple_cnn", model, "TORCH", "CPU") returned_model = c.get_model("simple_cnn") assert model == returned_model @@ -41,7 +41,7 @@ def test_set_model(mock_model, use_cluster, context): def test_set_model_from_file(mock_model, use_cluster, context): try: mock_model.create_torch_cnn(filepath="./torch_cnn.pt") - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) c.set_model_from_file("file_cnn", "./torch_cnn.pt", "TORCH", "CPU") assert c.model_exists("file_cnn") returned_model = c.get_model("file_cnn") @@ -57,7 +57,7 @@ def test_set_model_from_file(mock_model, use_cluster, context): def test_torch_inference(mock_model, use_cluster, context): # get model and set into database model = mock_model.create_torch_cnn() - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) c.set_model("torch_cnn", model, "TORCH") # setup input tensor diff --git a/tests/python/test_nonkeyed_cmd.py b/tests/python/test_nonkeyed_cmd.py index 28e89bb84..76f014b6d 100644 --- a/tests/python/test_nonkeyed_cmd.py +++ b/tests/python/test_nonkeyed_cmd.py @@ -38,7 +38,7 @@ def test_dbnode_info_command(use_cluster, context): db_info_addr = [ssdb] del os.environ["SSDB"] - client = Client(address=ssdb, cluster=use_cluster, client_id=context) + client = Client(address=ssdb, cluster=use_cluster, logger_name=context) info = client.get_db_node_info(db_info_addr) @@ -51,7 +51,7 @@ def test_dbcluster_info_command(mock_model, use_cluster, context): address = [ssdb] del os.environ["SSDB"] - client = Client(address=ssdb, cluster=use_cluster, client_id=context) + client = Client(address=ssdb, cluster=use_cluster, logger_name=context) if use_cluster: info = client.get_db_cluster_info(address) @@ -67,7 +67,7 @@ def test_dbcluster_info_command(mock_model, use_cluster, context): del os.environ["SSDB"] # Init client - client = Client(address=ssdb, cluster=use_cluster, client_id=context) + client = Client(address=ssdb, cluster=use_cluster, logger_name=context) # Get a mock model model = mock_model.create_torch_cnn() @@ -98,7 +98,7 @@ def test_flushdb_command(use_cluster, context): address = [ssdb] del os.environ["SSDB"] - client = Client(address=ssdb, cluster=use_cluster, client_id=context) + client = Client(address=ssdb, cluster=use_cluster, logger_name=context) # add key to client via put_tensor tensor = np.array([1, 2]) @@ -115,7 +115,7 @@ def test_config_set_get_command(use_cluster, context): del os.environ["SSDB"] - client = Client(address=ssdb, cluster=use_cluster, client_id=context) + client = Client(address=ssdb, cluster=use_cluster, logger_name=context) value = "6000" client.config_set("lua-time-limit", value, ssdb) @@ -131,7 +131,7 @@ def test_config_set_command_DNE(use_cluster, context): del os.environ["SSDB"] - client = Client(address=ssdb, cluster=use_cluster, client_id=context) + client = Client(address=ssdb, cluster=use_cluster, logger_name=context) # The CONFIG parameter "config_param_DNE" is unsupported with pytest.raises(RedisReplyError): @@ -144,7 +144,7 @@ def test_config_get_command_DNE(use_cluster, context): del os.environ["SSDB"] - client = Client(address=ssdb, cluster=use_cluster, client_id=context) + client = Client(address=ssdb, cluster=use_cluster, logger_name=context) # CONFIG GET returns an empty dictionary if the config_param is unsupported get_reply = client.config_get("config_param_DNE", ssdb) @@ -161,7 +161,7 @@ def test_save_command(use_cluster, mock_data, context): del os.environ["SSDB"] # client init should fail if SSDB not set - client = Client(address=ssdb, cluster=use_cluster, client_id=context) + client = Client(address=ssdb, cluster=use_cluster, logger_name=context) # for each address, check that the timestamp of the last SAVE increases after calling Client::save for address in addresses: diff --git a/tests/python/test_put_get_dataset.py b/tests/python/test_put_get_dataset.py index e481c0563..9b349d655 100644 --- a/tests/python/test_put_get_dataset.py +++ b/tests/python/test_put_get_dataset.py @@ -43,7 +43,7 @@ def test_put_get_dataset(mock_data, use_cluster, context): key = f"tensor_{str(index)}" dataset.add_tensor(key, tensor) - client = Client(None, use_cluster, client_id=context) + client = Client(None, use_cluster, logger_name=context) assert not client.dataset_exists( "nonexistent-dataset" @@ -75,7 +75,7 @@ def test_augment_dataset(mock_data, use_cluster, context): dataset_name = "augment-dataset" # Initialize a client - client = Client(None, use_cluster, client_id=context) + client = Client(None, use_cluster, logger_name=context) # Create a dataset to put into the database dataset = Dataset(dataset_name) diff --git a/tests/python/test_put_get_tensor.py b/tests/python/test_put_get_tensor.py index 98146a99f..a086d20ad 100644 --- a/tests/python/test_put_get_tensor.py +++ b/tests/python/test_put_get_tensor.py @@ -34,7 +34,7 @@ def test_1D_put_get(mock_data, use_cluster, context): """Test put/get_tensor for 1D numpy arrays""" - client = Client(None, use_cluster, client_id=context) + client = Client(None, use_cluster, logger_name=context) data = mock_data.create_data(10) send_get_arrays(client, data) @@ -43,7 +43,7 @@ def test_1D_put_get(mock_data, use_cluster, context): def test_2D_put_get(mock_data, use_cluster, context): """Test put/get_tensor for 2D numpy arrays""" - client = Client(None, use_cluster, client_id=context) + client = Client(None, use_cluster, logger_name=context) data = mock_data.create_data((10, 10)) send_get_arrays(client, data) @@ -52,7 +52,7 @@ def test_2D_put_get(mock_data, use_cluster, context): def test_3D_put_get(mock_data, use_cluster, context): """Test put/get_tensor for 3D numpy arrays""" - client = Client(None, use_cluster, client_id=context) + client = Client(None, use_cluster, logger_name=context) data = mock_data.create_data((10, 10, 10)) send_get_arrays(client, data) diff --git a/tests/python/test_script_methods.py b/tests/python/test_script_methods.py index 2d09e6d38..e0c1efd72 100644 --- a/tests/python/test_script_methods.py +++ b/tests/python/test_script_methods.py @@ -35,7 +35,7 @@ def test_set_get_function(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) c.set_function("test-set-function", one_to_one) script = c.get_script("test-set-function") sent_script = inspect.getsource(one_to_one) @@ -43,7 +43,7 @@ def test_set_get_function(use_cluster, context): def test_set_get_script(use_cluster, context): - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) sent_script = read_script_from_file() c.set_script("test-set-script", sent_script) script = c.get_script("test-set-script") @@ -52,7 +52,7 @@ def test_set_get_script(use_cluster, context): def test_set_script_from_file(use_cluster, context): sent_script = read_script_from_file() - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) c.set_script_from_file( "test-script-file", osp.join(file_path, "./data_processing_script.txt") ) @@ -66,7 +66,7 @@ def test_set_script_from_file(use_cluster, context): def test_run_script(use_cluster, context): data = np.array([[1, 2, 3, 4, 5]]) - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) c.put_tensor("script-test-data", data) c.set_function("one-to-one", one_to_one) c.run_script("one-to-one", "one_to_one", ["script-test-data"], ["script-test-out"]) @@ -78,7 +78,7 @@ def test_run_script_multi(use_cluster, context): data = np.array([[1, 2, 3, 4]]) data_2 = np.array([[5, 6, 7, 8]]) - c = Client(None, use_cluster, client_id=context) + c = Client(None, use_cluster, logger_name=context) c.put_tensor("srpt-multi-out-data-1", data) c.put_tensor("srpt-multi-out-data-2", data_2) c.set_function("two-to-one", two_to_one) diff --git a/tests/python/test_tensor_ops.py b/tests/python/test_tensor_ops.py index d0befa5bb..1fb37e403 100644 --- a/tests/python/test_tensor_ops.py +++ b/tests/python/test_tensor_ops.py @@ -34,7 +34,7 @@ def test_copy_tensor(use_cluster, context): # test copying tensor - client = Client(None, use_cluster, client_id=context) + client = Client(None, use_cluster, logger_name=context) tensor = np.array([1, 2]) client.put_tensor("test_copy", tensor) @@ -49,7 +49,7 @@ def test_copy_tensor(use_cluster, context): def test_rename_tensor(use_cluster, context): # test renaming tensor - client = Client(None, use_cluster, client_id=context) + client = Client(None, use_cluster, logger_name=context) tensor = np.array([1, 2]) client.put_tensor("test_rename", tensor) @@ -64,7 +64,7 @@ def test_rename_tensor(use_cluster, context): def test_delete_tensor(use_cluster, context): # test renaming tensor - client = Client(None, use_cluster, client_id=context) + client = Client(None, use_cluster, logger_name=context) tensor = np.array([1, 2]) client.put_tensor("test_delete", tensor) @@ -78,14 +78,14 @@ def test_delete_tensor(use_cluster, context): def test_rename_nonexisting_key(use_cluster, context): - client = Client(None, use_cluster, client_id=context) + client = Client(None, use_cluster, logger_name=context) with pytest.raises(RedisReplyError): client.rename_tensor("not-a-tensor", "still-not-a-tensor") def test_copy_nonexistant_key(use_cluster, context): - client = Client(None, use_cluster, client_id=context) + client = Client(None, use_cluster, logger_name=context) with pytest.raises(RedisReplyError): client.copy_tensor("not-a-tensor", "still-not-a-tensor") @@ -94,7 +94,7 @@ def test_copy_not_tensor(use_cluster, context): def test_func(param): print(param) - client = Client(None, use_cluster, client_id=context) + client = Client(None, use_cluster, logger_name=context) client.set_function("test_func", test_func) with pytest.raises(RedisReplyError): client.copy_tensor("test_func", "test_fork") From 654ab9039c4463c64e0f723c4965b7b341d77d61 Mon Sep 17 00:00:00 2001 From: billschereriii Date: Tue, 6 Dec 2022 16:32:01 -0600 Subject: [PATCH 25/37] Clean up test case --- tests/python/test_logging.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/python/test_logging.py b/tests/python/test_logging.py index 973dbfdc2..557c1d45f 100644 --- a/tests/python/test_logging.py +++ b/tests/python/test_logging.py @@ -24,10 +24,6 @@ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -import os - -import numpy as np -import pytest from smartredis import * from smartredis.error import * From b8432ee40c3a74959bc87feff2dba443c1316cf7 Mon Sep 17 00:00:00 2001 From: billschereriii Date: Tue, 6 Dec 2022 17:58:54 -0600 Subject: [PATCH 26/37] New base class SRObject for Client, DataSet, LogContext --- CMakeLists.txt | 1 + include/client.h | 5 +- include/dataset.h | 9 ++- include/logcontext.h | 59 ++++++++++++++++ include/srobject.h | 104 ++++++++++++++++++++++++++++ src/cpp/client.cpp | 1 + src/cpp/dataset.cpp | 2 +- src/cpp/srobject.cpp | 55 +++++++++++++++ tests/cpp/unit-tests/CMakeLists.txt | 1 + 9 files changed, 228 insertions(+), 9 deletions(-) create mode 100644 include/logcontext.h create mode 100644 include/srobject.h create mode 100644 src/cpp/srobject.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 6ca86c154..cdf731b77 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,6 +89,7 @@ set(CLIENT_SRC src/cpp/threadpool.cpp src/cpp/utility.cpp src/cpp/logger.cpp + src/cpp/srobject.cpp ) include_directories(SYSTEM diff --git a/include/client.h b/include/client.h index ea2396f5a..621ca8c18 100644 --- a/include/client.h +++ b/include/client.h @@ -37,6 +37,7 @@ #include #include #include +#include "srobject.h" #include "redisserver.h" #include "rediscluster.h" #include "redis.h" @@ -54,8 +55,6 @@ namespace SmartRedis { -class Client; - /*! * \brief The database response to a command */ @@ -66,7 +65,7 @@ typedef redisReply ReplyElem; * \brief The Client class is the primary user-facing * class for executing server commands. */ -class Client +class Client : public SRObject { public: diff --git a/include/dataset.h b/include/dataset.h index ff9aa712e..db591b3c6 100644 --- a/include/dataset.h +++ b/include/dataset.h @@ -29,9 +29,10 @@ #ifndef SMARTREDIS_DATASET_H #define SMARTREDIS_DATASET_H #ifdef __cplusplus -#include "stdlib.h" +#include #include #include +#include "srobject.h" #include "tensor.h" #include "tensorpack.h" #include "metadata.h" @@ -40,9 +41,7 @@ ///@file -namespace SmartRedis{ - -class DataSet; +namespace SmartRedis { ///@file /*! @@ -56,7 +55,7 @@ class DataSet; * the DataSet name * (e.g. {dataset_name}.tensor_name). */ -class DataSet +class DataSet : public SRObject { public: diff --git a/include/logcontext.h b/include/logcontext.h new file mode 100644 index 000000000..a35658fa6 --- /dev/null +++ b/include/logcontext.h @@ -0,0 +1,59 @@ +/* + * BSD 2-Clause License + * + * Copyright (c) 2021-2022, Hewlett Packard Enterprise + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef LOG_CONTEXT_H +#define LOG_CONTEXT_H +#ifdef __cplusplus +#include +#include "srobject.h" + +///@file + +namespace SmartRedis{ + +///@file +/*! +* \brief The LogContext is a user-defined context for logging +*/ +class LogContext : public SRObject +{ + public: + + /*! + * \brief LogContext constructor + * \param logging_name The name to prefix log entries with + * when logging with this as a context + */ + LogContext(const std::string& logging_name) + : SRObject(logging_name) {} +}; + +} // namespace SmartRedis + +#endif // __cplusplus +#endif // LOG_CONTEXT_H diff --git a/include/srobject.h b/include/srobject.h new file mode 100644 index 000000000..32c0e6432 --- /dev/null +++ b/include/srobject.h @@ -0,0 +1,104 @@ +/* + * BSD 2-Clause License + * + * Copyright (c) 2021-2022, Hewlett Packard Enterprise + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SMARTREDIS_OBJECT_H +#define SMARTREDIS_OBJECT_H +#ifdef __cplusplus +#include "stdlib.h" +#include +#include +#include "tensor.h" +#include "tensorpack.h" +#include "metadata.h" +#include "sharedmemorylist.h" +#include "sr_enums.h" + +///@file + +namespace SmartRedis{ + +///@file +/*! +* \brief The SRObject is a common base class for SmartRedis +* objects that can represent a context for logging +*/ +class SRObject +{ + public: + + /*! + * \brief SRObject constructor + * \param logging_name The name to prefix log entries with + * when logging with this as a context + */ + SRObject(const std::string& logging_name); + + /*! + * \brief Conditionally log data if the logging level is high enough + * \param level Minimum logging level for data to be logged + * \param data Text of data to be logged + */ + virtual void log_data( + SRLoggingLevel level, const std::string& data); + + /*! + * \brief Conditionally log warning data if the logging level is + * high enough + * \param level Minimum logging level for data to be logged + * \param data Text of data to be logged + */ + virtual void log_warning( + SRLoggingLevel level, const std::string& data) + { + log_data(level, "WARNING: " + data); + } + + /*! + * \brief Conditionally log error data if the logging level is + * high enough + * \param level Minimum logging level for data to be logged + * \param data Text of data to be logged + */ + virtual void log_error( + SRLoggingLevel level, const std::string& data) + { + log_data(level, "ERROR: " + data); + } + + private: + + /*! + * \brief The name prefix log entries with + */ + std::string _lname; +}; + +} // namespace SmartRedis + +#endif // __cplusplus +#endif // SMARTREDIS_OBJECT_H diff --git a/src/cpp/client.cpp b/src/cpp/client.cpp index 59229b537..882528bbd 100644 --- a/src/cpp/client.cpp +++ b/src/cpp/client.cpp @@ -36,6 +36,7 @@ using namespace SmartRedis; // Constructor Client::Client(bool cluster, const std::string& logger_name) + : SRObject(logger_name) { // Set up logging Logger& logger = Logger::get_instance(); diff --git a/src/cpp/dataset.cpp b/src/cpp/dataset.cpp index 9f7b4f9ac..ac1e65b8c 100644 --- a/src/cpp/dataset.cpp +++ b/src/cpp/dataset.cpp @@ -35,7 +35,7 @@ using namespace SmartRedis; // DataSet constructor DataSet::DataSet(const std::string& name) - : _dsname(name) + : _dsname(name), SRObject(name) { // NOP } diff --git a/src/cpp/srobject.cpp b/src/cpp/srobject.cpp new file mode 100644 index 000000000..22ce3afd4 --- /dev/null +++ b/src/cpp/srobject.cpp @@ -0,0 +1,55 @@ +/* + * BSD 2-Clause License + * + * Copyright (c) 2021-2022, Hewlett Packard Enterprise + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "srobject.h" +#include "logger.h" + +using namespace SmartRedis; + +// SRObject constructor +SRObject::SRObject(const std::string& logging_name) + : _lname(logging_name) +{ + // NOP +} + + +// Conditionally log data if the logging level is high enough +void SRObject::log_data(SRLoggingLevel level, const std::string& data) +{ + Logger::get_instance().log_data(level, data); +} diff --git a/tests/cpp/unit-tests/CMakeLists.txt b/tests/cpp/unit-tests/CMakeLists.txt index 64b1e65fe..3b1ed1dfe 100644 --- a/tests/cpp/unit-tests/CMakeLists.txt +++ b/tests/cpp/unit-tests/CMakeLists.txt @@ -75,6 +75,7 @@ set(SOURCES ../../../src/cpp/threadpool.cpp ../../../src/cpp/utility.cpp ../../../src/cpp/logger.cpp + ../../../src/cpp/srobject.cpp ) # The unit tests to be executed From ad81e1f2ff35818b2342a411022ee7683075ac25 Mon Sep 17 00:00:00 2001 From: billschereriii Date: Wed, 7 Dec 2022 11:26:22 -0600 Subject: [PATCH 27/37] add virtual destructors --- include/client.h | 2 +- include/dataset.h | 5 +++++ include/logcontext.h | 6 ++++++ include/logger.h | 1 + include/srexception.h | 6 +++--- include/srobject.h | 13 +++++++------ 6 files changed, 23 insertions(+), 10 deletions(-) diff --git a/include/client.h b/include/client.h index 621ca8c18..58f43f737 100644 --- a/include/client.h +++ b/include/client.h @@ -103,7 +103,7 @@ class Client : public SRObject /*! * \brief Client destructor */ - ~Client(); + virtual ~Client(); /*! * \brief Send a DataSet object to the database diff --git a/include/dataset.h b/include/dataset.h index db591b3c6..26ce0c5b6 100644 --- a/include/dataset.h +++ b/include/dataset.h @@ -89,6 +89,11 @@ class DataSet : public SRObject */ DataSet& operator=(DataSet&& dataset) = default; + /*! + * \brief DataSet default destructor + */ + virtual ~DataSet() = default; + /*! * \brief Add a tensor to the DataSet. * \param name The name used to reference the tensor diff --git a/include/logcontext.h b/include/logcontext.h index a35658fa6..8098cc9ba 100644 --- a/include/logcontext.h +++ b/include/logcontext.h @@ -51,6 +51,12 @@ class LogContext : public SRObject */ LogContext(const std::string& logging_name) : SRObject(logging_name) {} + + /*! + * \brief LogContext default destructor + */ + virtual ~LogContext() = default; + }; } // namespace SmartRedis diff --git a/include/logger.h b/include/logger.h index 0b6deb61e..b4748aae7 100644 --- a/include/logger.h +++ b/include/logger.h @@ -35,6 +35,7 @@ #endif // __cplusplus #include #include "sr_enums.h" +#include "srobject.h" ///@file diff --git a/include/srexception.h b/include/srexception.h index 452a50018..c01e6a4a5 100644 --- a/include/srexception.h +++ b/include/srexception.h @@ -26,8 +26,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef SMARTREDIS_SRException_H -#define SMARTREDIS_SRException_H +#ifndef SMARTREDIS_SREXCEPTION_H +#define SMARTREDIS_SREXCEPTION_H #include #include @@ -472,4 +472,4 @@ class TypeException: public Exception } // namespace SmartRedis #endif // __cplusplus -#endif // SMARTREDIS_SRException_H +#endif // SMARTREDIS_SREXCEPTION_H diff --git a/include/srobject.h b/include/srobject.h index 32c0e6432..9574627d5 100644 --- a/include/srobject.h +++ b/include/srobject.h @@ -29,14 +29,10 @@ #ifndef SMARTREDIS_OBJECT_H #define SMARTREDIS_OBJECT_H #ifdef __cplusplus -#include "stdlib.h" +#include #include #include -#include "tensor.h" -#include "tensorpack.h" -#include "metadata.h" -#include "sharedmemorylist.h" -#include "sr_enums.h" +#include "logger.h" ///@file @@ -58,6 +54,11 @@ class SRObject */ SRObject(const std::string& logging_name); + /*! + * \brief SRObject default destructor + */ + virtual ~SRObject() = default; + /*! * \brief Conditionally log data if the logging level is high enough * \param level Minimum logging level for data to be logged From 0c2e09645f4d0fb52bd407679fce2b066b982429 Mon Sep 17 00:00:00 2001 From: billschereriii Date: Wed, 7 Dec 2022 12:25:49 -0600 Subject: [PATCH 28/37] Updates from MattD feedback --- conftest.py | 1 - src/cpp/logger.cpp | 3 --- tests/python/test_errors.py | 23 ++++++----------------- tests/python/test_logging.py | 22 ++++++++-------------- 4 files changed, 14 insertions(+), 35 deletions(-) diff --git a/conftest.py b/conftest.py index 637b154ba..3fed36865 100644 --- a/conftest.py +++ b/conftest.py @@ -32,7 +32,6 @@ import os import random import string -import inspect dtypes = [ np.float64, diff --git a/src/cpp/logger.cpp b/src/cpp/logger.cpp index dde0de7c9..93e3dc47b 100644 --- a/src/cpp/logger.cpp +++ b/src/cpp/logger.cpp @@ -135,9 +135,6 @@ void Logger::configure_logging(const std::string& logger_name) throw SRRuntimeException( "Unrecognized logging level: " + level); } - - // Done - _initialized = true; } // Conditionally log data if the logging level is high enough diff --git a/tests/python/test_errors.py b/tests/python/test_errors.py index 5619b2206..e4598438e 100644 --- a/tests/python/test_errors.py +++ b/tests/python/test_errors.py @@ -740,26 +740,15 @@ def test_bad_type_get_dataset_list_range(use_cluster, context): with pytest.raises(TypeError): c.get_dataset_list_range(listname, start_index, "not an integer") -def test_bad_type_log_data(use_cluster, context): +@pytest.mark.parametrize("log_fn", [ + (log_data,), (log_warning,), (log_error,) +]) +def test_bad_type_log_function(use_cluster, context, log_fn): c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): - log_data("Not a logging level", "Data to be logged") + log_fn("Not a logging level", "Data to be logged") with pytest.raises(TypeError): - log_data(LLInfo, 42) - -def test_bad_type_log_warning(use_cluster, context): - c = Client(None, use_cluster, logger_name=context) - with pytest.raises(TypeError): - log_warning("Not a logging level", "Data to be logged") - with pytest.raises(TypeError): - log_warning(LLInfo, 42) - -def test_bad_type_log_error(use_cluster, context): - c = Client(None, use_cluster, logger_name=context) - with pytest.raises(TypeError): - log_error("Not a logging level", "Data to be logged") - with pytest.raises(TypeError): - log_error(LLInfo, 42) + log_fn(LLInfo, 42) ##### # Test type errors from bad parameter types to Dataset API calls diff --git a/tests/python/test_logging.py b/tests/python/test_logging.py index 557c1d45f..29a02f076 100644 --- a/tests/python/test_logging.py +++ b/tests/python/test_logging.py @@ -26,20 +26,14 @@ from smartredis import * from smartredis.error import * +import pytest - -def test_logging(use_cluster, context): +@pytest.mark.parametrize("log_level", [ + LLQuiet, LLInfo, LLDebug, LLDeveloper +]) +def test_logging(use_cluster, context, log_level): c = Client(None, use_cluster, logger_name=context) - log_data(LLQuiet, "This is data logging (LLQuiet)") - log_warning(LLQuiet, "This is a warning (LLQuiet)") - log_error(LLQuiet, "This is an error (LLQuiet)") - log_data(LLInfo, "This is data logging (LLInfo)") - log_warning(LLInfo, "This is a warning (LLInfo)") - log_error(LLInfo, "This is an error (LLInfo)") - log_data(LLDebug, "This is data logging (LLDebug)") - log_warning(LLDebug, "This is a warning (LLDebug)") - log_error(LLDebug, "This is an error (LLDebug)") - log_data(LLDeveloper, "This is data logging (LLDeveloper)") - log_warning(LLDeveloper, "This is a warning (LLDeveloper)") - log_error(LLDeveloper, "This is an error (LLDeveloper)") + log_data(log_level, f"This is data logging ({log_level.name})") + log_warning(log_level, f"This is a warning ({log_level.name})") + log_error(log_level, f"This is an error ({log_level.name})") From c6530ca53bb66896d6282ad36ebe272b3ad34e4b Mon Sep 17 00:00:00 2001 From: billschereriii Date: Wed, 7 Dec 2022 12:43:24 -0600 Subject: [PATCH 29/37] Fix error? --- src/cpp/dataset.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cpp/dataset.cpp b/src/cpp/dataset.cpp index ac1e65b8c..1538ce6e3 100644 --- a/src/cpp/dataset.cpp +++ b/src/cpp/dataset.cpp @@ -35,7 +35,7 @@ using namespace SmartRedis; // DataSet constructor DataSet::DataSet(const std::string& name) - : _dsname(name), SRObject(name) + : SRObject(name), _dsname(name) { // NOP } From 973a8e23628be4ee23c0cc2ef9530086cc6f74b5 Mon Sep 17 00:00:00 2001 From: billschereriii Date: Thu, 8 Dec 2022 15:47:48 -0600 Subject: [PATCH 30/37] C++ tests fully working. Some python tests segfaulting --- CMakeLists.txt | 2 + include/dataset.h | 4 +- include/logger.h | 175 ++++++++++++------ include/pyclient.h | 13 +- include/pydataset.h | 17 +- include/pylogcontext.h | 88 +++++++++ include/pysrobject.h | 87 +++++++++ include/redis.h | 8 +- include/rediscluster.h | 8 +- include/redisserver.h | 11 +- include/srexception.h | 8 +- include/srobject.h | 8 +- include/threadpool.h | 11 +- src/cpp/client.cpp | 11 +- src/cpp/dataset.cpp | 10 +- src/cpp/logger.cpp | 88 +++++---- src/cpp/redis.cpp | 7 +- src/cpp/rediscluster.cpp | 7 +- src/cpp/redisserver.cpp | 7 +- src/cpp/srobject.cpp | 4 +- src/cpp/threadpool.cpp | 33 +++- src/cpp/utility.cpp | 14 +- src/python/bindings/bind.cpp | 28 ++- src/python/module/smartredis/logger.py | 21 ++- src/python/src/pyclient.cpp | 1 + src/python/src/pydataset.cpp | 10 + src/python/src/pylogcontext.cpp | 76 ++++++++ src/python/src/pysrobject.cpp | 76 ++++++++ tests/cpp/client_test_utils.h | 2 +- .../cpp/unit-tests/test_addressanycommand.cpp | 9 +- .../cpp/unit-tests/test_addressatcommand.cpp | 15 +- .../cpp/unit-tests/test_aggregation_list.cpp | 6 +- tests/cpp/unit-tests/test_client.cpp | 48 ++++- tests/cpp/unit-tests/test_client_ensemble.cpp | 14 +- .../unit-tests/test_clusterinfocommand.cpp | 6 +- tests/cpp/unit-tests/test_commandlist.cpp | 10 +- tests/cpp/unit-tests/test_commandreply.cpp | 46 +++-- tests/cpp/unit-tests/test_compoundcommand.cpp | 6 +- tests/cpp/unit-tests/test_dataset.cpp | 6 +- tests/cpp/unit-tests/test_dbinfocommand.cpp | 6 +- tests/cpp/unit-tests/test_dbnode.cpp | 6 +- tests/cpp/unit-tests/test_logger.cpp | 12 +- tests/cpp/unit-tests/test_metadata.cpp | 6 +- tests/cpp/unit-tests/test_multikeycommand.cpp | 6 +- tests/cpp/unit-tests/test_redisserver.cpp | 25 +-- .../cpp/unit-tests/test_singlekeycommand.cpp | 11 +- tests/cpp/unit-tests/test_ssdb.cpp | 8 +- tests/cpp/unit-tests/test_stringfield.cpp | 6 +- tests/cpp/unit-tests/test_tensor.cpp | 6 +- tests/cpp/unit-tests/test_tensorbase.cpp | 6 +- tests/python/test_dataset_aggregation.py | 16 +- tests/python/test_errors.py | 6 +- tests/python/test_logging.py | 6 +- 53 files changed, 844 insertions(+), 283 deletions(-) create mode 100644 include/pylogcontext.h create mode 100644 include/pysrobject.h create mode 100644 src/python/src/pylogcontext.cpp create mode 100644 src/python/src/pysrobject.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index cdf731b77..40a9e331f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -141,6 +141,8 @@ if(BUILD_PYTHON) add_library(smartredis_static STATIC ${CLIENT_SRC}) pybind11_add_module(smartredisPy + src/python/src/pysrobject.cpp + src/python/src/pylogcontext.cpp src/python/src/pyclient.cpp src/python/src/pydataset.cpp ${CLIENT_SRC} diff --git a/include/dataset.h b/include/dataset.h index 26ce0c5b6..948359056 100644 --- a/include/dataset.h +++ b/include/dataset.h @@ -90,9 +90,9 @@ class DataSet : public SRObject DataSet& operator=(DataSet&& dataset) = default; /*! - * \brief DataSet default destructor + * \brief DataSet destructor */ - virtual ~DataSet() = default; + virtual ~DataSet(); /*! * \brief Add a tensor to the DataSet. diff --git a/include/logger.h b/include/logger.h index b4748aae7..f9f3a5c42 100644 --- a/include/logger.h +++ b/include/logger.h @@ -51,39 +51,18 @@ #ifdef __cplusplus namespace SmartRedis { +class SRObject; + /*! * \brief The Logger class implements a logging facility for SmartRedis */ class Logger { - public: - - /*! - * \brief Retrieve the unique Logger instance - * \returns The actual logger instance - */ - static Logger& get_instance() - { - static Logger __instance; // instantiated on first acccess - return __instance; - } - - /*! - * \brief Set up logging for the current client - * \param logger_name ID to use for the current client - */ - void configure_logging(const std::string& logger_name); - - /*! - * \brief Rename the current client - * \param new_name new ID to use for the current client - */ - void rename_client(const std::string& new_name); - private: /*! - * \brief Logger constructor + * \brief Logger constructor. Do not use! To obtain the reference + * to the singleton Logger, use the get_instance() method */ Logger() { _initialized = false; } @@ -113,46 +92,59 @@ class Logger { public: /*! - * \brief Conditionally log data if the logging level is high enough - * \param level Minimum logging level for data to be logged - * \param data Text of data to be logged + * \brief Retrieve the unique Logger instance + * \returns The actual logger instance */ - void log_data(SRLoggingLevel level, const char* data); + static Logger& get_instance() + { + static Logger __instance; // instantiated on first acccess + return __instance; + } /*! - * \brief Conditionally log data if the logging level is high enough - * \param level Minimum logging level for data to be logged - * \param data Text of data to be logged + * \brief Set up logging for the current client */ - void log_data(SRLoggingLevel level, const std::string& data); + void configure_logging(); /*! * \brief Conditionally log data if the logging level is high enough + * \param context Logging context (string to prefix the log entry with) * \param level Minimum logging level for data to be logged * \param data Text of data to be logged */ - void log_data(SRLoggingLevel level, const std::string_view& data); + void log_data( + const std::string& context, + SRLoggingLevel level, + const std::string& data); /*! * \brief Conditionally log warning data if the logging level is * high enough + * \param context Logging context (string to prefix the log entry with) * \param level Minimum logging level for data to be logged * \param data Text of data to be logged */ - void log_warning(SRLoggingLevel level, const std::string& data) + void log_warning( + const std::string& context, + SRLoggingLevel level, + const std::string& data) { - log_data(level, "WARNING: " + data); + log_data(context, level, "WARNING: " + data); } /*! * \brief Conditionally log error data if the logging level is * high enough + * \param context Logging context (string to prefix the log entry with) * \param level Minimum logging level for data to be logged * \param data Text of data to be logged */ - void log_error(SRLoggingLevel level, const std::string& data) + void log_error( + const std::string& context, + SRLoggingLevel level, + const std::string& data) { - log_data(level, "ERROR: " + data); + log_data(context, level, "ERROR: " + data); } private: @@ -162,11 +154,6 @@ class Logger { */ bool _initialized; - /*! - * \brief The client ID for this client - */ - std::string _logger_name; - /*! * \brief The file to which to write log data */ @@ -180,32 +167,86 @@ class Logger { /*! * \brief Conditionally log data if the logging level is high enough +* \param context Logging context (string to prefix the log entry with) +* \param level Minimum logging level for data to be logged +* \param data Text of data to be logged +*/ +inline void log_data( + const std::string& context, + SRLoggingLevel level, + const std::string& data) +{ + Logger::get_instance().log_data(context, level, data); +} + +/*! +* \brief Conditionally log data if the logging level is high enough +* \param context Object containing the log context +* \param level Minimum logging level for data to be logged +* \param data Text of data to be logged +*/ +inline void log_data( + const SRObject* context, + SRLoggingLevel level, + const std::string& data) +{ + context->log_data(level, data); +} + +/*! +* \brief Conditionally log a warning if the logging level is high enough +* \param context Logging context (string to prefix the log entry with) * \param level Minimum logging level for data to be logged * \param data Text of data to be logged */ -inline void log_data(SRLoggingLevel level, const std::string& data) +inline void log_warning( + const std::string& context, + SRLoggingLevel level, + const std::string& data) { - Logger::get_instance().log_data(level, data); + Logger::get_instance().log_warning(context, level, data); } /*! * \brief Conditionally log a warning if the logging level is high enough +* \param context Object containing the log context +* \param level Minimum logging level for data to be logged +* \param data Text of data to be logged +*/ +inline void log_warning( + const SRObject* context, + SRLoggingLevel level, + const std::string& data) +{ + context->log_warning(level, data); +} + +/*! +* \brief Conditionally log an error if the logging level is high enough +* \param context Logging context (string to prefix the log entry with) * \param level Minimum logging level for data to be logged * \param data Text of data to be logged */ -inline void log_warning(SRLoggingLevel level, const std::string& data) +inline void log_error( + const std::string& context, + SRLoggingLevel level, + const std::string& data) { - Logger::get_instance().log_warning(level, data); + Logger::get_instance().log_error(context, level, data); } /*! * \brief Conditionally log an error if the logging level is high enough +* \param context Object containing the log context * \param level Minimum logging level for data to be logged * \param data Text of data to be logged */ -inline void log_error(SRLoggingLevel level, const std::string& data) +inline void log_error( + const SRObject* context, + SRLoggingLevel level, + const std::string& data) { - Logger::get_instance().log_error(level, data); + context->log_error(level, data); } @@ -223,10 +264,11 @@ class FunctionLogger { * \brief Logger constructor * \param function_name The name of the function to track */ - FunctionLogger(const char* function_name) - : _name(function_name) + FunctionLogger(const SRObject* context, const char* function_name) + : _name(function_name), _context(context) { - log_data(LLDebug, "API Function " + _name + " called"); + _context->log_data( + LLDebug, "API Function " + _name + " called"); } /*! @@ -234,19 +276,26 @@ class FunctionLogger { */ ~FunctionLogger() { - log_data(LLDebug, "API Function " + _name + " exited"); + _context->log_data( + LLDebug, "API Function " + _name + " exited"); } private: /*! * \brief The name of the current function */ std::string _name; + + /*! + * \brief The logging context (enclosing object for the API function) + */ + const SRObject* _context; }; /*! * \brief Instantiate a FunctionLogger for the enclosing API function */ -#define LOG_API_FUNCTION() FunctionLogger ___function_logger___(__func__) +#define LOG_API_FUNCTION() \ + FunctionLogger ___function_logger___(this, __func__) } //namespace SmartRedis @@ -267,29 +316,41 @@ class FunctionLogger { /*! * \brief Conditionally log data if the logging level is high enough +* \param context Object containing the log context * \param level Minimum logging level for data to be logged * \param data Text of data to be logged * \param data_len Length in characters of data to be logged */ C_API void log_data_noexcept( - SRLoggingLevel level, const char* data, size_t data_len); + const void* context, + SRLoggingLevel level, + const char* data, + size_t data_len); /*! * \brief Conditionally log a warning if the logging level is high enough +* \param context Object containing the log context * \param level Minimum logging level for data to be logged * \param data Text of data to be logged * \param data_len Length in characters of data to be logged */ C_API void log_warning_noexcept( - SRLoggingLevel level, const char* data, size_t data_len); + const void* context, + SRLoggingLevel level, + const char* data, + size_t data_len); /*! * \brief Conditionally log an error if the logging level is high enough +* \param context Object containing the log context * \param level Minimum logging level for data to be logged * \param data Text of data to be logged * \param data_len Length in characters of data to be logged */ C_API void log_error_noexcept( - SRLoggingLevel level, const char* data, size_t data_len); + const void* context, + SRLoggingLevel level, + const char* data, + size_t data_len); #endif //SMARTREDIS_LOGGER_H diff --git a/include/pyclient.h b/include/pyclient.h index 853206ffc..a7d33ea74 100644 --- a/include/pyclient.h +++ b/include/pyclient.h @@ -26,11 +26,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#ifndef PY_CLIENT_H #define PY_CLIENT_H -#ifdef __cplusplus -#include "client.h" -#include "pydataset.h" #include #include #include @@ -38,6 +36,9 @@ #include #include #include +#include "client.h" +#include "pydataset.h" +#include "pysrobject.h" ///@file @@ -45,14 +46,12 @@ namespace SmartRedis { namespace py = pybind11; -class PyClient; - /*! * \brief The PyClient class is a wrapper around the C++ client that is needed for the Python client. */ -class PyClient +class PyClient : public PySRObject { public: @@ -69,7 +68,7 @@ class PyClient /*! * \brief PyClient destructor */ - ~PyClient(); + virtual ~PyClient(); /*! * \brief Put a tensor into the database diff --git a/include/pydataset.h b/include/pydataset.h index 233b9d0fb..8afc4ec16 100644 --- a/include/pydataset.h +++ b/include/pydataset.h @@ -26,25 +26,26 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "dataset.h" +#ifndef PYDATASET_H +#define PYDATASET_H + #include #include #include #include - +#include "dataset.h" +#include "pysrobject.h" ///@file namespace py = pybind11; namespace SmartRedis { -class PyDataset; - /*! * \brief The PyDataset class is a wrapper around the C++ dataset abstraction class. */ -class PyDataset +class PyDataset : public PySRObject { public: @@ -68,7 +69,7 @@ class PyDataset /*! * \brief PyDataset destructor */ - ~PyDataset(); + virtual ~PyDataset(); /*! * \brief Add a tensor to the PyDataset @@ -147,4 +148,6 @@ class PyDataset DataSet* _dataset; }; -} //namespace SmartRedis \ No newline at end of file +} //namespace SmartRedis + +#endif // PYDATASET_H diff --git a/include/pylogcontext.h b/include/pylogcontext.h new file mode 100644 index 000000000..f9d9d5c54 --- /dev/null +++ b/include/pylogcontext.h @@ -0,0 +1,88 @@ +/* + * BSD 2-Clause License + * + * Copyright (c) 2021-2022, Hewlett Packard Enterprise + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PYLOGCONTEXT_H +#define PYLOGCONTEXT_H + +#include +#include +#include +#include "logcontext.h" +#include "pysrobject.h" + +///@file + +namespace py = pybind11; + +namespace SmartRedis { + +/*! +* \brief The PyLogContext class is a wrapper around the + C++ LogContext class. +*/ +class PyLogContext : public PySRObject +{ + public: + + /*! + * \brief PyLogContext constructor + * \param context The context to use for log messages + */ + PyLogContext(const std::string& context); + + /*! + * \brief PyLogContext constructor from a + * SmartRedis::LogContext object + * \param logcontext A SmartRedis::LogContext pointer to + * a SmartRedis::LogContext allocated on + * the heap. The SmartRedis::LogContext + * will be deleted upton PyLogContext + * deletion. + */ + PyLogContext(LogContext* logcontext); + + /*! + * \brief PyLogContext destructor + */ + virtual ~PyLogContext(); + + /*! + * \brief Retrieve a pointer to the underlying + * SmartRedis::LogContext object + * \returns LogContext pointer within PyLogContext + */ + LogContext* get(); + + private: + + LogContext* _logcontext; +}; + +} //namespace SmartRedis + +#endif // PYLOGCONTEXT_H diff --git a/include/pysrobject.h b/include/pysrobject.h new file mode 100644 index 000000000..82cb02b7b --- /dev/null +++ b/include/pysrobject.h @@ -0,0 +1,87 @@ +/* + * BSD 2-Clause License + * + * Copyright (c) 2021-2022, Hewlett Packard Enterprise + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PYSROBJECT_H +#define PYSROBJECT_H + +#include "srobject.h" +#include +#include +#include + +///@file + +namespace py = pybind11; + +namespace SmartRedis { + +/*! +* \brief The PySRObject class is a wrapper around the + C++ SRObject class. +*/ +class PySRObject +{ + public: + + /*! + * \brief PySRObject constructor + * \param context The context to use for log messages + */ + PySRObject(const std::string& context); + + /*! + * \brief PySRObject constructor from a + * SmartRedis::SRObject object + * \param logcontext A SmartRedis::SRObject pointer to + * a SmartRedis::SRObject allocated on + * the heap. The SmartRedis::SRObject + * will be deleted upton PySRObject + * deletion. + */ + PySRObject(SRObject* srobject); + + /*! + * \brief PySRObject destructor + */ + ~PySRObject(); + + /*! + * \brief Retrieve a pointer to the underlying + * SmartRedis::SRObject object + * \returns SRObject pointer within PySRObject + */ + SRObject* get(); + + private: + + SRObject* _srobject; +}; + +} //namespace SmartRedis + +#endif // PYSROBJECT_H diff --git a/include/redis.h b/include/redis.h index 0bccda933..7a99491b8 100644 --- a/include/redis.h +++ b/include/redis.h @@ -33,6 +33,8 @@ namespace SmartRedis { +class Client; + ///@file /*! @@ -44,16 +46,18 @@ class Redis : public RedisServer public: /*! * \brief Redis constructor. + * \param client The owning Client */ - Redis(); + Redis(const Client* client); /*! * \brief Redis constructor. * Uses address provided to constructor instead * of environment variables. + * \param client The owning Client * \param addr_spec The TCP or UDS server address */ - Redis(std::string addr_spec); + Redis(const Client* client, std::string addr_spec); /*! * \brief Redis copy constructor is not allowed diff --git a/include/rediscluster.h b/include/rediscluster.h index bf80809d0..b443ef0fc 100644 --- a/include/rediscluster.h +++ b/include/rediscluster.h @@ -43,7 +43,7 @@ namespace SmartRedis { ///@file -class RedisCluster; +class Client; /*! * \brief The RedisCluster class executes RedisServer @@ -55,16 +55,18 @@ class RedisCluster : public RedisServer /*! * \brief RedisCluster constructor. + * \param client The owning Client */ - RedisCluster(); + RedisCluster(const Client* client); /*! * \brief RedisCluster constructor. * Uses address provided to constructor instead * of environment variables. + * \param client The owning Client * \param address_spec The TCP or UDS address of the server */ - RedisCluster(std::string address_spec); + RedisCluster(const Client* client, std::string address_spec); /*! * \brief RedisCluster copy constructor is not allowed diff --git a/include/redisserver.h b/include/redisserver.h index c1061f115..f1eeb51b5 100644 --- a/include/redisserver.h +++ b/include/redisserver.h @@ -60,8 +60,7 @@ namespace SmartRedis { -class RedisServer; - +class Client; /*! * \brief Abstract class that defines interface for @@ -73,8 +72,9 @@ class RedisServer { /*! * \brief Default constructor + * \param client The owning Client */ - RedisServer(); + RedisServer(const Client* client); /*! * \brief Destructor @@ -562,6 +562,11 @@ class RedisServer { */ static constexpr int _DEFAULT_THREAD_COUNT = 4; + /*! + * \brief The owning Client + */ + const Client* _client; + /*! * \brief Seeding for the random number engine */ diff --git a/include/srexception.h b/include/srexception.h index c01e6a4a5..d44ee51c6 100644 --- a/include/srexception.h +++ b/include/srexception.h @@ -116,7 +116,9 @@ class Exception: public std::exception _loc(std::string("\"") + file + std::string("\", line ") + std::to_string(line)) { SRSetLastError(*this); - log_error(LLInfo, exception_class() + " at " + _loc + ": " + _msg); + log_error( + "SmartRedis Library", LLInfo, + exception_class() + " at " + _loc + ": " + _msg); } /*! @@ -130,7 +132,9 @@ class Exception: public std::exception _loc(std::string("\"") + file + std::string("\", line ") + std::to_string(line)) { SRSetLastError(*this); - log_error(LLInfo, exception_class() + " at " + _loc + ": " + _msg); + log_error( + "SmartRedis Library", LLInfo, + exception_class() + " at " + _loc + ": " + _msg); } /*! diff --git a/include/srobject.h b/include/srobject.h index 9574627d5..48287567e 100644 --- a/include/srobject.h +++ b/include/srobject.h @@ -32,7 +32,7 @@ #include #include #include -#include "logger.h" +#include "sr_enums.h" ///@file @@ -65,7 +65,7 @@ class SRObject * \param data Text of data to be logged */ virtual void log_data( - SRLoggingLevel level, const std::string& data); + SRLoggingLevel level, const std::string& data) const; /*! * \brief Conditionally log warning data if the logging level is @@ -74,7 +74,7 @@ class SRObject * \param data Text of data to be logged */ virtual void log_warning( - SRLoggingLevel level, const std::string& data) + SRLoggingLevel level, const std::string& data) const { log_data(level, "WARNING: " + data); } @@ -86,7 +86,7 @@ class SRObject * \param data Text of data to be logged */ virtual void log_error( - SRLoggingLevel level, const std::string& data) + SRLoggingLevel level, const std::string& data) const { log_data(level, "ERROR: " + data); } diff --git a/include/threadpool.h b/include/threadpool.h index 758490281..8dbd978c5 100644 --- a/include/threadpool.h +++ b/include/threadpool.h @@ -8,8 +8,11 @@ #include #ifndef SMARTREDIS_THREADPOOL_H +#define SMARTREDIS_THREADPOOL_H namespace SmartRedis { +class Client; + /*! * \brief A thread pool for concurrent execution of parallel jobs */ @@ -18,10 +21,11 @@ class ThreadPool public: /*! * \brief ThreadPool constructor + * \param client The owning client * \param num_threads The number of threads to create in the pool, * or 0 to use one thread per hardware context */ - ThreadPool(unsigned int num_threads=0); + ThreadPool(const Client* client, unsigned int num_threads=0); /*! * \brief ThreadPool destructor @@ -80,6 +84,11 @@ class ThreadPool * \brief Flag for if the thread pool shut down has completed. */ volatile bool shutdown_complete; + + /*! + * \brief Owning client object + */ + const Client* _client; }; } // namespace SmartRedis diff --git a/src/cpp/client.cpp b/src/cpp/client.cpp index 882528bbd..1795dcdca 100644 --- a/src/cpp/client.cpp +++ b/src/cpp/client.cpp @@ -38,16 +38,14 @@ using namespace SmartRedis; Client::Client(bool cluster, const std::string& logger_name) : SRObject(logger_name) { - // Set up logging - Logger& logger = Logger::get_instance(); - logger.configure_logging(logger_name); - logger.log_data(LLDebug, "New client created"); + // Log that a new client has been instantiated + log_data(LLDebug, "New client created"); // Set up Redis server connection // A std::bad_alloc exception on the initializer will be caught // by the call to new for the client - _redis_cluster = (cluster ? new RedisCluster() : NULL); - _redis = (cluster ? NULL : new Redis()); + _redis_cluster = (cluster ? new RedisCluster(this) : NULL); + _redis = (cluster ? NULL : new Redis(this)); if (cluster) _redis_server = _redis_cluster; else @@ -75,6 +73,7 @@ Client::~Client() } _redis_server = NULL; + // Log Client destruction log_data(LLDebug, "Client destroyed"); } diff --git a/src/cpp/dataset.cpp b/src/cpp/dataset.cpp index 1538ce6e3..270037010 100644 --- a/src/cpp/dataset.cpp +++ b/src/cpp/dataset.cpp @@ -37,7 +37,15 @@ using namespace SmartRedis; DataSet::DataSet(const std::string& name) : SRObject(name), _dsname(name) { - // NOP + // Log that a new DataSet has been instantiated + log_data(LLDebug, "New DataSet created"); +} + +// DataSet Destructor +DataSet::~DataSet() +{ + // Log DataSet destruction + log_data(LLDebug, "DataSet destroyed"); } // Add a tensor to the DataSet. diff --git a/src/cpp/logger.cpp b/src/cpp/logger.cpp index 93e3dc47b..de6f7d9be 100644 --- a/src/cpp/logger.cpp +++ b/src/cpp/logger.cpp @@ -38,6 +38,8 @@ #include "utility.h" #include "logger.h" #include "srexception.h" +#include "srassert.h" +#include "srobject.h" using namespace SmartRedis; @@ -50,23 +52,10 @@ void str_to_lower(std::string& str) ); } -// Rename the current client -void Logger::rename_client(const std::string& new_name) -{ - _logger_name = new_name; -} - - // Set up logging for the current client -void Logger::configure_logging(const std::string& logger_name) +void Logger::configure_logging() { - // If we're already initialized, they can set up a client ID - // Useful if they call a Dataset API point before setting up - // a Client object - _logger_name = logger_name; - if (_initialized) { - return; - } + // Mark ourselves as initialized now _initialized = true; // Get the logfile @@ -112,18 +101,22 @@ void Logger::configure_logging(const std::string& logger_name) } // Now that everything is configured, issue warning and - // error messages + // error messages. By deferring them, we may be able to + // issue them to the customer-requested logfile instead + // of to console, depending on what went wrong if (missingLogFile) { log_warning( + "SmartRedis Library", LLInfo, - "Environment variable SS_LOG_FILE is not set. " + "Environment variable SR_LOG_FILE is not set. " "Defaulting to stdout" ); } if (missingLogLevel) { log_warning( + "SmartRedis Library", LLInfo, - "Environment variable SS_LOG_LEVEL is not set. " + "Environment variable SR_LOG_LEVEL is not set. " "Defaulting to INFO" ); } @@ -138,13 +131,16 @@ void Logger::configure_logging(const std::string& logger_name) } // Conditionally log data if the logging level is high enough -void Logger::log_data(SRLoggingLevel level, const std::string& data) +void Logger::log_data( + const std::string& context, + SRLoggingLevel level, + const std::string& data) { // If we're not initialized, configure logging as a default // client. This can happen if a caller invokes a Dataset API point // without initializing a Client object if (!_initialized) - configure_logging("default"); + configure_logging(); // Silently ignore logging more verbose than requested if (level > _log_level) @@ -166,40 +162,32 @@ void Logger::log_data(SRLoggingLevel level, const std::string& data) // Switch to console and emit an error _logfile = ""; log_error( - LLInfo, "Logfile no longer writeable. Switching to console logging"); + "SmartRedis Library", + LLInfo, + "Logfile no longer writeable. Switching to console logging"); // Re-log this message since the current attempt has failed - log_data(level, data); + log_data(context, level, data); // Bail -- we're done here return; } } - log_target << _logger_name << "@" << timestamp << ":" << data + log_target << context << "@" << timestamp << ":" << data << std::endl; } -// Conditionally log data if the logging level is high enough -void Logger::log_data(SRLoggingLevel level, const char* data) -{ - const std::string _data(data); - log_data(level, _data); -} - -// Conditionally log data if the logging level is high enough -void Logger::log_data(SRLoggingLevel level, const std::string_view& data) -{ - const std::string _data(data); - log_data(level, _data); -} - // Conditionally log data if the logging level is high enough // (exception-free variant) extern "C" void log_data_noexcept( - SRLoggingLevel level, const char* data, size_t data_len) + const void* context, + SRLoggingLevel level, + const char* data, + size_t data_len) { - auto &logger = Logger::get_instance(); try { + SR_CHECK_PARAMS(context != NULL); + const SRObject* ctxt = reinterpret_cast(context); std::string strData(data, data_len); - logger.log_data(level, strData); + ctxt->log_data(level, strData); } catch (Exception& e) { std::cout << "Logging failure: " << e.where() @@ -210,12 +198,16 @@ extern "C" void log_data_noexcept( // Conditionally log a warning if the logging level is high enough // (exception-free variant) extern "C" void log_warning_noexcept( - SRLoggingLevel level, const char* data, size_t data_len) + const void* context, + SRLoggingLevel level, + const char* data, + size_t data_len) { - auto &logger = Logger::get_instance(); try { + SR_CHECK_PARAMS(context != NULL); + const SRObject* ctxt = reinterpret_cast(context); std::string strData(data, data_len); - logger.log_warning(level, strData); + ctxt->log_warning(level, strData); } catch (Exception& e) { std::cout << "Logging failure: " << e.where() @@ -226,12 +218,16 @@ extern "C" void log_warning_noexcept( // Conditionally log an error if the logging level is high enough // (exception-free variant) extern "C" void log_error_noexcept( - SRLoggingLevel level, const char* data, size_t data_len) + const void* context, + SRLoggingLevel level, + const char* data, + size_t data_len) { - auto &logger = Logger::get_instance(); try { + SR_CHECK_PARAMS(context != NULL); + const SRObject* ctxt = reinterpret_cast(context); std::string strData(data, data_len); - logger.log_error(level, strData); + ctxt->log_error(level, strData); } catch (Exception& e) { std::cout << "Logging failure: " << e.where() diff --git a/src/cpp/redis.cpp b/src/cpp/redis.cpp index fc7e3a685..922abda58 100644 --- a/src/cpp/redis.cpp +++ b/src/cpp/redis.cpp @@ -29,11 +29,13 @@ #include "redis.h" #include "srexception.h" #include "utility.h" +#include "client.h" using namespace SmartRedis; // Redis constructor. -Redis::Redis() : RedisServer() +Redis::Redis(const Client* client) + : RedisServer(client) { SRAddress db_address(_get_ssdb()); // Remember whether it's a unix domain socket for later @@ -43,7 +45,8 @@ Redis::Redis() : RedisServer() } // Redis constructor. Uses address provided to constructor instead of environment variables -Redis::Redis(std::string addr_spec) : RedisServer() +Redis::Redis(const Client* client, std::string addr_spec) + : RedisServer(client) { SRAddress db_address(addr_spec); _add_to_address_map(db_address); diff --git a/src/cpp/rediscluster.cpp b/src/cpp/rediscluster.cpp index 5f6daa9cd..c66232106 100644 --- a/src/cpp/rediscluster.cpp +++ b/src/cpp/rediscluster.cpp @@ -31,11 +31,13 @@ #include "keyedcommand.h" #include "srexception.h" #include "utility.h" +#include "client.h" using namespace SmartRedis; // RedisCluster constructor -RedisCluster::RedisCluster() : RedisServer() +RedisCluster::RedisCluster(const Client* client) + : RedisServer(client) { SRAddress db_address(_get_ssdb()); if (!db_address._is_tcp) { @@ -53,7 +55,8 @@ RedisCluster::RedisCluster() : RedisServer() // RedisCluster constructor. Uses address provided to constructor instead of // environment variables -RedisCluster::RedisCluster(std::string address_spec) : RedisServer() +RedisCluster::RedisCluster(const Client* client, std::string address_spec) + : RedisServer(client) { SRAddress db_address(address_spec); _connect(db_address); diff --git a/src/cpp/redisserver.cpp b/src/cpp/redisserver.cpp index 2be130958..b0f61ae5f 100644 --- a/src/cpp/redisserver.cpp +++ b/src/cpp/redisserver.cpp @@ -30,12 +30,13 @@ #include "redisserver.h" #include "srexception.h" #include "utility.h" +#include "client.h" using namespace SmartRedis; // RedisServer constructor -RedisServer::RedisServer() - : _gen(_rd()) +RedisServer::RedisServer(const Client* client) + : _client(client), _gen(_rd()) { get_config_integer(_connection_timeout, _CONN_TIMEOUT_ENV_VAR, _DEFAULT_CONN_TIMEOUT); @@ -56,7 +57,7 @@ RedisServer::RedisServer() _command_attempts = (_command_timeout * 1000) / _command_interval + 1; - _tp = new ThreadPool(_thread_count); + _tp = new ThreadPool(_client, _thread_count); } // RedisServer destructor diff --git a/src/cpp/srobject.cpp b/src/cpp/srobject.cpp index 22ce3afd4..b5ae9c49d 100644 --- a/src/cpp/srobject.cpp +++ b/src/cpp/srobject.cpp @@ -49,7 +49,7 @@ SRObject::SRObject(const std::string& logging_name) // Conditionally log data if the logging level is high enough -void SRObject::log_data(SRLoggingLevel level, const std::string& data) +void SRObject::log_data(SRLoggingLevel level, const std::string& data) const { - Logger::get_instance().log_data(level, data); + Logger::get_instance().log_data(_lname, level, data); } diff --git a/src/cpp/threadpool.cpp b/src/cpp/threadpool.cpp index 90a421ba0..e5d7c48b6 100644 --- a/src/cpp/threadpool.cpp +++ b/src/cpp/threadpool.cpp @@ -8,12 +8,27 @@ #include "threadpool.h" #include "srexception.h" #include "logger.h" +#include "client.h" using namespace SmartRedis; using namespace std::chrono_literals; +// Log safely, even if our _client pointer is NULL +// This is a workaround for the direct instantiation of Redis and RedisCluster +// objects in our unit tests that do not currently include a Client*. Once those +// usages are updated, this function can go away and all calls replaced with +// direct invocations of _client->log_data() +void safelog(const Client* client, SRLoggingLevel level, const std::string& msg) +{ + if (client != NULL) + client->log_data(level, msg); + else + log_data("Threadpool", level, msg); +} + // Constructor -ThreadPool::ThreadPool(unsigned int num_threads) +ThreadPool::ThreadPool(const Client* client, unsigned int num_threads) + : _client(client) { // Flags that we're initializing and not shutting down initialization_complete = false; @@ -26,7 +41,8 @@ ThreadPool::ThreadPool(unsigned int num_threads) // Create worker threads if (num_threads < 1) num_threads = 1; // Force a minimum of 1 thread for (unsigned int i = 0; i < num_threads; i++) { - log_data(LLDeveloper, "Kicking off thread " + std::to_string(i)); + safelog(_client, + LLDeveloper, "Kicking off thread " + std::to_string(i)); threads.push_back(std::thread(&ThreadPool::perform_jobs, this, i)); } @@ -51,7 +67,7 @@ void ThreadPool::shutdown() while (!initialization_complete) ; // Spin - log_data(LLDeveloper, "Shutting down thread pool"); + safelog(_client, LLDeveloper, "Shutting down thread pool"); // We're closed for business shutting_down = true; @@ -65,12 +81,12 @@ void ThreadPool::shutdown() "Waiting for thread to terminate (" + std::to_string(i++) + " of " + std::to_string(num_threads) + ")"; - log_data(LLDeveloper, message); + safelog(_client, LLDeveloper, message); thr.join(); // Blocks until the thread finishes execution } // Done - log_data(LLDeveloper, "Shutdown complete"); + safelog(_client, LLDeveloper, "Shutdown complete"); shutdown_complete = true; } @@ -78,7 +94,7 @@ void ThreadPool::shutdown() void ThreadPool::perform_jobs(unsigned int tid) { int jobid = 0; - log_data( + safelog(_client, LLDebug, "Thread " + std::to_string(tid) + " reporting for duty"); // Loop forever processing jobs until we get killed @@ -121,11 +137,12 @@ void ThreadPool::perform_jobs(unsigned int tid) ": " + std::to_string(get_job.count()) + " s; " + "time to execute job: " + std::to_string(execute_job.count()) + " s"; - log_data(LLDeveloper, message); + safelog(_client, LLDeveloper, message); } } - log_data(LLDeveloper, "Thread " + std::to_string(tid) + " shutting down"); + safelog(_client, + LLDeveloper, "Thread " + std::to_string(tid) + " shutting down"); } // Submit a job to threadpool for execution diff --git a/src/cpp/utility.cpp b/src/cpp/utility.cpp index 67e4e4465..359deca48 100644 --- a/src/cpp/utility.cpp +++ b/src/cpp/utility.cpp @@ -53,7 +53,7 @@ void get_config_integer(int& value, { value = default_value; std::string message = "Getting value for " + cfg_key; - log_data(LLDebug, message); + log_data("SmartRedis Library", LLDebug, message); char* cfg_val = std::getenv(cfg_key.c_str()); message = "Retrieved value \""; @@ -61,7 +61,7 @@ void get_config_integer(int& value, message += "\""; if (NULL == cfg_val) message += ". Using default value of " + std::to_string(default_value); - log_data(LLDebug, message); + log_data("SmartRedis Library", LLDebug, message); if (cfg_val != NULL && std::strlen(cfg_val) > 0) { // Enforce that all characters are digits because std::stoi @@ -95,13 +95,14 @@ void get_config_integer(int& value, } else if (!suppress_warning) { log_warning( + "SmartRedis Library", LLDebug, "Configuration variable " + cfg_key + " not set" ); } message = "Exiting with value \"" + std::to_string(value) + "\""; - log_data(LLDebug, message); + log_data("SmartRedis Library", LLDebug, message); } /*! @@ -120,7 +121,7 @@ void get_config_string(std::string& value, { value = default_value; std::string message = "Getting value for " + cfg_key; - log_data(LLDebug, message); + log_data("SmartRedis Library", LLDebug, message); char* cfg_val = std::getenv(cfg_key.c_str()); message = "Retrieved value \""; @@ -128,19 +129,20 @@ void get_config_string(std::string& value, message += "\""; if (NULL == cfg_val) message += ". Using default value of \"" + default_value + "\""; - log_data(LLDebug, message); + log_data("SmartRedis Library", LLDebug, message); if (cfg_val != NULL && std::strlen(cfg_val) > 0) value = cfg_val; else if (!suppress_warning) { log_warning( + "SmartRedis Library", LLDebug, "Configuration variable " + cfg_key + " not set" ); } message = "Exiting with value \"" + value + "\""; - log_data(LLDebug, message); + log_data("SmartRedis Library", LLDebug, message); } } // namespace SmartRedis { diff --git a/src/python/bindings/bind.cpp b/src/python/bindings/bind.cpp index e7592bc6e..2b3e67aba 100644 --- a/src/python/bindings/bind.cpp +++ b/src/python/bindings/bind.cpp @@ -26,9 +26,14 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "pysrobject.h" #include "pyclient.h" +#include "pydataset.h" +#include "pylogcontext.h" #include "srexception.h" #include "logger.h" +#include "srobject.h" +#include "logcontext.h" using namespace SmartRedis; namespace py = pybind11; @@ -37,8 +42,16 @@ namespace py = pybind11; PYBIND11_MODULE(smartredisPy, m) { m.doc() = "smartredis client"; // optional module docstring - // Python client bindings - py::class_(m, "PyClient") + // Python SRObject class + py::class_(m, "PySRObject") + .def(py::init()); + + // Python LogContext class + py::class_(m, "PyLogContext") + .def(py::init()); + + // Python client class + py::class_(m, "PyClient") .def(py::init()) .def("put_tensor", &PyClient::put_tensor) .def("get_tensor", &PyClient::get_tensor) @@ -99,7 +112,7 @@ PYBIND11_MODULE(smartredisPy, m) { .def("get_dataset_list_range", &PyClient::get_dataset_list_range); // Python Dataset class - py::class_(m, "PyDataset") + py::class_(m, "PyDataset") .def(py::init()) .def("add_tensor", &PyDataset::add_tensor) .def("get_tensor", &PyDataset::get_tensor) @@ -110,9 +123,12 @@ PYBIND11_MODULE(smartredisPy, m) { .def("get_name", &PyDataset::get_name); // Logging functions - m.def("cpp_log_data", &log_data) - .def("cpp_log_warning", &log_warning) - .def("cpp_log_error", &log_error); + m.def("cpp_log_data", py::overload_cast(&log_data)) + .def("cpp_log_data", py::overload_cast(&log_data)) + .def("cpp_log_warning", py::overload_cast(&log_warning)) + .def("cpp_log_warning", py::overload_cast(&log_warning)) + .def("cpp_log_error", py::overload_cast(&log_error)) + .def("cpp_log_error", py::overload_cast(&log_error)); // Logging levels py::enum_(m, "SRLoggingLevel") diff --git a/src/python/module/smartredis/logger.py b/src/python/module/smartredis/logger.py index 83e004637..ce47244e5 100644 --- a/src/python/module/smartredis/logger.py +++ b/src/python/module/smartredis/logger.py @@ -34,44 +34,53 @@ #LLDeveloper = 4 # Extra verbose logging for internal use @exception_handler -def log_data(level, data): +def log_data(context, level, data): """Log data to the SmartRedis logfile + :param context: Logging context (string to prefix the log entry with) + :type context: str :param level: minimum logging level for data to be logged with :type name: enum :param data: message data to log :type data: str :raises RedisReplyError: if logging fails """ + typecheck(context, "context", str) typecheck(level, "level", SRLoggingLevel) typecheck(data, "data", str) - cpp_log_data(level, data) + cpp_log_data(context, level, data) @exception_handler -def log_warning(level, data): +def log_warning(context, level, data): """Log a warning to the SmartRedis logfile + :param context: Logging context (string to prefix the log entry with) + :type context: str :param level: minimum logging level for data to be logged with :type name: enum :param data: message data to log :type data: str :raises RedisReplyError: if logging fails """ + typecheck(context, "context", str) typecheck(level, "level", SRLoggingLevel) typecheck(data, "data", str) - cpp_log_warning(level, data) + cpp_log_warning(context, level, data) @exception_handler -def log_error(level, data): +def log_error(context, level, data): """Log an error to the SmartRedis logfile + :param context: Logging context (string to prefix the log entry with) + :type context: str :param level: minimum logging level for data to be logged with :type name: enum :param data: message data to log :type data: str :raises RedisReplyError: if logging fails """ + typecheck(context, "context", str) typecheck(level, "level", SRLoggingLevel) typecheck(data, "data", str) - cpp_log_error(level, data) + cpp_log_error(context, level, data) diff --git a/src/python/src/pyclient.cpp b/src/python/src/pyclient.cpp index fa24ca750..95980f018 100644 --- a/src/python/src/pyclient.cpp +++ b/src/python/src/pyclient.cpp @@ -36,6 +36,7 @@ using namespace SmartRedis; namespace py = pybind11; PyClient::PyClient(bool cluster, const std::string& logger_name) + : PySRObject(logger_name) { _client = NULL; try { diff --git a/src/python/src/pydataset.cpp b/src/python/src/pydataset.cpp index 35280b52a..137c884be 100644 --- a/src/python/src/pydataset.cpp +++ b/src/python/src/pydataset.cpp @@ -29,13 +29,16 @@ #include "pydataset.h" #include "srexception.h" +#include "logger.h" using namespace SmartRedis; namespace py = pybind11; PyDataset::PyDataset(const std::string& name) + : PySRObject(name) { + log_data("PyDataset::PyDataset(const std::string& name)", LLInfo, "pydataset constructor (" + name + ")"); _dataset = NULL; try { _dataset = new DataSet(name); @@ -56,13 +59,20 @@ PyDataset::PyDataset(const std::string& name) } PyDataset::PyDataset(DataSet* dataset) + : PySRObject(dataset) { + log_data("PyDataset::PyDataset(DataSet* dataset)", LLInfo, "pydataset constructor"); + if (_dataset != NULL) + _dataset->log_data(LLInfo, "pydataset getting overwritten"); _dataset = dataset; + if (_dataset != NULL) + _dataset->log_data(LLInfo, "pydataset overwritten"); } PyDataset::~PyDataset() { if (_dataset != NULL) { + _dataset->log_data(LLInfo, "pydataset destructor"); delete _dataset; _dataset = NULL; } diff --git a/src/python/src/pylogcontext.cpp b/src/python/src/pylogcontext.cpp new file mode 100644 index 000000000..eb8e88815 --- /dev/null +++ b/src/python/src/pylogcontext.cpp @@ -0,0 +1,76 @@ +/* + * BSD 2-Clause License + * + * Copyright (c) 2021-2022, Hewlett Packard Enterprise + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "pylogcontext.h" +#include "logcontext.h" +#include "srexception.h" + +using namespace SmartRedis; + +namespace py = pybind11; + +PyLogContext::PyLogContext(const std::string& context) + : PySRObject(context) +{ + _logcontext = NULL; + try { + _logcontext = new LogContext(context); + } + catch (Exception& e) { + // exception is already prepared for caller + throw; + } + catch (std::exception& e) { + // should never happen + throw SRInternalException(e.what()); + } + catch (...) { + // should never happen + throw SRInternalException("A non-standard exception was encountered "\ + "during dataset construction."); + } +} + +PyLogContext::PyLogContext(LogContext* logcontext) + : PySRObject(logcontext) +{ + _logcontext = logcontext; +} + +PyLogContext::~PyLogContext() +{ + if (_logcontext != NULL) { + delete _logcontext; + _logcontext = NULL; + } +} + +LogContext* PyLogContext::get() { + return _logcontext; +} diff --git a/src/python/src/pysrobject.cpp b/src/python/src/pysrobject.cpp new file mode 100644 index 000000000..2afb874ca --- /dev/null +++ b/src/python/src/pysrobject.cpp @@ -0,0 +1,76 @@ +/* + * BSD 2-Clause License + * + * Copyright (c) 2021-2022, Hewlett Packard Enterprise + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "pysrobject.h" +#include "srobject.h" +#include "srexception.h" +#include "logger.h" + +using namespace SmartRedis; + +namespace py = pybind11; + +PySRObject::PySRObject(const std::string& context) +{ + _srobject = NULL; + try { + _srobject = new SRObject(context); + } + catch (Exception& e) { + // exception is already prepared for caller + throw; + } + catch (std::exception& e) { + // should never happen + throw SRInternalException(e.what()); + } + catch (...) { + // should never happen + throw SRInternalException("A non-standard exception was encountered "\ + "during dataset construction."); + } +} + +PySRObject::PySRObject(SRObject* srobject) +{ + _srobject = srobject; +} + +PySRObject::~PySRObject() +{ + if (_srobject != NULL) { + _srobject->log_data(LLInfo, "pysrobject destructor"); + delete _srobject; + _srobject = NULL; + } +} + +SRObject* PySRObject::get() { + return _srobject; +} diff --git a/tests/cpp/client_test_utils.h b/tests/cpp/client_test_utils.h index 4ab667049..78f126382 100644 --- a/tests/cpp/client_test_utils.h +++ b/tests/cpp/client_test_utils.h @@ -39,7 +39,7 @@ using namespace SmartRedis; class RedisClusterTestObject : public RedisCluster { public: - RedisClusterTestObject() : RedisCluster() {}; + RedisClusterTestObject() : RedisCluster(NULL) {}; std::string get_crc16_prefix(uint64_t hash_slot) { return _get_crc16_prefix(hash_slot); diff --git a/tests/cpp/unit-tests/test_addressanycommand.cpp b/tests/cpp/unit-tests/test_addressanycommand.cpp index 5d75fea00..31f5f9548 100644 --- a/tests/cpp/unit-tests/test_addressanycommand.cpp +++ b/tests/cpp/unit-tests/test_addressanycommand.cpp @@ -38,8 +38,8 @@ using namespace SmartRedis; SCENARIO("Testing assignment operator for AddressAnyCommand", "[AddressAnyCommand]") { std::cout << std::to_string(get_time_offset()) << ": Testing assignment operator for AddressAnyCommand" << std::endl; - Logger::get_instance().rename_client("test_addressanycommand"); - log_data(LLDebug, "***Beginning AddressAnyCommand testing***"); + std::string context("test_addressanycommand"); + log_data(context, LLDebug, "***Beginning AddressAnyCommand testing***"); GIVEN("An AddressAnyCommand object") { AddressAnyCommand cmd; @@ -103,11 +103,14 @@ SCENARIO("Testing assignment operator for AddressAnyCommand", "[AddressAnyComman } } } + log_data(context, LLDebug, "***End AddressAnyCommand testing***"); } SCENARIO("Testing AddressAnyCommand member variables", "[AddressAnyCommand]") { std::cout << std::to_string(get_time_offset()) << ": Testing AddressAnyCommand member variables" << std::endl; + std::string context("test_addressanycommand"); + log_data(context, LLDebug, "***Beginning AddressAnyCommand member testing***"); GIVEN("An AddressAnyCommand object and a db node address and port") { AddressAnyCommand cmd; @@ -124,5 +127,5 @@ SCENARIO("Testing AddressAnyCommand member variables", "[AddressAnyCommand]") } } } - log_data(LLDebug, "***End AddressAnyCommand testing***"); + log_data(context, LLDebug, "***End AddressAnyCommand member testing***"); } \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_addressatcommand.cpp b/tests/cpp/unit-tests/test_addressatcommand.cpp index 3d6959d7a..bf2934065 100644 --- a/tests/cpp/unit-tests/test_addressatcommand.cpp +++ b/tests/cpp/unit-tests/test_addressatcommand.cpp @@ -37,8 +37,8 @@ using namespace SmartRedis; SCENARIO("Ensuring the iterators for an AddressAtCommand are correct", "[AddressAtCommand]") { std::cout << std::to_string(get_time_offset()) << ": Ensuring the iterators for an AddressAtCommand are correct" << std::endl; - Logger::get_instance().rename_client("test_addressatcommand"); - log_data(LLDebug, "***Beginning AddressAtCommand testing***"); + std::string context("test_addressatcommand"); + log_data(context, LLDebug, "***Beginning AddressAtCommand testing***"); GIVEN("An AddressAtCommand with a single field") { @@ -63,11 +63,15 @@ SCENARIO("Ensuring the iterators for an AddressAtCommand are correct", "[Address } } } + log_data(context, LLDebug, "***End AddressAtCommand testing***"); } SCENARIO("Testing assignment operator for AddressAtCommand on heap", "[AddressAtCommand]") { std::cout << std::to_string(get_time_offset()) << ": Testing assignment operator for AddressAtCommand on heap" << std::endl; + std::string context("test_addressatcommand"); + log_data(context, LLDebug, "***Beginning AddressAtCommand heap testing***"); + GIVEN("An AddressAtCommand object on the heap") { AddressAtCommand* cmd = new AddressAtCommand; @@ -134,13 +138,14 @@ SCENARIO("Testing assignment operator for AddressAtCommand on heap", "[AddressAt } } } - log_data(LLDebug, "***End AddressAtCommand testing***"); + log_data(context, LLDebug, "***End AddressAtCommand heap testing***"); } SCENARIO("Testing AddressAtCommand member variables", "[AddressAtCommand]") { std::cout << std::to_string(get_time_offset()) << ": Testing AddressAnyCommand member variables" << std::endl; - log_data(LLDebug, "***Beginning AddressAtCommand variable testing***"); + std::string context("test_addressatcommand"); + log_data(context, LLDebug, "***Beginning AddressAtCommand variable testing***"); GIVEN("An AddressAtCommand object") { AddressAtCommand* cmd = new AddressAtCommand; @@ -154,5 +159,5 @@ SCENARIO("Testing AddressAtCommand member variables", "[AddressAtCommand]") } } } - log_data(LLDebug, "***End AddressAtCommand variable testing***"); + log_data(context, LLDebug, "***End AddressAtCommand variable testing***"); } \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_aggregation_list.cpp b/tests/cpp/unit-tests/test_aggregation_list.cpp index e038121f3..a82bd5a0b 100644 --- a/tests/cpp/unit-tests/test_aggregation_list.cpp +++ b/tests/cpp/unit-tests/test_aggregation_list.cpp @@ -147,8 +147,8 @@ bool is_same_dataset(DataSet& dataset_1, DataSet& dataset_2) SCENARIO("Testing Dataset aggregation via our client", "[List]") { std::cout << std::to_string(get_time_offset()) << ": Testing Dataset aggregation via our client" << std::endl; - Logger::get_instance().rename_client("test_aggregation_list"); - log_data(LLDebug, "***Beginning DataSet Aggregation testing***"); + std::string context("test_aggregation_list"); + log_data(context, LLDebug, "***Beginning DataSet Aggregation testing***"); GIVEN("A Client object and vector of DataSet objects") { @@ -504,5 +504,5 @@ SCENARIO("Testing Dataset aggregation via our client", "[List]") } } } - log_data(LLDebug, "***End DataSet Aggregation testing***"); + log_data(context, LLDebug, "***End DataSet Aggregation testing***"); } diff --git a/tests/cpp/unit-tests/test_client.cpp b/tests/cpp/unit-tests/test_client.cpp index 40655530a..4edc6189b 100644 --- a/tests/cpp/unit-tests/test_client.cpp +++ b/tests/cpp/unit-tests/test_client.cpp @@ -96,8 +96,8 @@ void check_all_data(size_t length, std::vector& original_datas, SCENARIO("Testing Dataset Functions on Client Object", "[Client]") { std::cout << std::to_string(get_time_offset()) << ": Testing Dataset Functions on Client Object" << std::endl; - Logger::get_instance().rename_client("test_client"); - log_data(LLDebug, "***Beginning Client testing***"); + std::string context("test_client"); + log_data(context, LLDebug, "***Beginning Client testing***"); GIVEN("A Client object") { Client client(use_cluster(), "test_client"); @@ -189,11 +189,14 @@ SCENARIO("Testing Dataset Functions on Client Object", "[Client]") } } } + log_data(context, LLDebug, "***End Client testing***"); } SCENARIO("Testing Tensor Functions on Client Object", "[Client]") { std::cout << std::to_string(get_time_offset()) << ": Testing Tensor Functions on Client Object" << std::endl; + std::string context("test_client"); + log_data(context, LLDebug, "***Beginning Client tensor testing***"); GIVEN("A Client object") { Client client(use_cluster(), "test_client"); @@ -469,11 +472,14 @@ SCENARIO("Testing Tensor Functions on Client Object", "[Client]") } } } + log_data(context, LLDebug, "***End Client tensor testing***"); } SCENARIO("Testing INFO Functions on Client Object", "[Client]") { std::cout << std::to_string(get_time_offset()) << ": Testing INFO Functions on Client Object" << std::endl; + std::string context("test_client"); + log_data(context, LLDebug, "***Beginning Client INFO testing***"); GIVEN("A Client object") { Client client(use_cluster(), "test_client"); @@ -518,11 +524,14 @@ SCENARIO("Testing INFO Functions on Client Object", "[Client]") } } } + log_data(context, LLDebug, "***End Client tensor testing***"); } SCENARIO("Testing AI.INFO Functions on Client Object", "[Client]") { std::cout << std::to_string(get_time_offset()) << ": Testing AI.INFO Functions on Client Object" << std::endl; + std::string context("test_client"); + log_data(context, LLDebug, "***Beginning Client AI.INFO testing***"); GIVEN("A Client object") { Client client(use_cluster(), "test_client"); @@ -567,11 +576,15 @@ SCENARIO("Testing AI.INFO Functions on Client Object", "[Client]") } } } + log_data(context, LLDebug, "***End Client AI.INFO testing***"); } SCENARIO("Testing FLUSHDB on empty Client Object", "[Client][FLUSHDB]") { std::cout << std::to_string(get_time_offset()) << ": Testing FLUSHDB on empty Client Object" << std::endl; + std::string context("test_client"); + log_data(context, LLDebug, "***Beginning Client empty FLIUSHDB testing***"); + GIVEN("An empty non-cluster Client object") { Client client(use_cluster(), "test_client"); @@ -602,11 +615,15 @@ SCENARIO("Testing FLUSHDB on empty Client Object", "[Client][FLUSHDB]") } } } + log_data(context, LLDebug, "***End Client empty FLUSHDB testing***"); } SCENARIO("Testing FLUSHDB on Client Object", "[Client][FLUSHDB]") { std::cout << std::to_string(get_time_offset()) << ": Testing FLUSHDB on Client Object" << std::endl; + std::string context("test_client"); + log_data(context, LLDebug, "***Beginning Client FLUSHDB testing***"); + GIVEN("A non-cluster Client object") { // From within the testing framework, there is no way of knowing @@ -643,11 +660,15 @@ SCENARIO("Testing FLUSHDB on Client Object", "[Client][FLUSHDB]") } } } + log_data(context, LLDebug, "***End Client FLUSHDB testing***"); } SCENARIO("Testing CONFIG GET and CONFIG SET on Client Object", "[Client]") { std::cout << std::to_string(get_time_offset()) << ": Testing CONFIG GET and CONFIG SET on Client Object" << std::endl; + std::string context("test_client"); + log_data(context, LLDebug, "***Beginning Client config get/set testing***"); + GIVEN("A Client object") { Client client(use_cluster(), "test_client"); @@ -688,11 +709,15 @@ SCENARIO("Testing CONFIG GET and CONFIG SET on Client Object", "[Client]") } } } + log_data(context, LLDebug, "***End Client config get/set testing***"); } SCENARIO("Test CONFIG GET on an unsupported command", "[Client]") { std::cout << std::to_string(get_time_offset()) << ": Test CONFIG GET on an unsupported command" << std::endl; + std::string context("test_client"); + log_data(context, LLDebug, "***Beginning Client config get unsupported testing***"); + GIVEN("A client object") { Client client(use_cluster(), "test_client"); @@ -709,11 +734,15 @@ SCENARIO("Test CONFIG GET on an unsupported command", "[Client]") } } } + log_data(context, LLDebug, "***End Client config get unsupported testing***"); } SCENARIO("Test CONFIG SET on an unsupported command", "[Client]") { std::cout << std::to_string(get_time_offset()) << ": Test CONFIG SET on an unsupported command" << std::endl; + std::string context("test_client"); + log_data(context, LLDebug, "***Beginning Client config set unsupported testing***"); + GIVEN("A client object") { Client client(use_cluster(), "test_client"); @@ -730,11 +759,15 @@ SCENARIO("Test CONFIG SET on an unsupported command", "[Client]") } } } + log_data(context, LLDebug, "***End Client config get unsupported testing***"); } SCENARIO("Testing SAVE command on Client Object", "[!mayfail][Client][SAVE]") { std::cout << std::to_string(get_time_offset()) << ": Testing SAVE command on Client Object" << std::endl; + std::string context("test_client"); + log_data(context, LLDebug, "***Beginning Client SAVE unsupported testing***"); + GIVEN("A client object and some data") { Client client(use_cluster(), "test_client"); @@ -770,11 +803,15 @@ SCENARIO("Testing SAVE command on Client Object", "[!mayfail][Client][SAVE]") } } } + log_data(context, LLDebug, "***End Client SAVE unsupported testing***"); } SCENARIO("Test that prefixing covers all hash slots of a cluster", "[Client]") { std::cout << std::to_string(get_time_offset()) << ": Test that prefixing covers all hash slots of a cluster" << std::endl; + std::string context("test_client"); + log_data(context, LLDebug, "***Beginning Client prefix coverage testing***"); + if(use_cluster()==false) return; @@ -807,13 +844,16 @@ SCENARIO("Test that prefixing covers all hash slots of a cluster", "[Client]") RuntimeException); } } - } + log_data(context, LLDebug, "***End Client prefix coverage testing***"); } SCENARIO("Testing Multi-GPU Function error cases", "[Client]") { std::cout << std::to_string(get_time_offset()) << ": Testing Multi-GPU Function error cases" << std::endl; + std::string context("test_client"); + log_data(context, LLDebug, "***Beginning Client multigpu error testing***"); + GIVEN("A Client object, a script, and a model") { Client client(use_cluster(), "test_client"); @@ -956,5 +996,5 @@ SCENARIO("Testing Multi-GPU Function error cases", "[Client]") } } } - log_data(LLDebug, "***End Client testing***"); + log_data(context, LLDebug, "***End Client multigpu error testing***"); } diff --git a/tests/cpp/unit-tests/test_client_ensemble.cpp b/tests/cpp/unit-tests/test_client_ensemble.cpp index cde438554..d1968f4ed 100644 --- a/tests/cpp/unit-tests/test_client_ensemble.cpp +++ b/tests/cpp/unit-tests/test_client_ensemble.cpp @@ -40,7 +40,6 @@ using namespace SmartRedis; // variables to their original state void reset_env_vars(const char* old_keyin, const char* old_keyout) { - log_data(LLDebug, "Resetting SSKEYIN and SSKEYOUT"); if (old_keyin != nullptr) { setenv("SSKEYIN", old_keyin, 1); } @@ -80,8 +79,8 @@ void load_mnist_image_to_array(float**** img) SCENARIO("Testing Client ensemble using a producer/consumer paradigm") { std::cout << std::to_string(get_time_offset()) << ": Testing Client ensemble using a producer/consumer paradigm" << std::endl; - Logger::get_instance().rename_client("test_client_ensemble"); - log_data(LLDebug, "***Beginning Client Ensemble testing***"); + std::string context("test_client_ensemble"); + log_data(context, LLDebug, "***Beginning Client Ensemble testing***"); GIVEN("Variables that will be used by the producer and consumer") { @@ -128,7 +127,7 @@ SCENARIO("Testing Client ensemble using a producer/consumer paradigm") { //////////////////////////////////////////////////////////// // do producer stuff - log_data(LLDebug, "***Beginning producer operations***"); + log_data(context, LLDebug, "***Beginning producer operations***"); setenv("SSKEYIN", keyin_env_put, (old_keyin != NULL)); setenv("SSKEYOUT", keyout_env_put, (old_keyout != NULL)); @@ -177,11 +176,11 @@ SCENARIO("Testing Client ensemble using a producer/consumer paradigm") producer_client.run_model(model_name, {script_out_key_ds}, {out_key_ds}); free_4D_array(mnist_array, 1, 1, 28); - log_data(LLDebug, "***End producer operations***"); + log_data(context, LLDebug, "***End producer operations***"); //////////////////////////////////////////////////////////// // do consumer stuff - log_data(LLDebug, "***Beginning consumer operations***"); + log_data(context, LLDebug, "***Beginning consumer operations***"); setenv("SSKEYIN", keyin_env_get, 1); setenv("SSKEYOUT", keyout_env_get, 1); @@ -248,7 +247,8 @@ SCENARIO("Testing Client ensemble using a producer/consumer paradigm") // reset environment variables to their original state reset_env_vars(old_keyin, old_keyout); + log_data(context, LLDebug, "***End consumer operations***"); } } - log_data(LLDebug, "***End Client Ensemble testing***"); + log_data(context, LLDebug, "***End Client Ensemble testing***"); } \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_clusterinfocommand.cpp b/tests/cpp/unit-tests/test_clusterinfocommand.cpp index 08071afc0..69c22ff0b 100644 --- a/tests/cpp/unit-tests/test_clusterinfocommand.cpp +++ b/tests/cpp/unit-tests/test_clusterinfocommand.cpp @@ -37,8 +37,8 @@ using namespace SmartRedis; SCENARIO("Parsing an empty string for cluster info") { std::cout << std::to_string(get_time_offset()) << ": Parsing an empty string for cluster info" << std::endl; - Logger::get_instance().rename_client("test_clusterinfocommand"); - log_data(LLDebug, "***Beginning ClusterInfoCommand testing***"); + std::string context("test_clusterinfocommand"); + log_data(context, LLDebug, "***Beginning ClusterInfoCommand testing***"); GIVEN("A ClusterInfoCommand and an empty string") { @@ -53,5 +53,5 @@ SCENARIO("Parsing an empty string for cluster info") } } } - log_data(LLDebug, "***End ClusterInfoCommand testing***"); + log_data(context, LLDebug, "***End ClusterInfoCommand testing***"); } \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_commandlist.cpp b/tests/cpp/unit-tests/test_commandlist.cpp index 1156c818c..84892f27f 100644 --- a/tests/cpp/unit-tests/test_commandlist.cpp +++ b/tests/cpp/unit-tests/test_commandlist.cpp @@ -43,8 +43,8 @@ using namespace SmartRedis; SCENARIO("Testing CommandList object", "[CommandList]") { std::cout << std::to_string(get_time_offset()) << ": Testing CommandList objectinfo" << std::endl; - Logger::get_instance().rename_client("test_commandlist"); - log_data(LLDebug, "***Beginning CommandList testing***"); + std::string context("test_commandlist"); + log_data(context, LLDebug, "***Beginning CommandList testing***"); GIVEN("A CommandList object") { CommandList cmd_lst; @@ -288,11 +288,15 @@ SCENARIO("Testing CommandList object", "[CommandList]") } } } + log_data(context, LLDebug, "***End CommandList testing***"); } SCENARIO("Testing CommandList object on heap", "[CommandList]") { std::cout << std::to_string(get_time_offset()) << ": Testing CommandList object on heap" << std::endl; + std::string context("test_commandlist"); + log_data(context, LLDebug, "***Beginning CommandList heap testing***"); + GIVEN("A CommandList object on the heap with three Commands") { CommandList* cmd_lst = new CommandList; @@ -337,5 +341,5 @@ SCENARIO("Testing CommandList object on heap", "[CommandList]") } } } - log_data(LLDebug, "***End CommandList testing***"); + log_data(context, LLDebug, "***End CommandList heap testing***"); } \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_commandreply.cpp b/tests/cpp/unit-tests/test_commandreply.cpp index 0cf432ad8..b7e4c3c63 100644 --- a/tests/cpp/unit-tests/test_commandreply.cpp +++ b/tests/cpp/unit-tests/test_commandreply.cpp @@ -105,8 +105,8 @@ void fill_reply_array(redisReply*& reply, int num_of_children) SCENARIO("Testing CommandReply object", "[CommandReply]") { std::cout << std::to_string(get_time_offset()) << ": Testing CommandReply object" << std::endl; - Logger::get_instance().rename_client("test_commandreply"); - log_data(LLDebug, "***Beginning CommandReply object testing***"); + std::string context("test_commandreply"); + log_data(context, LLDebug, "***Beginning CommandReply object testing***"); GIVEN("A CommandReply object with type REDIS_REPLY_INTEGER") { @@ -163,14 +163,15 @@ SCENARIO("Testing CommandReply object", "[CommandReply]") CHECK_THROWS_AS(cmd_reply.redis_reply_type(), RuntimeException); } } - log_data(LLDebug, "***End CommandReply object testing***"); + log_data(context, LLDebug, "***End CommandReply object testing***"); } SCENARIO("Test CommandReply copy assignment operator and copy " "constructor on simple REDIS_REPLY_TYPES", "[CommandReply]") { std::cout << std::to_string(get_time_offset()) << ": Test CommandReply copy assignment operator and copy" << std::endl; - log_data(LLDebug, "***Beginning CommandReply copy testing***"); + std::string context("test_commandreply"); + log_data(context, LLDebug, "***Beginning CommandReply copy testing***"); GIVEN("A CommandReply") { @@ -212,13 +213,14 @@ SCENARIO("Test CommandReply copy assignment operator and copy " } } } - log_data(LLDebug, "***End CommandReply copy testing***"); + log_data(context, LLDebug, "***End CommandReply copy testing***"); } SCENARIO("Test CommandReply::has_error", "[CommandReply]") { std::cout << std::to_string(get_time_offset()) << ": Test CommandReply::has_error" << std::endl; - log_data(LLDebug, "***Beginning CommandReply has_error testing***"); + std::string context("test_commandreply"); + log_data(context, LLDebug, "***Beginning CommandReply has_error testing***"); GIVEN("A parent and child redisReply") { @@ -240,14 +242,15 @@ SCENARIO("Test CommandReply::has_error", "[CommandReply]") } } } - log_data(LLDebug, "***End CommandReply has_error testing***"); + log_data(context, LLDebug, "***End CommandReply has_error testing***"); } SCENARIO("CommandReply copy assignment operator preserves the state of the " "rvalue and the lvalue when one of the objects are deleted", "[CommandReply]") { std::cout << std::to_string(get_time_offset()) << ": CommandReply copy assignment operator preserves the state of the" << std::endl; - log_data(LLDebug, "***Beginning CommandReply delete testing***"); + std::string context("test_commandreply"); + log_data(context, LLDebug, "***Beginning CommandReply delete testing***"); GIVEN("Two dynamically allocated CommandReply. One with a complex " "redisReply, and the other with a simple redisReply") @@ -332,13 +335,14 @@ SCENARIO("CommandReply copy assignment operator preserves the state of the " } } } - log_data(LLDebug, "***End CommandReply delete testing***"); + log_data(context, LLDebug, "***End CommandReply delete testing***"); } SCENARIO("Simple tests on CommandReply constructors that use redisReply*", "[CommandReply]") { std::cout << std::to_string(get_time_offset()) << ": Simple tests on CommandReply constructors that use redisReply*" << std::endl; - log_data(LLDebug, "***Beginning CommandReply redisReply testing***"); + std::string context("test_commandreply"); + log_data(context, LLDebug, "***Beginning CommandReply redisReply testing***"); GIVEN("A redisReply") { @@ -381,13 +385,14 @@ SCENARIO("Simple tests on CommandReply constructors that use redisReply*", "[Com } } } - log_data(LLDebug, "***End CommandReply redisReply testing***"); + log_data(context, LLDebug, "***End CommandReply redisReply testing***"); } SCENARIO("Test CommandReply copy constructor with an inconsistent redisReply", "[CommandReply]") { std::cout << std::to_string(get_time_offset()) << ": Test CommandReply copy constructor with an inconsistent redisReply" << std::endl; - log_data(LLDebug, "***Beginning CommandReply inconsistent redisReply testing***"); + std::string context("test_commandreply"); + log_data(context, LLDebug, "***Beginning CommandReply inconsistent redisReply testing***"); GIVEN("An inconsistent redisReply where its 'elements' doesn't "\ "correspond to its 'element'") @@ -410,13 +415,14 @@ SCENARIO("Test CommandReply copy constructor with an inconsistent redisReply", " } } } - log_data(LLDebug, "***End CommandReply inconsistent redisReply testing***"); + log_data(context, LLDebug, "***End CommandReply inconsistent redisReply testing***"); } SCENARIO("Test CommandReply's redisReply deep copy on a shallow copy", "[CommandReply]") { std::cout << std::to_string(get_time_offset()) << ": Test CommandReply's redisReply deep copy on a shallow copy" << std::endl; - log_data(LLDebug, "***Beginning CommandReply deep copy testing***"); + std::string context("test_commandreply"); + log_data(context, LLDebug, "***Beginning CommandReply deep copy testing***"); GIVEN("A CommandReply with redisReply type REDIS_REPLY_ARRAY") { char const* strs[] = {"zero", "one"}; @@ -451,13 +457,14 @@ SCENARIO("Test CommandReply's redisReply deep copy on a shallow copy", "[Command } } } - log_data(LLDebug, "***End CommandReply deep copy testing***"); + log_data(context, LLDebug, "***End CommandReply deep copy testing***"); } SCENARIO("Test CommandReply string retrieval for non REDIS_REPLY_STRING", "[CommandReply]") { std::cout << std::to_string(get_time_offset()) << ": Test CommandReply string retrieval for non REDIS_REPLY_STRING" << std::endl; - log_data(LLDebug, "***Beginning CommandReply string retrieval testing***"); + std::string context("test_commandreply"); + log_data(context, LLDebug, "***Beginning CommandReply string retrieval testing***"); char const* strs[] = {"OK", "42.5", "99999999999999999999", "Verbatim string"}; int lens[] = {3, 5, 21, 16}; @@ -492,14 +499,15 @@ SCENARIO("Test CommandReply string retrieval for non REDIS_REPLY_STRING", "[Comm } delete cmd_reply; } - log_data(LLDebug, "***End CommandReply string retrieval testing***"); + log_data(context, LLDebug, "***End CommandReply string retrieval testing***"); } SCENARIO("Test REDIS_REPLY_ERROR retrieval from a CommandReply", "[CommandReply]") { std::cout << std::to_string(get_time_offset()) << ": Test REDIS_REPLY_ERROR retrieval from a CommandReply" << std::endl; - log_data(LLDebug, "***Beginning CommandReply REDIS_REPLY_ERROR retrieval testing***"); + std::string context("test_commandreply"); + log_data(context, LLDebug, "***Beginning CommandReply REDIS_REPLY_ERROR retrieval testing***"); /* CommanReply (ARRAY) LEVEL 0 @@ -543,5 +551,5 @@ SCENARIO("Test REDIS_REPLY_ERROR retrieval from a CommandReply", "[CommandReply] } } } - log_data(LLDebug, "***End CommandReply REDIS_REPLY_ERROR retrieval testing***"); + log_data(context, LLDebug, "***End CommandReply REDIS_REPLY_ERROR retrieval testing***"); } \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_compoundcommand.cpp b/tests/cpp/unit-tests/test_compoundcommand.cpp index 28702ef05..72d5d29bd 100644 --- a/tests/cpp/unit-tests/test_compoundcommand.cpp +++ b/tests/cpp/unit-tests/test_compoundcommand.cpp @@ -37,8 +37,8 @@ using namespace SmartRedis; SCENARIO("Testing copy constructor and deep copy operator for CompoundCommand", "[CompoundCommand]") { std::cout << std::to_string(get_time_offset()) << ": Testing copy constructor and deep copy operator for CompoundCommand" << std::endl; - Logger::get_instance().rename_client("test_compoundcommand"); - log_data(LLDebug, "***Beginning CompoundCommand testing***"); + std::string context("test_compoundcommand"); + log_data(context, LLDebug, "***Beginning CompoundCommand testing***"); GIVEN("A CompoundCommand object") { @@ -137,5 +137,5 @@ SCENARIO("Testing copy constructor and deep copy operator for CompoundCommand", } } } - log_data(LLDebug, "***End CompoundCommand testing***"); + log_data(context, LLDebug, "***End CompoundCommand testing***"); } \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_dataset.cpp b/tests/cpp/unit-tests/test_dataset.cpp index 22a67a538..cbfa9d293 100644 --- a/tests/cpp/unit-tests/test_dataset.cpp +++ b/tests/cpp/unit-tests/test_dataset.cpp @@ -43,8 +43,8 @@ const char *currentExceptionTypeName() { SCENARIO("Testing DataSet object", "[DataSet]") { std::cout << std::to_string(get_time_offset()) << ": Testing DataSet object" << std::endl; - Logger::get_instance().rename_client("test_dataset"); - log_data(LLDebug, "***Beginning DataSet testing***"); + std::string context("test_dataset"); + log_data(context, LLDebug, "***Beginning DataSet testing***"); GIVEN("A DataSet object") { @@ -210,5 +210,5 @@ SCENARIO("Testing DataSet object", "[DataSet]") } } } - log_data(LLDebug, "***End DataSet testing***"); + log_data(context, LLDebug, "***End DataSet testing***"); } \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_dbinfocommand.cpp b/tests/cpp/unit-tests/test_dbinfocommand.cpp index f80eb2066..1b57b73ea 100644 --- a/tests/cpp/unit-tests/test_dbinfocommand.cpp +++ b/tests/cpp/unit-tests/test_dbinfocommand.cpp @@ -37,8 +37,8 @@ using namespace SmartRedis; SCENARIO("Parsing an empty string for db info") { std::cout << std::to_string(get_time_offset()) << ": Parsing an empty string for db info" << std::endl; - Logger::get_instance().rename_client("test_dbinfocommand"); - log_data(LLDebug, "***Beginning DBInfoCommand testing***"); + std::string context("test_dbinfocommand"); + log_data(context, LLDebug, "***Beginning DBInfoCommand testing***"); GIVEN("A DBInfoCommand and an empty string") { @@ -53,5 +53,5 @@ SCENARIO("Parsing an empty string for db info") } } } - log_data(LLDebug, "***End DBInfoCommand testing***"); + log_data(context, LLDebug, "***End DBInfoCommand testing***"); } \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_dbnode.cpp b/tests/cpp/unit-tests/test_dbnode.cpp index cd0fe750b..f0970805e 100644 --- a/tests/cpp/unit-tests/test_dbnode.cpp +++ b/tests/cpp/unit-tests/test_dbnode.cpp @@ -38,8 +38,8 @@ using namespace SmartRedis; SCENARIO("Testing DBNode object", "[DBNode]") { std::cout << std::to_string(get_time_offset()) << ": Testing DBNode object" << std::endl; - Logger::get_instance().rename_client("test_dbnode"); - log_data(LLDebug, "***Beginning DBNode testing***"); + std::string context("test_dbnode"); + log_data(context, LLDebug, "***Beginning DBNode testing***"); GIVEN("Two DBNode objects created with the default contructor") { @@ -96,5 +96,5 @@ SCENARIO("Testing DBNode object", "[DBNode]") CHECK(node_1 < node_2); } } - log_data(LLDebug, "***End DBNode testing***"); + log_data(context, LLDebug, "***End DBNode testing***"); } \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_logger.cpp b/tests/cpp/unit-tests/test_logger.cpp index 5aeb657d9..d47b2719b 100644 --- a/tests/cpp/unit-tests/test_logger.cpp +++ b/tests/cpp/unit-tests/test_logger.cpp @@ -40,8 +40,8 @@ using namespace SmartRedis; SCENARIO("Additional Testing for logging", "[LOG]") { std::cout << std::to_string(get_time_offset()) << ": Additional Testing for logging" << std::endl; - Logger::get_instance().rename_client("test_logger"); - log_data(LLDebug, "***Beginning Logger testing***"); + std::string context("test_logger"); + log_data(context, LLDebug, "***Beginning Logger testing***"); GIVEN("A Client object") { @@ -50,14 +50,14 @@ SCENARIO("Additional Testing for logging", "[LOG]") THEN("Logging should be able to be done") { // log_data() - log_data(LLInfo, "This is data logged at the Info level"); + log_data(context, LLInfo, "This is data logged at the Info level"); // log_warning() - log_warning(LLInfo, "This is a warning logged at the Info level"); + log_warning(context, LLInfo, "This is a warning logged at the Info level"); // log_error() - log_error(LLInfo, "This is an error logged at the Info level"); + log_error(context, LLInfo, "This is an error logged at the Info level"); } } - log_data(LLDebug, "***End Logger testing***"); + log_data(context, LLDebug, "***End Logger testing***"); } \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_metadata.cpp b/tests/cpp/unit-tests/test_metadata.cpp index 998645763..b21531ab3 100644 --- a/tests/cpp/unit-tests/test_metadata.cpp +++ b/tests/cpp/unit-tests/test_metadata.cpp @@ -132,8 +132,8 @@ void check_metadata_copied_correctly(MetaData metadata, MetaData metadata_cpy) SCENARIO("Test MetaData", "[MetaData]") { std::cout << std::to_string(get_time_offset()) << ": Test MetaData" << std::endl; - Logger::get_instance().rename_client("test_metadata"); - log_data(LLDebug, "***Beginning Metadata testing***"); + std::string context("test_metadata"); + log_data(context, LLDebug, "***Beginning Metadata testing***"); GIVEN("A MetaData object") { MetaData metadata; @@ -360,5 +360,5 @@ SCENARIO("Test MetaData", "[MetaData]") } } } - log_data(LLDebug, "***End DBNode testing***"); + log_data(context, LLDebug, "***End DBNode testing***"); } \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_multikeycommand.cpp b/tests/cpp/unit-tests/test_multikeycommand.cpp index 8fc5987a7..051ca87b9 100644 --- a/tests/cpp/unit-tests/test_multikeycommand.cpp +++ b/tests/cpp/unit-tests/test_multikeycommand.cpp @@ -37,8 +37,8 @@ using namespace SmartRedis; SCENARIO("Adding fields of different types", "[MultiKeyCommand]") { std::cout << std::to_string(get_time_offset()) << ": Adding fields of different types" << std::endl; - Logger::get_instance().rename_client("test_multikeycommand"); - log_data(LLDebug, "***Beginning MultiKeyCommand testing***"); + std::string context("test_multikeycommand"); + log_data(context, LLDebug, "***Beginning MultiKeyCommand testing***"); GIVEN("A MultiKeyCommand object") { @@ -78,5 +78,5 @@ SCENARIO("Adding fields of different types", "[MultiKeyCommand]") } } } - log_data(LLDebug, "***End MultiKeyCommand testing***"); + log_data(context, LLDebug, "***End MultiKeyCommand testing***"); } \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_redisserver.cpp b/tests/cpp/unit-tests/test_redisserver.cpp index e21776492..9b5230e14 100644 --- a/tests/cpp/unit-tests/test_redisserver.cpp +++ b/tests/cpp/unit-tests/test_redisserver.cpp @@ -36,6 +36,7 @@ #include "redis.h" #include "srexception.h" #include "logger.h" +#include "client.h" unsigned long get_time_offset(); @@ -55,6 +56,7 @@ using namespace SmartRedis; class RedisTest : public Redis { public: + RedisTest(Client* c) : Redis(c) {} int get_connection_timeout() {return _connection_timeout;} int get_connection_interval() {return _connection_interval;} int get_command_timeout() {return _command_timeout;} @@ -70,6 +72,7 @@ class RedisTest : public Redis class RedisClusterTest : public RedisCluster { public: + RedisClusterTest(Client* c) : RedisCluster(c) {} int get_connection_timeout() {return _connection_timeout;} int get_connection_interval() {return _connection_interval;} int get_command_timeout() {return _command_timeout;} @@ -94,10 +97,10 @@ const char* CMD_INTERVAL_ENV_VAR = "SR_CMD_INTERVAL"; void invoke_constructor() { if (use_cluster()) { - RedisClusterTest cluster_obj; + RedisClusterTest cluster_obj(NULL); } else { - RedisTest non_cluster_obj; + RedisTest non_cluster_obj(NULL); } } @@ -169,8 +172,8 @@ void check_all_defaults(T& server) SCENARIO("Test runtime settings are initialized correctly", "[RedisServer]") { std::cout << std::to_string(get_time_offset()) << ": Test runtime settings are initialized correctly" << std::endl; - Logger::get_instance().rename_client("test_redisserver"); - log_data(LLDebug, "***Beginning RedisServer testing***"); + std::string context("test_redisserver"); + log_data(context, LLDebug, "***Beginning RedisServer testing***"); char* __conn_timeout; char* __conn_interval; @@ -182,14 +185,14 @@ SCENARIO("Test runtime settings are initialized correctly", "[RedisServer]") { unset_all_env_vars(); if (use_cluster()) { - RedisClusterTest redis_server; + RedisClusterTest redis_server(NULL); THEN("Default member variable values are used") { check_all_defaults(redis_server); } } else { - RedisTest redis_server; + RedisTest redis_server(NULL); THEN("Default member variable values are used") { check_all_defaults(redis_server); @@ -205,14 +208,14 @@ SCENARIO("Test runtime settings are initialized correctly", "[RedisServer]") setenv(CMD_INTERVAL_ENV_VAR, "", true); if (use_cluster()) { - RedisClusterTest redis_server; + RedisClusterTest redis_server(NULL); THEN("Default member variable values are used") { check_all_defaults(redis_server); } } else { - RedisTest redis_server; + RedisTest redis_server(NULL); THEN("Default member variable values are used") { check_all_defaults(redis_server); @@ -235,7 +238,7 @@ SCENARIO("Test runtime settings are initialized correctly", "[RedisServer]") setenv(CMD_INTERVAL_ENV_VAR, std::to_string(cmd_interval).c_str(), true); if (use_cluster()) { - RedisClusterTest redis_server; + RedisClusterTest redis_server(NULL); THEN("Environment variables are used for member variables") { CHECK(redis_server.get_connection_timeout() == @@ -254,7 +257,7 @@ SCENARIO("Test runtime settings are initialized correctly", "[RedisServer]") } } else { - RedisTest redis_server; + RedisTest redis_server(NULL); THEN("Environment variables are used for member variables") { CHECK(redis_server.get_connection_timeout() == @@ -354,5 +357,5 @@ SCENARIO("Test runtime settings are initialized correctly", "[RedisServer]") } } restore_env_vars(__conn_timeout, __conn_interval, __cmd_timeout, __cmd_interval); - log_data(LLDebug, "***End RedisServer testing***"); + log_data(context, LLDebug, "***End RedisServer testing***"); } \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_singlekeycommand.cpp b/tests/cpp/unit-tests/test_singlekeycommand.cpp index fb70fee29..ed8c0f9d5 100644 --- a/tests/cpp/unit-tests/test_singlekeycommand.cpp +++ b/tests/cpp/unit-tests/test_singlekeycommand.cpp @@ -38,8 +38,8 @@ using namespace SmartRedis; SCENARIO("Retrieve field to empty SingleKeyCommand", "[SingleKeyCommand]") { std::cout << std::to_string(get_time_offset()) << ": Retrieve field to empty SingleKeyCommand" << std::endl; - Logger::get_instance().rename_client("test_singlekeycommand"); - log_data(LLDebug, "***Beginning SingleKeyCommand empty testing***"); + std::string context("test_singlekeycommand"); + log_data(context, LLDebug, "***Beginning SingleKeyCommand empty testing***"); GIVEN("An empty SingleKeyCommand object") { @@ -54,13 +54,14 @@ SCENARIO("Retrieve field to empty SingleKeyCommand", "[SingleKeyCommand]") } } } - log_data(LLDebug, "***End SingleKeyCommand empty testing***"); + log_data(context, LLDebug, "***End SingleKeyCommand empty testing***"); } SCENARIO("Testing copy constructor for SingleKeyCommand on heap", "[SingleKeyCommand]") { std::cout << std::to_string(get_time_offset()) << ": Testing copy constructor for SingleKeyCommand on heap" << std::endl; - log_data(LLDebug, "***Beginning SingleKeyCommand copy testing***"); + std::string context("test_singlekeycommand"); + log_data(context, LLDebug, "***Beginning SingleKeyCommand copy testing***"); GIVEN("A SingleKeyCommand object on the heap") { @@ -126,5 +127,5 @@ SCENARIO("Testing copy constructor for SingleKeyCommand on heap", "[SingleKeyCom delete cmd_cpy; } } - log_data(LLDebug, "***End SingleKeyCommand copy testing***"); + log_data(context, LLDebug, "***End SingleKeyCommand copy testing***"); } \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_ssdb.cpp b/tests/cpp/unit-tests/test_ssdb.cpp index 6c4c6bada..abfa8a356 100644 --- a/tests/cpp/unit-tests/test_ssdb.cpp +++ b/tests/cpp/unit-tests/test_ssdb.cpp @@ -40,7 +40,7 @@ using namespace SmartRedis; class TestSSDB : public Redis { public: - TestSSDB() : Redis() {} + TestSSDB() : Redis(NULL) {} SRAddress get_ssdb() { @@ -60,8 +60,8 @@ void setenv_ssdb(const char* ssdb) SCENARIO("Additional Testing for various SSDBs", "[SSDB]") { std::cout << std::to_string(get_time_offset()) << ": Additional Testing for various SSDBs" << std::endl; - Logger::get_instance().rename_client("test_ssdb"); - log_data(LLDebug, "***Beginning SSDB testing***"); + std::string context("test_ssdb"); + log_data(context, LLDebug, "***Beginning SSDB testing***"); GIVEN("A TestSSDB object") { @@ -96,5 +96,5 @@ SCENARIO("Additional Testing for various SSDBs", "[SSDB]") setenv_ssdb(old_ssdb); } } - log_data(LLDebug, "***End SSDB testing***"); + log_data(context, LLDebug, "***End SSDB testing***"); } \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_stringfield.cpp b/tests/cpp/unit-tests/test_stringfield.cpp index df729699b..5467ab3e8 100644 --- a/tests/cpp/unit-tests/test_stringfield.cpp +++ b/tests/cpp/unit-tests/test_stringfield.cpp @@ -35,8 +35,8 @@ unsigned long get_time_offset(); SCENARIO("Test StringField", "[StringField]") { std::cout << std::to_string(get_time_offset()) << ": Test StringField" << std::endl; - Logger::get_instance().rename_client("test_stringfield"); - log_data(LLDebug, "***Beginning StringField testing***"); + std::string context("test_stringfield"); + log_data(context, LLDebug, "***Beginning StringField testing***"); GIVEN("A StringField object constructed with the string field name") { @@ -99,5 +99,5 @@ SCENARIO("Test StringField", "[StringField]") } // TODO: Test serializing the StringField } - log_data(LLDebug, "***End StringField testing***"); + log_data(context, LLDebug, "***End StringField testing***"); } \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_tensor.cpp b/tests/cpp/unit-tests/test_tensor.cpp index 6aff47f4b..4446c8363 100644 --- a/tests/cpp/unit-tests/test_tensor.cpp +++ b/tests/cpp/unit-tests/test_tensor.cpp @@ -38,8 +38,8 @@ using namespace SmartRedis; SCENARIO("Testing Tensor", "[Tensor]") { std::cout << std::to_string(get_time_offset()) << ": Testing Tensor" << std::endl; - Logger::get_instance().rename_client("test_tensor"); - log_data(LLDebug, "***Beginning Tensor testing***"); + std::string context("test_tensor"); + log_data(context, LLDebug, "***Beginning Tensor testing***"); GIVEN("Two Tensors") { @@ -139,5 +139,5 @@ SCENARIO("Testing Tensor", "[Tensor]") } } } - log_data(LLDebug, "***End Tensor testing***"); + log_data(context, LLDebug, "***End Tensor testing***"); } \ No newline at end of file diff --git a/tests/cpp/unit-tests/test_tensorbase.cpp b/tests/cpp/unit-tests/test_tensorbase.cpp index 3f1f62b93..5671dbfbe 100644 --- a/tests/cpp/unit-tests/test_tensorbase.cpp +++ b/tests/cpp/unit-tests/test_tensorbase.cpp @@ -39,8 +39,8 @@ using namespace SmartRedis; SCENARIO("Testing TensorBase through TensorPack", "[TensorBase]") { std::cout << std::to_string(get_time_offset()) << ": Testing TensorBase through TensorPack" << std::endl; - Logger::get_instance().rename_client("test_tensorbase"); - log_data(LLDebug, "***Beginning TensorBase testing***"); + std::string context("test_tensorbase"); + log_data(context, LLDebug, "***Beginning TensorBase testing***"); SRTensorType tensor_type = GENERATE(SRTensorTypeDouble, SRTensorTypeFloat, SRTensorTypeInt64, SRTensorTypeInt32, @@ -237,5 +237,5 @@ SCENARIO("Testing TensorBase through TensorPack", "[TensorBase]") } } } - log_data(LLDebug, "***End TensorBase testing***"); + log_data(context, LLDebug, "***End TensorBase testing***"); } \ No newline at end of file diff --git a/tests/python/test_dataset_aggregation.py b/tests/python/test_dataset_aggregation.py index d71ab8711..8ab6833e5 100644 --- a/tests/python/test_dataset_aggregation.py +++ b/tests/python/test_dataset_aggregation.py @@ -29,23 +29,28 @@ import pytest from smartredis import Client, Dataset from smartredis.error import * +from smartredis import * def test_aggregation(use_cluster, context): num_datasets = 4 client = Client(None, use_cluster, logger_name=context) + log_data(context, LLDebug, "Initialization complete") # Build datasets original_datasets = [create_dataset(f"dataset_{i}") for i in range(num_datasets)] + log_data(context, LLDebug, "DataSets built") # Make sure the list is cleared list_name = "dataset_test_list" client.delete_list(list_name) + log_data(context, LLDebug, "list cleared") # Put datasets into the list for i in range(num_datasets): client.put_dataset(original_datasets[i]) client.append_to_list(list_name, original_datasets[i]) + log_data(context, LLDebug, "DataSets added to list") # Confirm that poll for list length works correctly actual_length = num_datasets @@ -54,12 +59,14 @@ def test_aggregation(use_cluster, context): raise RuntimeError( f"Polling for list length of {actual_length} returned " f"False for known length of {actual_length}.") + log_data(context, LLDebug, "Polling 1") poll_result = client.poll_list_length(list_name, actual_length + 1, 100, 5) if (poll_result == True): raise RuntimeError( f"Polling for list length of {actual_length + 1} returned " f"True for known length of {actual_length}.") + log_data(context, LLDebug, "Polling 2") # Confirm that poll for greater than or equal list length works correctly poll_result = client.poll_list_length_gte(list_name, actual_length - 1, 100, 5) @@ -67,18 +74,21 @@ def test_aggregation(use_cluster, context): raise RuntimeError( f"Polling for list length greater than or equal to {actual_length - 1} " f"returned False for known length of {actual_length}.") + log_data(context, LLDebug, "Polling 3") poll_result = client.poll_list_length_gte(list_name, actual_length, 100, 5) if (poll_result == False): raise RuntimeError( f"Polling for list length greater than or equal to {actual_length} " f"returned False for known length of {actual_length}.") + log_data(context, LLDebug, "Polling 4") poll_result = client.poll_list_length_gte(list_name, actual_length + 1, 100, 5) if (poll_result == True): raise RuntimeError( f"Polling for list length greater than or equal to {actual_length + 1} " f"returned True for known length of {actual_length}.") + log_data(context, LLDebug, "Polling 5") # Confirm that poll for less than or equal list length works correctly poll_result = client.poll_list_length_lte(list_name, actual_length - 1, 100, 5) @@ -86,26 +96,29 @@ def test_aggregation(use_cluster, context): raise RuntimeError( f"Polling for list length less than or equal to {actual_length - 1} " f"returned True for known length of {actual_length}.") + log_data(context, LLDebug, "Polling 6") poll_result = client.poll_list_length_lte(list_name, actual_length, 100, 5) if (poll_result == False): raise RuntimeError( f"Polling for list length less than or equal to {actual_length} " f"returned False for known length of {actual_length}.") + log_data(context, LLDebug, "Polling 7") poll_result = client.poll_list_length_lte(list_name, actual_length + 1, 100, 5) if (poll_result == False): raise RuntimeError( f"Polling for list length less than or equal to {actual_length + 1} " f"returned False for known length of {actual_length}.") + log_data(context, LLDebug, "Polling 8") # Check the list length list_length = client.get_list_length(list_name) - if (list_length != actual_length): raise RuntimeError( f"The list length of {list_length} does not match expected " f"value of {actual_length}.") + log_data(context, LLDebug, "List length check") # Retrieve datasets via the aggregation list datasets = client.get_datasets_from_list(list_name) @@ -115,6 +128,7 @@ def test_aggregation(use_cluster, context): f"does not match expected value of {list_length}.") for ds in datasets: check_dataset(ds) + log_data(context, LLDebug, "DataSet retrieval") # ------------ helper functions --------------------------------- diff --git a/tests/python/test_errors.py b/tests/python/test_errors.py index e4598438e..627af2a00 100644 --- a/tests/python/test_errors.py +++ b/tests/python/test_errors.py @@ -746,9 +746,11 @@ def test_bad_type_get_dataset_list_range(use_cluster, context): def test_bad_type_log_function(use_cluster, context, log_fn): c = Client(None, use_cluster, logger_name=context) with pytest.raises(TypeError): - log_fn("Not a logging level", "Data to be logged") + log_fn(42, LLInfo, "Data to be logged") with pytest.raises(TypeError): - log_fn(LLInfo, 42) + log_fn("test_bad_type_log_function", "Not a logging level", "Data to be logged") + with pytest.raises(TypeError): + log_fn("test_bad_type_log_function", LLInfo, 42) ##### # Test type errors from bad parameter types to Dataset API calls diff --git a/tests/python/test_logging.py b/tests/python/test_logging.py index 29a02f076..a87d5f9b8 100644 --- a/tests/python/test_logging.py +++ b/tests/python/test_logging.py @@ -33,7 +33,7 @@ ]) def test_logging(use_cluster, context, log_level): c = Client(None, use_cluster, logger_name=context) - log_data(log_level, f"This is data logging ({log_level.name})") - log_warning(log_level, f"This is a warning ({log_level.name})") - log_error(log_level, f"This is an error ({log_level.name})") + log_data(context, log_level, f"This is data logging ({log_level.name})") + log_warning(context, log_level, f"This is a warning ({log_level.name})") + log_error(context, log_level, f"This is an error ({log_level.name})") From 0a4f5cacd9a9ddd1dee3fe804b1bcb265ca99bd6 Mon Sep 17 00:00:00 2001 From: billschereriii Date: Thu, 8 Dec 2022 18:38:25 -0600 Subject: [PATCH 31/37] Python tests working again --- include/pydataset.h | 1 + include/srobject.h | 9 +++ src/python/bindings/bind.cpp | 5 +- src/python/module/smartredis/logcontext.py | 79 ++++++++++++++++++++++ src/python/module/smartredis/srobject.py | 79 ++++++++++++++++++++++ src/python/src/pydataset.cpp | 8 +-- src/python/src/pylogcontext.cpp | 2 +- 7 files changed, 173 insertions(+), 10 deletions(-) create mode 100644 src/python/module/smartredis/logcontext.py create mode 100644 src/python/module/smartredis/srobject.py diff --git a/include/pydataset.h b/include/pydataset.h index 8afc4ec16..323c9b094 100644 --- a/include/pydataset.h +++ b/include/pydataset.h @@ -35,6 +35,7 @@ #include #include "dataset.h" #include "pysrobject.h" + ///@file namespace py = pybind11; diff --git a/include/srobject.h b/include/srobject.h index 48287567e..22a2d0c0d 100644 --- a/include/srobject.h +++ b/include/srobject.h @@ -91,6 +91,15 @@ class SRObject log_data(level, "ERROR: " + data); } + /*! + * \brief Retrieve the context for this object + * \returns The context for this object + */ + virtual std::string get_context() const + { + return _lname; + } + private: /*! diff --git a/src/python/bindings/bind.cpp b/src/python/bindings/bind.cpp index 2b3e67aba..f504f92f0 100644 --- a/src/python/bindings/bind.cpp +++ b/src/python/bindings/bind.cpp @@ -32,8 +32,8 @@ #include "pylogcontext.h" #include "srexception.h" #include "logger.h" -#include "srobject.h" -#include "logcontext.h" +//#include "srobject.h" +//#include "logcontext.h" using namespace SmartRedis; namespace py = pybind11; @@ -137,6 +137,7 @@ PYBIND11_MODULE(smartredisPy, m) { .value("LLDebug", LLDebug) .value("LLDeveloper", LLDeveloper) .export_values(); + // Error management routines m.def("c_get_last_error_location", &SRGetLastErrorLocation); diff --git a/src/python/module/smartredis/logcontext.py b/src/python/module/smartredis/logcontext.py new file mode 100644 index 000000000..42d702f87 --- /dev/null +++ b/src/python/module/smartredis/logcontext.py @@ -0,0 +1,79 @@ +# BSD 2-Clause License +# +# Copyright (c) 2021-2022, Hewlett Packard Enterprise +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +from .smartredisPy import PyLogContext +from .util import exception_handler, typecheck + +from .error import * + +class LogContext: + def __init__(self, context): + """Initialize a LogContext object + + :param context: logging context + :type name: str + """ + typecheck(context, "context", str) + self._name = context + self._data = PyLogContext(context) + + + @staticmethod + def from_pybind(logcontext): + """Initialize a LogContext object from + a PyLogContext object + + :param logcontext: The pybind PyLogContext object + to use for construction + :type logcontext: PyLogContext + :return: The newly constructor LogContext from + the PyLogContext + :rtype: LogContext + """ + typecheck(logcontext, "logcontext", PyLogContext) + new_logcontext = LogContext(logcontext._name) + new_logcontext.set_data(logcontext) + return new_logcontext + + @exception_handler + def get_data(self): + """Return the PyLogContext attribute + + :return: The PyLogContext attribute containing + the logcontext information + :rtype: PyLogContext + """ + return self._data + + @exception_handler + def set_data(self, logcontext): + """Set the PyLogContext attribute + + :param logcontext: The PyLogContext object + :type logcontext: PyLogContext + """ + typecheck(logcontext, "logcontext", PyLogContext) + self._data = logcontext diff --git a/src/python/module/smartredis/srobject.py b/src/python/module/smartredis/srobject.py new file mode 100644 index 000000000..1ed2acecc --- /dev/null +++ b/src/python/module/smartredis/srobject.py @@ -0,0 +1,79 @@ +# BSD 2-Clause License +# +# Copyright (c) 2021-2022, Hewlett Packard Enterprise +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +from .smartredisPy import PySRObject +from .util import exception_handler, typecheck + +from .error import * + +class SRObject: + def __init__(self, context): + """Initialize a SRObject object + + :param context: logging context + :type name: str + """ + typecheck(context, "context", str) + self._name = context + self._data = PySRObject(context) + + + @staticmethod + def from_pybind(srobject): + """Initialize a SRObject object from + a PySRObject object + + :param srobject: The pybind PySRObject object + to use for construction + :type srobject: PySRObject + :return: The newly constructor SRObject from + the PySRObject + :rtype: SRObject + """ + typecheck(srobject, "srobject", PySRObject) + new_srobject = SRObject(srobject._name) + new_srobject.set_data(srobject) + return new_srobject + + @exception_handler + def get_data(self): + """Return the PySRObject attribute + + :return: The PySRObject attribute containing + the srobject information + :rtype: PySRObject + """ + return self._data + + @exception_handler + def set_data(self, srobject): + """Set the PySRObject attribute + + :param srobject: The PySRObject object + :type srobject: PySRObject + """ + typecheck(srobject, "srobject", PySRObject) + self._data = srobject diff --git a/src/python/src/pydataset.cpp b/src/python/src/pydataset.cpp index 137c884be..308f6db69 100644 --- a/src/python/src/pydataset.cpp +++ b/src/python/src/pydataset.cpp @@ -38,7 +38,6 @@ namespace py = pybind11; PyDataset::PyDataset(const std::string& name) : PySRObject(name) { - log_data("PyDataset::PyDataset(const std::string& name)", LLInfo, "pydataset constructor (" + name + ")"); _dataset = NULL; try { _dataset = new DataSet(name); @@ -59,14 +58,9 @@ PyDataset::PyDataset(const std::string& name) } PyDataset::PyDataset(DataSet* dataset) - : PySRObject(dataset) + : PySRObject(dataset->get_context()) { - log_data("PyDataset::PyDataset(DataSet* dataset)", LLInfo, "pydataset constructor"); - if (_dataset != NULL) - _dataset->log_data(LLInfo, "pydataset getting overwritten"); _dataset = dataset; - if (_dataset != NULL) - _dataset->log_data(LLInfo, "pydataset overwritten"); } PyDataset::~PyDataset() diff --git a/src/python/src/pylogcontext.cpp b/src/python/src/pylogcontext.cpp index eb8e88815..f8af470be 100644 --- a/src/python/src/pylogcontext.cpp +++ b/src/python/src/pylogcontext.cpp @@ -58,7 +58,7 @@ PyLogContext::PyLogContext(const std::string& context) } PyLogContext::PyLogContext(LogContext* logcontext) - : PySRObject(logcontext) + : PySRObject(logcontext->get_context()) { _logcontext = logcontext; } From c836a1db4c181ad4a088b182c4cdc538e1590e42 Mon Sep 17 00:00:00 2001 From: billschereriii Date: Thu, 8 Dec 2022 18:45:34 -0600 Subject: [PATCH 32/37] Remove unneeded logging --- src/python/src/pydataset.cpp | 1 - src/python/src/pysrobject.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/src/python/src/pydataset.cpp b/src/python/src/pydataset.cpp index 308f6db69..10e274c68 100644 --- a/src/python/src/pydataset.cpp +++ b/src/python/src/pydataset.cpp @@ -66,7 +66,6 @@ PyDataset::PyDataset(DataSet* dataset) PyDataset::~PyDataset() { if (_dataset != NULL) { - _dataset->log_data(LLInfo, "pydataset destructor"); delete _dataset; _dataset = NULL; } diff --git a/src/python/src/pysrobject.cpp b/src/python/src/pysrobject.cpp index 2afb874ca..e8f6b3934 100644 --- a/src/python/src/pysrobject.cpp +++ b/src/python/src/pysrobject.cpp @@ -65,7 +65,6 @@ PySRObject::PySRObject(SRObject* srobject) PySRObject::~PySRObject() { if (_srobject != NULL) { - _srobject->log_data(LLInfo, "pysrobject destructor"); delete _srobject; _srobject = NULL; } From 894bd4061e6232e61a2dad8b9eb7137852963dd1 Mon Sep 17 00:00:00 2001 From: billschereriii Date: Thu, 8 Dec 2022 19:34:21 -0600 Subject: [PATCH 33/37] C tests work again --- CMakeLists.txt | 1 + include/c_logcontext.h | 66 ++++++++++++++++++ src/c/c_dataset.cpp | 2 +- src/c/c_logcontext.cpp | 95 +++++++++++++++++++++++++ tests/c/client_test_logging.c | 126 ++++++++++++++++++++++++++++------ 5 files changed, 269 insertions(+), 21 deletions(-) create mode 100644 include/c_logcontext.h create mode 100644 src/c/c_logcontext.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 40a9e331f..78b5c910a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,6 +59,7 @@ set(CLIENT_SRC src/c/c_client.cpp src/c/c_dataset.cpp src/c/c_error.cpp + src/c/c_logcontext.cpp src/cpp/address.cpp src/cpp/client.cpp src/cpp/dataset.cpp diff --git a/include/c_logcontext.h b/include/c_logcontext.h new file mode 100644 index 000000000..874d9d8cb --- /dev/null +++ b/include/c_logcontext.h @@ -0,0 +1,66 @@ + +/* + * BSD 2-Clause License + * + * Copyright (c) 2021-2022, Hewlett Packard Enterprise + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SMARTREDIS_C_LOGCONTEXT_H +#define SMARTREDIS_C_LOGCONTEXT_H +///@file +///\brief C-wrappers for the C++ LogContext class +#include "logcontext.h" +#include "sr_enums.h" +#include "srexception.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*! +* \brief C-LogContext constructor +* \param context Logging context (string to prefix log entries with) +* \param context_length The length of the context name string, +* excluding null terminating character +* \param new_logcontext Receives the new logcontext +* \return Returns SRNoError on success or an error code on failure +*/ +SRError SmartRedisCLogContext( + const char* context, + const size_t context_length, + void** new_logcontext); + +/*! +* \brief C-LogContext destructor +* \param logcontext A pointer to the logcontext to release. The logcontext +* is set to NULL on completion +* \return Returns SRNoError on success or an error code on failure +*/ +SRError DeallocateLogContext(void** logcontext); + +#ifdef __cplusplus +} +#endif +#endif //SMARTREDIS_C_LOGCONTEXT_H diff --git a/src/c/c_dataset.cpp b/src/c/c_dataset.cpp index 59d5c848f..6773a93e8 100644 --- a/src/c/c_dataset.cpp +++ b/src/c/c_dataset.cpp @@ -48,7 +48,7 @@ SRError CDataSet(const char* name, const size_t name_length, void** new_dataset) } catch (const std::bad_alloc& e) { *new_dataset = NULL; - SRSetLastError(SRBadAllocException("client allocation")); + SRSetLastError(SRBadAllocException("dataset allocation")); result = SRBadAllocError; } catch (const Exception& e) { diff --git a/src/c/c_logcontext.cpp b/src/c/c_logcontext.cpp new file mode 100644 index 000000000..ff5ac243a --- /dev/null +++ b/src/c/c_logcontext.cpp @@ -0,0 +1,95 @@ +/* + * BSD 2-Clause License + * + * Copyright (c) 2021-2022, Hewlett Packard Enterprise + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "c_logcontext.h" +#include "srexception.h" +#include "srassert.h" + +using namespace SmartRedis; + +// Create a new LogContext. +// The user is responsible for deallocating the LogContext +// via DeallocateeLogContext() +extern "C" +SRError SmartRedisCLogContext( + const char* context, + const size_t context_length, + void** new_logcontext) +{ + SRError result = SRNoError; + try { + // Sanity check params + SR_CHECK_PARAMS(context != NULL && new_logcontext != NULL); + + std::string context_str(context, context_length); + LogContext* logcontext = new LogContext(context_str); + *new_logcontext = reinterpret_cast(logcontext); + } + catch (const std::bad_alloc& e) { + *new_logcontext = NULL; + SRSetLastError(SRBadAllocException("logcontext allocation")); + result = SRBadAllocError; + } + catch (const Exception& e) { + *new_logcontext = NULL; + result = e.to_error_code(); + } + catch (...) { + *new_logcontext = NULL; + SRSetLastError(SRInternalException("Unknown exception occurred")); + result = SRInternalError; + } + + return result; +} + +// Deallocate a LogContext +extern "C" +SRError DeallocateLogContext(void** logcontext) +{ + SRError result = SRNoError; + try + { + // Sanity check params + SR_CHECK_PARAMS(logcontext != NULL); + + LogContext* lc = reinterpret_cast(*logcontext); + delete lc; + *logcontext = NULL; + } + catch (const Exception& e) { + SRSetLastError(e); + result = e.to_error_code(); + } + catch (...) { + SRSetLastError(SRInternalException("Unknown exception occurred")); + result = SRInternalError; + } + + return result; +} diff --git a/tests/c/client_test_logging.c b/tests/c/client_test_logging.c index 79651616d..58e5f54f6 100644 --- a/tests/c/client_test_logging.c +++ b/tests/c/client_test_logging.c @@ -28,6 +28,7 @@ #include "c_client.h" #include "c_dataset.h" +#include "c_logcontext.h" #include "c_client_test_utils.h" #include #include @@ -38,35 +39,120 @@ bool cluster = true; -#define TEST_LOG(logtype, loglevel, logmessage) \ -log_##logtype(loglevel, logmessage, strlen(logmessage)) +#define TEST_LOG(logtype, context, loglevel, logmessage) \ +log_##logtype(context, loglevel, logmessage, strlen(logmessage)) int main(int argc, char* argv[]) { int result = 0; - void *client = NULL; - const char* logger_name = "client_test_logging"; - size_t cid_len = strlen(logger_name); + void* client = NULL; + void* dataset = NULL; + void* logcontext = NULL; + const char* ctx_client = "client_test_logging (client)"; + const char* ctx_dataset = "client_test_logging (dataset)"; + const char* ctx_logcontext = "client_test_logging (logcontext)"; + size_t ctx_client_len = strlen(ctx_client); + size_t ctx_dataset_len = strlen(ctx_dataset); + size_t ctx_logcontext_len = strlen(ctx_logcontext); - // Initialize client - if (SRNoError != SmartRedisCClient(use_cluster(), logger_name, cid_len, &client) || NULL == client) + // Initialize client, dataset, logcontext + if (SRNoError != SmartRedisCClient( + use_cluster(), ctx_client, ctx_client_len, + &client) || NULL == client) { return -1; + } + if (SRNoError != CDataSet( + ctx_dataset, ctx_dataset_len, &dataset) || NULL == dataset) { + return -1; + } + if (SRNoError != SmartRedisCLogContext( + ctx_logcontext, ctx_logcontext_len, &logcontext) || NULL == logcontext) { + return -1; + } + + // Log stuff against a client + TEST_LOG(data, client, LLQuiet, + "This is data logged against the client at the Quiet level"); + TEST_LOG(data, client, LLInfo, + "This is data logged against the client at the Info level"); + TEST_LOG(data, client, LLDebug, + "This is data logged against the client at the Debug level"); + TEST_LOG(data, client, LLDeveloper, + "This is data logged against the client at the Developer level"); + + TEST_LOG(warning, client, LLQuiet, + "This is a warning logged against the client at the Quiet level"); + TEST_LOG(warning, client, LLInfo, + "This is a warning logged against the client at the Info level"); + TEST_LOG(warning, client, LLDebug, + "This is a warning logged against the client at the Debug level"); + TEST_LOG(warning, client, LLDeveloper, + "This is a warning logged against the client at the Developer level"); + + TEST_LOG(error, client, LLQuiet, + "This is an error logged against the client at the Quiet level"); + TEST_LOG(error, client, LLInfo, + "This is an error logged against the client at the Info level"); + TEST_LOG(error, client, LLDebug, + "This is an error logged against the client at the Debug level"); + TEST_LOG(error, client, LLDeveloper, + "This is an error logged against the client at the Developer level"); + + // Log stuff against a dataset + TEST_LOG(data, dataset, LLQuiet, + "This is data logged against the dataset at the Quiet level"); + TEST_LOG(data, dataset, LLInfo, + "This is data logged against the dataset at the Info level"); + TEST_LOG(data, dataset, LLDebug, + "This is data logged against the dataset at the Debug level"); + TEST_LOG(data, dataset, LLDeveloper, + "This is data logged against the dataset at the Developer level"); + + TEST_LOG(warning, dataset, LLQuiet, + "This is a warning logged against the dataset at the Quiet level"); + TEST_LOG(warning, dataset, LLInfo, + "This is a warning logged against the dataset at the Info level"); + TEST_LOG(warning, dataset, LLDebug, + "This is a warning logged against the dataset at the Debug level"); + TEST_LOG(warning, dataset, LLDeveloper, + "This is a warning logged against the dataset at the Developer level"); + + TEST_LOG(error, dataset, LLQuiet, + "This is an error logged against the dataset at the Quiet level"); + TEST_LOG(error, dataset, LLInfo, + "This is an error logged against the dataset at the Info level"); + TEST_LOG(error, dataset, LLDebug, + "This is an error logged against the dataset at the Debug level"); + TEST_LOG(error, dataset, LLDeveloper, + "This is an error logged against the dataset at the Developer level"); - // Log stuff - TEST_LOG(data, LLQuiet, "This is data logged at the Quiet level"); - TEST_LOG(data, LLInfo, "This is data logged at the Info level"); - TEST_LOG(data, LLDebug, "This is data logged at the Debug level"); - TEST_LOG(data, LLDeveloper, "This is data logged at the Developer level"); + // Log stuff against a logcontext + TEST_LOG(data, logcontext, LLQuiet, + "This is data logged against the logcontext at the Quiet level"); + TEST_LOG(data, logcontext, LLInfo, + "This is data logged against the logcontext at the Info level"); + TEST_LOG(data, logcontext, LLDebug, + "This is data logged against the logcontext at the Debug level"); + TEST_LOG(data, logcontext, LLDeveloper, + "This is data logged against the logcontext at the Developer level"); - TEST_LOG(warning, LLQuiet, "This is a warning logged at the Quiet level"); - TEST_LOG(warning, LLInfo, "This is a warning logged at the Info level"); - TEST_LOG(warning, LLDebug, "This is a warning logged at the Debug level"); - TEST_LOG(warning, LLDeveloper, "This is a warning logged at the Developer level"); + TEST_LOG(warning, logcontext, LLQuiet, + "This is a warning logged against the logcontext at the Quiet level"); + TEST_LOG(warning, logcontext, LLInfo, + "This is a warning logged against the logcontext at the Info level"); + TEST_LOG(warning, logcontext, LLDebug, + "This is a warning logged against the logcontext at the Debug level"); + TEST_LOG(warning, logcontext, LLDeveloper, + "This is a warning logged against the logcontext at the Developer level"); - TEST_LOG(error, LLQuiet, "This is an error logged at the Quiet level"); - TEST_LOG(error, LLInfo, "This is an error logged at the Info level"); - TEST_LOG(error, LLDebug, "This is an error logged at the Debug level"); - TEST_LOG(error, LLDeveloper, "This is an error logged at the Developer level"); + TEST_LOG(error, logcontext, LLQuiet, + "This is an error logged against the logcontext at the Quiet level"); + TEST_LOG(error, logcontext, LLInfo, + "This is an error logged against the logcontext at the Info level"); + TEST_LOG(error, logcontext, LLDebug, + "This is an error logged against the logcontext at the Debug level"); + TEST_LOG(error, logcontext, LLDeveloper, + "This is an error logged against the logcontexts at the Developer level"); // Done printf("Test passed: %s\n", result == 0 ? "YES" : "NO"); From dbd1d11f03eb9046a8f16fc1c2b5717c9eda859c Mon Sep 17 00:00:00 2001 From: billschereriii Date: Thu, 8 Dec 2022 20:35:12 -0600 Subject: [PATCH 34/37] Fortran interface for LogContext --- CMakeLists.txt | 7 +- src/fortran/logcontext.F90 | 73 +++++++++++++++++++ .../logcontext/logcontext_interfaces.inc | 37 ++++++++++ 3 files changed, 114 insertions(+), 3 deletions(-) create mode 100644 src/fortran/logcontext.F90 create mode 100644 src/fortran/logcontext/logcontext_interfaces.inc diff --git a/CMakeLists.txt b/CMakeLists.txt index 78b5c910a..82ec722e4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -100,11 +100,12 @@ include_directories(SYSTEM if (BUILD_FORTRAN) set(FORTRAN_SRC - src/fortran/fortran_c_interop.F90 - src/fortran/dataset.F90 src/fortran/client.F90 - src/fortran/logger.F90 + src/fortran/dataset.F90 src/fortran/errors.F90 + src/fortran/fortran_c_interop.F90 + src/fortran/logcontext.F90 + src/fortran/logger.F90 ) include_directories(src/fortran) # Note the following has to be before ANY add_library command) diff --git a/src/fortran/logcontext.F90 b/src/fortran/logcontext.F90 new file mode 100644 index 000000000..12c44632c --- /dev/null +++ b/src/fortran/logcontext.F90 @@ -0,0 +1,73 @@ +! BSD 2-Clause License +! +! Copyright (c) 2021-2022, Hewlett Packard Enterprise +! All rights reserved. +! +! Redistribution and use in source and binary forms, with or without +! modification, are permitted provided that the following conditions are met: +! +! 1. Redistributions of source code must retain the above copyright notice, this +! list of conditions and the following disclaimer. +! +! 2. Redistributions in binary form must reproduce the above copyright notice, +! this list of conditions and the following disclaimer in the documentation +! and/or other materials provided with the distribution. +! +! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +! DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +! FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +! DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +! SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +! OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +module smartredis_logcontext + +use iso_c_binding, only : c_ptr, c_null_ptr, c_char, c_int, c_size_t +use iso_c_binding, only : c_loc, c_f_pointer +use fortran_c_interop, only : enum_kind + +implicit none; private + +include 'enum_fortran.inc' +include 'logcontext/logcontext_interfaces.inc' + +public :: enum_kind !< The kind of integer equivalent to a C enum. According to C an Fortran + !! standards this should be c_int, but is renamed here to ensure that + !! users do not have to import the iso_c_binding module into their + !! programs + +!> Contains a context against to emit log messages +type, public :: logcontext_type + type(c_ptr) :: logcontext_ptr !< A pointer to the initialized logcontext object + + contains + + !> Initialize a new dataset with a given name + procedure :: initialize => initialize_logcontext + +end type logcontext_type + +contains + + +!> Initialize the logcontext +function initialize_logcontext(self, context) result(code) + class(logcontext_type), intent(inout) :: self !< Receives the logcontext + character(len=*), intent(in) :: context !< Context for the logcontext + integer(kind=enum_kind) :: code !< Result of the operation + + ! Local variables + integer(kind=c_size_t) :: context_length + character(kind=c_char, len=len_trim(context)) :: c_context + + context_length = len_trim(context) + c_context = trim(context) + + code = logcontext_constructor(c_context, context_length, self%logcontext_ptr) +end function initialize_logcontext + +end module smartredis_logcontext diff --git a/src/fortran/logcontext/logcontext_interfaces.inc b/src/fortran/logcontext/logcontext_interfaces.inc new file mode 100644 index 000000000..463c71ccc --- /dev/null +++ b/src/fortran/logcontext/logcontext_interfaces.inc @@ -0,0 +1,37 @@ +! BSD 2-Clause License +! +! Copyright (c) 2021-2022, Hewlett Packard Enterprise +! All rights reserved. +! +! Redistribution and use in source and binary forms, with or without +! modification, are permitted provided that the following conditions are met: +! +! 1. Redistributions of source code must retain the above copyright notice, this +! list of conditions and the following disclaimer. +! +! 2. Redistributions in binary form must reproduce the above copyright notice, +! this list of conditions and the following disclaimer in the documentation +! and/or other materials provided with the distribution. +! +! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +! DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +! FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +! DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +! SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +! OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +interface + function logcontext_constructor( context, context_length, logcontext ) & + bind(c, name="SmartRedisCLogContext") + use iso_c_binding, only : c_ptr, c_char, c_size_t + import :: enum_kind + integer(kind=enum_kind) :: logcontext_constructor + character(kind=c_char) :: context !< Context for logging + integer(kind=c_size_t), value :: context_length !< How many characters in context + type(c_ptr) :: logcontext !< Receives the constructed logcontext + end function logcontext_constructor +end interface From ca12f0ed6553d67930ca68aed497eab027aafca6 Mon Sep 17 00:00:00 2001 From: billschereriii Date: Thu, 8 Dec 2022 23:27:44 -0600 Subject: [PATCH 35/37] Fortran logging works now --- include/logcontext.h | 5 +- src/fortran/client.F90 | 9 ++ src/fortran/dataset.F90 | 9 ++ src/fortran/logcontext.F90 | 10 +- src/fortran/logger.F90 | 160 +++++++++++++++++++++-- src/fortran/logger/logger_interfaces.inc | 9 +- tests/fortran/client_test_logging.F90 | 119 ++++++++++++++--- 7 files changed, 284 insertions(+), 37 deletions(-) diff --git a/include/logcontext.h b/include/logcontext.h index 8098cc9ba..aa94be809 100644 --- a/include/logcontext.h +++ b/include/logcontext.h @@ -50,7 +50,10 @@ class LogContext : public SRObject * when logging with this as a context */ LogContext(const std::string& logging_name) - : SRObject(logging_name) {} + : SRObject(logging_name) + { + log_data(LLDebug, "New LogContext created"); + } /*! * \brief LogContext default destructor diff --git a/src/fortran/client.F90 b/src/fortran/client.F90 index 62ccea93c..28635f1ca 100644 --- a/src/fortran/client.F90 +++ b/src/fortran/client.F90 @@ -79,6 +79,8 @@ module smartredis_client procedure :: isinitialized !> Destructs a new instance of the SmartRedis client procedure :: destructor + !> Access the raw C pointer for the client + procedure :: get_c_pointer !> Check the database for the existence of a specific model procedure :: model_exists !> Check the database for the existence of a specific tensor @@ -273,6 +275,13 @@ function destructor(self) self%client_ptr = C_NULL_PTR end function destructor +!> Access the raw C pointer for the client +function get_c_pointer(self) + type(c_ptr) :: get_c_pointer + class(client_type), intent(in) :: self + get_c_pointer = self%client_ptr +end function get_c_pointer + !> Check if the specified key exists in the database function key_exists(self, key, exists) class(client_type), intent(in) :: self !< The client diff --git a/src/fortran/dataset.F90 b/src/fortran/dataset.F90 index aa19bd5d9..be489279b 100644 --- a/src/fortran/dataset.F90 +++ b/src/fortran/dataset.F90 @@ -52,6 +52,8 @@ module smartredis_dataset !> Initialize a new dataset with a given name procedure :: initialize => initialize_dataset + !> Access the raw C pointer for the client + procedure :: get_c_pointer !> Add metadata to the dataset with a given field and string procedure :: add_meta_string ! procedure :: get_meta_strings ! Not supported currently @@ -110,6 +112,13 @@ function initialize_dataset(self, name) result(code) code = dataset_constructor(c_name, name_length, self%dataset_ptr) end function initialize_dataset +!> Access the raw C pointer for the dataset +function get_c_pointer(self) + type(c_ptr) :: get_c_pointer + class(dataset_type), intent(in) :: self + get_c_pointer = self%dataset_ptr +end function get_c_pointer + !> Add a tensor to a dataset whose Fortran type is the equivalent 'int8' C-type function add_tensor_i8(self, name, data, dims) result(code) integer(kind=c_int8_t), dimension(..), target, intent(in) :: data !< Data to be sent diff --git a/src/fortran/logcontext.F90 b/src/fortran/logcontext.F90 index 12c44632c..a9488457f 100644 --- a/src/fortran/logcontext.F90 +++ b/src/fortran/logcontext.F90 @@ -48,12 +48,13 @@ module smartredis_logcontext !> Initialize a new dataset with a given name procedure :: initialize => initialize_logcontext + !> Access the raw C pointer for the client + procedure :: get_c_pointer end type logcontext_type contains - !> Initialize the logcontext function initialize_logcontext(self, context) result(code) class(logcontext_type), intent(inout) :: self !< Receives the logcontext @@ -70,4 +71,11 @@ function initialize_logcontext(self, context) result(code) code = logcontext_constructor(c_context, context_length, self%logcontext_ptr) end function initialize_logcontext +!> Access the raw C pointer for the logcontext +function get_c_pointer(self) + type(c_ptr) :: get_c_pointer + class(logcontext_type), intent(in) :: self + get_c_pointer = self%logcontext_ptr +end function get_c_pointer + end module smartredis_logcontext diff --git a/src/fortran/logger.F90 b/src/fortran/logger.F90 index 8a7de2e78..27d5752a0 100644 --- a/src/fortran/logger.F90 +++ b/src/fortran/logger.F90 @@ -32,11 +32,27 @@ module smartredis_logger use fortran_c_interop, only : convert_char_array_to_c, enum_kind, C_MAX_STRING use, intrinsic :: iso_fortran_env, only: stderr => error_unit +use smartredis_client, only : client_type +use smartredis_dataset, only : dataset_type +use smartredis_logcontext, only : logcontext_type + implicit none; private #include "enum_fortran.inc" #include "logger/logger_interfaces.inc" +interface log_data + module procedure log_data_client, log_data_dataset, log_data_logcontext +end interface log_data + +interface log_warning + module procedure log_warning_client, log_warning_dataset, log_warning_logcontext +end interface log_warning + +interface log_error + module procedure log_error_client, log_error_dataset, log_error_logcontext +end interface log_error + public :: enum_kind !< The kind of integer equivalent to a C enum. According to C an Fortran !! standards this should be c_int, but is renamed here to ensure that !! users do not have to import the iso_c_binding module into their @@ -46,8 +62,126 @@ module smartredis_logger contains -!> Log data to the SmartRedis log -subroutine log_data(level, data) +! log_data overloads +! ================== + +!> Log data to the SmartRedis log against a Client object +subroutine log_data_client(context, level, data) + type(client_type), intent(in) :: context + integer (kind=enum_kind), intent(in) :: level !< Minimum logging level to log the data at + character(len=*), intent(in) :: data !< Data to be logged + + ! Local variables + character(kind=c_char, len=:), allocatable :: c_data + integer(kind=c_size_t) :: c_data_length + + allocate(character(kind=c_char, len=len_trim(data)) :: c_data) + c_data = data + c_data_length = len_trim(data) + + call c_log_data(context%get_c_pointer(), level, c_data, c_data_length) + deallocate(c_data) +end subroutine log_data_client + +!> Log data to the SmartRedis log against a Dataset object +subroutine log_data_dataset(context, level, data) + type(dataset_type), intent(in) :: context + integer (kind=enum_kind), intent(in) :: level !< Minimum logging level to log the data at + character(len=*), intent(in) :: data !< Data to be logged + + ! Local variables + character(kind=c_char, len=:), allocatable :: c_data + integer(kind=c_size_t) :: c_data_length + + allocate(character(kind=c_char, len=len_trim(data)) :: c_data) + c_data = data + c_data_length = len_trim(data) + + call c_log_data(context%get_c_pointer(), level, c_data, c_data_length) + deallocate(c_data) +end subroutine log_data_dataset + +!> Log data to the SmartRedis log against a Logcontext object +subroutine log_data_logcontext(context, level, data) + type(logcontext_type), intent(in) :: context + integer (kind=enum_kind), intent(in) :: level !< Minimum logging level to log the data at + character(len=*), intent(in) :: data !< Data to be logged + + ! Local variables + character(kind=c_char, len=:), allocatable :: c_data + integer(kind=c_size_t) :: c_data_length + + allocate(character(kind=c_char, len=len_trim(data)) :: c_data) + c_data = data + c_data_length = len_trim(data) + + call c_log_data(context%get_c_pointer(), level, c_data, c_data_length) + deallocate(c_data) +end subroutine log_data_logcontext + +! log_warning overloads +! ===================== + +!> Log a warning to the SmartRedis log against a Client object +subroutine log_warning_client(context, level, data) + type(client_type), intent(in) :: context + integer (kind=enum_kind), intent(in) :: level !< Minimum logging level to log the data at + character(len=*), intent(in) :: data !< Data to be logged + + ! Local variables + character(kind=c_char, len=:), allocatable :: c_data + integer(kind=c_size_t) :: c_data_length + + allocate(character(kind=c_char, len=len_trim(data)) :: c_data) + c_data = data + c_data_length = len_trim(data) + + call c_log_warning(context%get_c_pointer(), level, c_data, c_data_length) + deallocate(c_data) +end subroutine log_warning_client + +!> Log a warning to the SmartRedis log against a Dataset object +subroutine log_warning_dataset(context, level, data) + type(dataset_type), intent(in) :: context + integer (kind=enum_kind), intent(in) :: level !< Minimum logging level to log the data at + character(len=*), intent(in) :: data !< Data to be logged + + ! Local variables + character(kind=c_char, len=:), allocatable :: c_data + integer(kind=c_size_t) :: c_data_length + + allocate(character(kind=c_char, len=len_trim(data)) :: c_data) + c_data = data + c_data_length = len_trim(data) + + call c_log_warning(context%get_c_pointer(), level, c_data, c_data_length) + deallocate(c_data) +end subroutine log_warning_dataset + +!> Log a warning to the SmartRedis log against a LogContext object +subroutine log_warning_logcontext(context, level, data) + type(logcontext_type), intent(in) :: context + integer (kind=enum_kind), intent(in) :: level !< Minimum logging level to log the data at + character(len=*), intent(in) :: data !< Data to be logged + + ! Local variables + character(kind=c_char, len=:), allocatable :: c_data + integer(kind=c_size_t) :: c_data_length + + allocate(character(kind=c_char, len=len_trim(data)) :: c_data) + c_data = data + c_data_length = len_trim(data) + + call c_log_warning(context%get_c_pointer(), level, c_data, c_data_length) + deallocate(c_data) +end subroutine log_warning_logcontext + +! log_error overloads +! =================== + +!> Log an error to the SmartRedis log against a Client object +subroutine log_error_client(context, level, data) + type(client_type), intent(in) :: context integer (kind=enum_kind), intent(in) :: level !< Minimum logging level to log the data at character(len=*), intent(in) :: data !< Data to be logged @@ -59,12 +193,13 @@ subroutine log_data(level, data) c_data = data c_data_length = len_trim(data) - call c_log_data(level, c_data, c_data_length) + call c_log_error(context%get_c_pointer(), level, c_data, c_data_length) deallocate(c_data) -end subroutine log_data +end subroutine log_error_client -!> Log a warning to the SmartRedis log -subroutine log_warning(level, data) +!> Log an error to the SmartRedis log against a Dataset object +subroutine log_error_dataset(context, level, data) + type(dataset_type), intent(in) :: context integer (kind=enum_kind), intent(in) :: level !< Minimum logging level to log the data at character(len=*), intent(in) :: data !< Data to be logged @@ -76,12 +211,13 @@ subroutine log_warning(level, data) c_data = data c_data_length = len_trim(data) - call c_log_warning(level, c_data, c_data_length) + call c_log_error(context%get_c_pointer(), level, c_data, c_data_length) deallocate(c_data) -end subroutine log_warning +end subroutine log_error_dataset -!> Log an error to the SmartRedis log -subroutine log_error(level, data) +!> Log an error to the SmartRedis log against a LogContext object +subroutine log_error_logcontext(context, level, data) + type(logcontext_type), intent(in) :: context integer (kind=enum_kind), intent(in) :: level !< Minimum logging level to log the data at character(len=*), intent(in) :: data !< Data to be logged @@ -93,9 +229,9 @@ subroutine log_error(level, data) c_data = data c_data_length = len_trim(data) - call c_log_error(level, c_data, c_data_length) + call c_log_error(context%get_c_pointer(), level, c_data, c_data_length) deallocate(c_data) -end subroutine log_error +end subroutine log_error_logcontext end module smartredis_logger diff --git a/src/fortran/logger/logger_interfaces.inc b/src/fortran/logger/logger_interfaces.inc index 04dfd29de..0c6ae2843 100644 --- a/src/fortran/logger/logger_interfaces.inc +++ b/src/fortran/logger/logger_interfaces.inc @@ -25,9 +25,10 @@ ! OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. interface - subroutine c_log_data(level, data, data_length) bind(c, name="log_data_noexcept") + subroutine c_log_data(context, level, data, data_length) bind(c, name="log_data_noexcept") use iso_c_binding, only : c_ptr, c_char, c_size_t import :: enum_kind + type(c_ptr), value :: context integer(kind=enum_kind), value :: level character(kind=c_char) :: data(*) integer(kind=c_size_t), value :: data_length @@ -35,9 +36,10 @@ interface end interface interface - subroutine c_log_warning(level, data, data_length) bind(c, name="log_warning_noexcept") + subroutine c_log_warning(context, level, data, data_length) bind(c, name="log_warning_noexcept") use iso_c_binding, only : c_ptr, c_char, c_size_t import :: enum_kind + type(c_ptr), value :: context integer(kind=enum_kind), value :: level character(kind=c_char) :: data(*) integer(kind=c_size_t), value :: data_length @@ -45,9 +47,10 @@ interface end interface interface - subroutine c_log_error(level, data, data_length) bind(c, name="log_error_noexcept") + subroutine c_log_error(context, level, data, data_length) bind(c, name="log_error_noexcept") use iso_c_binding, only : c_ptr, c_char, c_size_t import :: enum_kind + type(c_ptr), value :: context integer(kind=enum_kind), value :: level character(kind=c_char) :: data(*) integer(kind=c_size_t), value :: data_length diff --git a/tests/fortran/client_test_logging.F90 b/tests/fortran/client_test_logging.F90 index d80608079..7ce1e3903 100644 --- a/tests/fortran/client_test_logging.F90 +++ b/tests/fortran/client_test_logging.F90 @@ -26,6 +26,8 @@ program main use smartredis_client, only : client_type + use smartredis_dataset, only : dataset_type + use smartredis_logcontext, only : logcontext_type use smartredis_logger, only : log_data, log_warning, log_error use test_utils, only : use_cluster use iso_fortran_env, only : STDERR => error_unit @@ -36,28 +38,105 @@ program main #include "enum_fortran.inc" - type(client_type) :: client - integer :: result + type(client_type) :: client + type(dataset_type) :: dataset + type(logcontext_type) :: logcontext + integer :: result - result = client%initialize(use_cluster(), "client_test_logging") + result = logcontext%initialize("client_test_logging (logcontext)") + if (result .ne. SRNoError) error stop + result = client%initialize(use_cluster(), "client_test_logging (client)") + if (result .ne. SRNoError) error stop + result = dataset%initialize("client_test_logging (dataset)") if (result .ne. SRNoError) error stop - call log_data(LLQuiet, "This is data logged at the Quiet level") - call log_data(LLInfo, "This is data logged at the Info level") - call log_data(LLDebug, "This is data logged at the Debug level") - call log_data(LLDeveloper, & - "This is data logged at the Developer level") - - call log_warning(LLQuiet, "This is a warning logged at the Quiet level") - call log_warning(LLInfo, "This is a warning logged at the Info level") - call log_warning(LLDebug, "This is a warning logged at the Debug level") - call log_warning(LLDeveloper, & - "This is a warning logged at the Developer level") - write(*,*) "client logging: passed" + ! Logging against the Client + ! ========================== + call log_data(client, LLQuiet, & + "This is data logged against the Client at the Quiet level") + call log_data(client, LLInfo, & + "This is data logged against the Client at the Info level") + call log_data(client, LLDebug, & + "This is data logged against the Client at the Debug level") + call log_data(client, LLDeveloper, & + "This is data logged against the Client at the Developer level") + + call log_warning(client, LLQuiet, & + "This is a warning logged against the Client at the Quiet level") + call log_warning(client, LLInfo, & + "This is a warning logged against the Client at the Info level") + call log_warning(client, LLDebug, & + "This is a warning logged against the Client at the Debug level") + call log_warning(client, LLDeveloper, & + "This is a warning logged against the Client at the Developer level") + + call log_error(client, LLQuiet, & + "This is an error logged against the Client at the Quiet level") + call log_error(client, LLInfo, & + "This is an error logged against the Client at the Info level") + call log_error(client, LLDebug, & + "This is an error logged against the Client at the Debug level") + call log_error(client, LLDeveloper, & + "This is an error logged against the Client at the Developer level") + + ! Logging against the Dataset + ! =========================== + call log_data(dataset, LLQuiet, & + "This is data logged against the Dataset at the Quiet level") + call log_data(dataset, LLInfo, & + "This is data logged against the Dataset at the Info level") + call log_data(dataset, LLDebug, & + "This is data logged against the Dataset at the Debug level") + call log_data(dataset, LLDeveloper, & + "This is data logged against the Dataset at the Developer level") - call log_error(LLQuiet, "This is an error logged at the Quiet level") - call log_error(LLInfo, "This is an error logged at the Info level") - call log_error(LLDebug, "This is an error logged at the Debug level") - call log_error(LLDeveloper, & - "This is an error logged at the Developer level") + call log_warning(dataset, LLQuiet, & + "This is a warning logged against the Dataset at the Quiet level") + call log_warning(dataset, LLInfo, & + "This is a warning logged against the Dataset at the Info level") + call log_warning(dataset, LLDebug, & + "This is a warning logged against the Dataset at the Debug level") + call log_warning(dataset, LLDeveloper, & + "This is a warning logged against the Dataset at the Developer level") + + call log_error(dataset, LLQuiet, & + "This is an error logged against the Dataset at the Quiet level") + call log_error(dataset, LLInfo, & + "This is an error logged against the Dataset at the Info level") + call log_error(dataset, LLDebug, & + "This is an error logged against the Dataset at the Debug level") + call log_error(dataset, LLDeveloper, & + "This is an error logged against the Dataset at the Developer level") + + ! Logging against the LogContext + ! ============================== + call log_data(logcontext, LLQuiet, & + "This is data logged against the LogContext at the Quiet level") + call log_data(logcontext, LLInfo, & + "This is data logged against the LogContext at the Info level") + call log_data(logcontext, LLDebug, & + "This is data logged against the LogContext at the Debug level") + call log_data(logcontext, LLDeveloper, & + "This is data logged against the LogContext at the Developer level") + + call log_warning(logcontext, LLQuiet, & + "This is a warning logged against the LogContext at the Quiet level") + call log_warning(logcontext, LLInfo, & + "This is a warning logged against the LogContext at the Info level") + call log_warning(logcontext, LLDebug, & + "This is a warning logged against the LogContext at the Debug level") + call log_warning(logcontext, LLDeveloper, & + "This is a warning logged against the LogContext at the Developer level") + + call log_error(logcontext, LLQuiet, & + "This is an error logged against the LogContext at the Quiet level") + call log_error(logcontext, LLInfo, & + "This is an error logged against the LogContext at the Info level") + call log_error(logcontext, LLDebug, & + "This is an error logged against the LogContext at the Debug level") + call log_error(logcontext, LLDeveloper, & + "This is an error logged against the LogContext at the Developer level") + + ! Done + write(*,*) "client logging: passed" end program main From 3ffbe06dec205314480ba27c8b3e9562ac4ea39a Mon Sep 17 00:00:00 2001 From: billschereriii Date: Wed, 14 Dec 2022 13:53:07 -0600 Subject: [PATCH 36/37] Eliminate hard-coded string lengths --- src/fortran/client.F90 | 8 ++++---- src/python/module/smartredis/__init__.py | 4 ++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/fortran/client.F90 b/src/fortran/client.F90 index 28635f1ca..8d1eab232 100644 --- a/src/fortran/client.F90 +++ b/src/fortran/client.F90 @@ -245,13 +245,13 @@ function initialize_client(self, cluster, logger_name) integer(kind=c_size_t) :: logger_name_length if (present(logger_name)) then - allocate(character(kind=c_char, len=len_trim(logger_name)) :: c_logger_name) - c_logger_name = logger_name logger_name_length = len_trim(logger_name) + allocate(character(kind=c_char, len=logger_name_length) :: c_logger_name) + c_logger_name = logger_name else - allocate(character(kind=c_char, len=10) :: c_logger_name) + logger_name_length = len_trim(c_logger_name) + allocate(character(kind=c_char, len=logger_name_length) :: c_logger_name) c_logger_name = 'default' - logger_name_length = 8 endif if (present(cluster)) self%cluster = cluster diff --git a/src/python/module/smartredis/__init__.py b/src/python/module/smartredis/__init__.py index 63e2b8c59..0fc804c6b 100644 --- a/src/python/module/smartredis/__init__.py +++ b/src/python/module/smartredis/__init__.py @@ -27,6 +27,8 @@ __all__ = [ "Client", "Dataset", + "SRObject", + "LogContext", "DatasetConverter", "log_data", "log_warning", @@ -43,6 +45,8 @@ from .logger import ( log_data, log_warning, log_error ) +from .srobject import SRObject +from .logcontext import LogContext from .smartredisPy import ( LLQuiet, LLInfo, LLDebug, LLDeveloper ) From 79b78ec1304ef27900b2acf1506ff37491fd83cc Mon Sep 17 00:00:00 2001 From: billschereriii Date: Wed, 14 Dec 2022 14:28:46 -0600 Subject: [PATCH 37/37] Cleaner way to handle default logger_name --- src/fortran/client.F90 | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/fortran/client.F90 b/src/fortran/client.F90 index 8d1eab232..e56715c75 100644 --- a/src/fortran/client.F90 +++ b/src/fortran/client.F90 @@ -245,14 +245,11 @@ function initialize_client(self, cluster, logger_name) integer(kind=c_size_t) :: logger_name_length if (present(logger_name)) then - logger_name_length = len_trim(logger_name) - allocate(character(kind=c_char, len=logger_name_length) :: c_logger_name) c_logger_name = logger_name else - logger_name_length = len_trim(c_logger_name) - allocate(character(kind=c_char, len=logger_name_length) :: c_logger_name) c_logger_name = 'default' endif + logger_name_length = len_trim(c_logger_name) if (present(cluster)) self%cluster = cluster initialize_client = c_constructor(self%cluster, c_logger_name, logger_name_length, self%client_ptr)