mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
func: and file: prefix for RUBY_DEBUG_LOG_FILTER
`RUBY_DEBUG_LOG_FILTER` specified only function names but this patch also check file names for each log events. If you specify `file:` or `func:` prefix, it's only filter file names or func names (otherwize check both). foo # show log when file or func names are mached with foo func:foo # show log when func name matches foo file:foo # show log when file name matches foo -file:foo,func:bar # show log when file name does not contains foo # and func name matches bar
This commit is contained in:
parent
8d57336360
commit
5a4f997b2e
Notes:
git
2022-06-09 01:51:40 +09:00
1 changed files with 120 additions and 44 deletions
164
debug.c
164
debug.c
|
@ -273,10 +273,26 @@ ruby_set_debug_option(const char *str)
|
||||||
|
|
||||||
enum ruby_debug_log_mode ruby_debug_log_mode;
|
enum ruby_debug_log_mode ruby_debug_log_mode;
|
||||||
|
|
||||||
|
struct debug_log_filter {
|
||||||
|
enum debug_log_filter_type {
|
||||||
|
dlf_all,
|
||||||
|
dlf_file, // "file:..."
|
||||||
|
dlf_func, // "func:..."
|
||||||
|
} type;
|
||||||
|
bool negative;
|
||||||
|
char str[MAX_DEBUG_LOG_FILTER_LEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *dlf_type_names[] = {
|
||||||
|
"all",
|
||||||
|
"file",
|
||||||
|
"func",
|
||||||
|
};
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
char *mem;
|
char *mem;
|
||||||
unsigned int cnt;
|
unsigned int cnt;
|
||||||
char filters[MAX_DEBUG_LOG_FILTER_NUM][MAX_DEBUG_LOG_FILTER_LEN];
|
struct debug_log_filter filters[MAX_DEBUG_LOG_FILTER_NUM];
|
||||||
unsigned int filters_num;
|
unsigned int filters_num;
|
||||||
rb_nativethread_lock_t lock;
|
rb_nativethread_lock_t lock;
|
||||||
FILE *output;
|
FILE *output;
|
||||||
|
@ -288,6 +304,23 @@ RUBY_DEBUG_LOG_MEM_ENTRY(unsigned int index)
|
||||||
return &debug_log.mem[MAX_DEBUG_LOG_MESSAGE_LEN * index];
|
return &debug_log.mem[MAX_DEBUG_LOG_MESSAGE_LEN * index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static enum debug_log_filter_type
|
||||||
|
filter_type(const char *str, int *skiplen)
|
||||||
|
{
|
||||||
|
if (strncmp(str, "file:", 5) == 0) {
|
||||||
|
*skiplen = 5;
|
||||||
|
return dlf_file;
|
||||||
|
}
|
||||||
|
else if(strncmp(str, "func:", 5) == 0) {
|
||||||
|
*skiplen = 5;
|
||||||
|
return dlf_func;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*skiplen = 0;
|
||||||
|
return dlf_all;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
setup_debug_log(void)
|
setup_debug_log(void)
|
||||||
{
|
{
|
||||||
|
@ -323,30 +356,75 @@ setup_debug_log(void)
|
||||||
const char *filter_config = getenv("RUBY_DEBUG_LOG_FILTER");
|
const char *filter_config = getenv("RUBY_DEBUG_LOG_FILTER");
|
||||||
if (filter_config && strlen(filter_config) > 0) {
|
if (filter_config && strlen(filter_config) > 0) {
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
for (i=0; i<MAX_DEBUG_LOG_FILTER_NUM; i++) {
|
for (i=0; i<MAX_DEBUG_LOG_FILTER_NUM && filter_config; i++) {
|
||||||
|
size_t len;
|
||||||
|
const char *str = filter_config;
|
||||||
const char *p;
|
const char *p;
|
||||||
if ((p = strchr(filter_config, ',')) == NULL) {
|
|
||||||
if (strlen(filter_config) >= MAX_DEBUG_LOG_FILTER_LEN) {
|
if ((p = strchr(str, ',')) == NULL) {
|
||||||
fprintf(stderr, "too long: %s (max:%d)\n", filter_config, MAX_DEBUG_LOG_FILTER_LEN);
|
len = strlen(str);
|
||||||
exit(1);
|
filter_config = NULL;
|
||||||
}
|
|
||||||
strncpy(debug_log.filters[i], filter_config, MAX_DEBUG_LOG_FILTER_LEN - 1);
|
|
||||||
i++;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
size_t n = p - filter_config;
|
len = p - str - 1; // 1 is ','
|
||||||
if (n >= MAX_DEBUG_LOG_FILTER_LEN) {
|
filter_config = p + 1;
|
||||||
fprintf(stderr, "too long: %s (max:%d)\n", filter_config, MAX_DEBUG_LOG_FILTER_LEN);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
strncpy(debug_log.filters[i], filter_config, n);
|
|
||||||
filter_config = p+1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// positive/negative
|
||||||
|
if (*str == '-') {
|
||||||
|
debug_log.filters[i].negative = true;
|
||||||
|
str++;
|
||||||
|
} else if (*str == '+') {
|
||||||
|
// negative is false on default.
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// type
|
||||||
|
int skiplen;
|
||||||
|
debug_log.filters[i].type = filter_type(str, &skiplen);
|
||||||
|
len -= skiplen;
|
||||||
|
|
||||||
|
if (len >= MAX_DEBUG_LOG_FILTER_LEN) {
|
||||||
|
fprintf(stderr, "too long: %s (max:%d)\n", str, MAX_DEBUG_LOG_FILTER_LEN - 1);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// body
|
||||||
|
strncpy(debug_log.filters[i].str, str + skiplen, len);
|
||||||
|
debug_log.filters[i].str[len] = 0;
|
||||||
}
|
}
|
||||||
debug_log.filters_num = i;
|
debug_log.filters_num = i;
|
||||||
|
|
||||||
for (i=0; i<debug_log.filters_num; i++) {
|
for (i=0; i<debug_log.filters_num; i++) {
|
||||||
fprintf(stderr, "RUBY_DEBUG_LOG_FILTER[%d]=%s\n", i, debug_log.filters[i]);
|
fprintf(stderr, "RUBY_DEBUG_LOG_FILTER[%d]=%s (%s%s)\n", i,
|
||||||
|
debug_log.filters[i].str,
|
||||||
|
debug_log.filters[i].negative ? "-" : "",
|
||||||
|
dlf_type_names[debug_log.filters[i].type]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
check_filter(const char *str, const struct debug_log_filter *filter, bool *state)
|
||||||
|
{
|
||||||
|
if (filter->negative) {
|
||||||
|
if (strstr(str, filter->str) == NULL) {
|
||||||
|
*state = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*state = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (strstr(str, filter->str) != NULL) {
|
||||||
|
*state = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*state = false;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -354,47 +432,45 @@ setup_debug_log(void)
|
||||||
//
|
//
|
||||||
// RUBY_DEBUG_LOG_FILTER=-foo,-bar,baz,boo
|
// RUBY_DEBUG_LOG_FILTER=-foo,-bar,baz,boo
|
||||||
// returns true if
|
// returns true if
|
||||||
// func_name doesn't contain foo
|
// (func_name or file_name) doesn't contain foo
|
||||||
// and
|
// and
|
||||||
// func_name doesn't contain bar
|
// (func_name or file_name) doesn't contain bar
|
||||||
// and
|
// and
|
||||||
// func_name contains baz or boo
|
// (func_name or file_name) contains baz or boo
|
||||||
//
|
//
|
||||||
// RUBY_DEBUG_LOG_FILTER=foo,bar,-baz,-boo
|
// RUBY_DEBUG_LOG_FILTER=foo,bar,-baz,-boo
|
||||||
// retunrs true if
|
// retunrs true if
|
||||||
// func_name contains foo or bar
|
// (func_name or file_name) contains foo or bar
|
||||||
// or
|
// or
|
||||||
// func_name doesn't contain baz and
|
// (func_name or file_name) doesn't contain baz and
|
||||||
// func_name doesn't contain boo and
|
// (func_name or file_name) doesn't contain boo and
|
||||||
|
//
|
||||||
|
// You can specify "file:" (ex file:foo) or "func:" (ex func:foo)
|
||||||
|
// prefixes to specify the filter for.
|
||||||
//
|
//
|
||||||
bool
|
bool
|
||||||
ruby_debug_log_filter(const char *func_name)
|
ruby_debug_log_filter(const char *func_name, const char *file_name)
|
||||||
{
|
{
|
||||||
if (debug_log.filters_num > 0) {
|
if (debug_log.filters_num > 0) {
|
||||||
bool status = false;
|
bool state = false;
|
||||||
|
|
||||||
for (unsigned int i = 0; i<debug_log.filters_num; i++) {
|
for (unsigned int i = 0; i<debug_log.filters_num; i++) {
|
||||||
const char *filter = debug_log.filters[i];
|
const struct debug_log_filter *filter = &debug_log.filters[i];
|
||||||
|
|
||||||
if (*filter == '-') {
|
switch (filter->type) {
|
||||||
if (strstr(func_name, &filter[1]) == NULL) {
|
case dlf_all:
|
||||||
status = true;
|
if (check_filter(func_name, filter, &state)) return state;
|
||||||
}
|
if (check_filter(file_name, filter, &state)) return state;
|
||||||
else {
|
break;
|
||||||
return false;
|
case dlf_func:
|
||||||
}
|
if (check_filter(func_name, filter, &state)) return state;
|
||||||
}
|
break;
|
||||||
else {
|
case dlf_file:
|
||||||
if (strstr(func_name, filter) != NULL) {
|
if (check_filter(file_name, filter, &state)) return state;
|
||||||
return true;
|
break;
|
||||||
}
|
|
||||||
else {
|
|
||||||
status = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return state;
|
||||||
return status;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return true;
|
return true;
|
||||||
|
|
Loading…
Add table
Reference in a new issue