*/
#undef FEATURE_PCRE_HOST_PATTERNS
+/*
+ * Gather extended statistics.
+ */
+#undef FEATURE_EXTENDED_STATISTICS
+
/*
* Allow filtering with scripts and programs.
*/
}
+#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),
+ "<tr><td>%s</td><td style=\"text-align: right\">%llu</td>"
+ "<td style=\"text-align: right\">%llu</td>"
+ "<td style=\"text-align: right\">%llu</td><tr>\n",
+ b->name, executions, pages_modified, hits);
+
+ if (!err) err = string_append(&statistics, buf);
+ }
+ }
+ }
+
+ return statistics;
+
+}
+#endif
+
+
/*********************************************************************
*
* Function : cgi_show_status
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
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.],
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;
}
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:
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 */
/*
#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;
#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
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 */
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;
}
# 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:
</tr>
<!-- if-statistics-end@ -->
+<!-- @if-extended-statistics-start -->
+ <tr>
+ <td class="box">
+ <h2>Content Filter Statistics:</h2>
+ <table summary="Statistics for content filters" border="1">
+ <tr><th>Filter name</th><th>Executions</th><th>Pages modified</th><th>Hits</th></tr>
+@filter-statistics@ </table>
+ </td>
+ </tr>
+<!-- if-extended-statistics-end@ -->
+
<tr>
<td class="box">
<h2>Conditional #defines:</h2>