diff --git a/server/modules/filter/qlafilter/qlafilter.cc b/server/modules/filter/qlafilter/qlafilter.cc index 1e4d9225f..3181326bb 100644 --- a/server/modules/filter/qlafilter/qlafilter.cc +++ b/server/modules/filter/qlafilter/qlafilter.cc @@ -21,9 +21,8 @@ * in a single GWBUF. */ -#define MXS_MODULE_NAME "qlafilter" -#include +#include "qlafilter.hh" #include #include @@ -39,10 +38,8 @@ #include #include -#include #include #include -#include #include #include #include @@ -53,9 +50,6 @@ using std::string; class QlaFilterSession; class QlaInstance; -/* Date string buffer size */ -#define QLA_DATE_BUFFER_SIZE 20 - /* Log file save mode flags */ #define CONFIG_FILE_SESSION (1 << 0) // Default value, session specific files #define CONFIG_FILE_UNIFIED (1 << 1) // One file shared by all sessions @@ -136,94 +130,6 @@ static const MXS_ENUM_VALUE log_data_values[] = {NULL} }; -/** - * Helper struct for holding data before it's written to file. - */ -class LogEventData -{ -private: - LogEventData(const LogEventData&); - LogEventData& operator=(const LogEventData&); - -public: - LogEventData() - : has_message(false) - , query_clone(NULL) - , begin_time( - { - 0, 0 - }) - { - } - - ~LogEventData() - { - mxb_assert(query_clone == NULL); - } - - /** - * Resets event data. - * - * @param event Event to reset - */ - void clear() - { - has_message = false; - gwbuf_free(query_clone); - query_clone = NULL; - query_date[0] = '\0'; - begin_time = {0, 0}; - } - - bool has_message; // Does message data exist? - GWBUF* query_clone; // Clone of the query buffer. - char query_date[QLA_DATE_BUFFER_SIZE]; // Text representation of date. - timespec begin_time; // Timer value at the moment of receiving query. -}; - -/** - * A instance structure, the assumption is that the option passed - * to the filter is simply a base for the filename to which the queries - * are logged. - * - * To this base a session number is attached such that each session will - * have a unique name. - */ -class QlaInstance -{ -private: - QlaInstance(const QlaInstance&); - QlaInstance& operator=(const QlaInstance&); - -public: - QlaInstance(const char* name, MXS_CONFIG_PARAMETER* params); - ~QlaInstance(); - - string name; /* Filter definition name */ - - uint32_t log_mode_flags; /* Log file mode settings */ - uint32_t log_file_data_flags; /* What data is saved to the files */ - - string filebase; /* The filename base */ - string unified_filename; /* Filename of the unified log file */ - FILE* unified_fp; /* Unified log file. The pointer needs to be shared here - * to avoid garbled printing. */ - bool flush_writes; /* Flush log file after every write? */ - bool append; /* Open files in append-mode? */ - string query_newline; /* Character(s) used to replace a newline within a query */ - string separator; /* Character(s) used to separate elements */ - bool write_warning_given; /* Avoid repeatedly printing some errors/warnings. */ - - string user_name; /* The user name to filter on */ - string source; /* The source of the client connection to filter on */ - - string match; /* Optional text to match against */ - string exclude; /* Optional text to match against for exclusion */ - pcre2_code* re_match; /* Compiled regex text */ - pcre2_code* re_exclude; /* Compiled regex nomatch text */ - uint32_t ovec_size; /* PCRE2 match data ovector size */ -}; - QlaInstance::QlaInstance(const char* name, MXS_CONFIG_PARAMETER* params) : name(name) , log_mode_flags(params->get_enum(PARAM_LOG_TYPE, log_type_values)) @@ -255,46 +161,10 @@ QlaInstance::~QlaInstance() } } -/* The session structure for this QLA filter. */ -class QlaFilterSession -{ -private: - QlaFilterSession(const QlaFilterSession&); - QlaFilterSession& operator=(const QlaFilterSession&); - -public: - 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); - ~QlaFilterSession(); - - 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 */ - 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. */ - LogEventData m_event_data; /* Information about the latest event, used if logging execution time. */ - - MXS_UPSTREAM up; - MXS_DOWNSTREAM down; -}; - -QlaFilterSession::QlaFilterSession(const char* user, - const char* remote, - bool ses_active, +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) + const string& ses_filename, FILE* ses_file, + size_t ses_id, const char* service) : m_user(user) , m_remote(remote) , m_active(ses_active) @@ -313,143 +183,6 @@ QlaFilterSession::~QlaFilterSession() mxb_assert(m_logfile == NULL && m_event_data.has_message == false); } -MXS_BEGIN_DECLS - -/** - * The module entry point routine. - * - * @return The module object - */ -MXS_MODULE* MXS_CREATE_MODULE() -{ - modulecmd_arg_type_t args[] = - { - { - MODULECMD_ARG_FILTER | MODULECMD_ARG_NAME_MATCHES_DOMAIN, - "Filter to read logs from" - }, - { - MODULECMD_ARG_STRING | MODULECMD_ARG_OPTIONAL, - "Start reading from this line" - }, - { - MODULECMD_ARG_STRING | MODULECMD_ARG_OPTIONAL, - "Stop reading at this line (exclusive)" - } - }; - - modulecmd_register_command(MXS_MODULE_NAME, - "log", - MODULECMD_TYPE_PASSIVE, - cb_log, - 3, - args, - "Show unified log file as a JSON array"); - - static MXS_FILTER_OBJECT MyObject = - { - createInstance, - newSession, - closeSession, - freeSession, - setDownstream, - setUpstream, - routeQuery, - clientReply, - diagnostic, - diagnostic_json, - getCapabilities, - NULL, // No destroyInstance - }; - - static MXS_MODULE info = - { - MXS_MODULE_API_FILTER, - MXS_MODULE_GA, - MXS_FILTER_VERSION, - "A simple query logging filter", - "V1.1.1", - RCAP_TYPE_CONTIGUOUS_INPUT, - &MyObject, - NULL, /* Process init. */ - NULL, /* Process finish. */ - NULL, /* Thread init. */ - NULL, /* Thread finish. */ - { - { - PARAM_MATCH, - MXS_MODULE_PARAM_REGEX - }, - { - PARAM_EXCLUDE, - MXS_MODULE_PARAM_REGEX - }, - { - PARAM_USER, - MXS_MODULE_PARAM_STRING - }, - { - PARAM_SOURCE, - MXS_MODULE_PARAM_STRING - }, - { - PARAM_FILEBASE, - MXS_MODULE_PARAM_STRING, - NULL, - MXS_MODULE_OPT_REQUIRED - }, - { - PARAM_OPTIONS, - MXS_MODULE_PARAM_ENUM, - "ignorecase", - MXS_MODULE_OPT_NONE, - option_values - }, - { - PARAM_LOG_TYPE, - MXS_MODULE_PARAM_ENUM, - "session", - MXS_MODULE_OPT_NONE, - log_type_values - }, - { - PARAM_LOG_DATA, - MXS_MODULE_PARAM_ENUM, - LOG_DATA_DEFAULT, - MXS_MODULE_OPT_NONE, - log_data_values - }, - { - PARAM_NEWLINE, - MXS_MODULE_PARAM_QUOTEDSTRING, - "\" \"", - MXS_MODULE_OPT_NONE - }, - { - PARAM_SEPARATOR, - MXS_MODULE_PARAM_QUOTEDSTRING, - ",", - MXS_MODULE_OPT_NONE - }, - { - PARAM_FLUSH, - MXS_MODULE_PARAM_BOOL, - "false" - }, - { - PARAM_APPEND, - MXS_MODULE_PARAM_BOOL, - "false" - }, - {MXS_END_MODULE_PARAMS} - } - }; - - return &info; -} - -MXS_END_DECLS - /** * Create an instance of the filter for a particular service within MaxScale. * @@ -1241,3 +974,108 @@ static bool cb_log(const MODULECMD_ARG* argv, json_t** output) return rval; } + +/** + * The module entry point routine. + * + * @return The module object + */ +extern "C" MXS_MODULE* MXS_CREATE_MODULE() +{ + modulecmd_arg_type_t args[] = + { + { + MODULECMD_ARG_FILTER | MODULECMD_ARG_NAME_MATCHES_DOMAIN, + "Filter to read logs from" + }, + { + MODULECMD_ARG_STRING | MODULECMD_ARG_OPTIONAL, + "Start reading from this line" + }, + { + MODULECMD_ARG_STRING | MODULECMD_ARG_OPTIONAL, + "Stop reading at this line (exclusive)" + } + }; + + modulecmd_register_command(MXS_MODULE_NAME, "log", MODULECMD_TYPE_PASSIVE, + cb_log, 3, args, + "Show unified log file as a JSON array"); + + static MXS_FILTER_OBJECT MyObject = + { + createInstance, + newSession, + closeSession, + freeSession, + setDownstream, + setUpstream, + routeQuery, + clientReply, + diagnostic, + diagnostic_json, + getCapabilities, + NULL, // No destroyInstance + }; + + static const char description[] = "A simple query logging filter"; + uint64_t capabilities = RCAP_TYPE_CONTIGUOUS_INPUT; + static MXS_MODULE info = + { + MXS_MODULE_API_FILTER, + MXS_MODULE_GA, + MXS_FILTER_VERSION, + description, + "V1.1.1", + capabilities, + &MyObject, + NULL, /* Process init. */ + NULL, /* Process finish. */ + NULL, /* Thread init. */ + NULL, /* Thread finish. */ + { + { + PARAM_MATCH, MXS_MODULE_PARAM_REGEX + }, + { + PARAM_EXCLUDE, MXS_MODULE_PARAM_REGEX + }, + { + PARAM_USER, MXS_MODULE_PARAM_STRING + }, + { + PARAM_SOURCE, MXS_MODULE_PARAM_STRING + }, + { + PARAM_FILEBASE, MXS_MODULE_PARAM_STRING, NULL, MXS_MODULE_OPT_REQUIRED + }, + { + PARAM_OPTIONS, MXS_MODULE_PARAM_ENUM, "ignorecase", MXS_MODULE_OPT_NONE, + option_values + }, + { + PARAM_LOG_TYPE, MXS_MODULE_PARAM_ENUM, "session", MXS_MODULE_OPT_NONE, + log_type_values + }, + { + PARAM_LOG_DATA, MXS_MODULE_PARAM_ENUM, LOG_DATA_DEFAULT, MXS_MODULE_OPT_NONE, + log_data_values + }, + { + PARAM_NEWLINE, MXS_MODULE_PARAM_QUOTEDSTRING, "\" \"", MXS_MODULE_OPT_NONE + }, + { + PARAM_SEPARATOR,MXS_MODULE_PARAM_QUOTEDSTRING, ",", MXS_MODULE_OPT_NONE + }, + { + PARAM_FLUSH, MXS_MODULE_PARAM_BOOL, "false" + }, + { + PARAM_APPEND, MXS_MODULE_PARAM_BOOL, "false" + }, + {MXS_END_MODULE_PARAMS} + } + }; + + return &info; +} diff --git a/server/modules/filter/qlafilter/qlafilter.hh b/server/modules/filter/qlafilter/qlafilter.hh new file mode 100644 index 000000000..17eb577b9 --- /dev/null +++ b/server/modules/filter/qlafilter/qlafilter.hh @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2019 MariaDB Corporation Ab + * + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file and at www.mariadb.com/bsl11. + * + * Change Date: 2022-01-01 + * + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2 or later of the General + * Public License. + */ + +#define MXS_MODULE_NAME "qlafilter" + +#include + +#include +#include +#include +#include + + +/* Date string buffer size */ +#define QLA_DATE_BUFFER_SIZE 20 + +/** + * Helper struct for holding data before it's written to file. + */ +class LogEventData +{ +public: + LogEventData(const LogEventData&) = delete; + LogEventData& operator=(const LogEventData&) = default; + LogEventData() = default; + + ~LogEventData() + { + mxb_assert(query_clone == NULL); + } + + /** + * Resets event data. + * + * @param event Event to reset + */ + void clear() + { + gwbuf_free(query_clone); + *this = LogEventData(); + } + + bool has_message {false}; // Does message data exist? + GWBUF* query_clone {nullptr}; // Clone of the query buffer. + char query_date[QLA_DATE_BUFFER_SIZE]; // Text representation of date. + timespec begin_time {0, 0}; // Timer value at the moment of receiving query. +}; + +/** + * A instance structure, the assumption is that the option passed + * to the filter is simply a base for the filename to which the queries + * are logged. + * + * To this base a session number is attached such that each session will + * have a unique name. + */ +class QlaInstance +{ +public: + QlaInstance(const QlaInstance&) = delete; + QlaInstance& operator=(const QlaInstance&) = delete; + QlaInstance(const char* name, MXS_CONFIG_PARAMETER* params); + ~QlaInstance(); + + std::string name; /* Filter definition name */ + + uint32_t log_mode_flags; /* Log file mode settings */ + uint32_t log_file_data_flags; /* What data is saved to the files */ + + std::string filebase; /* The filename base */ + std::string unified_filename; /* Filename of the unified log file */ + FILE* unified_fp; /* Unified log file. The pointer needs to be shared here + * to avoid garbled printing. */ + bool flush_writes; /* Flush log file after every write? */ + bool append; /* Open files in append-mode? */ + std::string query_newline; /* Character(s) used to replace a newline within a query */ + std::string separator; /* Character(s) used to separate elements */ + bool write_warning_given;/* Avoid repeatedly printing some errors/warnings. */ + + std::string user_name; /* The user name to filter on */ + std::string source; /* The source of the client connection to filter on */ + + std::string match; /* Optional text to match against */ + std::string exclude; /* Optional text to match against for exclusion */ + pcre2_code* re_match; /* Compiled regex text */ + pcre2_code* re_exclude; /* Compiled regex nomatch text */ + uint32_t ovec_size; /* PCRE2 match data ovector size */ +}; + +/* The session structure for this QLA filter. */ +class QlaFilterSession +{ +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); + ~QlaFilterSession(); + + 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. */ + LogEventData m_event_data; /* Information about the latest event, used if logging execution time. */ + + MXS_UPSTREAM up; + MXS_DOWNSTREAM down; +};