From ab082f57780b5acb5b1305d82309a1dea8c026a1 Mon Sep 17 00:00:00 2001 From: Fabian Keil Date: Thu, 6 Aug 2020 11:52:19 +0200 Subject: [PATCH 1/1] Add FEATURE_EXTENDED_STATISTICS to gather filter statistics Sponsored by: Robert Klemme --- acconfig.h | 5 ++ cgisimple.c | 82 +++++++++++++++++++++++ configure.in | 6 ++ filters.c | 150 +++++++++++++++++++++++++++++++++++++++++- filters.h | 9 +++ jcc.c | 6 ++ jcc.h | 4 ++ loaders.c | 4 +- templates/show-status | 16 +++++ 9 files changed, 280 insertions(+), 2 deletions(-) diff --git a/acconfig.h b/acconfig.h index a55d20a5..9ec87fdc 100644 --- a/acconfig.h +++ b/acconfig.h @@ -127,6 +127,11 @@ */ #undef FEATURE_PCRE_HOST_PATTERNS +/* + * Gather extended statistics. + */ +#undef FEATURE_EXTENDED_STATISTICS + /* * Allow filtering with scripts and programs. */ diff --git a/cgisimple.c b/cgisimple.c index 3be01e39..2fcd0022 100644 --- a/cgisimple.c +++ b/cgisimple.c @@ -1031,6 +1031,72 @@ jb_err cgi_send_user_manual(struct client_state *csp, } +#ifdef FEATURE_EXTENDED_STATISTICS +/********************************************************************* + * + * Function : get_filter_statistics_table + * + * Description : Produces the filter statistic table content. + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * + * Returns : Pointer to the HTML statistic table content or + * NULL on out of memory + * + *********************************************************************/ +static char *get_filter_statistics_table(const struct client_state *csp) +{ + char buf[BUFFER_SIZE]; + char *statistics; + int i; + struct file_list *fl; + struct re_filterfile_spec *b; + jb_err err = JB_ERR_OK; + + statistics = strdup_or_die(""); + + for (i = 0; i < MAX_AF_FILES; i++) + { + fl = csp->rlist[i]; + if ((NULL == fl) || (NULL == fl->f)) + { + /* + * Either there are no filter files left or this + * filter file just contains no valid filters. + * + * Continue to be sure we don't miss valid filter + * files that are chained after empty or invalid ones. + */ + continue; + } + + for (b = fl->f; b != NULL; b = b->next) + { + if (b->type == FT_CONTENT_FILTER) + { + unsigned long long executions; + unsigned long long pages_modified; + unsigned long long hits; + + get_filter_statistics(b->name, &executions, &pages_modified, &hits); + snprintf(buf, sizeof(buf), + "%s%llu" + "%llu" + "%llu\n", + b->name, executions, pages_modified, hits); + + if (!err) err = string_append(&statistics, buf); + } + } + } + + return statistics; + +} +#endif + + /********************************************************************* * * Function : cgi_show_status @@ -1143,6 +1209,22 @@ jb_err cgi_show_status(struct client_state *csp, if (!err) err = map_block_killer(exports, "statistics"); #endif /* ndef FEATURE_STATISTICS */ +#ifdef FEATURE_EXTENDED_STATISTICS + { + char *filter_statistics = get_filter_statistics_table(csp); + if (filter_statistics != NULL) + { + if (!err) err = map(exports, "filter-statistics", 1, filter_statistics, 0); + } + else + { + if (!err) err = map_block_killer(exports, "extended-statistics"); + } + } +#else /* ndef FEATURE_EXTENDED_STATISTICS */ + if (!err) err = map_block_killer(exports, "extended-statistics"); +#endif /* def FEATURE_EXTENDED_STATISTICS */ + /* * List all action files in use, together with view and edit links, * except for standard.action, which should only be viewable. (Not diff --git a/configure.in b/configure.in index 39059713..a0640734 100644 --- a/configure.in +++ b/configure.in @@ -934,6 +934,12 @@ AC_ARG_ENABLE(stats, AC_DEFINE(FEATURE_STATISTICS) fi],AC_DEFINE(FEATURE_STATISTICS)) +AC_ARG_ENABLE(extended-statistics, +[ --enable-extended-statistics Gather extended statistics.], +[if test $enableval = yes; then + AC_DEFINE(FEATURE_EXTENDED_STATISTICS) +fi]) + AC_ARG_ENABLE(image-blocking, [ --disable-image-blocking Don't try to figure out whether a request is for an image or HTML - assume HTML.], diff --git a/filters.c b/filters.c index b490353b..82f79db4 100644 --- a/filters.c +++ b/filters.c @@ -1654,7 +1654,9 @@ static char *pcrs_filter_response(struct client_state *csp) log_error(LOG_LEVEL_RE_FILTER, "filtering %s%s (size %d) with \'%s\' produced %d hits (new size %d).", csp->http->hostport, csp->http->path, prev_size, b->name, current_hits, size); - +#ifdef FEATURE_EXTENDED_STATISTICS + update_filter_statistics(b->name, current_hits); +#endif hits += current_hits; } @@ -2750,6 +2752,152 @@ int filters_available(const struct client_state *csp) return FALSE; } +#ifdef FEATURE_EXTENDED_STATISTICS + +struct filter_statistics_entry +{ + char *filter; + unsigned long long executions; + unsigned long long pages_modified; + unsigned long long hits; + + struct filter_statistics_entry *next; +}; + +static struct filter_statistics_entry *filter_statistics = NULL; + + +/********************************************************************* + * + * Function : register_filter_for_statistics + * + * Description : Registers a filter so we can gather statistics for + * it unless the filter has already been registered + * before. + * + * Parameters : + * 1 : filter = Name of the filter to register + * + * Returns : void + * + *********************************************************************/ +void register_filter_for_statistics(const char *filter) +{ + struct filter_statistics_entry *entry; + + privoxy_mutex_lock(&filter_statistics_mutex); + + if (filter_statistics == NULL) + { + filter_statistics = zalloc_or_die(sizeof(struct filter_statistics_entry)); + entry = filter_statistics; + entry->filter = strdup_or_die(filter); + privoxy_mutex_unlock(&filter_statistics_mutex); + return; + } + entry = filter_statistics; + while (entry != NULL) + { + if (!strcmp(entry->filter, filter)) + { + /* Already registered, nothing to do. */ + break; + } + if (entry->next == NULL) + { + entry->next = zalloc_or_die(sizeof(struct filter_statistics_entry)); + entry->next->filter = strdup_or_die(filter); + break; + } + entry = entry->next; + } + + privoxy_mutex_unlock(&filter_statistics_mutex); + +} + + +/********************************************************************* + * + * Function : update_filter_statistics + * + * Description : Updates the statistics for a filter. + * + * Parameters : + * 1 : filter = Name of the filter to update + * 2 : hits = Hit count. + * + * Returns : void + * + *********************************************************************/ +void update_filter_statistics(const char *filter, int hits) +{ + struct filter_statistics_entry *entry; + + privoxy_mutex_lock(&filter_statistics_mutex); + + entry = filter_statistics; + while (entry != NULL) + { + if (!strcmp(entry->filter, filter)) + { + entry->executions++; + if (hits != 0) + { + entry->pages_modified++; + entry->hits += (unsigned)hits; + } + break; + } + entry = entry->next; + } + + privoxy_mutex_unlock(&filter_statistics_mutex); + +} + + +/********************************************************************* + * + * Function : get_filter_statistics + * + * Description : Gets the statistics for a filter. + * + * Parameters : + * 1 : filter = Name of the filter to get statistics for. + * 2 : executions = Storage for the execution count. + * 3 : pages_modified = Storage for the number of modified pages. + * 4 : hits = Storage for the number of hits. + * + * Returns : void + * + *********************************************************************/ +void get_filter_statistics(const char *filter, unsigned long long *executions, + unsigned long long *pages_modified, + unsigned long long *hits) +{ + struct filter_statistics_entry *entry; + + privoxy_mutex_lock(&filter_statistics_mutex); + + entry = filter_statistics; + while (entry != NULL) + { + if (!strcmp(entry->filter, filter)) + { + *executions = entry->executions; + *pages_modified = entry->pages_modified; + *hits = entry->hits; + break; + } + entry = entry->next; + } + + privoxy_mutex_unlock(&filter_statistics_mutex); + +} + +#endif /* def FEATURE_EXTENDED_STATISTICS */ /* Local Variables: diff --git a/filters.h b/filters.h index 441f4b62..dcd58e21 100644 --- a/filters.h +++ b/filters.h @@ -104,6 +104,15 @@ extern char *gif_deanimate_response(struct client_state *csp); extern jb_err remove_chunked_transfer_coding(char *buffer, size_t *size); #endif +#ifdef FEATURE_EXTENDED_STATISTICS +extern void register_filter_for_statistics(const char *filter); +extern void update_filter_statistics(const char *filter, int hits); +extern void get_filter_statistics(const char *filter, + unsigned long long *executions, + unsigned long long *pages_modified, + unsigned long long *hits); +#endif + #endif /* ndef FILTERS_H_INCLUDED */ /* diff --git a/jcc.c b/jcc.c index d29b5117..5846f8a2 100644 --- a/jcc.c +++ b/jcc.c @@ -204,6 +204,9 @@ privoxy_mutex_t external_filter_mutex; #ifdef FEATURE_CLIENT_TAGS privoxy_mutex_t client_tags_mutex; #endif +#ifdef FEATURE_EXTENDED_STATISTICS +privoxy_mutex_t filter_statistics_mutex; +#endif #if !defined(HAVE_GETHOSTBYADDR_R) || !defined(HAVE_GETHOSTBYNAME_R) privoxy_mutex_t resolver_mutex; @@ -4567,6 +4570,9 @@ static void initialize_mutexes(void) #ifdef FEATURE_CLIENT_TAGS privoxy_mutex_init(&client_tags_mutex); #endif +#ifdef FEATURE_EXTENDED_STATISTICS + privoxy_mutex_init(&filter_statistics_mutex); +#endif /* * XXX: The assumptions below are a bit naive diff --git a/jcc.h b/jcc.h index 8458aa16..3412ab29 100644 --- a/jcc.h +++ b/jcc.h @@ -86,6 +86,10 @@ extern privoxy_mutex_t external_filter_mutex; extern privoxy_mutex_t client_tags_mutex; #endif +#ifdef FEATURE_EXTENDED_STATISTICS +extern privoxy_mutex_t filter_statistics_mutex; +#endif + #ifndef HAVE_GMTIME_R extern privoxy_mutex_t gmtime_mutex; #endif /* ndef HAVE_GMTIME_R */ diff --git a/loaders.c b/loaders.c index fdf17bbb..3bfcdd27 100644 --- a/loaders.c +++ b/loaders.c @@ -1226,7 +1226,9 @@ int load_one_re_filterfile(struct client_state *csp, int fileid) bl = new_bl; log_error(LOG_LEVEL_RE_FILTER, "Reading in filter \"%s\" (\"%s\")", bl->name, bl->description); - +#ifdef FEATURE_EXTENDED_STATISTICS + register_filter_for_statistics(bl->name); +#endif freez(buf); continue; } diff --git a/templates/show-status b/templates/show-status index c5a747b3..39f906bd 100644 --- a/templates/show-status +++ b/templates/show-status @@ -91,6 +91,11 @@ # The percentage of blocked requests # have-no-stats: # There haven't any statistics been collected yet +# extended-statistics: +# Privoxy was compiled with extended statistiscs support. +# In this case the following symbol is available: +# filter-statistics: +# Table content of content filter statistics. # pcrs-support: # Privoxy was compiled with pcrs support # trust-support: @@ -214,6 +219,17 @@ + + + +

Content Filter Statistics:

+ + +@filter-statistics@
Filter nameExecutionsPages modifiedHits
+ + + +

Conditional #defines:

-- 2.39.2