Browse code

xhttp_prom: add support for histogram metrics.

Vicente Hernando Ara authored on 10/08/2020 17:52:59
Showing 1 changed files
... ...
@@ -39,23 +39,22 @@
39 39
 #include "prom.h"
40 40
 #include "prom_metric.h"
41 41
 
42
-/** @addtogroup xhttp_prom
43
- * @ingroup modules
44
- * @{
42
+/**
43
+ * @file
44
+ * @brief xHTTP_PROM :: main file for xhttp_prom module.
45 45
  *
46
- * <h1>Overview of Operation</h1>
47 46
  * This module provides a web interface for Prometheus server.
48 47
  * It is built on top of the xhttp API module.
49
- */
50
-
51
-/** @file
52 48
  *
53 49
  * This is the main file of xhttp_prom module which contains all the functions
54 50
  * related to http processing, as well as the module interface.
51
+ *
52
+ * @addtogroup xhttp_prom
55 53
  */
56 54
 
57 55
 MODULE_VERSION
58 56
 
57
+
59 58
 /* Declaration of static functions. */
60 59
 
61 60
 str XHTTP_PROM_REASON_OK = str_init("OK");
... ...
@@ -82,13 +81,19 @@ static int w_prom_gauge_set_l0(struct sip_msg* msg, char *pname, char* pnumber);
82 81
 static int w_prom_gauge_set_l1(struct sip_msg* msg, char *pname, char* pnumber, char *l1);
83 82
 static int w_prom_gauge_set_l2(struct sip_msg* msg, char *pname, char* pnumber, char *l1, char *l2);
84 83
 static int w_prom_gauge_set_l3(struct sip_msg* msg, char *pname, char* pnumber, char *l1, char *l2, char *l3);
84
+static int w_prom_histogram_observe_l0(struct sip_msg* msg, char *pname, char* pnumber);
85
+static int w_prom_histogram_observe_l1(struct sip_msg* msg, char *pname, char* pnumber, char *l1);
86
+static int w_prom_histogram_observe_l2(struct sip_msg* msg, char *pname, char* pnumber, char *l1, char *l2);
87
+static int w_prom_histogram_observe_l3(struct sip_msg* msg, char *pname, char* pnumber, char *l1, char *l2, char *l3);
85 88
 static int fixup_metric_reset(void** param, int param_no);
86 89
 static int fixup_counter_inc(void** param, int param_no);
87 90
 
88 91
 int prom_counter_param(modparam_t type, void *val);
89 92
 int prom_gauge_param(modparam_t type, void *val);
93
+int prom_histogram_param(modparam_t type, void *val);
90 94
 
91
-/** The context of the xhttp_prom request being processed.
95
+/**
96
+ * @brief The context of the xhttp_prom request being processed.
92 97
  *
93 98
  * This is a global variable that records the context of the xhttp_prom request
94 99
  * being currently processed.
... ...
@@ -98,11 +103,22 @@ static prom_ctx_t ctx;
98 103
 
99 104
 static xhttp_api_t xhttp_api;
100 105
 
101
-/* It does not show Kamailio statistics by default. */
106
+/**
107
+ * @brief String to indicate which statistics to display.
108
+ *
109
+ * It does not show Kamailio statistics by default.
110
+ */
102 111
 str xhttp_prom_stats = str_init("");
103 112
 
104
-int buf_size = 0;
105
-int timeout_minutes = 0;
113
+/**
114
+ * @brief string for beginning of metrics.
115
+ */
116
+str xhttp_prom_beginning = str_init("kamailio_");
117
+
118
+int buf_size = 0; /**< size of buffer that contains the reply. */
119
+
120
+int timeout_minutes = 60; /**< timeout in minutes to delete old metrics. */
121
+
106 122
 char error_buf[ERROR_REASON_BUF_LEN];
107 123
 
108 124
 /* module commands */
... ...
@@ -143,14 +159,24 @@ static cmd_export_t cmds[] = {
143 159
 	 0, ANY_ROUTE},
144 160
 	{"prom_gauge_set", (cmd_function)w_prom_gauge_set_l3, 5, fixup_metric_reset,
145 161
 	 0, ANY_ROUTE},
162
+	{"prom_histogram_observe", (cmd_function)w_prom_histogram_observe_l0, 2, fixup_metric_reset,
163
+	 0, ANY_ROUTE},
164
+	{"prom_histogram_observe", (cmd_function)w_prom_histogram_observe_l1, 3, fixup_metric_reset,
165
+	 0, ANY_ROUTE},
166
+	{"prom_histogram_observe", (cmd_function)w_prom_histogram_observe_l2, 4, fixup_metric_reset,
167
+	 0, ANY_ROUTE},
168
+	{"prom_histogram_observe", (cmd_function)w_prom_histogram_observe_l3, 5, fixup_metric_reset,
169
+	 0, ANY_ROUTE},
146 170
 	{ 0, 0, 0, 0, 0, 0}
147 171
 };
148 172
 
149 173
 static param_export_t params[]={
150 174
 	{"xhttp_prom_buf_size",	INT_PARAM,	&buf_size},
151 175
 	{"xhttp_prom_stats",	PARAM_STR,	&xhttp_prom_stats},
176
+	{"xhttp_prom_beginning",	PARAM_STR,	&xhttp_prom_beginning},
152 177
 	{"prom_counter",        PARAM_STRING|USE_FUNC_PARAM, (void*)prom_counter_param},
153 178
 	{"prom_gauge",          PARAM_STRING|USE_FUNC_PARAM, (void*)prom_gauge_param},
179
+	{"prom_histogram",      PARAM_STRING|USE_FUNC_PARAM, (void*)prom_histogram_param},
154 180
 	{"xhttp_prom_timeout",	INT_PARAM,	&timeout_minutes},
155 181
 	{0, 0, 0}
156 182
 };
... ...
@@ -168,7 +194,8 @@ struct module_exports exports = {
168 194
 	mod_destroy     /* destroy function */
169 195
 };
170 196
 
171
-/** Implementation of prom_fault function required by the management API.
197
+/**
198
+ * @brief Implementation of prom_fault function required by the management API.
172 199
  *
173 200
  * This function will be called whenever a management function
174 201
  * indicates that an error ocurred while it was processing the request. The
... ...
@@ -215,13 +242,8 @@ static int mod_init(void)
215 242
 	if (buf_size == 0)
216 243
 		buf_size = pkg_mem_size/3;
217 244
 
218
-	/* Check xhttp_prom_timeout param */
219
-	if (timeout_minutes == 0) {
220
-		timeout_minutes = 60;
221
-	}
222
-
223 245
 	/* Initialize Prometheus metrics. */
224
-	if (prom_metric_init(timeout_minutes)) {
246
+	if (prom_metric_init()) {
225 247
 		LM_ERR("Cannot initialize Prometheus metrics\n");
226 248
 		return -1;
227 249
 	}
... ...
@@ -237,7 +259,7 @@ static void mod_destroy(void)
237 259
 }
238 260
 
239 261
 /**
240
- * Parse parameters to create a counter.
262
+ * @brief Parse parameters to create a counter.
241 263
  */
242 264
 int prom_counter_param(modparam_t type, void *val)
243 265
 {
... ...
@@ -245,14 +267,22 @@ int prom_counter_param(modparam_t type, void *val)
245 267
 }
246 268
 
247 269
 /**
248
- * Parse parameters to create a gauge.
270
+ * @brief Parse parameters to create a gauge.
249 271
  */
250 272
 int prom_gauge_param(modparam_t type, void *val)
251 273
 {
252 274
 	return prom_gauge_create((char*)val);
253 275
 }
254 276
 
255
-#define PROMETHEUS_URI "/metrics"
277
+/**
278
+ * @brief Parse parameters to create a histogram.
279
+ */
280
+int prom_histogram_param(modparam_t type, void *val)
281
+{
282
+	return prom_histogram_create((char*)val);
283
+}
284
+
285
+#define PROMETHEUS_URI "/metrics" /**< URI to get Prometheus metrics. */
256 286
 static str prom_uri = str_init(PROMETHEUS_URI);
257 287
 
258 288
 static int ki_xhttp_prom_check_uri(sip_msg_t* msg)
... ...
@@ -299,11 +329,13 @@ static int w_prom_check_uri(sip_msg_t* msg)
299 329
 	return -1;
300 330
 }
301 331
 
302
-/** Initialize xhttp_prom reply data structure.
332
+/**
333
+ * @brief Initialize xhttp_prom reply data structure.
303 334
  *
304 335
  * This function initializes the data structure that contains all data related
305 336
  * to the xhttp_prom reply being created. The function must be called before any
306 337
  * other function that adds data to the reply.
338
+ *
307 339
  * @param ctx prom_ctx_t structure to be initialized.
308 340
  * @return 0 on success, a negative number on error.
309 341
  */
... ...
@@ -326,7 +358,7 @@ static int init_xhttp_prom_reply(prom_ctx_t *ctx)
326 358
 }
327 359
 
328 360
 /**
329
- * Free buffer in reply.
361
+ * @brief Free buffer in reply.
330 362
  */
331 363
 static void xhttp_prom_reply_free(prom_ctx_t *ctx)
332 364
 {
... ...
@@ -439,7 +471,7 @@ static int fixup_metric_reset(void** param, int param_no)
439 471
 /* } */
440 472
 
441 473
 /**
442
- * Reset a counter (No labels)
474
+ * @brief Reset a counter (No labels)
443 475
  */
444 476
 static int ki_xhttp_prom_counter_reset_l0(struct sip_msg* msg, str *s_name)
445 477
 {
... ...
@@ -458,7 +490,7 @@ static int ki_xhttp_prom_counter_reset_l0(struct sip_msg* msg, str *s_name)
458 490
 }
459 491
 
460 492
 /**
461
- * Reset a counter (1 label)
493
+ * @brief Reset a counter (1 label)
462 494
  */
463 495
 static int ki_xhttp_prom_counter_reset_l1(struct sip_msg* msg, str *s_name, str *l1)
464 496
 {
... ...
@@ -485,7 +517,7 @@ static int ki_xhttp_prom_counter_reset_l1(struct sip_msg* msg, str *s_name, str
485 517
 }
486 518
 
487 519
 /**
488
- * Reset a counter (2 labels)
520
+ * @brief Reset a counter (2 labels)
489 521
  */
490 522
 static int ki_xhttp_prom_counter_reset_l2(struct sip_msg* msg, str *s_name, str *l1, str *l2)
491 523
 {
... ...
@@ -521,7 +553,7 @@ static int ki_xhttp_prom_counter_reset_l2(struct sip_msg* msg, str *s_name, str
521 553
 }
522 554
 
523 555
 /**
524
- * Reset a counter (3 labels)
556
+ * @brief Reset a counter (3 labels)
525 557
  */
526 558
 static int ki_xhttp_prom_counter_reset_l3(struct sip_msg* msg, str *s_name, str *l1, str *l2,
527 559
 										  str *l3)
... ...
@@ -565,7 +597,7 @@ static int ki_xhttp_prom_counter_reset_l3(struct sip_msg* msg, str *s_name, str
565 597
 }
566 598
 
567 599
 /**
568
- * Reset a counter.
600
+ * @brief Reset a counter.
569 601
  */
570 602
 static int w_prom_counter_reset(struct sip_msg* msg, char* pname, char *l1, char *l2,
571 603
 								char *l3)
... ...
@@ -641,7 +673,7 @@ static int w_prom_counter_reset(struct sip_msg* msg, char* pname, char *l1, char
641 673
 }
642 674
 
643 675
 /**
644
- * Reset a counter (no labels)
676
+ * @brief Reset a counter (no labels)
645 677
  */
646 678
 static int w_prom_counter_reset_l0(struct sip_msg* msg, char* pname)
647 679
 {
... ...
@@ -649,7 +681,7 @@ static int w_prom_counter_reset_l0(struct sip_msg* msg, char* pname)
649 681
 }
650 682
 
651 683
 /**
652
- * Reset a counter (one label)
684
+ * @brief Reset a counter (one label)
653 685
  */
654 686
 static int w_prom_counter_reset_l1(struct sip_msg* msg, char* pname, char *l1)
655 687
 {
... ...
@@ -657,7 +689,7 @@ static int w_prom_counter_reset_l1(struct sip_msg* msg, char* pname, char *l1)
657 689
 }
658 690
 
659 691
 /**
660
- * Reset a counter (two labels)
692
+ * @brief Reset a counter (two labels)
661 693
  */
662 694
 static int w_prom_counter_reset_l2(struct sip_msg* msg, char* pname, char *l1, char *l2)
663 695
 {
... ...
@@ -665,7 +697,7 @@ static int w_prom_counter_reset_l2(struct sip_msg* msg, char* pname, char *l1, c
665 697
 }
666 698
 
667 699
 /**
668
- * Reset a counter (three labels)
700
+ * @brief Reset a counter (three labels)
669 701
  */
670 702
 static int w_prom_counter_reset_l3(struct sip_msg* msg, char* pname, char *l1, char *l2,
671 703
 	char *l3)
... ...
@@ -674,7 +706,7 @@ static int w_prom_counter_reset_l3(struct sip_msg* msg, char* pname, char *l1, c
674 706
 }
675 707
 
676 708
 /**
677
- * Reset a gauge (No labels)
709
+ * @brief Reset a gauge (No labels)
678 710
  */
679 711
 static int ki_xhttp_prom_gauge_reset_l0(struct sip_msg* msg, str *s_name)
680 712
 {
... ...
@@ -693,7 +725,7 @@ static int ki_xhttp_prom_gauge_reset_l0(struct sip_msg* msg, str *s_name)
693 725
 }
694 726
 
695 727
 /**
696
- * Reset a gauge (1 label)
728
+ * @brief Reset a gauge (1 label)
697 729
  */
698 730
 static int ki_xhttp_prom_gauge_reset_l1(struct sip_msg* msg, str *s_name, str *l1)
699 731
 {
... ...
@@ -720,7 +752,7 @@ static int ki_xhttp_prom_gauge_reset_l1(struct sip_msg* msg, str *s_name, str *l
720 752
 }
721 753
 
722 754
 /**
723
- * Reset a gauge (2 labels)
755
+ * @brief Reset a gauge (2 labels)
724 756
  */
725 757
 static int ki_xhttp_prom_gauge_reset_l2(struct sip_msg* msg, str *s_name, str *l1, str *l2)
726 758
 {
... ...
@@ -756,7 +788,7 @@ static int ki_xhttp_prom_gauge_reset_l2(struct sip_msg* msg, str *s_name, str *l
756 788
 }
757 789
 
758 790
 /**
759
- * Reset a gauge (3 labels)
791
+ * @brief Reset a gauge (3 labels)
760 792
  */
761 793
 static int ki_xhttp_prom_gauge_reset_l3(struct sip_msg* msg, str *s_name, str *l1, str *l2,
762 794
 										  str *l3)
... ...
@@ -800,7 +832,7 @@ static int ki_xhttp_prom_gauge_reset_l3(struct sip_msg* msg, str *s_name, str *l
800 832
 }
801 833
 
802 834
 /**
803
- * Reset a gauge.
835
+ * @brief Reset a gauge.
804 836
  */
805 837
 static int w_prom_gauge_reset(struct sip_msg* msg, char* pname, char *l1, char *l2,
806 838
 								char *l3)
... ...
@@ -876,7 +908,7 @@ static int w_prom_gauge_reset(struct sip_msg* msg, char* pname, char *l1, char *
876 908
 }
877 909
 
878 910
 /**
879
- * Reset a gauge (no labels)
911
+ * @brief Reset a gauge (no labels)
880 912
  */
881 913
 static int w_prom_gauge_reset_l0(struct sip_msg* msg, char* pname)
882 914
 {
... ...
@@ -884,7 +916,7 @@ static int w_prom_gauge_reset_l0(struct sip_msg* msg, char* pname)
884 916
 }
885 917
 
886 918
 /**
887
- * Reset a gauge (one label)
919
+ * @brief Reset a gauge (one label)
888 920
  */
889 921
 static int w_prom_gauge_reset_l1(struct sip_msg* msg, char* pname, char *l1)
890 922
 {
... ...
@@ -892,7 +924,7 @@ static int w_prom_gauge_reset_l1(struct sip_msg* msg, char* pname, char *l1)
892 924
 }
893 925
 
894 926
 /**
895
- * Reset a gauge (two labels)
927
+ * @brief Reset a gauge (two labels)
896 928
  */
897 929
 static int w_prom_gauge_reset_l2(struct sip_msg* msg, char* pname, char *l1, char *l2)
898 930
 {
... ...
@@ -900,7 +932,7 @@ static int w_prom_gauge_reset_l2(struct sip_msg* msg, char* pname, char *l1, cha
900 932
 }
901 933
 
902 934
 /**
903
- * Reset a gauge (three labels)
935
+ * @brief Reset a gauge (three labels)
904 936
  */
905 937
 static int w_prom_gauge_reset_l3(struct sip_msg* msg, char* pname, char *l1, char *l2,
906 938
 	char *l3)
... ...
@@ -927,7 +959,7 @@ static int fixup_counter_inc(void** param, int param_no)
927 959
 /* } */
928 960
 
929 961
 /**
930
- * Add an integer to a counter (No labels).
962
+ * @brief Add an integer to a counter (No labels).
931 963
  */
932 964
 static int ki_xhttp_prom_counter_inc_l0(struct sip_msg* msg, str *s_name, int number)
933 965
 {
... ...
@@ -951,7 +983,7 @@ static int ki_xhttp_prom_counter_inc_l0(struct sip_msg* msg, str *s_name, int nu
951 983
 }
952 984
 
953 985
 /**
954
- * Add an integer to a counter (1 label).
986
+ * @brief Add an integer to a counter (1 label).
955 987
  */
956 988
 static int ki_xhttp_prom_counter_inc_l1(struct sip_msg* msg, str *s_name, int number, str *l1)
957 989
 {
... ...
@@ -987,7 +1019,7 @@ static int ki_xhttp_prom_counter_inc_l1(struct sip_msg* msg, str *s_name, int nu
987 1019
 }
988 1020
 
989 1021
 /**
990
- * Add an integer to a counter (2 labels).
1022
+ * @brief Add an integer to a counter (2 labels).
991 1023
  */
992 1024
 static int ki_xhttp_prom_counter_inc_l2(struct sip_msg* msg, str *s_name, int number,
993 1025
 										str *l1, str *l2)
... ...
@@ -1031,7 +1063,7 @@ static int ki_xhttp_prom_counter_inc_l2(struct sip_msg* msg, str *s_name, int nu
1031 1063
 }
1032 1064
 
1033 1065
 /**
1034
- * Add an integer to a counter (3 labels).
1066
+ * @brief Add an integer to a counter (3 labels).
1035 1067
  */
1036 1068
 static int ki_xhttp_prom_counter_inc_l3(struct sip_msg* msg, str *s_name, int number,
1037 1069
 										str *l1, str *l2, str *l3)
... ...
@@ -1082,7 +1114,7 @@ static int ki_xhttp_prom_counter_inc_l3(struct sip_msg* msg, str *s_name, int nu
1082 1114
 }
1083 1115
 
1084 1116
 /**
1085
- * Add an integer to a counter.
1117
+ * @brief Add an integer to a counter.
1086 1118
  */
1087 1119
 static int w_prom_counter_inc(struct sip_msg* msg, char *pname, char* pnumber,
1088 1120
 							  char *l1, char *l2, char *l3)
... ...
@@ -1168,7 +1200,7 @@ static int w_prom_counter_inc(struct sip_msg* msg, char *pname, char* pnumber,
1168 1200
 }
1169 1201
 
1170 1202
 /**
1171
- * Add an integer to a counter (no labels)
1203
+ * @brief Add an integer to a counter (no labels)
1172 1204
  */
1173 1205
 static int w_prom_counter_inc_l0(struct sip_msg* msg, char *pname, char* pnumber)
1174 1206
 {
... ...
@@ -1176,7 +1208,7 @@ static int w_prom_counter_inc_l0(struct sip_msg* msg, char *pname, char* pnumber
1176 1208
 }
1177 1209
 
1178 1210
 /**
1179
- * Add an integer to a counter (1 labels)
1211
+ * @brief Add an integer to a counter (1 labels)
1180 1212
  */
1181 1213
 static int w_prom_counter_inc_l1(struct sip_msg* msg, char *pname, char* pnumber,
1182 1214
 								 char *l1)
... ...
@@ -1185,7 +1217,7 @@ static int w_prom_counter_inc_l1(struct sip_msg* msg, char *pname, char* pnumber
1185 1217
 }
1186 1218
 
1187 1219
 /**
1188
- * Add an integer to a counter (2 labels)
1220
+ * @brief Add an integer to a counter (2 labels)
1189 1221
  */
1190 1222
 static int w_prom_counter_inc_l2(struct sip_msg* msg, char *pname, char* pnumber,
1191 1223
 								 char *l1, char *l2)
... ...
@@ -1194,7 +1226,7 @@ static int w_prom_counter_inc_l2(struct sip_msg* msg, char *pname, char* pnumber
1194 1226
 }
1195 1227
 
1196 1228
 /**
1197
- * Add an integer to a counter (3 labels)
1229
+ * @brief Add an integer to a counter (3 labels)
1198 1230
  */
1199 1231
 static int w_prom_counter_inc_l3(struct sip_msg* msg, char *pname, char* pnumber,
1200 1232
 								 char *l1, char *l2, char *l3)
... ...
@@ -1203,57 +1235,7 @@ static int w_prom_counter_inc_l3(struct sip_msg* msg, char *pname, char* pnumber
1203 1235
 }
1204 1236
 
1205 1237
 /**
1206
- * Parse a string and convert to double.
1207
- *
1208
- * /param s_number pointer to number string.
1209
- * /param number double passed as reference.
1210
- *
1211
- * /return 0 on success.
1212
- * On error value pointed by pnumber is undefined.
1213
- */
1214
-static int double_parse_str(str *s_number, double *pnumber)
1215
-{
1216
-	char *s = NULL;
1217
-	
1218
-	if (!s_number || !s_number->s || s_number->len == 0) {
1219
-		LM_ERR("Bad s_number to convert to double\n");
1220
-		goto error;
1221
-	}
1222
-
1223
-	if (!pnumber) {
1224
-		LM_ERR("No double passed by reference\n");
1225
-		goto error;
1226
-	}
1227
-
1228
-	/* We generate a zero terminated string. */
1229
-
1230
-	/* We set last character to zero to get a zero terminated string. */
1231
-	int len = s_number->len;
1232
-	s = pkg_malloc(len + 1);
1233
-	if (!s) {
1234
-		PKG_MEM_ERROR;
1235
-		goto error;
1236
-	}
1237
-	memcpy(s, s_number->s, len);
1238
-	s[len] = '\0'; /* Zero terminated string. */
1239
-
1240
-	/* atof function does not check for errors. */
1241
-	double num = atof(s);
1242
-	LM_DBG("double number (%.*s) -> %f\n", len, s, num);
1243
-
1244
-	*pnumber = num;
1245
-	pkg_free(s);
1246
-	return 0;
1247
-
1248
-error:
1249
-	if (s) {
1250
-		pkg_free(s);
1251
-	}
1252
-	return -1;
1253
-}
1254
-
1255
-/**
1256
- * Set a number to a gauge (No labels).
1238
+ * @brief Set a number to a gauge (No labels).
1257 1239
  */
1258 1240
 static int ki_xhttp_prom_gauge_set_l0(struct sip_msg* msg, str *s_name, str *s_number)
1259 1241
 {
... ...
@@ -1283,7 +1265,7 @@ static int ki_xhttp_prom_gauge_set_l0(struct sip_msg* msg, str *s_name, str *s_n
1283 1265
 }
1284 1266
 
1285 1267
 /**
1286
- * Assign a number to a gauge (1 label).
1268
+ * @brief Assign a number to a gauge (1 label).
1287 1269
  */
1288 1270
 static int ki_xhttp_prom_gauge_set_l1(struct sip_msg* msg, str *s_name, str *s_number, str *l1)
1289 1271
 {
... ...
@@ -1324,7 +1306,7 @@ static int ki_xhttp_prom_gauge_set_l1(struct sip_msg* msg, str *s_name, str *s_n
1324 1306
 }
1325 1307
 
1326 1308
 /**
1327
- * Assign a number to a gauge (2 labels).
1309
+ * @brief Assign a number to a gauge (2 labels).
1328 1310
  */
1329 1311
 static int ki_xhttp_prom_gauge_set_l2(struct sip_msg* msg, str *s_name, str *s_number,
1330 1312
 									  str *l1, str *l2)
... ...
@@ -1374,7 +1356,7 @@ static int ki_xhttp_prom_gauge_set_l2(struct sip_msg* msg, str *s_name, str *s_n
1374 1356
 }
1375 1357
 
1376 1358
 /**
1377
- * Assign a number to a gauge (3 labels).
1359
+ * @brief Assign a number to a gauge (3 labels).
1378 1360
  */
1379 1361
 static int ki_xhttp_prom_gauge_set_l3(struct sip_msg* msg, str *s_name, str *s_number,
1380 1362
 									  str *l1, str *l2, str *l3)
... ...
@@ -1431,7 +1413,7 @@ static int ki_xhttp_prom_gauge_set_l3(struct sip_msg* msg, str *s_name, str *s_n
1431 1413
 }
1432 1414
 
1433 1415
 /**
1434
- * Assign a number to a gauge.
1416
+ * @brief Assign a number to a gauge.
1435 1417
  */
1436 1418
 static int w_prom_gauge_set(struct sip_msg* msg, char *pname, char* pnumber,
1437 1419
 							char *l1, char *l2, char *l3)
... ...
@@ -1523,7 +1505,7 @@ static int w_prom_gauge_set(struct sip_msg* msg, char *pname, char* pnumber,
1523 1505
 }
1524 1506
 
1525 1507
 /**
1526
- * Assign a number to a gauge (no labels)
1508
+ * @brief Assign a number to a gauge (no labels)
1527 1509
  */
1528 1510
 static int w_prom_gauge_set_l0(struct sip_msg* msg, char *pname, char* pnumber)
1529 1511
 {
... ...
@@ -1531,7 +1513,7 @@ static int w_prom_gauge_set_l0(struct sip_msg* msg, char *pname, char* pnumber)
1531 1513
 }
1532 1514
 
1533 1515
 /**
1534
- * Assign a number to a gauge (1 labels)
1516
+ * @brief Assign a number to a gauge (1 labels)
1535 1517
  */
1536 1518
 static int w_prom_gauge_set_l1(struct sip_msg* msg, char *pname, char* pnumber,
1537 1519
 							   char *l1)
... ...
@@ -1540,7 +1522,7 @@ static int w_prom_gauge_set_l1(struct sip_msg* msg, char *pname, char* pnumber,
1540 1522
 }
1541 1523
 
1542 1524
 /**
1543
- * Assign a number to a gauge (2 labels)
1525
+ * @brief Assign a number to a gauge (2 labels)
1544 1526
  */
1545 1527
 static int w_prom_gauge_set_l2(struct sip_msg* msg, char *pname, char* pnumber,
1546 1528
 							   char *l1, char *l2)
... ...
@@ -1549,7 +1531,7 @@ static int w_prom_gauge_set_l2(struct sip_msg* msg, char *pname, char* pnumber,
1549 1531
 }
1550 1532
 
1551 1533
 /**
1552
- * Assign a number to a gauge (3 labels)
1534
+ * @brief Assign a number to a gauge (3 labels)
1553 1535
  */
1554 1536
 static int w_prom_gauge_set_l3(struct sip_msg* msg, char *pname, char* pnumber,
1555 1537
 							   char *l1, char *l2, char *l3)
... ...
@@ -1557,6 +1539,312 @@ static int w_prom_gauge_set_l3(struct sip_msg* msg, char *pname, char* pnumber,
1557 1539
 	return w_prom_gauge_set(msg, pname, pnumber, l1, l2, l3);
1558 1540
 }
1559 1541
 
1542
+/**
1543
+ * @brief Observe a number in a histogram (No labels).
1544
+ */
1545
+static int ki_xhttp_prom_histogram_observe_l0(struct sip_msg* msg, str *s_name, str *s_number)
1546
+{
1547
+	if (s_name == NULL || s_name->s == NULL || s_name->len == 0) {
1548
+		LM_ERR("Invalid name string\n");
1549
+		return -1;
1550
+	}
1551
+
1552
+	if (s_number == NULL || s_number->s == NULL || s_number->len == 0) {
1553
+		LM_ERR("Invalid number string\n");
1554
+		return -1;
1555
+	}
1556
+
1557
+	double number;
1558
+	if (double_parse_str(s_number, &number)) {
1559
+		LM_ERR("Cannot parse double\n");
1560
+		return -1;
1561
+	}
1562
+
1563
+	if (prom_histogram_observe(s_name, number, NULL, NULL, NULL)) {
1564
+		LM_ERR("Cannot observe number: %f in histogram: %.*s\n", number, s_name->len, s_name->s);
1565
+		return -1;
1566
+	}
1567
+
1568
+	LM_DBG("Observed %f in histogram %.*s\n", number, s_name->len, s_name->s);
1569
+	return 1;
1570
+}
1571
+
1572
+/**
1573
+ * @brief Observe a number in a histogram (1 label).
1574
+ */
1575
+static int ki_xhttp_prom_histogram_observe_l1(struct sip_msg* msg, str *s_name, str *s_number, str *l1)
1576
+{
1577
+	if (s_name == NULL || s_name->s == NULL || s_name->len == 0) {
1578
+		LM_ERR("Invalid name string\n");
1579
+		return -1;
1580
+	}
1581
+
1582
+	if (s_number == NULL || s_number->s == NULL || s_number->len == 0) {
1583
+		LM_ERR("Invalid number string\n");
1584
+		return -1;
1585
+	}
1586
+
1587
+	double number;
1588
+	if (double_parse_str(s_number, &number)) {
1589
+		LM_ERR("Cannot parse double\n");
1590
+		return -1;
1591
+	}
1592
+
1593
+	if (l1 == NULL || l1->s == NULL || l1->len == 0) {
1594
+		LM_ERR("Invalid l1 string\n");
1595
+		return -1;
1596
+	}
1597
+
1598
+	if (prom_histogram_observe(s_name, number, l1, NULL, NULL)) {
1599
+		LM_ERR("Cannot observe number: %f in histogram: %.*s (%.*s)\n",
1600
+			   number, s_name->len, s_name->s,
1601
+			   l1->len, l1->s
1602
+			);
1603
+		return -1;
1604
+	}
1605
+
1606
+	LM_DBG("Observed %f in histogram %.*s (%.*s)\n", number,
1607
+		   s_name->len, s_name->s,
1608
+		   l1->len, l1->s
1609
+		);
1610
+	return 1;
1611
+}
1612
+
1613
+/**
1614
+ * @brief Observe a number in a histogram (2 labels).
1615
+ */
1616
+static int ki_xhttp_prom_histogram_observe_l2(struct sip_msg* msg, str *s_name, str *s_number,
1617
+									  str *l1, str *l2)
1618
+{
1619
+	if (s_name == NULL || s_name->s == NULL || s_name->len == 0) {
1620
+		LM_ERR("Invalid name string\n");
1621
+		return -1;
1622
+	}
1623
+
1624
+	if (s_number == NULL || s_number->s == NULL || s_number->len == 0) {
1625
+		LM_ERR("Invalid number string\n");
1626
+		return -1;
1627
+	}
1628
+
1629
+	double number;
1630
+	if (double_parse_str(s_number, &number)) {
1631
+		LM_ERR("Cannot parse double\n");
1632
+		return -1;
1633
+	}
1634
+
1635
+	if (l1 == NULL || l1->s == NULL || l1->len == 0) {
1636
+		LM_ERR("Invalid l1 string\n");
1637
+		return -1;
1638
+	}
1639
+
1640
+	if (l2 == NULL || l2->s == NULL || l2->len == 0) {
1641
+		LM_ERR("Invalid l2 string\n");
1642
+		return -1;
1643
+	}
1644
+
1645
+	if (prom_histogram_observe(s_name, number, l1, l2, NULL)) {
1646
+		LM_ERR("Cannot observe number: %f in histogram: %.*s (%.*s, %.*s)\n",
1647
+			   number, s_name->len, s_name->s,
1648
+			   l1->len, l1->s,
1649
+			   l2->len, l2->s
1650
+			);
1651
+		return -1;
1652
+	}
1653
+
1654
+	LM_DBG("Observed %f in histogram %.*s (%.*s, %.*s)\n", number,
1655
+		   s_name->len, s_name->s,
1656
+		   l1->len, l1->s,
1657
+		   l2->len, l2->s
1658
+		);
1659
+
1660
+	return 1;
1661
+}
1662
+
1663
+/**
1664
+ * @brief Observe a number in a histogram (3 labels).
1665
+ */
1666
+static int ki_xhttp_prom_histogram_observe_l3(struct sip_msg* msg, str *s_name, str *s_number,
1667
+									  str *l1, str *l2, str *l3)
1668
+{
1669
+	if (s_name == NULL || s_name->s == NULL || s_name->len == 0) {
1670
+		LM_ERR("Invalid name string\n");
1671
+		return -1;
1672
+	}
1673
+
1674
+	if (s_number == NULL || s_number->s == NULL || s_number->len == 0) {
1675
+		LM_ERR("Invalid number string\n");
1676
+		return -1;
1677
+	}
1678
+
1679
+	double number;
1680
+	if (double_parse_str(s_number, &number)) {
1681
+		LM_ERR("Cannot parse double\n");
1682
+		return -1;
1683
+	}
1684
+
1685
+	if (l1 == NULL || l1->s == NULL || l1->len == 0) {
1686
+		LM_ERR("Invalid l1 string\n");
1687
+		return -1;
1688
+	}
1689
+
1690
+	if (l2 == NULL || l2->s == NULL || l2->len == 0) {
1691
+		LM_ERR("Invalid l2 string\n");
1692
+		return -1;
1693
+	}
1694
+
1695
+	if (l3 == NULL || l3->s == NULL || l3->len == 0) {
1696
+		LM_ERR("Invalid l3 string\n");
1697
+		return -1;
1698
+	}
1699
+
1700
+	if (prom_histogram_observe(s_name, number, l1, l2, l3)) {
1701
+		LM_ERR("Cannot observe number: %f in histogram: %.*s (%.*s, %.*s, %.*s)\n",
1702
+			   number, s_name->len, s_name->s,
1703
+			   l1->len, l1->s,
1704
+			   l2->len, l2->s,
1705
+			   l3->len, l3->s
1706
+			);
1707
+		return -1;
1708
+	}
1709
+
1710
+	LM_DBG("Observed %f in histogram %.*s (%.*s, %.*s, %.*s)\n", number,
1711
+		   s_name->len, s_name->s,
1712
+		   l1->len, l1->s,
1713
+		   l2->len, l2->s,
1714
+		   l3->len, l3->s
1715
+		);
1716
+
1717
+	return 1;
1718
+}
1719
+
1720
+/**
1721
+ * @brief Observe function for a histogram.
1722
+ */
1723
+static int w_prom_histogram_observe(struct sip_msg* msg, char *pname, char* pnumber,
1724
+									char *l1, char *l2, char *l3)
1725
+{
1726
+	str s_number;
1727
+	str s_name;
1728
+
1729
+	if (pname == NULL || pnumber == 0) {
1730
+		LM_ERR("Invalid parameters\n");
1731
+		return -1;
1732
+	}
1733
+
1734
+	if (get_str_fparam(&s_name, msg, (gparam_t*)pname)!=0) {
1735
+		LM_ERR("No histogram name\n");
1736
+		return -1;
1737
+	}
1738
+	if (s_name.s == NULL || s_name.len == 0) {
1739
+		LM_ERR("Invalid name string\n");
1740
+		return -1;
1741
+	}
1742
+
1743
+	if (get_str_fparam(&s_number, msg, (gparam_t*)pnumber)!=0) {
1744
+		LM_ERR("No histogram number to observe\n");
1745
+		return -1;
1746
+	}
1747
+	if (s_number.s == NULL || s_number.len == 0) {
1748
+		LM_ERR("Invalid number string\n");
1749
+		return -1;
1750
+	}
1751
+
1752
+	double number;
1753
+	if (double_parse_str(&s_number, &number)) {
1754
+		LM_ERR("Cannot parse double\n");
1755
+		return -1;
1756
+	}
1757
+
1758
+	str l1_str, l2_str, l3_str;
1759
+	if (l1 != NULL) {
1760
+		if (get_str_fparam(&l1_str, msg, (gparam_t*)l1)!=0) {
1761
+			LM_ERR("No label l1 in counter\n");
1762
+			return -1;
1763
+		}
1764
+		if (l1_str.s == NULL || l1_str.len == 0) {
1765
+			LM_ERR("Invalid l1 string\n");
1766
+			return -1;
1767
+		}
1768
+
1769
+		if (l2 != NULL) {
1770
+			if (get_str_fparam(&l2_str, msg, (gparam_t*)l2)!=0) {
1771
+				LM_ERR("No label l2 in counter\n");
1772
+				return -1;
1773
+			}
1774
+			if (l2_str.s == NULL || l2_str.len == 0) {
1775
+				LM_ERR("Invalid l2 string\n");
1776
+				return -1;
1777
+			}
1778
+
1779
+			if (l3 != NULL) {
1780
+				if (get_str_fparam(&l3_str, msg, (gparam_t*)l3)!=0) {
1781
+					LM_ERR("No label l3 in counter\n");
1782
+					return -1;
1783
+				}
1784
+				if (l3_str.s == NULL || l3_str.len == 0) {
1785
+					LM_ERR("Invalid l3 string\n");
1786
+					return -1;
1787
+				}
1788
+			} /* if l3 != NULL */
1789
+			
1790
+		} else {
1791
+			l3 = NULL;
1792
+		} /* if l2 != NULL */
1793
+		
1794
+	} else {
1795
+		l2 = NULL;
1796
+		l3 = NULL;
1797
+	} /* if l1 != NULL */
1798
+
1799
+	if (prom_histogram_observe(&s_name, number,
1800
+							   (l1!=NULL)?&l1_str:NULL,
1801
+							   (l2!=NULL)?&l2_str:NULL,
1802
+							   (l3!=NULL)?&l3_str:NULL
1803
+			)) {
1804
+		LM_ERR("Cannot observe number: %f in histogram : %.*s\n",
1805
+			   number, s_name.len, s_name.s);
1806
+		return -1;
1807
+	}
1808
+
1809
+	LM_DBG("Observed %f in histogram %.*s\n", number, s_name.len, s_name.s);
1810
+	return 1;
1811
+}
1812
+
1813
+/**
1814
+ * @brief Observe a number in a histogram (no labels)
1815
+ */
1816
+static int w_prom_histogram_observe_l0(struct sip_msg* msg, char *pname, char* pnumber)
1817
+{
1818
+	return w_prom_histogram_observe(msg, pname, pnumber, NULL, NULL, NULL);
1819
+}
1820
+
1821
+/**
1822
+ * @brief Observe a number in a histogram (1 labels)
1823
+ */
1824
+static int w_prom_histogram_observe_l1(struct sip_msg* msg, char *pname, char* pnumber,
1825
+									   char *l1)
1826
+{
1827
+	return w_prom_histogram_observe(msg, pname, pnumber, l1, NULL, NULL);
1828
+}
1829
+
1830
+/**
1831
+ * @brief Observe a number in a histogram (2 labels)
1832
+ */
1833
+static int w_prom_histogram_observe_l2(struct sip_msg* msg, char *pname, char* pnumber,
1834
+									   char *l1, char *l2)
1835
+{
1836
+	return w_prom_histogram_observe(msg, pname, pnumber, l1, l2, NULL);
1837
+}
1838
+
1839
+/**
1840
+ * @brief Observe a number in a histogram (3 labels)
1841
+ */
1842
+static int w_prom_histogram_observe_l3(struct sip_msg* msg, char *pname, char* pnumber,
1843
+									   char *l1, char *l2, char *l3)
1844
+{
1845
+	return w_prom_histogram_observe(msg, pname, pnumber, l1, l2, l3);
1846
+}
1847
+
1560 1848
 /**
1561 1849
  *
1562 1850
  */
... ...
@@ -1652,6 +1940,26 @@ static sr_kemi_t sr_kemi_xhttp_prom_exports[] = {
1652 1940
 		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_STR,
1653 1941
 			SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE }
1654 1942
 	},
1943
+	{ str_init("xhttp_prom"), str_init("histogram_observe_l0"),
1944
+	    SR_KEMIP_INT, ki_xhttp_prom_histogram_observe_l0,
1945
+		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
1946
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1947
+	},
1948
+	{ str_init("xhttp_prom"), str_init("histogram_observe_l1"),
1949
+	    SR_KEMIP_INT, ki_xhttp_prom_histogram_observe_l1,
1950
+		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_STR,
1951
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1952
+	},
1953
+	{ str_init("xhttp_prom"), str_init("histogram_observe_l2"),
1954
+	    SR_KEMIP_INT, ki_xhttp_prom_histogram_observe_l2,
1955
+		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_STR,
1956
+			SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE }
1957
+	},
1958
+	{ str_init("xhttp_prom"), str_init("histogram_observe_l3"),
1959
+	    SR_KEMIP_INT, ki_xhttp_prom_histogram_observe_l3,
1960
+		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_STR,
1961
+			SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE }
1962
+	},
1655 1963
 
1656 1964
 	{ {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
1657 1965
 };
... ...
@@ -2027,6 +2335,104 @@ static void rpc_prom_gauge_set(rpc_t *rpc, void *ct)
2027 2335
 	return;
2028 2336
 }
2029 2337
 
2338
+/**
2339
+ * @brief Observe a number in a histogram via RPC.
2340
+ */
2341
+static void rpc_prom_histogram_observe(rpc_t *rpc, void *ct)
2342
+{
2343
+	str s_name;
2344
+
2345
+	if (rpc->scan(ct, "S", &s_name) < 1) {
2346
+		rpc->fault(ct, 400, "required histogram identifier");
2347
+		return;
2348
+	}
2349
+
2350
+	if (s_name.len == 0 || s_name.s == NULL) {
2351
+		rpc->fault(ct, 400, "invalid histogram identifier");
2352
+		return;
2353
+	}
2354
+
2355
+	double number;
2356
+	if (rpc->scan(ct, "f", &number) < 1) {
2357