Gather statistics for block reasons
authorFabian Keil <fk@fabiankeil.de>
Fri, 7 Aug 2020 09:08:23 +0000 (11:08 +0200)
committerFabian Keil <fk@fabiankeil.de>
Mon, 10 Aug 2020 14:58:37 +0000 (16:58 +0200)
... if FEATURE_EXTENDED_STATISTICS is enabled.

Sponsored by: Robert Klemme

actions.c
cgisimple.c
filters.c
filters.h
jcc.c
jcc.h
templates/show-status

index a1c00f9..087f59d 100644 (file)
--- a/actions.c
+++ b/actions.c
@@ -547,6 +547,12 @@ jb_err get_actions(char *line,
                         return JB_ERR_PARSE;
                      }
                   }
+#ifdef FEATURE_EXTENDED_STATISTICS
+                  if (0 == strcmpic(action->name, "+block"))
+                  {
+                     register_block_reason_for_statistics(value);
+                  }
+#endif
                   /* FIXME: should validate option string here */
                   freez (cur_action->string[action->index]);
                   cur_action->string[action->index] = strdup(value);
index 3428d81..e738a60 100644 (file)
@@ -1032,6 +1032,76 @@ jb_err cgi_send_user_manual(struct client_state *csp,
 
 
 #ifdef FEATURE_EXTENDED_STATISTICS
+/*********************************************************************
+ *
+ * Function    :  get_block_reason_statistics_table
+ *
+ * Description :  Produces the block reason 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_block_reason_statistics_table(const struct client_state *csp)
+{
+   char buf[BUFFER_SIZE];
+   char *statistics;
+   int i;
+   struct file_list *fl;
+   jb_err err = JB_ERR_OK;
+
+   statistics = strdup_or_die("");
+
+   /* Run through all action files. */
+   for (i = 0; i < MAX_AF_FILES; i++)
+   {
+      struct url_actions *b;
+      struct action_spec *last_action = NULL;
+
+      if (((fl = csp->actions_list[i]) == NULL) || ((b = fl->f) == NULL))
+      {
+         /* Skip empty files */
+         continue;
+      }
+
+      /* Go through all the actions. */
+      for (b = b->next; NULL != b; b = b->next)
+      {
+         if (last_action == b->action)
+         {
+            continue;
+         }
+         if ((b->action->add & ACTION_BLOCK))
+         {
+            unsigned long long count;
+            const char *block_reason = b->action->string[ACTION_STRING_BLOCK];
+            const char *encoded_block_reason = html_encode(block_reason);
+
+            if (encoded_block_reason == NULL)
+            {
+               freez(statistics);
+               return NULL;
+            }
+            get_block_reason_count(block_reason, &count);
+            snprintf(buf, sizeof(buf),
+               "<tr><td>%s</td><td style=\"text-align: right\">%llu</td>",
+               encoded_block_reason, count);
+            freez(encoded_block_reason);
+
+            if (!err) err = string_append(&statistics, buf);
+         }
+         last_action = b->action;
+      }
+   }
+
+   return statistics;
+
+}
+
+
 /*********************************************************************
  *
  * Function    :  get_filter_statistics_table
@@ -1094,7 +1164,7 @@ static char *get_filter_statistics_table(const struct client_state *csp)
    return statistics;
 
 }
-#endif
+#endif /* def FEATURE_EXTENDED_STATISTICS */
 
 
 /*********************************************************************
@@ -1210,6 +1280,17 @@ jb_err cgi_show_status(struct client_state *csp,
 #endif /* ndef FEATURE_STATISTICS */
 
 #ifdef FEATURE_EXTENDED_STATISTICS
+   {
+      char *block_reason_statistics = get_block_reason_statistics_table(csp);
+      if (block_reason_statistics != NULL)
+      {
+         if (!err) err = map(exports, "block-reason-statistics", 1, block_reason_statistics, 0);
+      }
+      else
+      {
+         if (!err) err = map_block_killer(exports, "extended-statistics");
+      }
+   }
    {
       char *filter_statistics = get_filter_statistics_table(csp);
       if (filter_statistics != NULL)
index 82f79db..0c33890 100644 (file)
--- a/filters.c
+++ b/filters.c
@@ -87,6 +87,10 @@ static void apply_url_actions(struct current_action_spec *action,
 #endif
                               struct url_actions *b);
 
+#ifdef FEATURE_EXTENDED_STATISTICS
+static void increment_block_reason_counter(const char *block_reason);
+#endif
+
 #ifdef FEATURE_ACL
 #ifdef HAVE_RFC2553
 /*********************************************************************
@@ -557,6 +561,13 @@ struct http_response *block_url(struct client_state *csp)
       return cgi_error_memory();
    }
 
+#ifdef FEATURE_EXTENDED_STATISTICS
+   if (csp->action->string[ACTION_STRING_BLOCK] != NULL)
+   {
+      increment_block_reason_counter(csp->action->string[ACTION_STRING_BLOCK]);
+   }
+#endif
+
    /*
     * If it's an image-url, send back an image or redirect
     * as specified by the relevant +image action
@@ -2897,6 +2908,136 @@ void get_filter_statistics(const char *filter, unsigned long long *executions,
 
 }
 
+
+struct block_statistics_entry
+{
+   char *block_reason;
+   unsigned long long count;
+
+   struct block_statistics_entry *next;
+};
+
+static struct block_statistics_entry *block_statistics = NULL;
+
+/*********************************************************************
+ *
+ * Function    :  register_block_reason_for_statistics
+ *
+ * Description :  Registers a block reason so we can gather statistics
+ *                for it unless the block reason has already been
+ *                registered before.
+ *
+ * Parameters  :
+ *          1  :  block_reason = Block reason to register
+ *
+ * Returns     :  void
+ *
+ *********************************************************************/
+void register_block_reason_for_statistics(const char *block_reason)
+{
+   struct block_statistics_entry *entry;
+
+   privoxy_mutex_lock(&block_statistics_mutex);
+
+   if (block_statistics == NULL)
+   {
+      block_statistics = zalloc_or_die(sizeof(struct block_statistics_entry));
+      entry = block_statistics;
+      entry->block_reason = strdup_or_die(block_reason);
+      privoxy_mutex_unlock(&block_statistics_mutex);
+      return;
+   }
+   entry = block_statistics;
+   while (entry != NULL)
+   {
+      if (!strcmp(entry->block_reason, block_reason))
+      {
+         /* Already registered, nothing to do. */
+         break;
+      }
+      if (entry->next == NULL)
+      {
+         entry->next = zalloc_or_die(sizeof(struct block_statistics_entry));
+         entry->next->block_reason = strdup_or_die(block_reason);
+         break;
+      }
+      entry = entry->next;
+   }
+
+   privoxy_mutex_unlock(&block_statistics_mutex);
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  increment_block_reason_counter
+ *
+ * Description :  Updates the counter for a block reason.
+ *
+ * Parameters  :
+ *          1  :  block_reason = Block reason to count
+ *
+ * Returns     :  void
+ *
+ *********************************************************************/
+static void increment_block_reason_counter(const char *block_reason)
+{
+   struct block_statistics_entry *entry;
+
+   privoxy_mutex_lock(&block_statistics_mutex);
+
+   entry = block_statistics;
+   while (entry != NULL)
+   {
+      if (!strcmp(entry->block_reason, block_reason))
+      {
+         entry->count++;
+         break;
+      }
+      entry = entry->next;
+   }
+
+   privoxy_mutex_unlock(&block_statistics_mutex);
+
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  get_block_reason_count
+ *
+ * Description :  Gets number of times a block reason was used.
+ *
+ * Parameters  :
+ *          1  :  block_reason = Block reason to get statistics for.
+ *          2  :  count = Storage for the number of times the block
+ *                        reason was used.
+ *
+ * Returns     :  void
+ *
+ *********************************************************************/
+void get_block_reason_count(const char *block_reason, unsigned long long *count)
+{
+   struct block_statistics_entry *entry;
+
+   privoxy_mutex_lock(&block_statistics_mutex);
+
+   entry = block_statistics;
+   while (entry != NULL)
+   {
+      if (!strcmp(entry->block_reason, block_reason))
+      {
+         *count = entry->count;
+         break;
+      }
+      entry = entry->next;
+   }
+
+   privoxy_mutex_unlock(&block_statistics_mutex);
+
+}
+
 #endif /* def FEATURE_EXTENDED_STATISTICS */
 
 /*
index dcd58e2..b8004fe 100644 (file)
--- a/filters.h
+++ b/filters.h
@@ -111,6 +111,10 @@ extern void get_filter_statistics(const char *filter,
                                   unsigned long long *executions,
                                   unsigned long long *pages_modified,
                                   unsigned long long *hits);
+
+extern void register_block_reason_for_statistics(const char *block_reason);
+extern void get_block_reason_count(const char *block_reason,
+                                   unsigned long long *count);
 #endif
 
 #endif /* ndef FILTERS_H_INCLUDED */
diff --git a/jcc.c b/jcc.c
index 5846f8a..1380100 100644 (file)
--- a/jcc.c
+++ b/jcc.c
@@ -206,6 +206,7 @@ privoxy_mutex_t client_tags_mutex;
 #endif
 #ifdef FEATURE_EXTENDED_STATISTICS
 privoxy_mutex_t filter_statistics_mutex;
+privoxy_mutex_t block_statistics_mutex;
 #endif
 
 #if !defined(HAVE_GETHOSTBYADDR_R) || !defined(HAVE_GETHOSTBYNAME_R)
@@ -4572,6 +4573,7 @@ static void initialize_mutexes(void)
 #endif
 #ifdef FEATURE_EXTENDED_STATISTICS
    privoxy_mutex_init(&filter_statistics_mutex);
+   privoxy_mutex_init(&block_statistics_mutex);
 #endif
 
    /*
diff --git a/jcc.h b/jcc.h
index 3412ab2..ad68f42 100644 (file)
--- a/jcc.h
+++ b/jcc.h
@@ -88,6 +88,7 @@ extern privoxy_mutex_t client_tags_mutex;
 
 #ifdef FEATURE_EXTENDED_STATISTICS
 extern privoxy_mutex_t filter_statistics_mutex;
+extern privoxy_mutex_t block_statistics_mutex;
 #endif
 
 #ifndef HAVE_GMTIME_R
index 39f906b..fe34b4f 100644 (file)
@@ -93,7 +93,9 @@
 #    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:
+#    In this case the following symbols are available:
+#    block-reason-statistics:
+#      Table content of block reasons and how often they were used.
 #    filter-statistics:
 #      Table content of content filter statistics.
 #  pcrs-support:
 <!-- if-statistics-end@ -->
 
 <!-- @if-extended-statistics-start -->
+    <tr>
+      <td class="box">
+        <h2>Block Reason Statistics:</h2>
+        <table summary="Statistics for block reasons" border="1">
+         <tr><th>Block reason</th><th>Count</th></tr>
+@block-reason-statistics@        </table>
+      </td>
+    </tr>
     <tr>
       <td class="box">
         <h2>Content Filter Statistics:</h2>