Add generic debug flag to MaxScale
MXS-1282. The flags "-g=arglist" or "--debug=arglist" activate the debug settings specified in the comma-separated list arglist. Currently, the setting "disable-module-unloading", which prevents modules (.so-files) from being unloaded at exit, is supported. This allows Valgrind to produce line numbers for leak reports when the memory was allocated in a module. The setting "enable-module-unloading" is also available, but this is activated by default. The debug arguments and their actions are defined in a structure array, so adding more is straightforward.
This commit is contained in:
@ -125,12 +125,15 @@ static struct option long_options[] =
|
||||
{"version-full", no_argument, 0, 'V'},
|
||||
{"help", no_argument, 0, '?'},
|
||||
{"connector_plugindir", required_argument, 0, 'H'},
|
||||
{"debug", required_argument, 0, 'g'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
static bool syslog_configured = false;
|
||||
static bool maxlog_configured = false;
|
||||
static bool log_to_shm_configured = false;
|
||||
static volatile sig_atomic_t last_signal = 0;
|
||||
static bool unload_modules_at_exit = true;
|
||||
|
||||
static int cnf_preparser(void* data, const char* section, const char* name, const char* value);
|
||||
static void log_flush_shutdown(void);
|
||||
@ -145,6 +148,7 @@ static int ntfw_cb(const char*, const struct stat*, int, struct FTW*);
|
||||
static bool file_is_readable(const char* absolute_pathname);
|
||||
static bool file_is_writable(const char* absolute_pathname);
|
||||
bool handle_path_arg(char** dest, const char* path, const char* arg, bool rd, bool wr);
|
||||
static bool handle_debug_args(char* args);
|
||||
static void set_log_augmentation(const char* value);
|
||||
static void usage(void);
|
||||
static char* get_expanded_pathname(
|
||||
@ -172,6 +176,32 @@ static bool daemonize();
|
||||
static bool sniff_configuration(const char* filepath);
|
||||
static bool modules_process_init();
|
||||
static void modules_process_finish();
|
||||
static void disable_module_unloading();
|
||||
static void enable_module_unloading();
|
||||
|
||||
struct DEBUG_ARGUMENT
|
||||
{
|
||||
const char* name; /**< The name of the debug argument */
|
||||
void (*action)(); /**< The function implementing the argument */
|
||||
const char* description; /**< Help text */
|
||||
};
|
||||
|
||||
#define SPACER " "
|
||||
|
||||
const DEBUG_ARGUMENT debug_arguments[] =
|
||||
{
|
||||
{
|
||||
"disable-module-unloading", disable_module_unloading,
|
||||
"disable module unloading at exit. Will produce better\n"
|
||||
SPACER "Valgring leak reports if leaked memory was allocated in\n"
|
||||
SPACER "a shared library"
|
||||
},
|
||||
{
|
||||
"enable-module-unloading", enable_module_unloading,
|
||||
"cancels disable-module-unloading"
|
||||
},
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
/** SSL multi-threading functions and structures */
|
||||
|
||||
@ -916,6 +946,14 @@ static void usage(void)
|
||||
" -S, --maxlog=[yes|no] log messages to MaxScale log (default: yes)\n"
|
||||
" -G, --log_augmentation=0|1 augment messages with the name of the function\n"
|
||||
" where the message was logged (default: 0)\n"
|
||||
" -g, --debug=arg1,arg2,... enable or disable debug features. Supported arguments:\n",
|
||||
progname);
|
||||
for (int i = 0; debug_arguments[i].action != NULL; i++)
|
||||
{
|
||||
fprintf(stderr,
|
||||
" %-24s %s\n", debug_arguments[i].name, debug_arguments[i].description);
|
||||
}
|
||||
fprintf(stderr,
|
||||
" -v, --version print version info and exit\n"
|
||||
" -V, --version-full print full version info and exit\n"
|
||||
" -?, --help show this help\n"
|
||||
@ -940,7 +978,6 @@ static void usage(void)
|
||||
"dir will be '/path/maxscale/var/log/maxscale', the config dir will be\n"
|
||||
"'/path/maxscale/etc' and the default config file will be\n"
|
||||
"'/path/maxscale/etc/maxscale.cnf'.\n",
|
||||
progname,
|
||||
get_configdir(), default_cnf_fname,
|
||||
get_configdir(), get_logdir(), get_cachedir(), get_libdir(),
|
||||
get_datadir(), get_execdir(), get_langdir(), get_piddir(),
|
||||
@ -1299,7 +1336,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
while ((opt = getopt_long(argc, argv, "dcf:l:vVs:S:?L:D:C:B:U:A:P:G:N:E:F:M:H:",
|
||||
while ((opt = getopt_long(argc, argv, "dcf:g:l:vVs:S:?L:D:C:B:U:A:P:G:N:E:F:M:H:",
|
||||
long_options, &option_index)) != -1)
|
||||
{
|
||||
bool succp = true;
|
||||
@ -1565,6 +1602,13 @@ int main(int argc, char **argv)
|
||||
config_check = true;
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
if (!handle_debug_args(optarg))
|
||||
{
|
||||
succp = false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
usage();
|
||||
succp = false;
|
||||
@ -2067,8 +2111,10 @@ int main(int argc, char **argv)
|
||||
utils_end();
|
||||
cleanup_process_datadir();
|
||||
MXS_NOTICE("MaxScale shutdown completed.");
|
||||
|
||||
unload_all_modules();
|
||||
if (unload_modules_at_exit)
|
||||
{
|
||||
unload_all_modules();
|
||||
}
|
||||
/* Remove Pidfile */
|
||||
unlock_pidfile();
|
||||
unlink_pidfile();
|
||||
@ -2899,3 +2945,87 @@ static void modules_process_finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void enable_module_unloading()
|
||||
{
|
||||
unload_modules_at_exit = true;
|
||||
}
|
||||
|
||||
static void disable_module_unloading()
|
||||
{
|
||||
unload_modules_at_exit = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process command line debug arguments
|
||||
*
|
||||
* @param args The debug argument list
|
||||
* @return True on success, false on error
|
||||
*/
|
||||
static bool handle_debug_args(char* args)
|
||||
{
|
||||
bool arg_error = false;
|
||||
int args_found = 0;
|
||||
char *endptr = NULL;
|
||||
char* token = strtok_r(args, ",", &endptr);
|
||||
while (token)
|
||||
{
|
||||
bool found = false;
|
||||
for (int i = 0; debug_arguments[i].action != NULL; i++)
|
||||
{
|
||||
// Debug features are activated by running functions in the struct-array.
|
||||
if (strcmp(token, debug_arguments[i].name) == 0)
|
||||
{
|
||||
found = true;
|
||||
args_found++;
|
||||
debug_arguments[i].action();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
const char UNRECOG_P1[] = "Unrecognized debug setting: '";
|
||||
const char UNRECOG_P2[] = "'.";
|
||||
size_t unrecog_msg_len = sizeof(UNRECOG_P1) + strlen(token) + sizeof(UNRECOG_P2);
|
||||
char unrecog_msg[unrecog_msg_len];
|
||||
snprintf(unrecog_msg, unrecog_msg_len, "%s%s%s", UNRECOG_P1, token, UNRECOG_P2);
|
||||
print_log_n_stderr(true, true, unrecog_msg, unrecog_msg, 0);
|
||||
arg_error = true;
|
||||
}
|
||||
token = strtok_r(NULL, ",", &endptr);
|
||||
}
|
||||
if (args_found == 0)
|
||||
{
|
||||
arg_error = true;
|
||||
}
|
||||
if (arg_error)
|
||||
{
|
||||
// Form a string with all debug argument names listed.
|
||||
size_t total_len = 0;
|
||||
for (int i = 0; debug_arguments[i].action != NULL; i++)
|
||||
{
|
||||
total_len += strlen(debug_arguments[i].name) + 1;
|
||||
}
|
||||
char arglist[total_len] = "";
|
||||
for (int i = 0; debug_arguments[i].action != NULL; i++)
|
||||
{
|
||||
strcat(arglist, debug_arguments[i].name);
|
||||
// If not the last element, add a comma
|
||||
if (debug_arguments[i + 1].action != NULL)
|
||||
{
|
||||
strcat(arglist, ", ");
|
||||
}
|
||||
}
|
||||
const char DEBUG_ERROR_P1[] =
|
||||
"Debug argument identifier '-g' or '--debug' was specified "
|
||||
"but no arguments were found or one of them was invalid. Supported "
|
||||
"arguments are: ";
|
||||
const char DEBUG_ERROR_P2[] = ".";
|
||||
size_t arg_error_msg_len = sizeof(DEBUG_ERROR_P1) + total_len + sizeof(DEBUG_ERROR_P2);
|
||||
char arg_error_msg[arg_error_msg_len];
|
||||
snprintf(arg_error_msg, arg_error_msg_len, "%s%s%s", DEBUG_ERROR_P1, arglist,
|
||||
DEBUG_ERROR_P2);
|
||||
print_log_n_stderr(true, true, arg_error_msg, arg_error_msg, 0);
|
||||
}
|
||||
return !arg_error;
|
||||
}
|
||||
|
Reference in New Issue
Block a user