mirror of https://github.com/sysown/proxysql
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
573 lines
18 KiB
573 lines
18 KiB
#include "proxysql.h"
|
|
#include "proxysql_atomic.h"
|
|
|
|
#include "sqlite3db.h"
|
|
#include "prometheus_helpers.h"
|
|
#include "gen_utils.h"
|
|
|
|
#include <set>
|
|
#include <cxxabi.h>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
#include <array>
|
|
|
|
using std::string;
|
|
using std::unordered_map;
|
|
|
|
#ifdef DEBUG
|
|
|
|
__thread unsigned long long pretime=0;
|
|
static pthread_mutex_t debug_mutex;
|
|
static pthread_rwlock_t filters_rwlock;
|
|
static SQLite3DB * debugdb_disk = NULL;
|
|
sqlite3_stmt *statement1=NULL;
|
|
static unsigned int debug_output = 1;
|
|
|
|
|
|
|
|
|
|
#define DEBUG_MSG_MAXSIZE 1024
|
|
|
|
|
|
struct DebugLogEntry {
|
|
unsigned long long time;
|
|
unsigned long long lapse;
|
|
int thr;
|
|
std::string file;
|
|
int line;
|
|
std::string funct;
|
|
int module;
|
|
std::string modname;
|
|
int verbosity;
|
|
std::string message;
|
|
std::string backtrace;
|
|
};
|
|
|
|
static const size_t limitSize = 100;
|
|
static std::vector<DebugLogEntry> log_buffer = {};
|
|
|
|
|
|
/**
|
|
* @brief Synchronizes the log buffer to the SQLite database.
|
|
*
|
|
* This function writes the contents of the shared log buffer to the SQLite database
|
|
* in a single transaction. It assumes that the log buffer is protected by a mutex
|
|
* and that the prepared statement `statement1` has already been prepared.
|
|
* This happens in proxy_debug_func()
|
|
*
|
|
* @param db A pointer to the SQLite3DB object.
|
|
*/
|
|
void sync_log_buffer_to_disk(SQLite3DB *db) {
|
|
int rc;
|
|
db->execute("BEGIN TRANSACTION");
|
|
for (const auto& entry : log_buffer) {
|
|
rc=(*proxy_sqlite3_bind_int64)(statement1, 1, entry.time); ASSERT_SQLITE_OK(rc, db);
|
|
rc=(*proxy_sqlite3_bind_int64)(statement1, 2, entry.lapse);ASSERT_SQLITE_OK(rc, db);
|
|
rc=(*proxy_sqlite3_bind_int64)(statement1, 3, entry.thr); ASSERT_SQLITE_OK(rc, db);
|
|
rc=(*proxy_sqlite3_bind_text)(statement1, 4, entry.file.c_str(), -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, db);
|
|
rc=(*proxy_sqlite3_bind_int64)(statement1, 5, entry.line); ASSERT_SQLITE_OK(rc, db);
|
|
rc=(*proxy_sqlite3_bind_text)(statement1, 6, entry.funct.c_str(), -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, db);
|
|
rc=(*proxy_sqlite3_bind_int64)(statement1, 7, entry.module); ASSERT_SQLITE_OK(rc, db);
|
|
rc=(*proxy_sqlite3_bind_text)(statement1, 8, entry.modname.c_str(), -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, db);
|
|
rc=(*proxy_sqlite3_bind_int64)(statement1, 9, entry.verbosity); ASSERT_SQLITE_OK(rc, db);
|
|
rc=(*proxy_sqlite3_bind_text)(statement1, 10, entry.message.c_str(), -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, db);
|
|
rc=(*proxy_sqlite3_bind_text)(statement1, 11, entry.backtrace.c_str(), -1, SQLITE_TRANSIENT); ASSERT_SQLITE_OK(rc, db);
|
|
SAFE_SQLITE3_STEP2(statement1);
|
|
rc=(*proxy_sqlite3_clear_bindings)(statement1); ASSERT_SQLITE_OK(rc, db);
|
|
// Note: no assert() in proxy_debug_func() after (*proxy_sqlite3_reset)() because it is possible that we are in shutdown
|
|
rc=(*proxy_sqlite3_reset)(statement1); // ASSERT_SQLITE_OK(rc, db);
|
|
}
|
|
db->execute("COMMIT");
|
|
log_buffer.clear();
|
|
}
|
|
|
|
/**
|
|
* @brief Contains all filters related to debug.
|
|
* @details The convention for key value is `filename:line:function`. This key structure also applies also
|
|
* applies if the line is `0` or function is empty, the `filename` is always mandatory.
|
|
*
|
|
* IMPORTANT: This structure is a pointer to avoid race conditions during process termination, otherwise the
|
|
* destruction of the object may be performed before working threads have exited. This structure will leak,
|
|
* this is intentional, since we can't synchronize the exit of the working threads with its destruction.
|
|
*/
|
|
std::set<std::string>* debug_filters = nullptr;
|
|
|
|
static bool filter_debug_entry(const char *__file, int __line, const char *__func) {
|
|
pthread_rwlock_rdlock(&filters_rwlock);
|
|
bool to_filter = false;
|
|
if (debug_filters && debug_filters->size()) { // if the set is empty we aren't performing any filter, so we won't search
|
|
std::string key(__file);
|
|
key += ":" + std::to_string(__line);
|
|
key += ":";
|
|
key += __func;
|
|
// we start with a full search
|
|
if (debug_filters->find(key) != debug_filters->end()) {
|
|
to_filter = true;
|
|
} else {
|
|
// we now search filename + line
|
|
key = __file;
|
|
key += ":" + std::to_string(__line);
|
|
// remember to add the final ":"
|
|
key += ":";
|
|
if (debug_filters->find(key) != debug_filters->end()) {
|
|
to_filter = true;
|
|
} else {
|
|
// we now search filename + function
|
|
key = __file;
|
|
// no line = 0
|
|
key += ":0:";
|
|
key += __func;
|
|
if (debug_filters->find(key) != debug_filters->end()) {
|
|
to_filter = true;
|
|
} else {
|
|
// we now search filename only
|
|
key = __file;
|
|
// remember to add ":" even if no line
|
|
key += ":0:";
|
|
if (debug_filters->find(key) != debug_filters->end()) {
|
|
to_filter = true;
|
|
} else {
|
|
// if we reached here, we couldn't find any filter
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
pthread_rwlock_unlock(&filters_rwlock);
|
|
return to_filter;
|
|
}
|
|
|
|
// we use this function to sent the filters to Admin
|
|
// we hold here the lock on filters_rwlock
|
|
void proxy_debug_get_filters(std::set<std::string>& f) {
|
|
pthread_rwlock_rdlock(&filters_rwlock);
|
|
if (debug_filters) {
|
|
f = *debug_filters;
|
|
}
|
|
pthread_rwlock_unlock(&filters_rwlock);
|
|
}
|
|
|
|
// we use this function to get the filters from Admin
|
|
// we hold here the lock on filters_rwlock
|
|
void proxy_debug_load_filters(std::set<std::string>& f) {
|
|
pthread_rwlock_wrlock(&filters_rwlock);
|
|
if (debug_filters) {
|
|
debug_filters->erase(debug_filters->begin(), debug_filters->end());
|
|
*debug_filters = f;
|
|
} else {
|
|
debug_filters = new std::set<std::string>(f);
|
|
}
|
|
pthread_rwlock_unlock(&filters_rwlock);
|
|
}
|
|
|
|
// REMINDER: This function should always save/restore 'errno', otherwise it could influence error handling.
|
|
void proxy_debug_func(
|
|
enum debug_module module,
|
|
int verbosity,
|
|
int thr,
|
|
const char *__file,
|
|
int __line,
|
|
const char *__func,
|
|
const char *fmt,
|
|
...
|
|
) {
|
|
int saved_errno = errno;
|
|
assert(module<PROXY_DEBUG_UNKNOWN);
|
|
if (pretime == 0) { // never initialized
|
|
pretime=realtime_time();
|
|
}
|
|
if (GloVars.global.gdbg_lvl[module].verbosity < verbosity) {
|
|
errno = saved_errno;
|
|
return;
|
|
}
|
|
// check if the entry must be filtered
|
|
if (filter_debug_entry(__file, __line, __func)) {
|
|
errno = saved_errno;
|
|
return;
|
|
}
|
|
|
|
char origdebugbuff[DEBUG_MSG_MAXSIZE];
|
|
char debugbuff[DEBUG_MSG_MAXSIZE];
|
|
char longdebugbuff[DEBUG_MSG_MAXSIZE*8];
|
|
char longdebugbuff2[DEBUG_MSG_MAXSIZE*8];
|
|
|
|
longdebugbuff[0]=0;
|
|
longdebugbuff2[0]=0;
|
|
|
|
unsigned long long curtime=realtime_time();
|
|
bool write_to_disk = false;
|
|
|
|
if (debugdb_disk != NULL && (debug_output == 2 || debug_output == 3)) {
|
|
write_to_disk = true;
|
|
}
|
|
|
|
if (
|
|
GloVars.global.foreground
|
|
||
|
|
write_to_disk == true
|
|
) {
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
vsnprintf(origdebugbuff, DEBUG_MSG_MAXSIZE,fmt,ap);
|
|
va_end(ap);
|
|
sprintf(longdebugbuff, "%llu(%llu): %d:%s:%d:%s(): MOD#%d#%s LVL#%d : %s" , curtime, curtime-pretime, thr, __file, __line, __func, module, GloVars.global.gdbg_lvl[module].name, verbosity, origdebugbuff);
|
|
}
|
|
#ifdef __GLIBC__
|
|
if (GloVars.global.gdbg_lvl[module].verbosity>=10) {
|
|
void *arr[20];
|
|
char **strings;
|
|
int s;
|
|
s = backtrace(arr, 20);
|
|
strings=backtrace_symbols(arr,s);
|
|
if (strings == NULL) {
|
|
perror("backtrace_symbols");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
for (int i=0; i<s; i++) {
|
|
debugbuff[0]=0;
|
|
sscanf(strings[i], "%*[^(](%100[^+]", debugbuff);
|
|
int status;
|
|
char *realname=NULL;
|
|
realname=abi::__cxa_demangle(debugbuff, 0, 0, &status);
|
|
if (realname) {
|
|
sprintf(debugbuff," ---- %s : %s\n", strings[i], realname);
|
|
strcat(longdebugbuff2,debugbuff);
|
|
}
|
|
}
|
|
free(strings);
|
|
}
|
|
#endif
|
|
pthread_mutex_lock(&debug_mutex);
|
|
if (debugdb_disk == NULL) {
|
|
// default behavior
|
|
if (longdebugbuff[0] != 0) {
|
|
fprintf(stderr, "%s", longdebugbuff);
|
|
}
|
|
if (longdebugbuff2[0] != 0) {
|
|
if (GloVars.global.gdbg_lvl[module].verbosity>=10) {
|
|
fprintf(stderr, "%s\n", longdebugbuff2);
|
|
}
|
|
}
|
|
} else {
|
|
SQLite3DB *db = debugdb_disk;
|
|
int rc = 0;
|
|
if (statement1==NULL) {
|
|
const char *a = "INSERT INTO debug_log (id, time, lapse, thread, file, line, funct, modnum, modname, verbosity, message, note, backtrace) VALUES (NULL, ?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, NULL, ?11)";
|
|
rc=db->prepare_v2(a, &statement1);
|
|
ASSERT_SQLITE_OK(rc, db);
|
|
}
|
|
if (debug_output == 1 || debug_output == 3) {
|
|
// to stderr
|
|
if (longdebugbuff[0] != 0) {
|
|
fprintf(stderr, "%s", longdebugbuff);
|
|
}
|
|
if (longdebugbuff2[0] != 0) {
|
|
fprintf(stderr, "%s", longdebugbuff2);
|
|
}
|
|
}
|
|
if (write_to_disk == true) {
|
|
// Create a DebugLogEntry
|
|
DebugLogEntry entry;
|
|
entry.time = curtime;
|
|
entry.lapse = curtime - pretime;
|
|
entry.thr = thr;
|
|
entry.file = __file;
|
|
entry.line = __line;
|
|
entry.funct = __func;
|
|
entry.module = module;
|
|
entry.modname = GloVars.global.gdbg_lvl[module].name;
|
|
entry.verbosity = verbosity;
|
|
entry.message = origdebugbuff;
|
|
entry.backtrace = longdebugbuff2;
|
|
log_buffer.push_back(entry);
|
|
// we now batch writes
|
|
// note1: in case of crash, the database will have some missing entries,
|
|
// but the entries can be read in `log_buffer` in the core dump
|
|
// note2: also in case of shutdown , `log_buffer` will have entries that won't be saved.
|
|
// if we really want *all* entries, we could just call sync_log_buffer_to_disk() on shutdown
|
|
if (
|
|
(log_buffer.size() >= limitSize)
|
|
||
|
|
(entry.file == "ProxySQL_Admin.cpp" && entry.funct == "flush_logs")
|
|
) {
|
|
sync_log_buffer_to_disk(db);
|
|
}
|
|
}
|
|
}
|
|
pthread_mutex_unlock(&debug_mutex);
|
|
if (curtime != 0)
|
|
pretime=curtime;
|
|
|
|
errno = saved_errno;
|
|
};
|
|
#endif
|
|
|
|
using metric_name = std::string;
|
|
using metric_help = std::string;
|
|
using metric_tags = std::map<std::string, std::string>;
|
|
|
|
using debug_dyn_counter_tuple = std::tuple<p_debug_dyn_counter::metric, metric_name, metric_help, metric_tags>;
|
|
using debug_dyn_counter_vector = std::vector<debug_dyn_counter_tuple>;
|
|
|
|
const std::tuple<debug_dyn_counter_vector> debug_metrics_map = std::make_tuple(
|
|
debug_dyn_counter_vector {
|
|
std::make_tuple (
|
|
p_debug_dyn_counter::proxysql_message_count,
|
|
"proxysql_message_count_total",
|
|
"Number of times a particular message has been logged by ProxySQL.",
|
|
metric_tags {}
|
|
)
|
|
}
|
|
);
|
|
|
|
std::map<std::string, prometheus::Counter*> p_proxysql_messages_map {};
|
|
std::array<prometheus::Family<prometheus::Counter>*, p_debug_dyn_counter::__size> p_debug_dyn_counter_array {};
|
|
std::mutex msg_stats_mutex {};
|
|
|
|
const int ProxySQL_MSG_STATS_FIELD_NUM = 7;
|
|
|
|
class ProxySQL_messages_stats {
|
|
public:
|
|
const int32_t message_id = 0;
|
|
const char* filename = nullptr;
|
|
const int32_t line = 0;
|
|
const char* func = nullptr;
|
|
|
|
uint64_t count_star = 0;
|
|
time_t first_seen = 0;
|
|
time_t last_seen = 0;
|
|
|
|
ProxySQL_messages_stats(
|
|
const int32_t message_id_, const char* filename_, const int32_t line_, const char* func_, time_t first_seen_,
|
|
time_t last_seen_, uint64_t count_star_
|
|
) : message_id(message_id_), filename(filename_), line(line_), func(func_), count_star(count_star_),
|
|
first_seen(first_seen_), last_seen(last_seen_)
|
|
{
|
|
assert(message_id_);
|
|
assert(filename_);
|
|
assert(line_);
|
|
assert(func_);
|
|
}
|
|
|
|
char** get_row() const {
|
|
char buf[128];
|
|
|
|
char** pta = static_cast<char**>(malloc(sizeof(char *)*ProxySQL_MSG_STATS_FIELD_NUM));
|
|
sprintf(buf,"%d",message_id);
|
|
pta[0]=strdup(buf);
|
|
pta[1]=strdup(filename);
|
|
sprintf(buf,"%d",line);
|
|
pta[2]=strdup(buf);
|
|
pta[3]=strdup(func);
|
|
sprintf(buf,"%lu",count_star);
|
|
pta[4]=strdup(buf);
|
|
sprintf(buf,"%ld", first_seen);
|
|
pta[5]=strdup(buf);
|
|
sprintf(buf,"%ld", last_seen);
|
|
pta[6]=strdup(buf);
|
|
|
|
return pta;
|
|
}
|
|
|
|
void add_time(uint64_t n) {
|
|
count_star++;
|
|
if (first_seen == 0) {
|
|
first_seen = n;
|
|
}
|
|
last_seen=n;
|
|
}
|
|
|
|
void free_row(char **pta) const {
|
|
for (int i=0; i < ProxySQL_MSG_STATS_FIELD_NUM; i++) {
|
|
assert(pta[i]);
|
|
free(pta[i]);
|
|
}
|
|
free(pta);
|
|
}
|
|
};
|
|
|
|
unordered_map<string, ProxySQL_messages_stats> umap_msg_stats {};
|
|
|
|
/**
|
|
* @brief Handles ProxySQL message logging.
|
|
* @details The extra variadic arguments are expected to be received in the following order:
|
|
* ```
|
|
* proxy_error_func(msgid, fmt_message, time_buf, __FILE__, __LINE__, __func__ , ## __VA_ARGS__);
|
|
* ```
|
|
* Any other use of the function is UNSAFE. And will result in unespecified behavior.
|
|
* @param msgid The message id of the message to be logged, when non-zero, stats about the message are updated in
|
|
* 'umap_msg_stats'.
|
|
* @param fmt The formatted string to be pass to 'vfprintf'.
|
|
* @param ... The variadic list of arguments to be passed to 'vfprintf'.
|
|
*/
|
|
void proxy_error_func(int msgid, const char *fmt, ...) {
|
|
va_list ap;
|
|
va_start(ap, fmt);
|
|
|
|
if (msgid != 0) {
|
|
va_list stats_params;
|
|
va_copy(stats_params, ap);
|
|
|
|
// ignore 'time' buffer argument
|
|
va_arg(stats_params, const char*);
|
|
|
|
// collect arguments '__FILE__', '__LINE__' and '__func__'
|
|
const char* file = va_arg(stats_params, const char*);
|
|
const int32_t line = va_arg(stats_params, int32_t);
|
|
const char* func = va_arg(stats_params, const char*);
|
|
|
|
std::lock_guard<std::mutex> msg_stats_guard { msg_stats_mutex };
|
|
|
|
string msg_stats_id { string { file } + ":" + std::to_string(line) + ":" + string { func } };
|
|
auto msg_stats = umap_msg_stats.find(msg_stats_id);
|
|
time_t tn = time(NULL);
|
|
|
|
const std::map<string,string> m_labels {
|
|
{ "message_id", std::to_string(msgid) }, { "filename", file },
|
|
{ "line", std::to_string(line) }, { "func", func }
|
|
};
|
|
|
|
prometheus::Family<prometheus::Counter>* m_family =
|
|
p_debug_dyn_counter_array[p_debug_dyn_counter::proxysql_message_count];
|
|
|
|
p_inc_map_counter(p_proxysql_messages_map, m_family, msg_stats_id, m_labels);
|
|
|
|
if (msg_stats != umap_msg_stats.end()) {
|
|
msg_stats->second.add_time(tn);
|
|
} else {
|
|
umap_msg_stats.insert(
|
|
{ msg_stats_id, ProxySQL_messages_stats(msgid, file, line, func, tn, tn, 1) }
|
|
);
|
|
}
|
|
}
|
|
|
|
vfprintf(stderr, fmt, ap);
|
|
va_end(ap);
|
|
};
|
|
|
|
SQLite3_result* proxysql_get_message_stats(bool reset) {
|
|
std::lock_guard<std::mutex> msg_stats_guard { msg_stats_mutex };
|
|
SQLite3_result* result = new SQLite3_result(ProxySQL_MSG_STATS_FIELD_NUM);
|
|
|
|
result->add_column_definition(SQLITE_TEXT,"message_id");
|
|
result->add_column_definition(SQLITE_TEXT,"filename");
|
|
result->add_column_definition(SQLITE_TEXT,"line");
|
|
result->add_column_definition(SQLITE_TEXT,"func");
|
|
result->add_column_definition(SQLITE_TEXT,"count_star");
|
|
result->add_column_definition(SQLITE_TEXT,"first_seen");
|
|
result->add_column_definition(SQLITE_TEXT,"last_seen");
|
|
|
|
for (const auto& msg_stats : umap_msg_stats) {
|
|
char** pta = msg_stats.second.get_row();
|
|
result->add_row(pta);
|
|
msg_stats.second.free_row(pta);
|
|
}
|
|
|
|
if (reset) {
|
|
umap_msg_stats.clear();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
void proxysql_init_debug_prometheus_metrics() {
|
|
init_prometheus_dyn_counter_array<debug_metrics_map_idx, p_debug_dyn_counter>(debug_metrics_map, p_debug_dyn_counter_array);
|
|
}
|
|
|
|
static void full_write(int fd, const char *buf, size_t len)
|
|
{
|
|
while (len > 0) {
|
|
ssize_t ret = write(fd, buf, len);
|
|
|
|
if ((ret == -1) && (errno != EINTR))
|
|
break;
|
|
|
|
buf += (size_t) ret;
|
|
len -= (size_t) ret;
|
|
}
|
|
}
|
|
|
|
void print_backtrace(void)
|
|
{
|
|
static const char start[] = "BACKTRACE ------------\n";
|
|
static const char end[] = "----------------------\n";
|
|
|
|
void *bt[1024];
|
|
int bt_size;
|
|
char **bt_syms;
|
|
int i;
|
|
|
|
bt_size = backtrace(bt, 1024);
|
|
bt_syms = backtrace_symbols(bt, bt_size);
|
|
full_write(STDERR_FILENO, start, strlen(start));
|
|
for (i = 1; i < bt_size; i++) {
|
|
size_t len = strlen(bt_syms[i]);
|
|
full_write(STDERR_FILENO, bt_syms[i], len);
|
|
full_write(STDERR_FILENO, "\n", 1);
|
|
}
|
|
full_write(STDERR_FILENO, end, strlen(end));
|
|
free(bt_syms);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
void init_debug_struct() {
|
|
int i;
|
|
pthread_mutex_init(&debug_mutex,NULL);
|
|
pthread_rwlock_init(&filters_rwlock, NULL);
|
|
GloVars.global.gdbg_lvl= (debug_level *) malloc(PROXY_DEBUG_UNKNOWN*sizeof(debug_level));
|
|
for (i=0;i<PROXY_DEBUG_UNKNOWN;i++) {
|
|
GloVars.global.gdbg_lvl[i].module=(enum debug_module)i;
|
|
GloVars.global.gdbg_lvl[i].verbosity=( GloVars.global.gdbg ? INT_MAX : 0 );
|
|
GloVars.global.gdbg_lvl[i].name=(char *)NULL;
|
|
}
|
|
GloVars.global.gdbg_lvl[PROXY_DEBUG_GENERIC].name=(char *)"debug_generic";
|
|
GloVars.global.gdbg_lvl[PROXY_DEBUG_NET].name=(char *)"debug_net";
|
|
GloVars.global.gdbg_lvl[PROXY_DEBUG_PKT_ARRAY].name=(char *)"debug_pkt_array";
|
|
GloVars.global.gdbg_lvl[PROXY_DEBUG_POLL].name=(char *)"debug_poll";
|
|
GloVars.global.gdbg_lvl[PROXY_DEBUG_MYSQL_COM].name=(char *)"debug_mysql_com";
|
|
GloVars.global.gdbg_lvl[PROXY_DEBUG_MYSQL_SERVER].name=(char *)"debug_mysql_server";
|
|
GloVars.global.gdbg_lvl[PROXY_DEBUG_MYSQL_CONNECTION].name=(char *)"debug_mysql_connection";
|
|
GloVars.global.gdbg_lvl[PROXY_DEBUG_MYSQL_CONNPOOL].name=(char *)"debug_mysql_connpool";
|
|
GloVars.global.gdbg_lvl[PROXY_DEBUG_MYSQL_RW_SPLIT].name=(char *)"debug_mysql_rw_split";
|
|
GloVars.global.gdbg_lvl[PROXY_DEBUG_MYSQL_AUTH].name=(char *)"debug_mysql_auth";
|
|
GloVars.global.gdbg_lvl[PROXY_DEBUG_MYSQL_PROTOCOL].name=(char *)"debug_mysql_protocol";
|
|
GloVars.global.gdbg_lvl[PROXY_DEBUG_MYSQL_QUERY_PROCESSOR].name=(char *)"debug_mysql_query_processor";
|
|
GloVars.global.gdbg_lvl[PROXY_DEBUG_MEMORY].name=(char *)"debug_memory";
|
|
GloVars.global.gdbg_lvl[PROXY_DEBUG_ADMIN].name=(char *)"debug_admin";
|
|
GloVars.global.gdbg_lvl[PROXY_DEBUG_SQLITE].name=(char *)"debug_sqlite";
|
|
GloVars.global.gdbg_lvl[PROXY_DEBUG_IPC].name=(char *)"debug_ipc";
|
|
GloVars.global.gdbg_lvl[PROXY_DEBUG_QUERY_CACHE].name=(char *)"debug_query_cache";
|
|
GloVars.global.gdbg_lvl[PROXY_DEBUG_QUERY_STATISTICS].name=(char *)"debug_query_statistics";
|
|
GloVars.global.gdbg_lvl[PROXY_DEBUG_RESTAPI].name=(char *)"debug_restapi";
|
|
GloVars.global.gdbg_lvl[PROXY_DEBUG_MONITOR].name=(char *)"debug_monitor";
|
|
GloVars.global.gdbg_lvl[PROXY_DEBUG_CLUSTER].name=(char *)"debug_cluster";
|
|
GloVars.global.gdbg_lvl[PROXY_DEBUG_GENAI].name=(char *)"debug_genai";
|
|
GloVars.global.gdbg_lvl[PROXY_DEBUG_NL2SQL].name=(char *)"debug_nl2sql";
|
|
GloVars.global.gdbg_lvl[PROXY_DEBUG_ANOMALY].name=(char *)"debug_anomaly";
|
|
|
|
for (i=0;i<PROXY_DEBUG_UNKNOWN;i++) {
|
|
// if this happen, the above table is not populated correctly
|
|
assert(GloVars.global.gdbg_lvl[i].name!=NULL);
|
|
}
|
|
}
|
|
|
|
|
|
void init_debug_struct_from_cmdline() {
|
|
if (GloVars.__cmd_proxysql_gdbg<0) return;
|
|
int i;
|
|
for (i=0;i<PROXY_DEBUG_UNKNOWN;i++) {
|
|
GloVars.global.gdbg_lvl[i].verbosity=GloVars.__cmd_proxysql_gdbg;
|
|
}
|
|
}
|
|
|
|
|
|
void proxysql_set_admin_debugdb_disk(SQLite3DB * _db) {
|
|
debugdb_disk = _db;
|
|
}
|
|
|
|
void proxysql_set_admin_debug_output(unsigned int _do) {
|
|
debug_output = _do;
|
|
}
|
|
|
|
#endif /* DEBUG */
|