From 16641a1f46b90d79c5ca17f3706a954d7df27caf Mon Sep 17 00:00:00 2001 From: Esa Korhonen Date: Fri, 8 Feb 2019 11:13:30 +0200 Subject: [PATCH] MXS-2050 Prepare to move file handling inside router sessions The sessions will need to reopen the log file if it's rotated. --- server/modules/filter/qlafilter/qlafilter.cc | 147 ++++++++----------- server/modules/filter/qlafilter/qlafilter.hh | 37 +++-- 2 files changed, 87 insertions(+), 97 deletions(-) diff --git a/server/modules/filter/qlafilter/qlafilter.cc b/server/modules/filter/qlafilter/qlafilter.cc index fda34e976..e12dcf613 100644 --- a/server/modules/filter/qlafilter/qlafilter.cc +++ b/server/modules/filter/qlafilter/qlafilter.cc @@ -113,8 +113,7 @@ QlaInstance::QlaInstance(const string& name, MXS_CONFIG_PARAMETER* params) } QlaInstance::Settings::Settings(MXS_CONFIG_PARAMETER* params) - : log_mode_flags(params->get_enum(PARAM_LOG_TYPE, log_type_values)) - , log_file_data_flags(params->get_enum(PARAM_LOG_DATA, log_data_values)) + : log_file_data_flags(params->get_enum(PARAM_LOG_DATA, log_data_values)) , filebase(params->get_string(PARAM_FILEBASE)) , flush_writes(params->get_bool(PARAM_FLUSH)) , append(params->get_bool(PARAM_APPEND)) @@ -125,6 +124,9 @@ QlaInstance::Settings::Settings(MXS_CONFIG_PARAMETER* params) , match(params->get_string(PARAM_MATCH)) , exclude(params->get_string(PARAM_EXCLUDE)) { + auto log_file_types = params->get_enum(PARAM_LOG_TYPE, log_type_values); + write_session_log = (log_file_types & CONFIG_FILE_SESSION); + write_unified_log = (log_file_types & CONFIG_FILE_UNIFIED); } QlaInstance::~QlaInstance() @@ -137,19 +139,12 @@ QlaInstance::~QlaInstance() } } -QlaFilterSession::QlaFilterSession(const char* user, const char* remote, bool ses_active, - pcre2_match_data* mdata, - const string& ses_filename, FILE* ses_file, - size_t ses_id, const char* service, QlaInstance& instance) +QlaFilterSession::QlaFilterSession(QlaInstance& instance, MXS_SESSION* session) : m_instance(instance) - , m_user(user) - , m_remote(remote) - , m_active(ses_active) - , m_mdata(mdata) - , m_filename(ses_filename) - , m_logfile(ses_file) - , m_ses_id(ses_id) - , m_service(service) + , m_user(session_get_user(session)) + , m_remote(session_get_remote(session)) + , m_service(session->service->name) + , m_ses_id(session->ses_id) { } @@ -162,7 +157,7 @@ QlaFilterSession::~QlaFilterSession() void QlaFilterSession::close() { - if (m_active && m_logfile) + if (m_logfile) { fclose(m_logfile); m_logfile = nullptr; @@ -197,7 +192,7 @@ QlaInstance* QlaInstance::create(const std::string name, MXS_CONFIG_PARAMETER* p my_instance->m_re_exclude = re_exclude; my_instance->m_ovec_size = ovec_size; // Try to open the unified log file - if (my_instance->m_settings.log_mode_flags & CONFIG_FILE_UNIFIED) + if (my_instance->m_settings.write_unified_log) { string unified_filename = my_instance->m_settings.filebase + ".unified"; // Open the file. It is only closed at program exit. @@ -239,80 +234,68 @@ QlaInstance* QlaInstance::create(const std::string name, MXS_CONFIG_PARAMETER* p QlaFilterSession* QlaInstance::newSession(MXS_SESSION* session) { - // Need the following values before session constructor - const char* remote = session_get_remote(session); - const char* userName = session_get_user(session); - pcre2_match_data* mdata = NULL; - bool ses_active = true; - string filename; - FILE* session_file = NULL; - - bool error = false; - - mxb_assert(userName && remote); - if ((!m_settings.source.empty() && remote && m_settings.source != remote) - || (!m_settings.user_name.empty() && userName && m_settings.user_name != userName)) + auto my_session = new (std::nothrow) QlaFilterSession(*this, session); + if (my_session) { - ses_active = false; - } - - if (m_ovec_size > 0) - { - mdata = pcre2_match_data_create(m_ovec_size, NULL); - if (mdata == NULL) + if (!my_session->prepare()) { - // Can this happen? Would require pcre2 to fail completely. - MXS_ERROR("pcre2_match_data_create returned NULL."); - error = true; - } - } - - // Only open the session file if the corresponding mode setting is used - if (!error && ses_active && m_settings.log_mode_flags & CONFIG_FILE_SESSION) - { - filename = mxb::string_printf("%s.%" PRIu64, m_settings.filebase.c_str(), session->ses_id); - - // Session numbers are not printed to session files - uint32_t data_flags = (m_settings.log_file_data_flags & ~LOG_DATA_SESSION); - - session_file = open_log_file(data_flags, filename.c_str()); - if (session_file == NULL) - { - MXS_ERROR("Opening output file for qla-filter failed due to %d, %s", - errno, - mxs_strerror(errno)); - error = true; - } - } - - QlaFilterSession* my_session = NULL; - if (!error) - { - my_session = new(std::nothrow) QlaFilterSession(userName, remote, ses_active, mdata, - filename, session_file, - session->ses_id, session->service->name, - *this); - if (my_session == NULL) - { - error = true; - } - } - - if (error) - { - pcre2_match_data_free(mdata); - if (session_file) - { - fclose(session_file); + my_session->close(); + delete my_session; + my_session = nullptr; } } return my_session; } +bool QlaFilterSession::prepare() +{ + const auto& settings = m_instance.m_settings; + bool hostname_ok = settings.source.empty() || (m_remote == settings.source); + bool username_ok = settings.user_name.empty() || (m_user == settings.user_name); + m_active = hostname_ok && username_ok; + + bool error = false; + + if (m_active) + { + auto ovec_size = m_instance.m_ovec_size; + if (ovec_size > 0) + { + m_mdata = pcre2_match_data_create(ovec_size, NULL); + if (!m_mdata) + { + MXS_ERROR("pcre2_match_data_create returned NULL."); + error = true; + } + } + + // Only open the session file if the corresponding mode setting is used. + if (!error && settings.write_session_log) + { + string filename = mxb::string_printf("%s.%" PRIu64, settings.filebase.c_str(), m_ses_id); + // Session numbers are not printed to session files. + uint32_t data_flags = (settings.log_file_data_flags & ~LOG_DATA_SESSION); + + m_logfile = m_instance.open_log_file(data_flags, filename.c_str()); + if (m_logfile) + { + m_filename = filename; + } + else + { + MXS_ERROR("Opening output file %s' for qla-filter failed due to %d, %s", + filename.c_str(), errno, mxs_strerror(errno)); + error = true; + } + } + } + return !error; +} + bool QlaInstance::read_to_json(int start, int end, json_t** output) const { bool rval = false; - if (m_settings.log_mode_flags & CONFIG_FILE_UNIFIED) + if (m_settings.write_unified_log) { mxb_assert(m_unified_fp && !m_unified_filename.empty()); std::ifstream file(m_unified_filename); @@ -417,7 +400,7 @@ void QlaFilterSession::write_log_entries(const char* date_string, const char* qu int elapsed_ms) { bool write_error = false; - if (m_instance.m_settings.log_mode_flags & CONFIG_FILE_SESSION) + if (m_instance.m_settings.write_session_log) { // In this case there is no need to write the session // number into the files. @@ -432,7 +415,7 @@ void QlaFilterSession::write_log_entries(const char* date_string, const char* qu write_error = true; } } - if (m_instance.m_settings.log_mode_flags & CONFIG_FILE_UNIFIED) + if (m_instance.m_settings.write_unified_log) { uint32_t data_flags = m_instance.m_settings.log_file_data_flags; if (write_log_entry(m_instance.m_unified_fp, diff --git a/server/modules/filter/qlafilter/qlafilter.hh b/server/modules/filter/qlafilter/qlafilter.hh index 315e857d4..a6bfb48e5 100644 --- a/server/modules/filter/qlafilter/qlafilter.hh +++ b/server/modules/filter/qlafilter/qlafilter.hh @@ -104,6 +104,7 @@ public: void diagnostics(DCB* dcb) const; json_t* diagnostics_json() const; + FILE* open_log_file(uint32_t, const char*); const std::string m_name; /* Filter definition name */ @@ -122,7 +123,8 @@ public: public: Settings(MXS_CONFIG_PARAMETER* params); - uint32_t log_mode_flags {0}; /* Log file mode settings */ + bool write_unified_log {false}; + bool write_session_log {false}; uint32_t log_file_data_flags {0}; /* What data is saved to the files */ std::string filebase; /* The filename base */ bool flush_writes {false}; /* Flush log file after every write? */ @@ -136,9 +138,6 @@ public: }; Settings m_settings; - -private: - FILE* open_log_file(uint32_t, const char*); }; /* The session structure for this QLA filter. */ @@ -147,11 +146,16 @@ class QlaFilterSession : public MXS_FILTER_SESSION public: QlaFilterSession(const QlaFilterSession&); QlaFilterSession& operator=(const QlaFilterSession&); - QlaFilterSession(const char* user, const char* remote, bool ses_active, - pcre2_match_data* mdata, const std::string& ses_filename, FILE* ses_file, - size_t ses_id, const char* service, QlaInstance& instance); + QlaFilterSession(QlaInstance& instance, MXS_SESSION* session); ~QlaFilterSession(); + /** + * Prepares a session for routing. Checks if username and/or host match and opens the log file. + * + * @return True on success. If false is returned, the session should be closed and deleted. + */ + bool prepare(); + /** * Route a query. * @@ -175,14 +179,17 @@ public: QlaInstance& m_instance; - const char* m_user; /* Client username */ - const char* m_remote; /* Client address */ - bool m_active; /* Is session active? */ - pcre2_match_data* m_mdata; /* Regex match data */ - std::string m_filename; /* The session-specific log file name */ - FILE* m_logfile; /* The session-specific log file */ - size_t m_ses_id; /* The session this filter session serves. */ - const char* m_service; /* The service name this filter is attached to. */ + const std::string m_user; /* Client username */ + const std::string m_remote; /* Client address */ + const std::string m_service; /* The service name this filter is attached to. */ + const uint64_t m_ses_id {0}; /* The session this filter session serves. */ + + bool m_active {false}; /* Is session active? */ + pcre2_match_data* m_mdata {nullptr}; /* Regex match data */ + + std::string m_filename; /* The session-specific log file name */ + FILE* m_logfile {nullptr}; /* The session-specific log file */ + LogEventData m_event_data; /* Information about the latest event, used if logging execution time. */ MXS_UPSTREAM up;