diff --git a/include/maxscale/log_manager.h b/include/maxscale/log_manager.h index 5b08f126d..0a5f47807 100644 --- a/include/maxscale/log_manager.h +++ b/include/maxscale/log_manager.h @@ -109,7 +109,7 @@ void mxs_log_stop_flush_thr(); int mxs_log_flush(); int mxs_log_flush_sync(); -int mxs_log_rotate(); +bool mxs_log_rotate(); int mxs_log_set_priority_enabled(int priority, bool enabled); void mxs_log_set_syslog_enabled(bool enabled); diff --git a/server/core/CMakeLists.txt b/server/core/CMakeLists.txt index 79f64e4a9..23e93448f 100644 --- a/server/core/CMakeLists.txt +++ b/server/core/CMakeLists.txt @@ -22,6 +22,7 @@ add_library(maxscale-common SHARED listener.cc load_utils.cc log_manager.cc + logger.cc mariadb.cc maxscale_pcre2.cc misc.cc diff --git a/server/core/log_manager.cc b/server/core/log_manager.cc index 4b049404a..f24efcb28 100644 --- a/server/core/log_manager.cc +++ b/server/core/log_manager.cc @@ -23,11 +23,15 @@ #include #include #include +#include #include #include #include #include +#include +#include + #include #include #include @@ -37,7 +41,9 @@ #include #include #include + #include "internal/mlist.h" +#include "internal/logger.hh" #define MAX_PREFIXLEN 250 #define MAX_SUFFIXLEN 250 @@ -49,6 +55,9 @@ # define _GNU_SOURCE #endif +using namespace maxscale; +static std::unique_ptr logger; + static const char LOGFILE_NAME_PREFIX[] = "maxscale"; static const char LOGFILE_NAME_SUFFIX[] = ".log"; @@ -130,7 +139,7 @@ static struct * Variable holding the enabled priorities information. * Used from logging macros. */ -int mxs_log_enabled_priorities = 0; +int mxs_log_enabled_priorities = (1 << LOG_ERR) | (1 << LOG_NOTICE) | (1 << LOG_WARNING); /** * BUFSIZ comes from the system. It equals with block size or @@ -160,13 +169,6 @@ static logmanager_t* lm; static bool flushall_flag; static bool flushall_started_flag; static bool flushall_done_flag; -namespace -{ - -class MessageRegistry; - -} -static MessageRegistry* message_registry; /** This is used to detect if the initialization of the log manager has failed * and that it isn't initialized again after a failure has occurred. */ @@ -636,18 +638,6 @@ static bool logmanager_init_nomutex(const char* ident, goto return_succ; } - /** Initialize logfile */ - if (!logfile_init(&lm->lm_logfile, lm, (lm->lm_target == MXS_LOG_TARGET_SHMEM))) - { - err = 1; - goto return_succ; - } - - /** - * Set global variable - */ - mxs_log_enabled_priorities = (1 << LOG_ERR) | (1 << LOG_NOTICE) | (1 << LOG_WARNING); - /** * Initialize filewriter data and open the log file * for each log file type. @@ -687,52 +677,54 @@ return_succ: return succ; } - +static std::unique_ptr message_registry; /** - * Initializes log managing routines in MariaDB Corporation MaxScale. + * Initializes log manager * * @param ident The syslog ident. If NULL, then the program name is used. - * @param logdir The directory for the log file. If NULL logging will be made to stdout. - * @param target Whether the log should be written to filesystem or shared memory. - * Meaningless if logdir is NULL. + * @param logdir The directory for the log file. + * @param target Logging target * * @return true if succeed, otherwise false * */ bool mxs_log_init(const char* ident, const char* logdir, mxs_log_target_t target) { - bool succ = false; + static bool log_init_done = false; + ss_dassert(!log_init_done); + log_init_done = true; - spinlock_acquire(&lmlock); + openlog(ident, LOG_PID | LOG_ODELAY, LOG_USER); - if (!lm) + // Tests mainly pass a NULL logdir with MXS_LOG_TARGET_STDOUT + std::string filename = "/dev/null"; + + if (logdir) { - ss_dassert(!message_registry); - - message_registry = new (std::nothrow) MessageRegistry; - - if (message_registry) - { - succ = logmanager_init_nomutex(ident, logdir, target, log_config.do_maxlog); - - if (!succ) - { - delete message_registry; - message_registry = NULL; - } - } - } - else - { - // TODO: This is not ok. If the parameters are different then - // TODO: we pretend something is what it is not. - succ = true; + filename = std::string(logdir) + "/" + LOGFILE_NAME_PREFIX + LOGFILE_NAME_SUFFIX; } - spinlock_release(&lmlock); + message_registry.reset(new (std::nothrow) MessageRegistry); - return succ; + switch (target) + { + case MXS_LOG_TARGET_FS: + case MXS_LOG_TARGET_DEFAULT: + logger = FileLogger::create(filename); + break; + + case MXS_LOG_TARGET_STDOUT: + logger = StdoutLogger::create(filename); + break; + + default: + ss_dassert(!true); + break; + } + + + return logger && message_registry; } /** @@ -776,9 +768,6 @@ static void logmanager_done_nomutex(void) /** Set global pointer NULL to prevent access to freed data. */ MXS_FREE(lm); lm = NULL; - - delete message_registry; - message_registry = NULL; } /** @@ -789,33 +778,9 @@ static void logmanager_done_nomutex(void) */ void mxs_log_finish(void) { - spinlock_acquire(&lmlock); - - if (lm) - { - CHK_LOGMANAGER(lm); - /** Mark logmanager unavailable */ - lm->lm_enabled = false; - - /** Wait until all users have left or someone shuts down - * logmanager between lock release and acquire. - */ - while (lm != NULL && lm->lm_nlinks != 0) - { - spinlock_release(&lmlock); - sched_yield(); - spinlock_acquire(&lmlock); - } - - /** Shut down if not already shutted down. */ - if (lm) - { - ss_dassert(lm->lm_nlinks == 0); - logmanager_done_nomutex(); - } - } - - spinlock_release(&lmlock); + closelog(); + logger.reset(); + message_registry.reset(); } static struct @@ -892,35 +857,22 @@ static logfile_t* logmanager_get_logfile(logmanager_t* lmgr) * @return 0 if succeed, -1 otherwise * */ -static int logmanager_write_log(int priority, - enum log_flush flush, - size_t prefix_len, - size_t str_len, - const char* str) +static int log_write(int priority, + size_t prefix_len, + size_t str_len, + const char* str) { - logfile_t* lf = NULL; - char* wp = NULL; int err = 0; - blockbuf_t* bb = NULL; - blockbuf_t* bb_c = NULL; size_t timestamp_len; - int i; // The config parameters are copied to local variables, because the values in // log_config may change during the course of the function, with would have // unpleasant side-effects. int do_highprecision = log_config.do_highprecision; - int do_maxlog = log_config.do_maxlog; int do_syslog = log_config.do_syslog; ss_dassert(str); ss_dassert((priority & ~(LOG_PRIMASK | LOG_FACMASK)) == 0); - CHK_LOGMANAGER(lm); - - // All messages are now logged to the error log file. - lf = &lm->lm_logfile; - CHK_LOGFILE(lf); - /** Length of string that will be written, limited by bufsize */ size_t safe_str_len; @@ -934,31 +886,14 @@ static int logmanager_write_log(int priority, } bool overflow = false; - /** Find out how much can be safely written with current block size */ - if (timestamp_len - sizeof(char) + str_len > lf->lf_buf_size) - { - safe_str_len = lf->lf_buf_size; - overflow = true; - } - else - { - safe_str_len = timestamp_len - sizeof(char) + str_len; - } + safe_str_len = timestamp_len - sizeof(char) + str_len; + /** * Seek write position and register to block buffer. * Then print formatted string to write position. */ - /** Book space for log string from buffer */ - if (do_maxlog) - { - // All messages are now logged to the error log file. - wp = blockbuf_get_writepos(&bb, safe_str_len, flush); - } - else - { - wp = (char*)MXS_MALLOC(sizeof(char) * (timestamp_len - sizeof(char) + str_len + 1)); - } + char wp[safe_str_len + 1]; if (wp == NULL) { @@ -1023,14 +958,7 @@ static int logmanager_write_log(int priority, } wp[safe_str_len - 1] = '\n'; - if (do_maxlog) - { - blockbuf_unregister(bb); - } - else - { - MXS_FREE(wp); - } + logger->write(wp, safe_str_len); return err; } @@ -1382,44 +1310,6 @@ void mxs_log_set_augmentation(int bits) log_config.augmentation = bits & MXS_LOG_AUGMENTATION_MASK; } -/** - * Helper for skygw_log_write and friends. - * - * @param int The syslog priority. - * @param file The name of the file where the logging was made. - * @param int The line where the logging was made. - * @param function The function where the logging was made. - * @param prefix_len The length of the text to be stripped away when syslogging. - * @param len Length of str, including terminating NULL. - * @param str String - * @param flush Whether the message should be flushed. - * - * @return 0 if the logging to at least one log succeeded. - */ - -static int log_write(int priority, - const char* file, - int line, - const char* function, - size_t prefix_len, - size_t len, - const char* str, - enum log_flush flush) -{ - int rv = -1; - - if (logmanager_register(true)) - { - CHK_LOGMANAGER(lm); - - rv = logmanager_write_log(priority, flush, prefix_len, len, str); - - logmanager_unregister(); - } - - return rv; -} - /** * @node Register as a logging client to logmanager. * @@ -2671,30 +2561,9 @@ int mxs_log_flush_sync(void) * successfully initiated, not whether the actual rotation has been * performed. */ -int mxs_log_rotate() +bool mxs_log_rotate() { - int err = -1; - - if (logmanager_register(false)) - { - CHK_LOGMANAGER(lm); - - logfile_t *lf = logmanager_get_logfile(lm); - CHK_LOGFILE(lf); - - MXS_NOTICE("Log rotation is called for %s.", lf->lf_full_file_name); - - logfile_rotate(lf); - err = 0; - - logmanager_unregister(); - } - else - { - LOG_ERROR("MaxScale Log: Error, Can't register to logmanager, rotating failed.\n"); - } - - return err; + return logger->rotate(); } static const char* level_name(int level) @@ -2895,6 +2764,7 @@ int mxs_log_message(int priority, { int err = 0; + ss_dassert(logger && message_registry); ss_dassert((priority & ~(LOG_PRIMASK | LOG_FACMASK)) == 0); int level = priority & LOG_PRIMASK; @@ -3045,9 +2915,7 @@ int mxs_log_message(int priority, sprintf(suppression_text, SUPPRESSION, suppress_ms); } - enum log_flush flush = level_to_flush(level); - - err = log_write(priority, file, line, function, prefix.len, buffer_len, buffer, flush); + err = log_write(priority, prefix.len, buffer_len, buffer); } } } @@ -3104,6 +2972,7 @@ json_t* get_log_priorities() json_t* mxs_logs_to_json(const char* host) { + ss_dassert(logger && message_registry); json_t* param = json_object(); json_object_set_new(param, "highprecision", json_boolean(log_config.do_highprecision)); json_object_set_new(param, "maxlog", json_boolean(log_config.do_maxlog)); @@ -3118,11 +2987,11 @@ json_t* mxs_logs_to_json(const char* host) json_object_set_new(param, "log_notice", json_boolean(mxs_log_priority_is_enabled(LOG_NOTICE))); json_object_set_new(param, "log_info", json_boolean(mxs_log_priority_is_enabled(LOG_INFO))); json_object_set_new(param, "log_debug", json_boolean(mxs_log_priority_is_enabled(LOG_DEBUG))); - json_object_set_new(param, "log_to_shm", json_boolean(config_get_global_options()->log_to_shm)); + json_object_set_new(param, "log_to_shm", json_boolean(false)); json_t* attr = json_object(); json_object_set_new(attr, CN_PARAMETERS, param); - json_object_set_new(attr, "log_file", json_string(lm->lm_filewriter.fwr_file->sf_fname)); + json_object_set_new(attr, "log_file", json_string(logger->filename())); json_object_set_new(attr, "log_priorities", get_log_priorities()); json_t* data = json_object(); diff --git a/server/core/resource.cc b/server/core/resource.cc index 0580de97f..86ec15145 100644 --- a/server/core/resource.cc +++ b/server/core/resource.cc @@ -662,7 +662,7 @@ HttpResponse cb_flush(const HttpRequest& request) int code = MHD_HTTP_INTERNAL_SERVER_ERROR; // Flush logs - if (mxs_log_rotate() == 0) + if (mxs_log_rotate()) { code = MHD_HTTP_NO_CONTENT; }