MXS-2050 Use global counter to detect log rotation request

Modules need to check the number regularly to detect a new log rotation.
This commit is contained in:
Esa Korhonen 2019-02-12 17:47:17 +02:00
parent 98a081f65b
commit 90e5b80b71
4 changed files with 77 additions and 23 deletions

View File

@ -51,9 +51,24 @@ typedef MXB_LOG_THROTTLING MXS_LOG_THROTTLING;
*/
bool mxs_log_init(const char* ident, const char* logdir, mxs_log_target_t target);
/**
* Close and reopen MaxScale log files. Also increments a global rotation counter which modules
* can read to see if they should rotate their own logs.
*
* @return True if MaxScale internal logs were rotated. If false is returned, the rotation counter is not
* incremented.
*/
bool mxs_log_rotate();
/**
* Get the value of the log rotation counter. The counter is incremented when user requests a log rotation.
*
* @return Counter value
*/
int mxs_get_log_rotation_count();
#define mxs_log_finish mxb_log_finish
#define mxs_log_message mxb_log_message
#define mxs_log_rotate mxb_log_rotate
#define mxs_log_get_throttling mxb_log_get_throttling
#define mxs_log_is_priority_enabled mxb_log_is_priority_enabled

View File

@ -16,6 +16,7 @@
#include <sys/time.h>
#include <syslog.h>
#include <atomic>
#include <cinttypes>
#include <maxbase/log.hh>
@ -28,6 +29,12 @@
namespace
{
struct ThisUnit
{
std::atomic<int> rotation_count {0};
};
ThisUnit this_unit;
const char* LOGFILE_NAME = "maxscale.log";
size_t mxs_get_context(char* buffer, size_t len)
@ -129,3 +136,18 @@ json_t* mxs_logs_to_json(const char* host)
return mxs_json_resource(host, MXS_JSON_API_LOGS, data);
}
bool mxs_log_rotate()
{
bool rotated = mxb_log_rotate();
if (rotated)
{
this_unit.rotation_count.fetch_add(1, std::memory_order_relaxed);
}
return rotated;
}
int mxs_get_log_rotation_count()
{
return this_unit.rotation_count.load(std::memory_order_relaxed);
}

View File

@ -99,14 +99,6 @@ const MXS_ENUM_VALUE log_data_values[] =
void print_string_replace_newlines(const char* sql_string, size_t sql_str_len,
const char* rep_newline, std::stringstream* output);
/**
* Open a file if it doesn't exist.
*
* @param filename Filename
* @param ppFile Double pointer to old file. The file can be null.
* @return True if new file was opened successfully. False, if file already existed or if new file
* could not be opened. If false is returned, the caller should check that the file object exists.
*/
bool check_replace_file(const string& filename, FILE** ppFile);
}
@ -115,6 +107,7 @@ QlaInstance::QlaInstance(const string& name, MXS_CONFIG_PARAMETER* params)
: m_settings(params)
, m_name(name)
, m_session_data_flags(m_settings.log_file_data_flags & ~LOG_DATA_SESSION)
, m_rotation_count(mxs_get_log_rotation_count())
{
}
@ -151,6 +144,7 @@ QlaFilterSession::QlaFilterSession(QlaInstance& instance, MXS_SESSION* session)
, m_remote(session_get_remote(session))
, m_service(session->service->name())
, m_ses_id(session->ses_id)
, m_rotation_count(mxs_get_log_rotation_count())
{
}
@ -374,22 +368,29 @@ json_t* QlaInstance::diagnostics_json() const
return rval;
}
void QlaFilterSession::check_session_log_rotation()
void QlaInstance::check_reopen_file(const string& filename, uint64_t data_flags, FILE** ppFile) const
{
if (check_replace_file(m_filename, &m_logfile))
if (check_replace_file(filename, ppFile))
{
auto fp = *ppFile;
// New file created, print the log header.
string header = m_instance.generate_log_header(m_instance.m_session_data_flags);
if (!m_instance.write_to_logfile(m_logfile, header))
string header = generate_log_header(data_flags);
if (!write_to_logfile(fp, header))
{
MXS_ERROR(HEADER_ERROR, m_filename.c_str(), errno, mxs_strerror(errno));
fclose(m_logfile);
m_logfile = nullptr;
MXS_ERROR(HEADER_ERROR, filename.c_str(), errno, mxs_strerror(errno));
fclose(fp);
fp = nullptr;
*ppFile = fp;
}
}
// Either the old file existed or file creation failed.
}
void QlaInstance::check_reopen_session_file(const std::string& filename, FILE** ppFile) const
{
check_reopen_file(filename, m_session_data_flags, ppFile);
}
/**
* Write QLA log entry/entries to disk
*
@ -397,13 +398,13 @@ void QlaFilterSession::check_session_log_rotation()
*/
void QlaFilterSession::write_log_entries(const LogEventElems& elems)
{
const int check_interval = 60; // Check log rotation once per minute.
if (m_instance.m_settings.write_session_log)
{
if (m_file_check_timer.split().secs() > check_interval)
int global_rot_count = mxs_get_log_rotation_count();
if (global_rot_count > m_rotation_count)
{
check_session_log_rotation();
m_file_check_timer.restart();
m_rotation_count = global_rot_count;
m_instance.check_reopen_session_file(m_filename, &m_logfile);
}
if (m_logfile)
@ -703,7 +704,13 @@ void QlaFilterSession::write_session_log_entry(const string& entry)
void QlaInstance::write_unified_log_entry(const string& entry)
{
std::lock_guard<std::mutex> guard(m_file_lock);
// TODO: Handle log rotation here.
int global_rot_count = mxs_get_log_rotation_count();
if (global_rot_count > m_rotation_count)
{
m_rotation_count = global_rot_count;
check_reopen_file(m_unified_filename, m_settings.log_file_data_flags, &m_unified_fp);
}
if (m_unified_fp)
{
if (!write_to_logfile(m_unified_fp, entry))
@ -773,6 +780,14 @@ void print_string_replace_newlines(const char* sql_string,
}
}
/**
* Open a file if it doesn't exist.
*
* @param filename Filename
* @param ppFile Double pointer to old file. The file can be null.
* @return True if new file was opened successfully. False, if file already existed or if new file
* could not be opened. If false is returned, the caller should check that the file object exists.
*/
bool check_replace_file(const string& filename, FILE** ppFile)
{
auto zfilename = filename.c_str();

View File

@ -86,6 +86,7 @@ public:
std::string generate_log_header(uint64_t data_flags) const;
FILE* open_session_log_file(const std::string& filename) const;
void check_reopen_session_file(const std::string& filename, FILE** ppFile) const;
void write_unified_log_entry(const std::string& contents);
bool write_to_logfile(FILE* fp, const std::string& contents) const;
@ -121,10 +122,12 @@ public:
private:
bool open_unified_logfile();
FILE* open_log_file(uint64_t data_flags, const std::string& filename) const;
void check_reopen_file(const std::string& filename, uint64_t data_flags, FILE** ppFile) const;
std::mutex m_file_lock; /* Protects access to the unified log file */
std::string m_unified_filename; /* Filename of the unified log file */
FILE* m_unified_fp {nullptr}; /* Unified log file. */
int m_rotation_count {0}; /* Log rotation counter */
bool m_write_error_logged {false}; /* Avoid repeatedly printing some errors/warnings. */
};
@ -183,7 +186,7 @@ private:
pcre2_match_data* m_mdata {nullptr}; /* Regex match data */
FILE* m_logfile {nullptr}; /* The session-specific log file */
mxb::StopWatch m_file_check_timer; /* When was file checked for rotation */
int m_rotation_count {0}; /* Log rotation counter */
bool m_write_error_logged {false}; /* Has write error been logged */
/**
@ -223,7 +226,6 @@ private:
LogEventData m_event_data; /* Information about the latest event, used if logging execution time. */
void check_session_log_rotation();
void write_log_entries(const LogEventElems& elems);
void write_session_log_entry(const std::string& entry);
std::string generate_log_entry(uint64_t data_flags, const LogEventElems& elems) const;