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:
@ -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);
|
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_finish mxb_log_finish
|
||||||
#define mxs_log_message mxb_log_message
|
#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_get_throttling mxb_log_get_throttling
|
||||||
#define mxs_log_is_priority_enabled mxb_log_is_priority_enabled
|
#define mxs_log_is_priority_enabled mxb_log_is_priority_enabled
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
|
|
||||||
#include <maxbase/log.hh>
|
#include <maxbase/log.hh>
|
||||||
@ -28,6 +29,12 @@
|
|||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
|
struct ThisUnit
|
||||||
|
{
|
||||||
|
std::atomic<int> rotation_count {0};
|
||||||
|
};
|
||||||
|
ThisUnit this_unit;
|
||||||
|
|
||||||
const char* LOGFILE_NAME = "maxscale.log";
|
const char* LOGFILE_NAME = "maxscale.log";
|
||||||
|
|
||||||
size_t mxs_get_context(char* buffer, size_t len)
|
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);
|
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);
|
||||||
|
}
|
@ -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,
|
void print_string_replace_newlines(const char* sql_string, size_t sql_str_len,
|
||||||
const char* rep_newline, std::stringstream* output);
|
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);
|
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_settings(params)
|
||||||
, m_name(name)
|
, m_name(name)
|
||||||
, m_session_data_flags(m_settings.log_file_data_flags & ~LOG_DATA_SESSION)
|
, 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_remote(session_get_remote(session))
|
||||||
, m_service(session->service->name())
|
, m_service(session->service->name())
|
||||||
, m_ses_id(session->ses_id)
|
, 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;
|
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.
|
// New file created, print the log header.
|
||||||
string header = m_instance.generate_log_header(m_instance.m_session_data_flags);
|
string header = generate_log_header(data_flags);
|
||||||
if (!m_instance.write_to_logfile(m_logfile, header))
|
if (!write_to_logfile(fp, header))
|
||||||
{
|
{
|
||||||
MXS_ERROR(HEADER_ERROR, m_filename.c_str(), errno, mxs_strerror(errno));
|
MXS_ERROR(HEADER_ERROR, filename.c_str(), errno, mxs_strerror(errno));
|
||||||
fclose(m_logfile);
|
fclose(fp);
|
||||||
m_logfile = nullptr;
|
fp = nullptr;
|
||||||
|
*ppFile = fp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Either the old file existed or file creation failed.
|
// 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
|
* 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)
|
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_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_rotation_count = global_rot_count;
|
||||||
m_file_check_timer.restart();
|
m_instance.check_reopen_session_file(m_filename, &m_logfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (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)
|
void QlaInstance::write_unified_log_entry(const string& entry)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> guard(m_file_lock);
|
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 (m_unified_fp)
|
||||||
{
|
{
|
||||||
if (!write_to_logfile(m_unified_fp, entry))
|
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)
|
bool check_replace_file(const string& filename, FILE** ppFile)
|
||||||
{
|
{
|
||||||
auto zfilename = filename.c_str();
|
auto zfilename = filename.c_str();
|
||||||
|
@ -86,6 +86,7 @@ public:
|
|||||||
std::string generate_log_header(uint64_t data_flags) const;
|
std::string generate_log_header(uint64_t data_flags) const;
|
||||||
|
|
||||||
FILE* open_session_log_file(const std::string& filename) 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);
|
void write_unified_log_entry(const std::string& contents);
|
||||||
bool write_to_logfile(FILE* fp, const std::string& contents) const;
|
bool write_to_logfile(FILE* fp, const std::string& contents) const;
|
||||||
|
|
||||||
@ -121,10 +122,12 @@ public:
|
|||||||
private:
|
private:
|
||||||
bool open_unified_logfile();
|
bool open_unified_logfile();
|
||||||
FILE* open_log_file(uint64_t data_flags, const std::string& filename) const;
|
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::mutex m_file_lock; /* Protects access to the unified log file */
|
||||||
std::string m_unified_filename; /* Filename of the unified log file */
|
std::string m_unified_filename; /* Filename of the unified log file */
|
||||||
FILE* m_unified_fp {nullptr}; /* 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. */
|
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 */
|
pcre2_match_data* m_mdata {nullptr}; /* Regex match data */
|
||||||
|
|
||||||
FILE* m_logfile {nullptr}; /* The session-specific log file */
|
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 */
|
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. */
|
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_log_entries(const LogEventElems& elems);
|
||||||
void write_session_log_entry(const std::string& entry);
|
void write_session_log_entry(const std::string& entry);
|
||||||
std::string generate_log_entry(uint64_t data_flags, const LogEventElems& elems) const;
|
std::string generate_log_entry(uint64_t data_flags, const LogEventElems& elems) const;
|
||||||
|
Reference in New Issue
Block a user