diff options
Diffstat (limited to 'lib/log.c')
-rw-r--r-- | lib/log.c | 195 |
1 files changed, 182 insertions, 13 deletions
@@ -65,6 +65,110 @@ const char *zlog_priority[] = { "notifications", "informational", "debugging", NULL, }; +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, loglock 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) +{ + pthread_mutex_lock(&loglock); + zlog_filter_count = 0; + pthread_mutex_unlock(&loglock); +} + +int zlog_filter_add(const char *filter) +{ + pthread_mutex_lock(&loglock); + + int ret = 0; + + if (zlog_filter_count >= ZLOG_FILTERS_MAX) { + ret = 1; + goto done; + } + + if (zlog_filter_lookup(filter) != -1) { + /* Filter already present */ + ret = -1; + goto done; + } + + 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 */ + ret = -1; + goto done; + } + + zlog_filter_count++; + +done: + pthread_mutex_unlock(&loglock); + return ret; +} + +int zlog_filter_del(const char *filter) +{ + pthread_mutex_lock(&loglock); + + int found_idx = zlog_filter_lookup(filter); + int last_idx = zlog_filter_count - 1; + int ret = 0; + + if (found_idx == -1) { + /* Didn't find the filter to delete */ + ret = -1; + goto done; + } + + /* 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--; + +done: + pthread_mutex_unlock(&loglock); + return ret; +} + +/* Dump all filters to buffer, delimited by new line */ +int zlog_filter_dump(char *buf, size_t max_size) +{ + pthread_mutex_lock(&loglock); + + int ret = 0; + int len = 0; + + for (int i = 0; i < zlog_filter_count; i++) { + ret = snprintf(buf + len, max_size - len, " %s\n", + zlog_filters[i]); + len += ret; + if ((ret < 0) || ((size_t)len >= max_size)) { + len = -1; + goto done; + } + } + +done: + pthread_mutex_unlock(&loglock); + return len; +} + /* * write_wrapper * @@ -178,17 +282,32 @@ size_t quagga_timestamp(int timestamp_precision, char *buf, size_t buflen) return 0; } -/* Utility routine for current time printing. */ -static void time_print(FILE *fp, struct timestamp_control *ctl) +static inline void timestamp_control_render(struct timestamp_control *ctl) { if (!ctl->already_rendered) { ctl->len = quagga_timestamp(ctl->precision, ctl->buf, sizeof(ctl->buf)); ctl->already_rendered = 1; } +} + +/* Utility routine for current time printing. */ +static void time_print(FILE *fp, struct timestamp_control *ctl) +{ + timestamp_control_render(ctl); fprintf(fp, "%s ", ctl->buf); } +static int time_print_buf(char *buf, int len, int max_size, + struct timestamp_control *ctl) +{ + timestamp_control_render(ctl); + + if (ctl->len + 1 >= (unsigned long)max_size) + return -1; + + return snprintf(buf + len, max_size - len, "%s ", ctl->buf); +} static void vzlog_file(struct zlog *zl, struct timestamp_control *tsctl, const char *proto_str, int record_priority, int priority, @@ -202,42 +321,92 @@ static void vzlog_file(struct zlog *zl, struct timestamp_control *tsctl, fflush(fp); } +/* Search a buf for the filter strings, loglock must be held */ +static int search_buf(const char *buf) +{ + char *found = NULL; + + for (int i = 0; i < zlog_filter_count; i++) { + found = strstr(buf, zlog_filters[i]); + if (found != NULL) + return 0; + } + + return -1; +} + +/* Filter out a log */ +static int vzlog_filter(struct zlog *zl, struct timestamp_control *tsctl, + const char *proto_str, int priority, const char *msg) +{ + int len = 0; + int ret = 0; + char buf[1024] = ""; + + ret = time_print_buf(buf, len, sizeof(buf), tsctl); + + len += ret; + if ((ret < 0) || ((size_t)len >= sizeof(buf))) + goto search; + + if (zl && zl->record_priority) + snprintf(buf + len, sizeof(buf) - len, "%s: %s: %s", + zlog_priority[priority], proto_str, msg); + else + snprintf(buf + len, sizeof(buf) - len, "%s: %s", proto_str, + msg); + +search: + return search_buf(buf); +} + /* va_list version of zlog. */ void vzlog(int priority, const char *format, va_list args) { pthread_mutex_lock(&loglock); - char proto_str[32]; + char proto_str[32] = ""; int original_errno = errno; - struct timestamp_control tsctl; + struct timestamp_control tsctl = {}; tsctl.already_rendered = 0; struct zlog *zl = zlog_default; char buf[256], *msg; - /* call external hook */ - hook_call(zebra_ext_log, priority, format, args); + if (zl == NULL) { + tsctl.precision = 0; + } else { + tsctl.precision = zl->timestamp_precision; + if (zl->instance) + sprintf(proto_str, "%s[%d]: ", zl->protoname, + zl->instance); + else + sprintf(proto_str, "%s: ", zl->protoname); + } msg = vasnprintfrr(MTYPE_TMP, buf, sizeof(buf), format, args); + /* If it doesn't match on a filter, do nothing with the debug log */ + if ((priority == LOG_DEBUG) && zlog_filter_count + && vzlog_filter(zl, &tsctl, proto_str, priority, msg)) { + pthread_mutex_unlock(&loglock); + goto out; + } + + /* call external hook */ + hook_call(zebra_ext_log, priority, format, args); + /* When zlog_default is also NULL, use stderr for logging. */ if (zl == NULL) { - tsctl.precision = 0; time_print(stderr, &tsctl); fprintf(stderr, "%s: %s\n", "unknown", msg); fflush(stderr); goto out; } - tsctl.precision = zl->timestamp_precision; /* Syslog output */ if (priority <= zl->maxlvl[ZLOG_DEST_SYSLOG]) syslog(priority | zlog_default->facility, "%s", msg); - if (zl->instance) - sprintf(proto_str, "%s[%d]: ", zl->protoname, zl->instance); - else - sprintf(proto_str, "%s: ", zl->protoname); - /* File output. */ if ((priority <= zl->maxlvl[ZLOG_DEST_FILE]) && zl->fp) vzlog_file(zl, &tsctl, proto_str, zl->record_priority, priority, |