]> git.proxmox.com Git - mirror_frr.git/commitdiff
lib/log: re-add log filtering
authorDavid Lamparter <equinox@diac24.net>
Tue, 17 Dec 2019 12:05:32 +0000 (13:05 +0100)
committerDavid Lamparter <equinox@diac24.net>
Wed, 1 Apr 2020 04:53:26 +0000 (06:53 +0200)
This is most of the old code bolted on top of the new "backend"
infrastructure.  It just wraps around zlog_fd() with the string search.

Originally-by: Stephen Worley <sworley@cumulusnetworks.com>
Signed-off-by: David Lamparter <equinox@diac24.net>
lib/log.h
lib/log_filter.c [new file with mode: 0644]
lib/log_vty.c
lib/subdir.am
lib/zlog_targets.c
lib/zlog_targets.h

index e7297337bedc17b1f22928fdff556068641573f5..b65ae5d5d5bdb4b0d0d78cb935be56b0d446692b 100644 (file)
--- a/lib/log.h
+++ b/lib/log.h
@@ -32,6 +32,7 @@
 
 #include "lib/hook.h"
 #include "lib/zlog.h"
+#include "lib/zlog_targets.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -73,6 +74,22 @@ struct message {
 
 extern void zlog_thread_info(int log_level);
 
+#define ZLOG_FILTERS_MAX 100      /* Max # of filters at once */
+#define ZLOG_FILTER_LENGTH_MAX 80 /* 80 character filter limit */
+
+struct zlog_cfg_filterfile {
+       struct zlog_cfg_file parent;
+};
+
+extern void zlog_filterfile_init(struct zlog_cfg_filterfile *zcf);
+extern void zlog_filterfile_fini(struct zlog_cfg_filterfile *zcf);
+
+/* Add/Del/Dump log filters */
+extern void zlog_filter_clear(void);
+extern int zlog_filter_add(const char *filter);
+extern int zlog_filter_del(const char *filter);
+extern int zlog_filter_dump(char *buf, size_t max_size);
+
 const char *lookup_msg(const struct message *mz, int kz, const char *nf);
 
 /* Safe version of strerror -- never returns NULL. */
diff --git a/lib/log_filter.c b/lib/log_filter.c
new file mode 100644 (file)
index 0000000..721e57a
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * Logging - Filtered file log target
+ * Copyright (C) 2019 Cumulus Networks, Inc.
+ *                    Stephen Worley
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "frr_pthread.h"
+#include "log.h"
+
+static pthread_mutex_t logfilterlock = PTHREAD_MUTEX_INITIALIZER;
+static char zlog_filters[ZLOG_FILTERS_MAX][ZLOG_FILTER_LENGTH_MAX + 1];
+static uint8_t zlog_filter_count;
+
+/*
+ * look for a match on the filter in the current filters,
+ * logfilterlock must be held
+ */
+static int zlog_filter_lookup(const char *lookup)
+{
+       for (int i = 0; i < zlog_filter_count; i++) {
+               if (strncmp(lookup, zlog_filters[i], sizeof(zlog_filters[0]))
+                   == 0)
+                       return i;
+       }
+       return -1;
+}
+
+void zlog_filter_clear(void)
+{
+       frr_with_mutex(&logfilterlock) {
+               zlog_filter_count = 0;
+       }
+}
+
+int zlog_filter_add(const char *filter)
+{
+       frr_with_mutex(&logfilterlock) {
+               if (zlog_filter_count >= ZLOG_FILTERS_MAX)
+                       return 1;
+
+               if (zlog_filter_lookup(filter) != -1)
+                       /* Filter already present */
+                       return -1;
+
+               strlcpy(zlog_filters[zlog_filter_count], filter,
+                       sizeof(zlog_filters[0]));
+
+               if (zlog_filters[zlog_filter_count][0] == '\0')
+                       /* Filter was either empty or didn't get copied
+                        * correctly
+                        */
+                       return -1;
+
+               zlog_filter_count++;
+       }
+       return 0;
+}
+
+int zlog_filter_del(const char *filter)
+{
+       frr_with_mutex(&logfilterlock) {
+               int found_idx = zlog_filter_lookup(filter);
+               int last_idx = zlog_filter_count - 1;
+
+               if (found_idx == -1)
+                       /* Didn't find the filter to delete */
+                       return -1;
+
+               /* Adjust the filter array */
+               memmove(zlog_filters[found_idx], zlog_filters[found_idx + 1],
+                       (last_idx - found_idx) * sizeof(zlog_filters[0]));
+
+               zlog_filter_count--;
+       }
+       return 0;
+}
+
+/* Dump all filters to buffer, delimited by new line */
+int zlog_filter_dump(char *buf, size_t max_size)
+{
+       int len = 0;
+
+       frr_with_mutex(&logfilterlock) {
+               for (int i = 0; i < zlog_filter_count; i++) {
+                       int ret;
+
+                       ret = snprintf(buf + len, max_size - len, " %s\n",
+                                      zlog_filters[i]);
+                       len += ret;
+                       if ((ret < 0) || ((size_t)len >= max_size))
+                               return -1;
+               }
+       }
+
+       return len;
+}
+
+static int search_buf(const char *buf)
+{
+       char *found = NULL;
+
+       frr_with_mutex(&logfilterlock) {
+               for (int i = 0; i < zlog_filter_count; i++) {
+                       found = strstr(buf, zlog_filters[i]);
+                       if (found != NULL)
+                               return 0;
+               }
+       }
+
+       return -1;
+}
+
+static void zlog_filterfile_fd(struct zlog_target *zt, struct zlog_msg *msgs[],
+                              size_t nmsgs)
+{
+       struct zlog_msg *msgfilt[nmsgs];
+       size_t i, o = 0;
+
+       for (i = 0; i < nmsgs; i++) {
+               if (zlog_msg_prio(msgs[i]) >= LOG_DEBUG
+                   && search_buf(zlog_msg_text(msgs[i], NULL)) < 0)
+                       continue;
+
+               msgfilt[o++] = msgs[i];
+       }
+
+       if (o)
+               zlog_fd(zt, msgfilt, o);
+}
+
+void zlog_filterfile_init(struct zlog_cfg_filterfile *zcf)
+{
+       zlog_file_init(&zcf->parent);
+       zcf->parent.zlog_wrap = zlog_filterfile_fd;
+}
+
+void zlog_filterfile_fini(struct zlog_cfg_filterfile *zcf)
+{
+       zlog_file_fini(&zcf->parent);
+}
index 01d19e679d77a41dbfd67a9fc4690ef5b6f9cb36..97026e5dbc771c8e385ace2687b6444bdb18f28b 100644 (file)
@@ -51,6 +51,11 @@ static struct zlog_cfg_file zt_file = {
 static struct zlog_cfg_file zt_stdout = {
        .prio_min = ZLOG_DISABLED,
 };
+static struct zlog_cfg_filterfile zt_filterfile = {
+       .parent = {
+               .prio_min = ZLOG_DISABLED,
+       },
+};
 
 static const char *zlog_progname;
 static const char *zlog_protoname;
@@ -122,6 +127,7 @@ int log_level_match(const char *s)
 void zlog_rotate(void)
 {
        zlog_file_rotate(&zt_file);
+       zlog_file_rotate(&zt_filterfile.parent);
        hook_call(zlog_rotate);
 }
 
@@ -164,6 +170,12 @@ DEFUN (show_logging,
                        zlog_priority[zt_file.prio_min], zt_file.filename);
        vty_out(vty, "\n");
 
+       if (zt_filterfile.parent.prio_min != ZLOG_DISABLED
+           && zt_filterfile.parent.filename)
+               vty_out(vty, "Filtered-file logging: level %s, filename %s\n",
+                       zlog_priority[zt_filterfile.parent.prio_min],
+                       zt_filterfile.parent.filename);
+
        if (log_cmdline_syslog_lvl != ZLOG_DISABLED)
                vty_out(vty,
                        "From command line: \"--log syslog --log-level %s\"\n",
@@ -458,6 +470,8 @@ DEFUN (config_log_record_priority,
        zlog_file_set_other(&zt_file);
        zt_stdout.record_priority = true;
        zlog_file_set_other(&zt_stdout);
+       zt_filterfile.parent.record_priority = true;
+       zlog_file_set_other(&zt_filterfile.parent);
        return CMD_SUCCESS;
 }
 
@@ -472,6 +486,8 @@ DEFUN (no_config_log_record_priority,
        zlog_file_set_other(&zt_file);
        zt_stdout.record_priority = false;
        zlog_file_set_other(&zt_stdout);
+       zt_filterfile.parent.record_priority = false;
+       zlog_file_set_other(&zt_filterfile.parent);
        return CMD_SUCCESS;
 }
 
@@ -487,6 +503,8 @@ DEFPY (config_log_timestamp_precision,
        zlog_file_set_other(&zt_file);
        zt_stdout.ts_subsec = precision;
        zlog_file_set_other(&zt_stdout);
+       zt_filterfile.parent.ts_subsec = precision;
+       zlog_file_set_other(&zt_filterfile.parent);
        return CMD_SUCCESS;
 }
 
@@ -503,6 +521,101 @@ DEFUN (no_config_log_timestamp_precision,
        zlog_file_set_other(&zt_file);
        zt_stdout.ts_subsec = 0;
        zlog_file_set_other(&zt_stdout);
+       zt_filterfile.parent.ts_subsec = 0;
+       zlog_file_set_other(&zt_filterfile.parent);
+       return CMD_SUCCESS;
+}
+
+DEFPY (config_log_filterfile,
+       config_log_filterfile_cmd,
+       "log filtered-file FILENAME [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>$levelarg]",
+       "Logging control\n"
+       "Logging to file with string filter\n"
+       "Logging filename\n"
+       LOG_LEVEL_DESC)
+{
+       int level = log_default_lvl;
+
+       if (levelarg) {
+               level = log_level_match(levelarg);
+               if (level == ZLOG_DISABLED)
+                       return CMD_ERR_NO_MATCH;
+       }
+       return set_log_file(&zt_filterfile.parent, vty, filename, level);
+}
+
+DEFUN (no_config_log_filterfile,
+       no_config_log_filterfile_cmd,
+       "no log filtered-file [FILENAME [LEVEL]]",
+       NO_STR
+       "Logging control\n"
+       "Cancel logging to file with string filter\n"
+       "Logging file name\n"
+       "Logging level\n")
+{
+       zt_filterfile.parent.prio_min = ZLOG_DISABLED;
+       zlog_file_set_other(&zt_filterfile.parent);
+       return CMD_SUCCESS;
+}
+
+DEFPY (log_filter,
+       log_filter_cmd,
+       "[no] log-filter WORD$filter",
+       NO_STR
+       FILTER_LOG_STR
+       "String to filter by\n")
+{
+       int ret = 0;
+
+       if (no)
+               ret = zlog_filter_del(filter);
+       else
+               ret = zlog_filter_add(filter);
+
+       if (ret == 1) {
+               vty_out(vty, "%% filter table full\n");
+               return CMD_WARNING;
+       } else if (ret != 0) {
+               vty_out(vty, "%% failed to %s log filter\n",
+                       (no ? "remove" : "apply"));
+               return CMD_WARNING;
+       }
+
+       vty_out(vty, " %s\n", filter);
+       return CMD_SUCCESS;
+}
+
+/* Clear all log filters */
+DEFPY (log_filter_clear,
+       log_filter_clear_cmd,
+       "clear log-filter",
+       CLEAR_STR
+       FILTER_LOG_STR)
+{
+       zlog_filter_clear();
+       return CMD_SUCCESS;
+}
+
+/* Show log filter */
+DEFPY (show_log_filter,
+       show_log_filter_cmd,
+       "show log-filter",
+       SHOW_STR
+       FILTER_LOG_STR)
+{
+       char log_filters[ZLOG_FILTERS_MAX * (ZLOG_FILTER_LENGTH_MAX + 3)] = "";
+       int len = 0;
+
+       len = zlog_filter_dump(log_filters, sizeof(log_filters));
+
+       if (len == -1) {
+               vty_out(vty, "%% failed to get filters\n");
+               return CMD_WARNING;
+       }
+
+       if (len != 0)
+               vty_out(vty, "%s", log_filters);
+
        return CMD_SUCCESS;
 }
 
@@ -518,6 +631,17 @@ void log_config_write(struct vty *vty)
                vty_out(vty, "\n");
        }
 
+       if (zt_filterfile.parent.prio_min != ZLOG_DISABLED
+           && zt_filterfile.parent.filename) {
+               vty_out(vty, "log filtered-file %s",
+                       zt_filterfile.parent.filename);
+
+               if (zt_filterfile.parent.prio_min != log_default_lvl)
+                       vty_out(vty, " %s",
+                               zlog_priority[zt_filterfile.parent.prio_min]);
+               vty_out(vty, "\n");
+       }
+
        if (log_config_stdout_lvl != ZLOG_DISABLED) {
                vty_out(vty, "log stdout");
 
@@ -577,6 +701,8 @@ static int log_vty_init(const char *progname, const char *protoname,
        zlog_progname = progname;
        zlog_protoname = protoname;
 
+       zlog_filterfile_init(&zt_filterfile);
+
        zlog_file_set_fd(&zt_stdout, STDOUT_FILENO);
        return 0;
 }
@@ -605,4 +731,10 @@ void log_cmd_init(void)
        install_element(CONFIG_NODE, &no_config_log_record_priority_cmd);
        install_element(CONFIG_NODE, &config_log_timestamp_precision_cmd);
        install_element(CONFIG_NODE, &no_config_log_timestamp_precision_cmd);
+
+       install_element(VIEW_NODE, &show_log_filter_cmd);
+       install_element(CONFIG_NODE, &log_filter_cmd);
+       install_element(CONFIG_NODE, &log_filter_clear_cmd);
+       install_element(CONFIG_NODE, &config_log_filterfile_cmd);
+       install_element(CONFIG_NODE, &no_config_log_filterfile_cmd);
 }
index 40c21dcfedc2291af4a4fd454272dde199292885..a01909e90d87d414b442ed3fd922e0c171a082b0 100644 (file)
@@ -45,6 +45,7 @@ lib_libfrr_la_SOURCES = \
        lib/libfrr.c \
        lib/linklist.c \
        lib/log.c \
+       lib/log_filter.c \
        lib/log_vty.c \
        lib/md5.c \
        lib/memory.c \
index 85991b0dde84ed139e5aa1ea096ae5116cbdd4e9..b23ab073b45ed161294a7d6ab87276b64963406d 100644 (file)
@@ -61,7 +61,7 @@ static const char * const prionames[] = {
        [LOG_DEBUG] =   "debugging: ",
 };
 
-static void zlog_fd(struct zlog_target *zt, struct zlog_msg *msgs[], size_t nmsgs)
+void zlog_fd(struct zlog_target *zt, struct zlog_msg *msgs[], size_t nmsgs)
 {
        struct zlt_fd *zte = container_of(zt, struct zlt_fd, zt);
        int fd;
@@ -221,7 +221,7 @@ static bool zlog_file_cycle(struct zlog_cfg_file *zcf)
                zlt->ts_subsec = zcf->ts_subsec;
 
                zlt->zt.prio_min = zcf->prio_min;
-               zlt->zt.logfn = zlog_fd;
+               zlt->zt.logfn = zcf->zlog_wrap ? zcf->zlog_wrap : zlog_fd;
                zlt->zt.logfn_sigsafe = zlog_fd_sigsafe;
        } while (0);
 
index 7d7b26e32b68519f9d4fa69ed3326fc5b9bfbdd4..f95d349a57db91dfb5082711397b376c087446bd 100644 (file)
@@ -38,6 +38,9 @@ struct zlog_cfg_file {
        /* call zlog_file_set_filename/fd() to change this */
        char *filename;
        int fd;
+
+       void (*zlog_wrap)(struct zlog_target *zt, struct zlog_msg *msgs[],
+                         size_t nmsgs);
 };
 
 extern void zlog_file_init(struct zlog_cfg_file *zcf);
@@ -48,6 +51,9 @@ extern bool zlog_file_set_filename(struct zlog_cfg_file *zcf, const char *name);
 extern bool zlog_file_set_fd(struct zlog_cfg_file *zcf, int fd);
 extern bool zlog_file_rotate(struct zlog_cfg_file *zcf);
 
+extern void zlog_fd(struct zlog_target *zt, struct zlog_msg *msgs[],
+                   size_t nmsgs);
+
 /* syslog is always limited to one target */
 
 extern void zlog_syslog_set_facility(int facility);