diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e945f6bf6a6972769ec5f984ecef778c272d74f..d5116a8964ed2795be526964117eb7c270994fd0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,10 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### New +- Support for client-side per process logging, activated + with `LIBGKFS_LOG_PER_PROCESS` ([!179](https://storage.bsc.es/gitlab/hpc/gekkofs/-/merge_requests/179)). +- Support mtime with option gkfs::config::metadata:: + use_mtime ([!178](https://storage.bsc.es/gitlab/hpc/gekkofs/-/merge_requests/178)) - Additional tests to increase code coverage ([!141](https://storage.bsc.es/gitlab/hpc/gekkofs/-/merge_requests/141)). - GKFS_ENABLE_UNUSED_FUNCTIONS added to disable code to increase code coverage. ([!141](https://storage.bsc.es/gitlab/hpc/gekkofs/-/merge_requests/141)). diff --git a/README.md b/README.md index 6f571eff69a818ce00c1c4ecfb64a9f6876bb9ba..4efc85273a166bc7adb4682646ef398c9c7c9f19 100644 --- a/README.md +++ b/README.md @@ -200,7 +200,8 @@ usage: gkfs [-h/--help] [-r/--rootdir ] [-m/--mountdir ] [-a/--args The following environment variables can be used to enable logging in the client library: `LIBGKFS_LOG=` and `LIBGKFS_LOG_OUTPUT=` to configure the output module and set the path to the log file of the client library. If not path is specified in `LIBGKFS_LOG_OUTPUT`, the client library will send log messages -to `/tmp/gkfs_client.log`. +to `/tmp/gkfs_client.log`. Use `LIBGKFS_LOG_PER_PROCESS=ON` to write separate logs per client process. +When enabled, the path specified with `LIBGKFS_LOG_OUTPUT=` is used as a directory. The following modules are available: diff --git a/docs/sphinx/users/running.md b/docs/sphinx/users/running.md index dff987d911cb3c3f0d72e3250e148e36e7e13f01..fa52e02ddb40e9e38bf660d7cb0bae593fb090f1 100644 --- a/docs/sphinx/users/running.md +++ b/docs/sphinx/users/running.md @@ -180,7 +180,8 @@ usage: gkfs [-h/--help] [-r/--rootdir ] [-m/--mountdir ] [-a/--args The following environment variables can be used to enable logging in the client library: `LIBGKFS_LOG=` and `LIBGKFS_LOG_OUTPUT=` to configure the output module and set the path to the log file of the client library. If not path is specified in `LIBGKFS_LOG_OUTPUT`, the client library will send log messages -to `/tmp/gkfs_client.log`. +to `/tmp/gkfs_client.log`. Use `LIBGKFS_LOG_PER_PROCESS=ON` to write separate logs per client process. +When enabled, the path specified with `LIBGKFS_LOG_OUTPUT=` is used as a directory. The following modules are available: @@ -216,4 +217,4 @@ the logging subsystem to truncate the file used for logging, rather than append For the daemon, the `GKFS_DAEMON_LOG_PATH=` environment variable can be provided to set the path to the log file, and the log module can be selected with the `GKFS_DAEMON_LOG_LEVEL={off,critical,err,warn,info,debug,trace}` -environment variable whereas `trace` produces the most trace records while `info` is the default value. \ No newline at end of file +environment variable whereas `trace` produces the most trace records while `info` is the default value. diff --git a/include/client/env.hpp b/include/client/env.hpp index c35ae1ad30a857ac037d593dba1cba979c08b787..2a58ecf81b5b6e22b59cd1830bb859864c684407 100644 --- a/include/client/env.hpp +++ b/include/client/env.hpp @@ -45,6 +45,7 @@ static constexpr auto LOG_SYSCALL_FILTER = ADD_PREFIX("LOG_SYSCALL_FILTER"); #endif static constexpr auto LOG_OUTPUT = ADD_PREFIX("LOG_OUTPUT"); +static constexpr auto LOG_PER_PROCESS = ADD_PREFIX("LOG_PER_PROCESS"); static constexpr auto LOG_OUTPUT_TRUNC = ADD_PREFIX("LOG_OUTPUT_TRUNC"); static constexpr auto CWD = ADD_PREFIX("CWD"); static constexpr auto HOSTS_FILE = ADD_PREFIX("HOSTS_FILE"); diff --git a/include/client/logging.hpp b/include/client/logging.hpp index ee570542f7578f8aee4ba16c81f150a203f315f6..8a7196a56ca2c188f1c499a74dee95a26f95a653 100644 --- a/include/client/logging.hpp +++ b/include/client/logging.hpp @@ -273,7 +273,8 @@ protected: struct logger { - logger(const std::string& opts, const std::string& path, bool trunc + logger(const std::string& opts, const std::string& path, + bool log_per_process, bool trunc #ifdef GKFS_DEBUG_BUILD , const std::string& filter, int verbosity @@ -293,7 +294,7 @@ struct logger { static_buffer buffer; detail::format_timestamp_to(buffer, timezone_); - fmt::format_to(buffer, "[{}] [{}] ", ::syscall_no_intercept(SYS_gettid), + fmt::format_to(buffer, "[{}] [{}] ", log_process_id_, lookup_level_name(level)); if(!!(level & log::debug)) { @@ -336,7 +337,7 @@ struct logger { static_buffer prefix; detail::format_timestamp_to(prefix); - fmt::format_to(prefix, "[{}] [{}] ", ::syscall_no_intercept(SYS_gettid), + fmt::format_to(prefix, "[{}] [{}] ", log_process_id_, lookup_level_name(level)); char buffer[max_buffer_size]; @@ -402,6 +403,7 @@ struct logger { } int log_fd_; + int log_process_id_; log_level log_mask_; #ifdef GKFS_DEBUG_BUILD diff --git a/src/client/logging.cpp b/src/client/logging.cpp index 2f060053ccc99387d0cc1790951d8036b3be3ca0..274844b788c1fe9eb3cfde04605eb5425c8c5950 100644 --- a/src/client/logging.cpp +++ b/src/client/logging.cpp @@ -31,6 +31,7 @@ #include #include #include +#include extern "C" { #include @@ -43,6 +44,8 @@ extern "C" { #endif +namespace fs = std::filesystem; + namespace { enum class split_str_mode { is_any_of, @@ -280,7 +283,8 @@ process_log_filter(const std::string& log_filter) { #endif // GKFS_DEBUG_BUILD -logger::logger(const std::string& opts, const std::string& path, bool trunc +logger::logger(const std::string& opts, const std::string& path, + bool log_per_process, bool trunc #ifdef GKFS_DEBUG_BUILD , const std::string& filter, int verbosity @@ -290,6 +294,7 @@ logger::logger(const std::string& opts, const std::string& path, bool trunc /* use stderr by default */ log_fd_ = 2; + log_process_id_ = ::syscall_no_intercept(SYS_gettid); log_mask_ = process_log_options(opts); #ifdef GKFS_DEBUG_BUILD @@ -304,11 +309,20 @@ logger::logger(const std::string& opts, const std::string& path, bool trunc flags &= ~O_TRUNC; } + std::string file_path = path; + if(log_per_process) { + if(fs::is_regular_file(file_path) && fs::exists(file_path)) { + fs::remove(file_path); + } + fs::create_directories(path); + file_path = fmt::format("{}/{}", path, log_process_id_); + } + // we use ::open() here rather than ::syscall_no_intercept(SYS_open) // because we want the call to be intercepted by our hooks, which // allows us to categorize the resulting fd as 'internal' and // relocate it to our private range - int fd = ::open(path.c_str(), flags, 0600); + int fd = ::open(file_path.c_str(), flags, 0600); if(fd == -1) { log(gkfs::log::error, __func__, __LINE__, diff --git a/src/client/preload_context.cpp b/src/client/preload_context.cpp index f8ac782fe6979f6c7a5c6e7dabf465aa8668c77a..0cc523f9e371bed1fc50f4e0c6f277ee705656d6 100644 --- a/src/client/preload_context.cpp +++ b/src/client/preload_context.cpp @@ -76,6 +76,10 @@ PreloadContext::init_logging() { const std::string log_output = gkfs::env::get_var( gkfs::env::LOG_OUTPUT, gkfs::config::log::client_log_path); + const bool log_per_process = + gkfs::env::get_var(gkfs::env::LOG_PER_PROCESS).empty() ? false + : true; + #ifdef GKFS_DEBUG_BUILD // atoi returns 0 if no int conversion can be performed, which works // for us since if the user provides a non-numeric value we can just treat @@ -92,7 +96,8 @@ PreloadContext::init_logging() { const bool log_trunc = (!trunc_val.empty() && trunc_val[0] != '0'); - gkfs::log::create_global_logger(log_opts, log_output, log_trunc + gkfs::log::create_global_logger(log_opts, log_output, log_per_process, + log_trunc #ifdef GKFS_DEBUG_BUILD , log_filter, log_verbosity