aboutsummaryrefslogtreecommitdiffstats
path: root/debug.c
diff options
context:
space:
mode:
authorKoichi Sasada <ko1@atdot.net>2022-06-08 16:14:20 +0900
committerKoichi Sasada <ko1@atdot.net>2022-06-09 01:51:19 +0900
commit5a4f997b2e8e819ed40731cd769826112072a9d4 (patch)
treedf6b99101e156fab3e7c4fa15ece1a5bfe5071fb /debug.c
parent8d57336360497e94403a71bd13de8faa76f1dbcb (diff)
downloadruby-5a4f997b2e8e819ed40731cd769826112072a9d4.tar.gz
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
Diffstat (limited to 'debug.c')
-rw-r--r--debug.c166
1 files changed, 121 insertions, 45 deletions
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_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;
- if ((p = strchr(filter_config, ',')) == NULL) {
- if (strlen(filter_config) >= 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; 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
// 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; i<debug_log.filters_num; i++) {
- const char *filter = debug_log.filters[i];
-
- if (*filter == '-') {
- if (strstr(func_name, &filter[1]) == NULL) {
- status = true;
- }
- else {
- return false;
- }
- }
- else {
- if (strstr(func_name, filter) != NULL) {
- return true;
- }
- else {
- status = false;
- }
+ const struct debug_log_filter *filter = &debug_log.filters[i];
+
+ switch (filter->type) {
+ 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;