diff --git a/capio/common/constants.hpp b/capio/common/constants.hpp index 3a230f4bc..e775dfd81 100644 --- a/capio/common/constants.hpp +++ b/capio/common/constants.hpp @@ -68,7 +68,7 @@ constexpr char CAPIO_SHM_OPEN_ERROR[] = // CAPIO logger - POSIX constexpr char CAPIO_LOG_POSIX_DEFAULT_LOG_FILE_PREFIX[] = "posix_thread_\0"; -constexpr char CAPIO_LOG_POSIX_SYSCALL_START[] = "\n+++++++++ SYSCALL %s (%d) +++++++++"; +constexpr char CAPIO_LOG_POSIX_SYSCALL_START[] = "\n+++++++++ START SYSCALL +++++++++"; constexpr char CAPIO_LOG_POSIX_SYSCALL_END[] = "~~~~~~~~~ END SYSCALL ~~~~~~~~~\n"; // CAPIO logger - server diff --git a/capio/common/env.hpp b/capio/common/env.hpp index cbfdc05aa..2b76a538c 100644 --- a/capio/common/env.hpp +++ b/capio/common/env.hpp @@ -10,7 +10,6 @@ #include #include "common/syscall.hpp" -#include "logger.hpp" // TODO: remove forward declaration of function by splitting into header and impl. capio/common inline bool is_forbidden_path(const std::string_view &path); diff --git a/capio/common/json_base_logger.hpp b/capio/common/json_base_logger.hpp new file mode 100644 index 000000000..bd1fd5066 --- /dev/null +++ b/capio/common/json_base_logger.hpp @@ -0,0 +1,276 @@ +#ifndef CAPIO_LOGGER_JSON_BASE_HPP +#define CAPIO_LOGGER_JSON_BASE_HPP + +// Pull in everything this header needs directly so it is self-contained +// regardless of include order. +#include // va_list, va_copy, va_end +#include // snprintf, vsnprintf +#include // strlen +#include // std::string (used in expandAndEscape) + +#include "constants.hpp" // CAPIO_LOG_MAX_MSG_LEN, CAPIO_DEFAULT_LOG_FOLDER, … +#include "syscall.hpp" // current_time_in_millis (declared in logger.hpp which + // includes syscall.hpp; guard against double-include + // by relying on header guards in logger.hpp) + +/** + * @file logger_json_base.hpp + * + * CRTP mixin that implements the full structured-JSON adapter interface + * required by TemplateLogger. Derived adapters only need to supply two + * I/O primitives as *static* methods: + * + * static void rawWriteBytes(const char *buf, int len); + * static void rawWriteStr (const char *buf); // NUL-terminated + * + * All JSON structure, indentation, pending-comma handling, and string + * escaping live here, shared between PosixLogWriteAdapter and + * ServerLogWriteAdapter. + */ +template +struct JsonLogBase { + + // ------------------------------------------------------------------ // + // Thread-local JSON state + // ------------------------------------------------------------------ // + + static thread_local int nestingDepth; + static thread_local bool rootArrayOpen; + + // Pending-line buffer: holds the last event/closing-brace WITHOUT its + // trailing newline. Flushed with ",\n" when a sibling follows, plain + // "\n" when the enclosing array closes. Avoids trailing commas on an + // append-only stream without any seek-back. + static thread_local int pendingLen; + static thread_local char pendingBuf[CAPIO_LOG_MAX_MSG_LEN * 6 + 256]; + + // ------------------------------------------------------------------ // + // TemplateLogger adapter interface + // ------------------------------------------------------------------ // + + static void write(const char * /*legacy*/, const size_t /*legacy*/) { + // ts_exit is written by writeEpilogue; nothing to do here. + } + + /** + * Called for every LOG(...) inside a syscall scope. + * Flushes the previous pending entry with a comma, then buffers this + * event object WITHOUT a trailing newline. + */ + static void printFormatted(unsigned long int timestamp, + const char *invoker, const char *file, int line, + const char * /*output_template*/, + const char *message_format, va_list args) { + + char escaped_args[CAPIO_LOG_MAX_MSG_LEN * 6]; + expandAndEscape(message_format, args, escaped_args, + static_cast(sizeof(escaped_args))); + + char escaped_invoker[512]; + jsonEscape(invoker, static_cast(::strlen(invoker)), + escaped_invoker, static_cast(sizeof(escaped_invoker))); + + char escaped_file[512]; + jsonEscape(file, static_cast(::strlen(file)), + escaped_file, static_cast(sizeof(escaped_file))); + + flushPending(true); // previous sibling gets a comma + + const int indent = indentSize(); + char *p = JsonLogBase::pendingBuf; + for (int i = 0; i < indent; ++i) { *p++ = ' '; } + p += ::snprintf(p, + sizeof(JsonLogBase::pendingBuf) - static_cast(indent) - 1, + "{ \"ts\": %lu, \"invoker\": \"%s\"," + " \"file\": \"%s\", \"line\": %d, \"args\": \"%s\" }", + timestamp, escaped_invoker, escaped_file, line, escaped_args); + JsonLogBase::pendingLen = static_cast( + p - JsonLogBase::pendingBuf); + } + + /** + * Called by TemplateLogger constructor (current_log_level == 1). + * + * Emits the opening of one syscall object: + * { + * "invoker": "...", + * "file": "...", + * "line": N, + * "ts_enter": T, + * "args": "...", + * "events": [ + */ + static void writeOpening(unsigned long int timestamp, + const char *invoker, const char *file, int line, + const char *message_format, va_list args) { + + if (!JsonLogBase::rootArrayOpen) { + Derived::rawWriteStr("[\n"); + JsonLogBase::rootArrayOpen = true; + JsonLogBase::nestingDepth = 1; + } + + char escaped_args[CAPIO_LOG_MAX_MSG_LEN * 6]; + expandAndEscape(message_format, args, escaped_args, + static_cast(sizeof(escaped_args))); + + char escaped_invoker[512]; + jsonEscape(invoker, static_cast(::strlen(invoker)), + escaped_invoker, static_cast(sizeof(escaped_invoker))); + + char escaped_file[512]; + jsonEscape(file, static_cast(::strlen(file)), + escaped_file, static_cast(sizeof(escaped_file))); + + flushPending(true); // flush previous top-level "}" with comma if present + + writeImmediate("{"); + JsonLogBase::nestingDepth++; + + writeField ("\"invoker\"", "\"%s\",", escaped_invoker); + writeField ("\"file\"", "\"%s\",", escaped_file); + writeFieldInt("\"line\"", "%d,", line); + writeFieldUL ("\"ts_enter\"", "%lu,", timestamp); + writeField ("\"args\"", "\"%s\",", escaped_args); + + writeImmediate("\"events\": ["); + JsonLogBase::nestingDepth++; + + JsonLogBase::pendingLen = 0; + } + + /** + * Called by TemplateLogger destructor (current_log_level == 1). + * Closes the events array, emits ts_exit, and stores the closing "}" + * as a new pending line so the next sibling gets a leading comma. + * Receives the timestamp captured at destructor time by TemplateLogger. + */ + static void writeEpilogue(unsigned long int timestamp) { + if (JsonLogBase::nestingDepth < 2) { return; } + + flushPending(false); // last event — no trailing comma + + JsonLogBase::nestingDepth--; + writeImmediate("],"); // close "events" array with trailing comma for ts_exit + + { + char buf[64]; + ::snprintf(buf, sizeof(buf), "\"ts_exit\": %lu", timestamp); + writeImmediate(buf); + } + + JsonLogBase::nestingDepth--; + char *p = JsonLogBase::pendingBuf; + const int indent = indentSize(); + for (int i = 0; i < indent; ++i) { *p++ = ' '; } + *p++ = '}'; + JsonLogBase::pendingLen = static_cast( + p - JsonLogBase::pendingBuf); + } + + protected: + // ------------------------------------------------------------------ // + // Pending-line management + // ------------------------------------------------------------------ // + + static void flushPending(bool withComma) { + if (JsonLogBase::pendingLen <= 0) { return; } + Derived::rawWriteBytes(JsonLogBase::pendingBuf, + JsonLogBase::pendingLen); + Derived::rawWriteStr(withComma ? ",\n" : "\n"); + JsonLogBase::pendingLen = 0; + } + + static void writeImmediate(const char *buf, int len = -1) { + if (len < 0) { len = static_cast(::strlen(buf)); } + const int indent = indentSize(); + char spaces[65] = {0}; + for (int i = 0; i < indent; ++i) { spaces[i] = ' '; } + Derived::rawWriteBytes(spaces, indent); + Derived::rawWriteBytes(buf, len); + Derived::rawWriteStr("\n"); + } + + static void writeField(const char *key, const char *fmt, const char *val) { + char tmp[768]; ::snprintf(tmp, sizeof(tmp), fmt, val); + char buf[1024]; ::snprintf(buf, sizeof(buf), "%s: %s", key, tmp); + writeImmediate(buf); + } + static void writeFieldInt(const char *key, const char *fmt, int val) { + char tmp[64]; ::snprintf(tmp, sizeof(tmp), fmt, val); + char buf[128]; ::snprintf(buf, sizeof(buf), "%s: %s", key, tmp); + writeImmediate(buf); + } + static void writeFieldUL(const char *key, const char *fmt, unsigned long val) { + char tmp[64]; ::snprintf(tmp, sizeof(tmp), fmt, val); + char buf[128]; ::snprintf(buf, sizeof(buf), "%s: %s", key, tmp); + writeImmediate(buf); + } + + static int indentSize() { + const int n = JsonLogBase::nestingDepth * 2; + return n < 64 ? n : 64; + } + + // ------------------------------------------------------------------ // + // String helpers + // ------------------------------------------------------------------ // + + static void expandAndEscape(const char *fmt, va_list args, + char *dst, int dst_size) { + va_list copy; + va_copy(copy, args); + const int raw_len = ::vsnprintf(nullptr, 0, fmt, copy); + va_end(copy); + + std::string raw(static_cast(raw_len) + 1, '\0'); + va_copy(copy, args); + ::vsnprintf(&raw[0], static_cast(raw_len) + 1, fmt, copy); + va_end(copy); + + jsonEscape(raw.c_str(), raw_len, dst, dst_size); + } + + static void jsonEscape(const char *src, int src_len, + char *dst, int dst_size) { + int di = 0; + for (int si = 0; si < src_len && di + 7 < dst_size; ++si) { + const unsigned char c = static_cast(src[si]); + if (c == '"' || c == '\\') { + dst[di++] = '\\'; dst[di++] = static_cast(c); + } else if (c == '\n') { dst[di++] = '\\'; dst[di++] = 'n'; + } else if (c == '\r') { dst[di++] = '\\'; dst[di++] = 'r'; + } else if (c == '\t') { dst[di++] = '\\'; dst[di++] = 't'; + } else if (c < 0x20 || c == 0x7f) { + dst[di++] = '\\'; dst[di++] = 'u'; + dst[di++] = '0'; dst[di++] = '0'; + dst[di++] = hexChar(c >> 4); + dst[di++] = hexChar(c & 0x0fu); + } else { + dst[di++] = static_cast(c); + } + } + dst[di] = '\0'; + } + + static char hexChar(unsigned int n) { + return static_cast(n < 10u ? '0' + n : 'a' + n - 10u); + } +}; + +// Out-of-class definitions for thread_local statics. +// The template parameter ensures PosixLogWriteAdapter and +// ServerLogWriteAdapter each get independent storage. +template +thread_local int JsonLogBase::nestingDepth = 0; + +template +thread_local bool JsonLogBase::rootArrayOpen = false; + +template +thread_local int JsonLogBase::pendingLen = 0; + +template +thread_local char JsonLogBase::pendingBuf[CAPIO_LOG_MAX_MSG_LEN * 6 + 256] = {'\0'}; + +#endif // CAPIO_LOGGER_JSON_BASE_HPP \ No newline at end of file diff --git a/capio/common/logger.hpp b/capio/common/logger.hpp index e507e5959..43a1b78bd 100644 --- a/capio/common/logger.hpp +++ b/capio/common/logger.hpp @@ -6,10 +6,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include "constants.hpp" @@ -23,7 +25,7 @@ template std::string demangled_name(const T &obj) { return status == 0 ? demangled.get() : mangled; } -inline bool continue_on_error = false; // if set to true, CAPIO does not terminate on ERR_EXIT +inline bool continue_on_error = false; inline void raise_termination(const bool raise_exception, const std::string &message) { if (raise_exception) { @@ -37,123 +39,20 @@ inline void raise_termination(const bool raise_exception, const std::string &mes #include "syscallnames.h" #endif -#ifndef __CAPIO_POSIX -#include -// FIXME: Remove the inline specifier by splitting into header and source code -inline thread_local std::ofstream logfile; // if building for server, self contained logfile -inline std::string log_master_dir_name = CAPIO_DEFAULT_LOG_FOLDER; -inline std::string logfile_prefix = CAPIO_SERVER_DEFAULT_LOG_FILE_PREFIX; +#ifdef __CAPIO_POSIX +// POSIX interceptor: logging starts disabled and is enabled explicitly +// after setup to prevent re-entrancy into the interceptor itself. +inline thread_local bool enable_logger = false; #else -inline thread_local bool logfileOpen = false; -inline thread_local int logfileFD = -1; -inline thread_local char logfile_path[PATH_MAX]{'\0'}; +// Server / non-POSIX: logging is always active from the first call. +inline thread_local bool enable_logger = true; #endif -// FIXME: Remove the inline specifier by splitting into header and source code -inline thread_local int current_log_level = 0; - -// this variable tells the logger that syscall logging -// has started, and we are not in setup phase -// FIXME: Remove the inline specifier by splitting into header and source code -inline thread_local bool logging_syscall = false; - -#ifndef CAPIO_MAX_LOG_LEVEL // capio max log level. defaults to -1, where everything is logged +#ifndef CAPIO_MAX_LOG_LEVEL #define CAPIO_MAX_LOG_LEVEL -1 #endif -// FIXME: Remove the inline specifier by splitting into header and source code inline int CAPIO_LOG_LEVEL = CAPIO_MAX_LOG_LEVEL; -#ifndef __CAPIO_POSIX -inline auto open_server_logfile() { - auto hostname = new char[HOST_NAME_MAX]; - gethostname(hostname, HOST_NAME_MAX); - - if (log_master_dir_name.empty()) { - log_master_dir_name = CAPIO_DEFAULT_LOG_FOLDER; - } - - const std::filesystem::path output_folder = - std::string{log_master_dir_name + "/server/" + hostname}; - - std::filesystem::create_directories(output_folder); - - const std::filesystem::path logfile_name = output_folder.string() + "/" + logfile_prefix + - std::to_string(capio_syscall(SYS_gettid)) + ".log"; - - logfile.open(logfile_name, std::ofstream::out); - delete[] hostname; - - return logfile_name; -} -#else - -inline auto get_hostname() { - static char *hostname_prefix = nullptr; - if (hostname_prefix == nullptr) { - hostname_prefix = new char[HOST_NAME_MAX]; - gethostname(hostname_prefix, HOST_NAME_MAX); - } - return hostname_prefix; -} - -inline auto get_log_dir() { - static char *posix_log_master_dir_name = nullptr; - if (posix_log_master_dir_name == nullptr) { - posix_log_master_dir_name = std::getenv("CAPIO_LOG_DIR"); - if (posix_log_master_dir_name == nullptr) { - posix_log_master_dir_name = new char[strlen(CAPIO_DEFAULT_LOG_FOLDER)]; - strcpy(posix_log_master_dir_name, CAPIO_DEFAULT_LOG_FOLDER); - } - } - return posix_log_master_dir_name; -} - -inline auto get_log_prefix() { - static char *posix_logfile_prefix = nullptr; - if (posix_logfile_prefix == nullptr) { - posix_logfile_prefix = std::getenv("CAPIO_LOG_PREFIX"); - if (posix_logfile_prefix == nullptr) { - posix_logfile_prefix = new char[strlen(CAPIO_LOG_POSIX_DEFAULT_LOG_FILE_PREFIX)]; - strcpy(posix_logfile_prefix, CAPIO_LOG_POSIX_DEFAULT_LOG_FILE_PREFIX); - } - } - return posix_logfile_prefix; -} - -inline auto get_posix_log_dir() { - static char *posix_log_dir_path = nullptr; - if (posix_log_dir_path == nullptr) { - // allocate space for a path in the following structure (including 10 digits for thread id - // max - // log_master_dir_name/posix/hostname/logfile_prefix_.log - auto len = strlen(get_log_dir()) + 7; - posix_log_dir_path = new char[len]{0}; - sprintf(posix_log_dir_path, "%s/posix", get_log_dir()); - } - return posix_log_dir_path; -} - -inline auto get_host_log_dir() { - static char *host_log_dir_path = nullptr; - if (host_log_dir_path == nullptr) { - // allocate space for a path in the following structure (including 10 digits for thread id - // max - // log_master_dir_name/posix/hostname/logfile_prefix_.log - auto len = strlen(get_posix_log_dir()) + HOST_NAME_MAX; - host_log_dir_path = new char[len]{0}; - sprintf(host_log_dir_path, "%s/%s", get_posix_log_dir(), get_hostname()); - } - return host_log_dir_path; -} - -inline void setup_posix_log_filename() { - if (logfile_path[0] == '\0') { - sprintf(logfile_path, "%s/%s%ld.log", get_host_log_dir(), get_log_prefix(), - capio_syscall(SYS_gettid)); - } -} -#endif - inline long long current_time_in_millis() { timespec ts{}; static long long start_time = -1; @@ -162,217 +61,164 @@ inline long long current_time_in_millis() { start_time = static_cast(ts.tv_sec) * 1000 + (ts.tv_nsec) / 1000000; } capio_syscall(SYS_clock_gettime, CLOCK_REALTIME, &ts); - const auto time_now = static_cast(ts.tv_sec) * 1000 + (ts.tv_nsec) / 1000000; - return time_now - start_time; + return static_cast(ts.tv_sec) * 1000 + (ts.tv_nsec) / 1000000 - start_time; } -inline void log_write_to(char *buffer, size_t bufflen) { -#ifdef __CAPIO_POSIX - if (current_log_level < CAPIO_MAX_LOG_LEVEL || CAPIO_MAX_LOG_LEVEL < 0) { - capio_syscall(SYS_write, logfileFD, buffer, bufflen); - capio_syscall(SYS_write, logfileFD, "\n", 1); - } -#else - if (current_log_level < CAPIO_LOG_LEVEL || CAPIO_LOG_LEVEL < 0) { - logfile << buffer << std::endl; - logfile.flush(); - } - -#endif -} - -/** - * @brief Class used to suspend the logging capabilities of CAPIO, by setting the logging_syscall - * flag to false at instantiation, and restarting the logging at destruction - * - */ class SyscallLoggingSuspender { public: - SyscallLoggingSuspender() { logging_syscall = false; } - ~SyscallLoggingSuspender() { logging_syscall = true; } + SyscallLoggingSuspender() { enable_logger = false; } + ~SyscallLoggingSuspender() { enable_logger = true; } }; /** - * @brief Class that provides logging capabilities to CAPIO. - * When compiled with the CAPIO intercepting library, it uses - * direct POSIX system calls. Otherwise, it relies on the STL. + * @brief Logging front-end, parameterised on an Adapter for the I/O backend. * + * Adapter contract + * ---------------- + * // Called once on entry (current_log_level == 1 after increment). + * // Receives all metadata so the adapter can open a structured record. + * static void writeOpening(unsigned long ts, const char *invoker, + * const char *file, int line, + * const char *message_format, va_list args); + * + * // Called for every LOG() inside a scope. + * static void printFormatted(unsigned long ts, const char *invoker, + * const char *file, int line, + * const char *output_template, + * const char *message_format, va_list args); + * + * // Called on scope exit to close the structured record. + * static void writeEpilogue(); + * + * // Legacy write — kept for ERR_EXIT paths; adapters may ignore it. + * static void write(const char *buf, size_t len); */ -class Logger { - private: +template class TemplateLogger { + static thread_local int current_log_level; + char invoker[256]{0}; char file[256]{0}; - char format[CAPIO_LOG_MAX_MSG_LEN]{0}; + unsigned int line{0}; + long int tid{0}; + + Adapter adapter; public: - inline Logger(const char invoker[], const char file[], int line, long int tid, - const char *message, ...) { -#ifndef __CAPIO_POSIX - if (!logfile.is_open()) { - // NOTE: should never get to this point as capio_server opens up the log file while - // parsing command line arguments. This is only for failsafe purpose - open_server_logfile(); - } -#else - if (!logfileOpen) { - setup_posix_log_filename(); - current_log_level = - 0; // reset log level after clone, avoiding propagation to child threads - - capio_syscall(SYS_mkdirat, AT_FDCWD, get_log_dir(), 0755); - capio_syscall(SYS_mkdirat, AT_FDCWD, get_posix_log_dir(), 0755); - capio_syscall(SYS_mkdirat, AT_FDCWD, get_host_log_dir(), 0755); - - logfileFD = capio_syscall(SYS_openat, AT_FDCWD, logfile_path, - O_CREAT | O_WRONLY | O_TRUNC, 0644); - - if (logfileFD == -1) { - capio_syscall(SYS_write, fileno(stdout), - "Err fopen file: ", strlen("Err fopen file: ")); - capio_syscall(SYS_write, fileno(stdout), logfile_path, strlen(logfile_path)); - capio_syscall(SYS_write, fileno(stdout), " ", 1); - capio_syscall(SYS_write, fileno(stdout), strerror(errno), strlen(strerror(errno))); - capio_syscall(SYS_write, fileno(stdout), "\n", 1); - exit(EXIT_FAILURE); - } - logfileOpen = true; + TemplateLogger(const char invoker[], const char file[], unsigned int line, long int tid, + const char *message, ...) { + this->tid = tid; + this->line = line; + strncpy(this->invoker, invoker, sizeof(this->invoker) - 1); + strncpy(this->file, file, sizeof(this->file) - 1); + + // Only track nesting when logging is actually active on this thread. + // If we incremented unconditionally, a START_LOG during the setup + // phase (before ENABLE_LOGGER) would leave current_log_level at 1 + // for the rest of the thread's lifetime, making every subsequent + // top-level call look like a nested one. + if (!enable_logger) { + return; } -#endif - strncpy(this->invoker, invoker, sizeof(this->invoker)); - strncpy(this->file, file, sizeof(this->file)); - - va_list argp, argpc; - - sprintf(format, CAPIO_LOG_PRE_MSG, current_time_in_millis(), this->invoker); - const size_t pre_msg_len = strlen(format); - strcpy(format + pre_msg_len, message); + current_log_level++; - va_start(argp, message); - va_copy(argpc, argp); + if (current_log_level < CAPIO_MAX_LOG_LEVEL || CAPIO_MAX_LOG_LEVEL < 0) { + va_list argp; + va_start(argp, message); -#if defined(CAPIO_LOG) && defined(__CAPIO_POSIX) - if (current_log_level == 0 && logging_syscall) { - int syscallNumber; - if (strcmp(invoker, "hook_clone_child") == 0) { - // Explicitly propagate SYS_clone to child thread after clone - // to avoid spurious unknown syscall logs - syscallNumber = SYS_clone; + if (current_log_level == 1) { + adapter.writeOpening(current_time_in_millis(), this->invoker, this->file, + this->line, message, argp); } else { - syscallNumber = va_arg(argp, int); + adapter.printFormatted(current_time_in_millis(), this->invoker, this->file, + this->line, CAPIO_LOG_PRE_MSG, message, argp); } - auto buf1 = reinterpret_cast(capio_syscall( - SYS_mmap, nullptr, 50, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)); - sprintf(buf1, CAPIO_LOG_POSIX_SYSCALL_START, sys_num_to_string(syscallNumber).c_str(), - syscallNumber); - log_write_to(buf1, strlen(buf1)); - capio_syscall(SYS_munmap, buf1, 50); + va_end(argp); } -#endif - - int size = vsnprintf(nullptr, 0U, format, argp); - auto buf = reinterpret_cast(capio_syscall(SYS_mmap, nullptr, size + 1, - PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)); - vsnprintf(buf, size + 1, format, argpc); - log_write_to(buf, strlen(buf)); - - va_end(argp); - va_end(argpc); - capio_syscall(SYS_munmap, buf, size); - current_log_level++; } - Logger(const Logger &) = delete; - Logger &operator=(const Logger &) = delete; + TemplateLogger(const TemplateLogger &) = delete; + TemplateLogger &operator=(const TemplateLogger &) = delete; - inline ~Logger() { - current_log_level--; - sprintf(format, CAPIO_LOG_PRE_MSG, current_time_in_millis(), this->invoker); - size_t pre_msg_len = strlen(format); - strcpy(format + pre_msg_len, "returned"); + ~TemplateLogger() { + if (!enable_logger) { + return; // level was never incremented for this instance + } - log_write_to(format, strlen(format)); -#ifdef __CAPIO_POSIX - if (current_log_level == 0 && logging_syscall) { - log_write_to(const_cast(CAPIO_LOG_POSIX_SYSCALL_END), - strlen(CAPIO_LOG_POSIX_SYSCALL_END)); + if (current_log_level == 1 && + (current_log_level < CAPIO_MAX_LOG_LEVEL || CAPIO_MAX_LOG_LEVEL < 0)) { + // Capture the exit timestamp here, as close to the actual return + // as possible, and pass it into the adapter so it doesn't need + // to call current_time_in_millis() itself. + adapter.writeEpilogue(static_cast(current_time_in_millis())); } -#endif + current_log_level--; } - inline void log(const char *message, ...) { - va_list argp, argpc; - - sprintf(format, CAPIO_LOG_PRE_MSG, current_time_in_millis(), this->invoker); - const size_t pre_msg_len = strlen(format); - - strcpy(format + pre_msg_len, message); - -#ifndef __CAPIO_POSIX - // if the log message to serve a new request or concludes, add new spaces - if (strcmp(invoker, "capio_server") == 0 && - (strcmp(CAPIO_LOG_SERVER_REQUEST_START, message) == 0 || - strcmp(CAPIO_LOG_SERVER_REQUEST_END, message) == 0)) { - logfile << message << std::endl; + void log(const char *message, ...) { + if (!enable_logger) { return; } -#endif - va_start(argp, message); - va_copy(argpc, argp); - const int size = vsnprintf(nullptr, 0U, format, argp); - const auto buf = reinterpret_cast( - capio_syscall(SYS_mmap, nullptr, size + 1, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)); - vsnprintf(buf, size + 1, format, argpc); - log_write_to(buf, strlen(buf)); - - va_end(argp); - va_end(argpc); - capio_syscall(SYS_munmap, buf, size); + // current_log_level is only incremented when enable_logger is true, + // so this check is always consistent with the constructor. + if (current_log_level < CAPIO_MAX_LOG_LEVEL || CAPIO_MAX_LOG_LEVEL < 0) { + va_list argp; + va_start(argp, message); + adapter.printFormatted(current_time_in_millis(), this->invoker, this->file, this->line, + CAPIO_LOG_PRE_MSG, message, argp); + va_end(argp); + } } + + std::string getLogFileName() { return adapter.getLogFileName(); } + + /** + * Resets the per-thread nesting counter to zero. + * Called by the server-side START_LOG macro before constructing a new + * Logger, so that every top-level server call always opens a fresh + * JSON object even when invoked from inside an existing Logger scope + * (e.g. the server main loop calling helper functions that also use + * START_LOG). Not used in the POSIX build where nesting is meaningful. + */ + static void reset_log_level() { current_log_level = 0; } }; +template inline thread_local int TemplateLogger::current_log_level = 0; + #ifdef CAPIO_LOG #define ERR_EXIT_EXCEPT_CHOICE(raise_exception, message, ...) \ log.log(message, ##__VA_ARGS__); \ if (!continue_on_error) { \ - if (!continue_on_error) { \ - char err_msg[CAPIO_LOG_MAX_MSG_LEN]; \ - snprintf(err_msg, CAPIO_LOG_MAX_MSG_LEN, message, ##__VA_ARGS__); \ - raise_termination(raise_exception, err_msg); \ - } \ + char err_msg[CAPIO_LOG_MAX_MSG_LEN]; \ + snprintf(err_msg, CAPIO_LOG_MAX_MSG_LEN, message, ##__VA_ARGS__); \ + raise_termination(raise_exception, err_msg); \ } #define ERR_EXIT(message, ...) ERR_EXIT_EXCEPT_CHOICE(true, message, ##__VA_ARGS__) #define LOG(message, ...) log.log(message, ##__VA_ARGS__) + +// On the POSIX build, enable_logger starts false and is flipped explicitly; +// nesting is meaningful so current_log_level is never reset. +// On the server build, enable_logger starts true (see declaration above) and +// current_log_level is reset to 0 on every START_LOG so that each top-level +// request handler always opens its own JSON object, even when called from +// inside an outer Logger scope. +#ifdef __CAPIO_POSIX #define START_LOG(tid, message, ...) \ Logger log(__func__, __FILE__, __LINE__, tid, message, ##__VA_ARGS__) -#define START_SYSCALL_LOGGING() logging_syscall = true -#define SUSPEND_SYSCALL_LOGGING() SyscallLoggingSuspender sls{}; +#else +#define START_LOG(tid, message, ...) \ + Logger::reset_log_level(); \ + Logger log(__func__, __FILE__, __LINE__, tid, message, ##__VA_ARGS__) +#endif + +#define ENABLE_LOGGER() enable_logger = true +#define DISABLE_LOGGER() \ + SyscallLoggingSuspender sls {} -/** - * This macro is used to inject code into debug mode. It needs a self calling lambda function, - * that is a lambda in the following form: - * - * [](){}() - * - * For example, a debug code to print a value might be injected in this way: - * - * int value = 10; - * DBG(tid, [](int i){printf("%d", i);}(value) ); - * - * This is useful to print or run debug actions with variables defined outside - * of the scope of the given lambda function Be careful that the code defined inside the DBG - * macro is not compiled when building in Release. - * - * Be even MORE CAREFUL to not use any STL code inside the DBG lambda function as it could be - * captured by syscall_intercept (ie do not use std::cout unless you are 100% sure of what you are - * doing) - */ #define DBG(tid, lambda) \ { \ START_LOG(tid, "[ DBG ]~~~~~~~~~~~~ START ~~~~~~~~~~~~~~[ DBG ]"); \ @@ -391,13 +237,13 @@ class Logger { #define ERR_EXIT(message, ...) ERR_EXIT_EXCEPT_CHOICE(true, message, ##__VA_ARGS__) #define LOG(message, ...) #define START_LOG(tid, message, ...) -#define START_SYSCALL_LOGGING() -#define SUSPEND_SYSCALL_LOGGING() #define SEM_CREATE_CHECK(sem, source) \ if (sem == SEM_FAILED) { \ __SHM_CHECK_CLI_MSG; \ } #define DBG(tid, lambda) +#define ENABLE_LOGGER() +#define DISABLE_LOGGER() #endif diff --git a/capio/posix/handlers/exit_group.hpp b/capio/posix/handlers/exit_group.hpp index 6c4acb454..498622dc0 100644 --- a/capio/posix/handlers/exit_group.hpp +++ b/capio/posix/handlers/exit_group.hpp @@ -3,8 +3,6 @@ #if defined(SYS_exit) || defined(SYS_exit_group) -#include "common/logger.hpp" - #include "utils/requests.hpp" /* diff --git a/capio/posix/libcapio_posix.cpp b/capio/posix/libcapio_posix.cpp index 3aedd1a46..45b3d9fa7 100644 --- a/capio/posix/libcapio_posix.cpp +++ b/capio/posix/libcapio_posix.cpp @@ -7,6 +7,8 @@ #include #include +#include "utils/posix_logger.hpp" + #include "common/syscall.hpp" #include "utils/clone.hpp" @@ -351,7 +353,8 @@ static int hook(long syscall_number, long arg0, long arg1, long arg2, long arg3, CAPIO_LOG_LEVEL = get_capio_log_level(); #endif - START_LOG(syscall_no_intercept(SYS_gettid), "call(syscall_number=%ld)", syscall_number); + START_LOG(syscall_no_intercept(SYS_gettid), "call(syscall_number=%ld, syscall_name=%s)", + syscall_number, sys_num_to_string(syscall_number).c_str()); // If the syscall_number is higher than the maximum // syscall captured by CAPIO, simply return @@ -408,5 +411,5 @@ static __attribute__((constructor)) void init() { intercept_hook_point_clone_child = hook_clone_child; intercept_hook_point_clone_parent = hook_clone_parent; intercept_hook_point = hook; - START_SYSCALL_LOGGING(); -} + ENABLE_LOGGER(); +} \ No newline at end of file diff --git a/capio/posix/utils/cache.hpp b/capio/posix/utils/cache.hpp index 597d644a5..7a4f4d0f8 100644 --- a/capio/posix/utils/cache.hpp +++ b/capio/posix/utils/cache.hpp @@ -185,4 +185,4 @@ class WriteCache { inline thread_local WriteCache *write_cache; inline thread_local ReadCache *read_cache; -#endif // CAPIO_SERVER_UTILS_CACHE +#endif // CAPIO_SERVER_UTILS_CACHE \ No newline at end of file diff --git a/capio/posix/utils/clone.hpp b/capio/posix/utils/clone.hpp index 54cd24b72..97bc869bf 100644 --- a/capio/posix/utils/clone.hpp +++ b/capio/posix/utils/clone.hpp @@ -4,6 +4,7 @@ #include "common/syscall.hpp" #include "data.hpp" #include "requests.hpp" +#include "utils/posix_logger.hpp" /** * Initialize the required data structures for the new child thread, and then proceed to execute a diff --git a/capio/posix/utils/common.hpp b/capio/posix/utils/common.hpp index 9727b334f..d8abba1e7 100644 --- a/capio/posix/utils/common.hpp +++ b/capio/posix/utils/common.hpp @@ -1,7 +1,8 @@ -#include - #ifndef CAPIO_FUNCTIONS_H #define CAPIO_FUNCTIONS_H +#include + +#include "utils/posix_logger.hpp" int posix_return_value(long res, long *result) { START_LOG(capio_syscall(SYS_gettid), "cal(res=%ld)", res); diff --git a/capio/posix/utils/env.hpp b/capio/posix/utils/env.hpp index c43f56fcb..0893ef500 100644 --- a/capio/posix/utils/env.hpp +++ b/capio/posix/utils/env.hpp @@ -2,9 +2,6 @@ #define CAPIO_POSIX_UTILS_ENV_HPP #include -#include - -#include "common/logger.hpp" inline const char *get_capio_app_name() { static char *capio_app_name = std::getenv("CAPIO_APP_NAME"); diff --git a/capio/posix/utils/filesystem.hpp b/capio/posix/utils/filesystem.hpp index 6ba6921e8..99c7ba257 100644 --- a/capio/posix/utils/filesystem.hpp +++ b/capio/posix/utils/filesystem.hpp @@ -12,8 +12,8 @@ #include "common/env.hpp" #include "common/filesystem.hpp" -#include "common/logger.hpp" #include "common/syscall.hpp" +#include "utils/posix_logger.hpp" #include "types.hpp" diff --git a/capio/posix/utils/posix_logger.hpp b/capio/posix/utils/posix_logger.hpp new file mode 100644 index 000000000..224bab459 --- /dev/null +++ b/capio/posix/utils/posix_logger.hpp @@ -0,0 +1,120 @@ +#ifndef CAPIO_POSIXLOGGER_HPP +#define CAPIO_POSIXLOGGER_HPP + +#include "common/logger.hpp" +#include "common/json_base_logger.hpp" + +struct PosixLogWriteAdapter : JsonLogBase { + + static thread_local int fileFD; + static thread_local char filePath[PATH_MAX]; + + // The constructor is called every time a Logger is constructed (i.e. + // on every START_LOG). It opens the per-thread log file on first call + // and is a no-op on subsequent calls. + explicit PosixLogWriteAdapter() { ensureFileOpen(); } + + // ------------------------------------------------------------------ // + // I/O primitives required by JsonLogBase + // + // These are static because JsonLogBase calls them as Derived::xxx(). + // They call ensureFileOpen() so that even if a new thread reaches a + // static write path before its first constructor call, the file is + // always valid. + // ------------------------------------------------------------------ // + + static void rawWriteBytes(const char *buf, int len) { + ensureFileOpen(); + capio_syscall(SYS_write, fileFD, buf, len); + } + + static void rawWriteStr(const char *buf) { + ensureFileOpen(); + capio_syscall(SYS_write, fileFD, buf, strlen(buf)); + } + + private: + // Opens the per-thread log file exactly once per thread. + // Safe to call from both instance constructor and static write paths. + static void ensureFileOpen() { + if (fileFD != -1) { return; } + + sprintf(filePath, "%s/%s%ld.log", + getHostLogDir(), getLogPrefix(), + capio_syscall(SYS_gettid)); + + capio_syscall(SYS_mkdirat, AT_FDCWD, getLogDir(), 0755); + capio_syscall(SYS_mkdirat, AT_FDCWD, getPosixLogDir(), 0755); + capio_syscall(SYS_mkdirat, AT_FDCWD, getHostLogDir(), 0755); + + fileFD = capio_syscall(SYS_openat, AT_FDCWD, filePath, + O_CREAT | O_WRONLY | O_APPEND, 0644); + + if (fileFD == -1) { + capio_syscall(SYS_write, fileno(stdout), + "Err fopen file: ", strlen("Err fopen file: ")); + capio_syscall(SYS_write, fileno(stdout), filePath, strlen(filePath)); + capio_syscall(SYS_write, fileno(stdout), " ", 1); + capio_syscall(SYS_write, fileno(stdout), strerror(errno), strlen(strerror(errno))); + capio_syscall(SYS_write, fileno(stdout), "\n", 1); + exit(EXIT_FAILURE); + } + } + + static const char *getHostname() { + static char hostname[HOST_NAME_MAX]{'\0'}; + if (hostname[0] == '\0') { gethostname(hostname, HOST_NAME_MAX); } + return hostname; + } + + static const char *getLogDir() { + static char *dir = nullptr; + if (dir == nullptr) { + dir = std::getenv("CAPIO_LOG_DIR"); + if (dir == nullptr) { + dir = new char[strlen(CAPIO_DEFAULT_LOG_FOLDER) + 1]; + strcpy(dir, CAPIO_DEFAULT_LOG_FOLDER); + } + } + return dir; + } + + static const char *getLogPrefix() { + static char *prefix = nullptr; + if (prefix == nullptr) { + prefix = std::getenv("CAPIO_LOG_PREFIX"); + if (prefix == nullptr) { + prefix = new char[strlen(CAPIO_LOG_POSIX_DEFAULT_LOG_FILE_PREFIX) + 1]; + strcpy(prefix, CAPIO_LOG_POSIX_DEFAULT_LOG_FILE_PREFIX); + } + } + return prefix; + } + + static const char *getPosixLogDir() { + static char *dir = nullptr; + if (dir == nullptr) { + const char *base = getLogDir(); + dir = new char[strlen(base) + 7]{0}; + sprintf(dir, "%s/posix", base); + } + return dir; + } + + static const char *getHostLogDir() { + static char *dir = nullptr; + if (dir == nullptr) { + const char *posixDir = getPosixLogDir(); + dir = new char[strlen(posixDir) + HOST_NAME_MAX]{0}; + sprintf(dir, "%s/%s", posixDir, getHostname()); + } + return dir; + } +}; + +inline thread_local int PosixLogWriteAdapter::fileFD = -1; +inline thread_local char PosixLogWriteAdapter::filePath[PATH_MAX] = {'\0'}; + +using Logger = TemplateLogger; + +#endif // CAPIO_POSIXLOGGER_HPP \ No newline at end of file diff --git a/capio/posix/utils/requests.hpp b/capio/posix/utils/requests.hpp index 4867e6117..da04be22c 100644 --- a/capio/posix/utils/requests.hpp +++ b/capio/posix/utils/requests.hpp @@ -6,6 +6,7 @@ #include "env.hpp" #include "filesystem.hpp" #include "types.hpp" +#include "utils/posix_logger.hpp" inline thread_local CircularBuffer *buf_requests; inline thread_local CircularBuffer *buff_response; diff --git a/capio/posix/utils/snapshot.hpp b/capio/posix/utils/snapshot.hpp index 55a85553b..1f06142ba 100644 --- a/capio/posix/utils/snapshot.hpp +++ b/capio/posix/utils/snapshot.hpp @@ -5,9 +5,8 @@ #include #include -#include "common/logger.hpp" - #include "types.hpp" +#include "utils/posix_logger.hpp" inline int *get_fd_snapshot(long tid) { return static_cast(get_shm_if_exist("capio_snapshot_" + std::to_string(tid))); diff --git a/capio/server/capio_server.cpp b/capio/server/capio_server.cpp index 403ec8f49..ef70188d6 100644 --- a/capio/server/capio_server.cpp +++ b/capio/server/capio_server.cpp @@ -17,6 +17,8 @@ #include #include +#include "utils/server_logger.hpp" + #include "capiocl.hpp" #include "capiocl/engine.h" #include "capiocl/parser.h" @@ -24,7 +26,6 @@ #include "client-manager/client_manager.hpp" #include "common/env.hpp" -#include "common/logger.hpp" #include "common/requests.hpp" #include "common/semaphore.hpp" #include "remote/backend.hpp" diff --git a/capio/server/include/client-manager/client_manager.hpp b/capio/server/include/client-manager/client_manager.hpp index 3c91eb705..4ea53b70d 100644 --- a/capio/server/include/client-manager/client_manager.hpp +++ b/capio/server/include/client-manager/client_manager.hpp @@ -5,6 +5,8 @@ #include #include +#include "utils/server_logger.hpp" + #include "common/queue.hpp" /** * @brief Class to handle libcapio_posix clients applications diff --git a/capio/server/include/remote/backend.hpp b/capio/server/include/remote/backend.hpp index f1c827821..02622f0b5 100644 --- a/capio/server/include/remote/backend.hpp +++ b/capio/server/include/remote/backend.hpp @@ -2,8 +2,7 @@ #define CAPIO_SERVER_REMOTE_BACKEND_HPP #include #include - -#include "common/logger.hpp" +#include class RemoteRequest { char *_buf_recv; diff --git a/capio/server/include/remote/handlers/read.hpp b/capio/server/include/remote/handlers/read.hpp index d4a4f6cd2..8c56321b9 100644 --- a/capio/server/include/remote/handlers/read.hpp +++ b/capio/server/include/remote/handlers/read.hpp @@ -4,6 +4,7 @@ #include "remote/backend.hpp" #include "remote/requests.hpp" #include "storage/manager.hpp" +#include "utils/server_logger.hpp" extern StorageManager *storage_manager; diff --git a/capio/server/include/remote/handlers/stat.hpp b/capio/server/include/remote/handlers/stat.hpp index 80cd4cc47..28219760c 100644 --- a/capio/server/include/remote/handlers/stat.hpp +++ b/capio/server/include/remote/handlers/stat.hpp @@ -5,6 +5,7 @@ #include "remote/backend.hpp" #include "remote/requests.hpp" #include "storage/manager.hpp" +#include "utils/server_logger.hpp" extern StorageManager *storage_manager; extern ClientManager *client_manager; diff --git a/capio/server/include/storage/capio_file.hpp b/capio/server/include/storage/capio_file.hpp index aca4ff842..58f3a8afa 100644 --- a/capio/server/include/storage/capio_file.hpp +++ b/capio/server/include/storage/capio_file.hpp @@ -10,6 +10,8 @@ #include #include +#include "utils/server_logger.hpp" + #include "common/queue.hpp" /** diff --git a/capio/server/include/utils/cli_parser.hpp b/capio/server/include/utils/cli_parser.hpp index be588b994..aec16d35f 100644 --- a/capio/server/include/utils/cli_parser.hpp +++ b/capio/server/include/utils/cli_parser.hpp @@ -1,5 +1,6 @@ #ifndef CAPIO_CLI_PARSER_HPP #define CAPIO_CLI_PARSER_HPP +#include "utils/server_logger.hpp" #include struct CapioParsedConfig { diff --git a/capio/server/include/utils/common.hpp b/capio/server/include/utils/common.hpp index a0f90cdbb..067507617 100644 --- a/capio/server/include/utils/common.hpp +++ b/capio/server/include/utils/common.hpp @@ -10,6 +10,7 @@ #include "common/dirent.hpp" #include "storage/capio_file.hpp" #include "storage/manager.hpp" +#include "utils/server_logger.hpp" extern ClientManager *client_manager; extern StorageManager *storage_manager; diff --git a/capio/server/include/utils/env.hpp b/capio/server/include/utils/env.hpp index ca41cb36d..98a9b3a61 100644 --- a/capio/server/include/utils/env.hpp +++ b/capio/server/include/utils/env.hpp @@ -4,6 +4,7 @@ #include #include "common/constants.hpp" +#include "utils/server_logger.hpp" off64_t get_file_initial_size() { START_LOG(gettid(), "call()"); diff --git a/capio/server/include/utils/location.hpp b/capio/server/include/utils/location.hpp index 3a14af685..9bb4bf8df 100644 --- a/capio/server/include/utils/location.hpp +++ b/capio/server/include/utils/location.hpp @@ -1,11 +1,11 @@ #ifndef CAPIO_SERVER_UTILS_LOCATIONS_HPP #define CAPIO_SERVER_UTILS_LOCATIONS_HPP - -#include "remote/backend.hpp" - #include #include +#include "remote/backend.hpp" + +#include "utils/server_logger.hpp" #include "utils/types.hpp" extern Backend *backend; diff --git a/capio/server/include/utils/server_logger.hpp b/capio/server/include/utils/server_logger.hpp new file mode 100644 index 000000000..a8ed5db65 --- /dev/null +++ b/capio/server/include/utils/server_logger.hpp @@ -0,0 +1,70 @@ +#ifndef CAPIO_SERVERLOGGER_HPP +#define CAPIO_SERVERLOGGER_HPP + +#include "common/logger.hpp" +#include "common/json_base_logger.hpp" + +struct ServerLogWriteAdapter : JsonLogBase { + + static thread_local std::ofstream *logfile; + static thread_local std::string *logFileName; + + explicit ServerLogWriteAdapter() { ensureFileOpen(); } + + std::string getLogFileName() const { + return logFileName ? *logFileName : std::string{}; + } + + // ------------------------------------------------------------------ // + // I/O primitives required by JsonLogBase + // ------------------------------------------------------------------ // + + static void rawWriteBytes(const char *buf, int len) { + ensureFileOpen(); + logfile->write(buf, len); + logfile->flush(); + } + + static void rawWriteStr(const char *buf) { + rawWriteBytes(buf, static_cast(strlen(buf))); + } + + private: + static void ensureFileOpen() { + if (logfile != nullptr && logfile->is_open()) { return; } + + std::string logDir; + std::string prefix; + + if (const char *tmp = std::getenv("CAPIO_LOG_DIR"); tmp != nullptr) { + logDir = tmp; + } else { + logDir = CAPIO_DEFAULT_LOG_FOLDER; + } + + if (const char *tmp = std::getenv("CAPIO_LOG_PREFIX"); tmp != nullptr) { + prefix = tmp; + } else { + prefix = CAPIO_SERVER_DEFAULT_LOG_FILE_PREFIX; + } + + char hostname[HOST_NAME_MAX]; + gethostname(hostname, HOST_NAME_MAX); + + const std::filesystem::path outputFolder{logDir + "/server/" + hostname}; + std::filesystem::create_directories(outputFolder); + + const std::filesystem::path path = + outputFolder / (prefix + std::to_string(capio_syscall(SYS_gettid)) + ".log"); + + logfile = new std::ofstream(path, std::ofstream::app); + logFileName = new std::string(path.string()); + } +}; + +inline thread_local std::ofstream *ServerLogWriteAdapter::logfile = nullptr; +inline thread_local std::string *ServerLogWriteAdapter::logFileName = nullptr; + +using Logger = TemplateLogger; + +#endif // CAPIO_SERVERLOGGER_HPP \ No newline at end of file diff --git a/capio/server/include/utils/signals.hpp b/capio/server/include/utils/signals.hpp index 94660c0a1..030924d23 100644 --- a/capio/server/include/utils/signals.hpp +++ b/capio/server/include/utils/signals.hpp @@ -5,6 +5,7 @@ #include "remote/backend.hpp" #include "server_println.hpp" +#include "utils/server_logger.hpp" #ifdef CAPIO_COVERAGE extern "C" void __gcov_dump(void); diff --git a/capio/server/src/backend.cpp b/capio/server/src/backend.cpp index 269893eae..96f69a0cf 100644 --- a/capio/server/src/backend.cpp +++ b/capio/server/src/backend.cpp @@ -1,6 +1,7 @@ #include "remote/backend.hpp" #include "utils/common.hpp" +#include "utils/server_logger.hpp" #include "utils/server_println.hpp" #include diff --git a/capio/server/src/cli_parser.cpp b/capio/server/src/cli_parser.cpp index a4f55cfa8..50f2b9693 100644 --- a/capio/server/src/cli_parser.cpp +++ b/capio/server/src/cli_parser.cpp @@ -9,7 +9,6 @@ CapioParsedConfig parseCLI(int argc, char **argv) { CapioParsedConfig capio_config; - Logger *log; args::ArgumentParser parser(CAPIO_SERVER_ARG_PARSER_PRE, CAPIO_SERVER_ARG_PARSER_EPILOGUE); parser.LongSeparator(" "); @@ -18,10 +17,6 @@ CapioParsedConfig parseCLI(int argc, char **argv) { args::Group arguments(parser, "Arguments"); args::HelpFlag help(arguments, "help", "Display this help menu", {'h', "help"}); - args::ValueFlag logfile_src(arguments, "filename", - CAPIO_SERVER_ARG_PARSER_LOGILE_OPT_HELP, {'l', "log"}); - args::ValueFlag logfile_folder( - arguments, "filename", CAPIO_SERVER_ARG_PARSER_LOGILE_DIR_OPT_HELP, {'d', "log-dir"}); args::ValueFlag resolve_prefix(arguments, "resolve-prefix", CAPIO_SERVER_ARG_PARSER_RESOLVE_PREFIX_OPT_HELP, {'r', "resolve-prefix"}); @@ -69,33 +64,9 @@ CapioParsedConfig parseCLI(int argc, char **argv) { #endif } - if (logfile_folder) { #ifdef CAPIO_LOG - log_master_dir_name = args::get(logfile_folder); -#else - server_println("Capio logfile folder, but logging capabilities not compiled into capio!", - get_capio_workflow_name(), CAPIO_LOG_SERVER_CLI_LEVEL_WARNING, "parseCLI"); -#endif - } - - if (logfile_src) { -#ifdef CAPIO_LOG - // log file was given - std::string token = args::get(logfile_src); - if (token.find(".log") != std::string::npos) { - token.erase(token.length() - 4); // delete .log if for some reason - // is given as parameter - } - logfile_prefix = token; -#else - server_println("Capio logfile provided, but logging capabilities not compiled into capio!", - get_capio_workflow_name(), CAPIO_LOG_SERVER_CLI_LEVEL_WARNING, "parseCLI"); -#endif - } -#ifdef CAPIO_LOG - auto logname = open_server_logfile(); - log = new Logger(__func__, __FILE__, __LINE__, gettid(), "Created new log file"); - server_println("started logging to logfile " + logname.string(), get_capio_workflow_name(), + auto log = new Logger(__func__, __FILE__, __LINE__, gettid(), "Created new log file"); + server_println("started logging to logfile " + log->getLogFileName(), get_capio_workflow_name(), CAPIO_LOG_SERVER_CLI_LEVEL_INFO, "parseCLI"); #endif diff --git a/capio/server/src/client_manager.cpp b/capio/server/src/client_manager.cpp index f8000c9a7..3548f1a21 100644 --- a/capio/server/src/client_manager.cpp +++ b/capio/server/src/client_manager.cpp @@ -1,12 +1,12 @@ #include -#include "utils/capiocl_adapter.hpp" - #include "client-manager/client_manager.hpp" + #include "common/constants.hpp" #include "common/queue.hpp" #include "utils/capiocl_adapter.hpp" #include "utils/common.hpp" +#include "utils/server_logger.hpp" #include "utils/server_println.hpp" ClientManager::ClientDataBuffers::ClientDataBuffers(const std::string &clientToServerName, diff --git a/capio/server/src/mpi_backend.cpp b/capio/server/src/mpi_backend.cpp index ead84a42c..57093f1ce 100644 --- a/capio/server/src/mpi_backend.cpp +++ b/capio/server/src/mpi_backend.cpp @@ -1,5 +1,7 @@ #include "remote/backend/mpi.hpp" + #include "utils/capiocl_adapter.hpp" +#include "utils/server_logger.hpp" #include "utils/server_println.hpp" MPIBackend::MPIBackend(int argc, char **argv) : Backend(MPI_MAX_PROCESSOR_NAME) { diff --git a/capio/server/src/none_backend.cpp b/capio/server/src/none_backend.cpp index e0e8e3208..5f6327584 100644 --- a/capio/server/src/none_backend.cpp +++ b/capio/server/src/none_backend.cpp @@ -1,7 +1,9 @@ #include #include "remote/backend/none.hpp" + #include "utils/capiocl_adapter.hpp" +#include "utils/server_logger.hpp" #include "utils/server_println.hpp" NoneBackend::NoneBackend(int argc, char **argv) : Backend(HOST_NAME_MAX) { diff --git a/capio/server/src/remote_request.cpp b/capio/server/src/remote_request.cpp index a15bab108..60bab8db5 100644 --- a/capio/server/src/remote_request.cpp +++ b/capio/server/src/remote_request.cpp @@ -1,5 +1,7 @@ #include "remote/backend.hpp" +#include "utils/server_logger.hpp" + RemoteRequest::RemoteRequest(char *buf_recv, const std::string &source) : _source(source) { START_LOG(gettid(), "call(buf_recv=%s, source=%s)", buf_recv, source.c_str()); int code; diff --git a/capio/server/src/storage_manager.cpp b/capio/server/src/storage_manager.cpp index 4b866bd27..13f7517eb 100644 --- a/capio/server/src/storage_manager.cpp +++ b/capio/server/src/storage_manager.cpp @@ -3,14 +3,15 @@ #include #include +#include "storage/manager.hpp" + #include "common/dirent.hpp" #include "common/filesystem.hpp" -#include "common/logger.hpp" #include "storage/capio_file.hpp" -#include "storage/manager.hpp" #include "utils/capiocl_adapter.hpp" #include "utils/common.hpp" #include "utils/location.hpp" +#include "utils/server_logger.hpp" #include "utils/shared_mutex.hpp" #include "utils/types.hpp" diff --git a/capio/tests/unit/posix/src/realpath.cpp b/capio/tests/unit/posix/src/realpath.cpp index cfa38e8ae..004f9e62c 100644 --- a/capio/tests/unit/posix/src/realpath.cpp +++ b/capio/tests/unit/posix/src/realpath.cpp @@ -4,6 +4,8 @@ #include +#include "posix/utils/posix_logger.hpp" + #include "utils/filesystem.hpp" class RealpathPosixTest : public testing::Test { diff --git a/capio/tests/unit/server/src/capio_file.cpp b/capio/tests/unit/server/src/capio_file.cpp index db7ead849..3dfc8cb77 100644 --- a/capio/tests/unit/server/src/capio_file.cpp +++ b/capio/tests/unit/server/src/capio_file.cpp @@ -323,34 +323,7 @@ TEST(ServerTest, TestFileSetCommitToFalse) { EXPECT_FALSE(file.isCommitted()); } -class MockBackend : public Backend { - public: - MockBackend() : Backend(HOST_NAME_MAX) {} - - void recv_file(char *shm, const std::string &source, const long int bytes_expected) override { - for (long int i = 0; i < bytes_expected; ++i) { - shm[i] = 33 + (i % 93); - } - } - - const std::set get_nodes() override { return {node_name}; } - void handshake_servers() override {} - RemoteRequest read_next_request() override { return {nullptr, ""}; } - void send_file(char *shm, long int nbytes, const std::string &target) override {} - void send_request(const char *message, int message_len, const std::string &target) override {} -}; - -class MockBackendTestFixture : public ::testing::Test { - protected: - void SetUp() override { - backend = new MockBackend(); - open_files_location(); - } - - void TearDown() override { delete backend; } -}; - -TEST_F(MockBackendTestFixture, TestReadFromNodeMockBackend) { +TEST(ServerTest, TestReadFromNodeMockBackend) { CapioFile file1; file1.createBuffer("testDir", true); @@ -377,7 +350,7 @@ TEST(ServerTest, TestGetSectorEnd) { EXPECT_EQ(file.getSectorEnd(12000), -1); } -TEST_F(MockBackendTestFixture, TestSimulateDirectoryStreaming) { +TEST(ServerTest, TestSimulateDirectoryStreaming) { constexpr int NUM_FILES_EXPECTED = 10; diff --git a/capio/tests/unit/server/src/main.cpp b/capio/tests/unit/server/src/main.cpp index 28cb277e4..b57f22e41 100644 --- a/capio/tests/unit/server/src/main.cpp +++ b/capio/tests/unit/server/src/main.cpp @@ -14,6 +14,23 @@ Backend *backend = nullptr; const capiocl::engine::Engine &CapioCLEngine::get() { return *capio_cl_engine; } +class MockBackend : public Backend { + public: + MockBackend() : Backend(HOST_NAME_MAX) {} + + void recv_file(char *shm, const std::string &source, const long int bytes_expected) override { + for (long int i = 0; i < bytes_expected; ++i) { + shm[i] = 33 + (i % 93); + } + } + + const std::set get_nodes() override { return {node_name}; } + void handshake_servers() override {} + RemoteRequest read_next_request() override { return {nullptr, ""}; } + void send_file(char *shm, long int nbytes, const std::string &target) override {} + void send_request(const char *message, int message_len, const std::string &target) override {} +}; + class ServerUnitTestEnvironment : public testing::Environment { public: explicit ServerUnitTestEnvironment() = default; @@ -22,12 +39,15 @@ class ServerUnitTestEnvironment : public testing::Environment { capio_cl_engine = new capiocl::engine::Engine(false); client_manager = new ClientManager(); storage_manager = new StorageManager(); + backend = new MockBackend(); + open_files_location(); } void TearDown() override { delete storage_manager; delete client_manager; delete capio_cl_engine; + delete backend; } };