stats/vty: Add selective show stats command

Currently there is only the 'show stats' command which shows all
counter and stat_item values. This can lead to many lines of output
if there are per-subscriber rate counters.

The new command added by this commit allows it to only show groups of
a certain level (class_id), similar to the 'level' configuration
command for stats reporter.

The new command is

  show stats level (global|peer|subscriber)

Sponsored-by: On-Waves ehf
diff --git a/include/osmocom/vty/misc.h b/include/osmocom/vty/misc.h
index f3b46db..97ad4a5 100644
--- a/include/osmocom/vty/misc.h
+++ b/include/osmocom/vty/misc.h
@@ -17,6 +17,8 @@
 			     struct osmo_stat_item_group *statg);
 
 void vty_out_statistics_full(struct vty *vty, const char *prefix);
+void vty_out_statistics_partial(struct vty *vty, const char *prefix,
+	int max_level);
 
 int osmo_vty_write_config_file(const char *filename);
 int osmo_vty_save_config_file(void);
diff --git a/src/vty/stats_vty.c b/src/vty/stats_vty.c
index 98253ff..feda2aa 100644
--- a/src/vty/stats_vty.c
+++ b/src/vty/stats_vty.c
@@ -340,6 +340,20 @@
 	return CMD_SUCCESS;
 }
 
+DEFUN(show_stats_level,
+      show_stats_level_cmd,
+      "show stats level (global|peer|subscriber)",
+      SHOW_STR SHOW_STATS_STR
+      "Show global groups only\n"
+      "Show global and network peer related groups\n"
+      "Show global, peer, and subscriber groups\n")
+{
+	int level = get_string_value(stats_class_strs, argv[0]);
+	vty_out_statistics_partial(vty, "", level);
+
+	return CMD_SUCCESS;
+}
+
 static int config_write_stats_reporter(struct vty *vty, struct osmo_stats_reporter *srep)
 {
 	if (srep == NULL)
@@ -406,6 +420,7 @@
 void osmo_stats_vty_add_cmds()
 {
 	install_element_ve(&show_stats_cmd);
+	install_element_ve(&show_stats_level_cmd);
 
 	install_element(CONFIG_NODE, &cfg_stats_reporter_statsd_cmd);
 	install_element(CONFIG_NODE, &cfg_no_stats_reporter_statsd_cmd);
diff --git a/src/vty/utils.c b/src/vty/utils.c
index 8df44ae..b15c8d8 100644
--- a/src/vty/utils.c
+++ b/src/vty/utils.c
@@ -24,6 +24,7 @@
 #include <inttypes.h>
 #include <string.h>
 #include <ctype.h>
+#include <limits.h>
 
 #include <osmocom/core/linuxlist.h>
 #include <osmocom/core/talloc.h>
@@ -44,6 +45,7 @@
 struct vty_out_context {
 	struct vty *vty;
 	const char *prefix;
+	int max_level;
 };
 
 static int rate_ctr_handler(
@@ -114,6 +116,9 @@
 	struct vty_out_context *vctx = vctx_;
 	struct vty *vty = vctx->vty;
 
+	if (statg->desc->class_id > vctx->max_level)
+		return 0;
+
 	if (statg->idx)
 		vty_out(vty, "%s%s (%d):%s", vctx->prefix,
 			statg->desc->group_description, statg->idx,
@@ -132,6 +137,9 @@
 	struct vty_out_context *vctx = vctx_;
 	struct vty *vty = vctx->vty;
 
+	if (ctrg->desc->class_id > vctx->max_level)
+		return 0;
+
 	if (ctrg->idx)
 		vty_out(vty, "%s%s (%d):%s", vctx->prefix,
 			ctrg->desc->group_description, ctrg->idx, VTY_NEWLINE);
@@ -156,9 +164,10 @@
 	return 0;
 }
 
-void vty_out_statistics_full(struct vty *vty, const char *prefix)
+void vty_out_statistics_partial(struct vty *vty, const char *prefix,
+	int max_level)
 {
-	struct vty_out_context vctx = {vty, prefix};
+	struct vty_out_context vctx = {vty, prefix, max_level};
 
 	vty_out(vty, "%sUngrouped counters:%s", prefix, VTY_NEWLINE);
 	osmo_counters_for_each(handle_counter, &vctx);
@@ -166,6 +175,11 @@
 	osmo_stat_item_for_each_group(osmo_stat_item_group_handler, &vctx);
 }
 
+void vty_out_statistics_full(struct vty *vty, const char *prefix)
+{
+	vty_out_statistics_partial(vty, prefix, INT_MAX);
+}
+
 /*! \brief Generate a VTY command string from value_string */
 char *vty_cmd_string_from_valstr(void *ctx, const struct value_string *vals,
 				 const char *prefix, const char *sep,