From 5a4f997b2e8e819ed40731cd769826112072a9d4 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Wed, 8 Jun 2022 16:14:20 +0900 Subject: 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 --- debug.c | 166 ++++++++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 121 insertions(+), 45 deletions(-) (limited to 'debug.c') diff --git a/debug.c b/debug.c index 6c9d6563db..b9df026af8 100644 --- a/debug.c +++ b/debug.c @@ -273,10 +273,26 @@ ruby_set_debug_option(const char *str) 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 { char *mem; 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; rb_nativethread_lock_t lock; FILE *output; @@ -288,6 +304,23 @@ RUBY_DEBUG_LOG_MEM_ENTRY(unsigned int 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 setup_debug_log(void) { @@ -323,30 +356,75 @@ setup_debug_log(void) const char *filter_config = getenv("RUBY_DEBUG_LOG_FILTER"); if (filter_config && strlen(filter_config) > 0) { unsigned int i; - for (i=0; i= MAX_DEBUG_LOG_FILTER_LEN) { - fprintf(stderr, "too long: %s (max:%d)\n", filter_config, MAX_DEBUG_LOG_FILTER_LEN); - exit(1); - } - strncpy(debug_log.filters[i], filter_config, MAX_DEBUG_LOG_FILTER_LEN - 1); - i++; - break; + + if ((p = strchr(str, ',')) == NULL) { + len = strlen(str); + filter_config = NULL; } else { - size_t n = p - filter_config; - if (n >= MAX_DEBUG_LOG_FILTER_LEN) { - 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; + len = p - str - 1; // 1 is ',' + 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; + for (i=0; inegative) { + 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 // returns true if -// func_name doesn't contain foo +// (func_name or file_name) doesn't contain foo // and -// func_name doesn't contain bar +// (func_name or file_name) doesn't contain bar // and -// func_name contains baz or boo +// (func_name or file_name) contains baz or boo // // RUBY_DEBUG_LOG_FILTER=foo,bar,-baz,-boo // retunrs true if -// func_name contains foo or bar +// (func_name or file_name) contains foo or bar // or -// func_name doesn't contain baz and -// func_name doesn't contain boo and +// (func_name or file_name) doesn't contain baz 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 -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) { - bool status = false; + bool state = false; for (unsigned int i = 0; itype) { + case dlf_all: + if (check_filter(func_name, filter, &state)) return state; + if (check_filter(file_name, filter, &state)) return state; + break; + case dlf_func: + if (check_filter(func_name, filter, &state)) return state; + break; + case dlf_file: + if (check_filter(file_name, filter, &state)) return state; + break; } } - - return status; + return state; } else { return true; -- cgit v1.2.1