diff options
| -rw-r--r-- | lib/log.h | 17 | ||||
| -rw-r--r-- | lib/log_filter.c | 156 | ||||
| -rw-r--r-- | lib/log_vty.c | 132 | ||||
| -rw-r--r-- | lib/subdir.am | 1 | ||||
| -rw-r--r-- | lib/zlog_targets.c | 4 | ||||
| -rw-r--r-- | lib/zlog_targets.h | 6 | 
6 files changed, 314 insertions, 2 deletions
@@ -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 index 0000000000..721e57a628 --- /dev/null +++ b/lib/log_filter.c @@ -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); +} diff --git a/lib/log_vty.c b/lib/log_vty.c index 01d19e679d..97026e5dbc 100644 --- a/lib/log_vty.c +++ b/lib/log_vty.c @@ -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);  } diff --git a/lib/subdir.am b/lib/subdir.am index 40c21dcfed..a01909e90d 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -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 \ diff --git a/lib/zlog_targets.c b/lib/zlog_targets.c index 85991b0dde..b23ab073b4 100644 --- a/lib/zlog_targets.c +++ b/lib/zlog_targets.c @@ -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); diff --git a/lib/zlog_targets.h b/lib/zlog_targets.h index 7d7b26e32b..f95d349a57 100644 --- a/lib/zlog_targets.h +++ b/lib/zlog_targets.h @@ -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);  | 
