From 97d3da2c591984b47839fd1d9a5cba24a7f05fa1 Mon Sep 17 00:00:00 2001 From: Stefan Sperling Date: Thu, 24 May 2018 16:42:43 +0200 Subject: introduce vty_out_rate_ctr_group_fmt() function This new function can be used to print a rate counter group according to a format string. The intention is to generalize and replace manual printing of counters as implemented for the 'show statistics' VTY command of osmo-bsc. Related: OS#3245 Related: osmo-bsc commit 71d524c059c5a5c90e7cb77d8a2134c1c68b9cde (g#9217) Change-Id: Idb3ec12494ff6a3a05efcc8818e78d1baa6546bd --- include/osmocom/vty/misc.h | 2 + src/vty/utils.c | 136 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) diff --git a/include/osmocom/vty/misc.h b/include/osmocom/vty/misc.h index 335558d8..2ad96508 100644 --- a/include/osmocom/vty/misc.h +++ b/include/osmocom/vty/misc.h @@ -14,6 +14,8 @@ char *vty_cmd_string_from_valstr(void *ctx, const struct value_string *vals, void vty_out_rate_ctr_group(struct vty *vty, const char *prefix, struct rate_ctr_group *ctrg); +void vty_out_rate_ctr_group_fmt(struct vty *vty, const char *fmt, + struct rate_ctr_group *ctrg); void vty_out_stat_item_group(struct vty *vty, const char *prefix, struct osmo_stat_item_group *statg); diff --git a/src/vty/utils.c b/src/vty/utils.c index 8cd0b35a..4d37093a 100644 --- a/src/vty/utils.c +++ b/src/vty/utils.c @@ -84,6 +84,142 @@ void vty_out_rate_ctr_group(struct vty *vty, const char *prefix, rate_ctr_for_each_counter(ctrg, rate_ctr_handler, &vctx); } +static char * +pad_append_str(char *s, const char *a, int minwidth) +{ + s = talloc_asprintf_append(s, "%*s", minwidth, a); + OSMO_ASSERT(s); + return s; +} + +static char * +pad_append_ctr(char *s, uint64_t ctr, int minwidth, void *ctx) +{ + s = talloc_asprintf_append(s, "%*" PRIu64, minwidth, ctr); + OSMO_ASSERT(s); + return s; +} + +static int rate_ctr_handler_fmt( + struct rate_ctr_group *ctrg, struct rate_ctr *ctr, + const struct rate_ctr_desc *desc, void *vctx_) +{ + struct vty_out_context *vctx = vctx_; + struct vty *vty = vctx->vty; + const char *fmt = vctx->prefix; + char *s = talloc_strdup(vty, ""); + OSMO_ASSERT(s); + + while (*fmt) { + int ch, minwidth = 0, sign = 1; + char *p = strchr(fmt, '%'); + + if (p == NULL) { + /* No further % directives in format string. Copy rest verbatim and exit. */ + s = talloc_strdup_append_buffer(s, fmt); + OSMO_ASSERT(s); + break; + } else { + ptrdiff_t len; + + OSMO_ASSERT(p >= fmt); + len = p - fmt; + if (len) { + /* Copy bytes verbatim until next '%' byte. */ + s = talloc_strndup_append_buffer(s, fmt, len); + OSMO_ASSERT(s); + } + fmt = (const char *)(p + 1); /* skip past '%' */ + if (*fmt == '\0') + break; + } + + ch = *fmt++; + if (ch == '-' && isdigit(*fmt)) { + sign = -1; + ch = *fmt++; + } + while (isdigit(ch) && *fmt != '\0') { + minwidth *= 10; + minwidth += (ch - '0'); + ch = *fmt++; + } + minwidth *= sign; + + switch (ch) { + case '%': + s = talloc_asprintf_append(s, "%c", ch); + OSMO_ASSERT(s); + break; + case 'd': + s = pad_append_str(s, desc->description, minwidth); + break; + case 'n': + s = pad_append_str(s, desc->name, minwidth); + break; + case 'c': + s = pad_append_ctr(s, ctr->current, minwidth, vty); + break; + case 'p': + s = pad_append_ctr(s, ctr->previous, minwidth, vty); + break; + case 'S': + s = pad_append_ctr(s, ctr->intv[RATE_CTR_INTV_SEC].rate, minwidth, vty); + break; + case 'M': + s = pad_append_ctr(s, ctr->intv[RATE_CTR_INTV_MIN].rate, minwidth, vty); + break; + case 'H': + s = pad_append_ctr(s, ctr->intv[RATE_CTR_INTV_HOUR].rate, minwidth, vty); + break; + case 'D': + s = pad_append_ctr(s, ctr->intv[RATE_CTR_INTV_DAY].rate, minwidth, vty); + break; + default: + break; + } + } + + vty_out(vty, "%s%s", s, VTY_NEWLINE); + talloc_free(s); + + return 0; +} + +/*! print a rate counter group to given VTY, formatting the line for each counter according to a format string. + * + * The following format string directives are supported: + * - %d: The description of the counter + * - %n: The name of the counter + * - %c: The current value of the counter + * - %p: The previous value of the counter + * - %S: The interval of the counter in seconds + * - %M: The interval of the counter in minutes + * - %H: The interval of the counter in hours + * - %D: The interval of the counter in days + * - %%: Print a literal %. + * + * An optional number between % and the letter in a format directive may be used to set a minimum field width. + * If the expanded format directive is smaller than this width (according to strlen()) the string will be + * left-padded (if the number is positive) or right-padded (if the number is negative) with spaces. + * For example, "%25n" prints the counter name left-padded up to a minimum width of 25 columns. + * + * VTY_NEWLINE will be appended to the format string when it is printed. + * + * \param[in] vty The VTY to which it should be printed + * \param[in] ctrg Rate counter group to be printed + * \param[in] fmt A format which may contain the above directives. + */ +void vty_out_rate_ctr_group_fmt(struct vty *vty, const char *fmt, + struct rate_ctr_group *ctrg) +{ + struct vty_out_context vctx = {vty, fmt}; + + vty_out(vty, "%s:%s", ctrg->desc->group_description, VTY_NEWLINE); + + rate_ctr_for_each_counter(ctrg, rate_ctr_handler_fmt, &vctx); +} + static int rate_ctr_group_handler(struct rate_ctr_group *ctrg, void *vctx_) { struct vty_out_context *vctx = vctx_; -- cgit v1.2.3