@@ -57,9 +57,14 @@ str prom_grp_label = str_init("group");
57
57
httpd_api_t prom_httpd_api ;
58
58
str prometheus_script_route = {NULL , 0 };
59
59
struct script_route_ref * prometheus_route_ref = NULL ;
60
+ static str * prometheus_route_page = NULL ;
61
+ static str prometheus_route_page_stat = {0 , 0 };
62
+ static int prometheus_route_page_max = 0 ;
60
63
61
64
static int prom_stats_param ( modparam_t type , void * val );
62
65
static int prom_labels_param ( modparam_t type , void * val );
66
+ static int w_prom_declare_stat (struct sip_msg * msg , str * name , str * type , str * help );
67
+ static int w_prom_push_stat (struct sip_msg * msg , int * label , str * labeln , str * labelv );
63
68
64
69
/* module parameters */
65
70
static const param_export_t mi_params [] = {
@@ -85,6 +90,22 @@ static const dep_export_t deps = {
85
90
},
86
91
};
87
92
93
+ static const cmd_export_t cmds []= {
94
+ {"prometheus_declare_stat" , (cmd_function )w_prom_declare_stat , {
95
+ {CMD_PARAM_STR , 0 , 0 },
96
+ {CMD_PARAM_STR |CMD_PARAM_OPT , 0 , 0 },
97
+ {CMD_PARAM_STR |CMD_PARAM_OPT , 0 , 0 },
98
+ {0 ,0 ,0 }},
99
+ REQUEST_ROUTE },
100
+ {"prometheus_push_stat" , (cmd_function )w_prom_push_stat , {
101
+ {CMD_PARAM_INT , 0 , 0 },
102
+ {CMD_PARAM_STR |CMD_PARAM_OPT , 0 , 0 },
103
+ {CMD_PARAM_STR |CMD_PARAM_OPT , 0 , 0 },
104
+ {0 ,0 ,0 }},
105
+ REQUEST_ROUTE },
106
+ {0 ,0 ,{{0 ,0 ,0 }},0 }
107
+ };
108
+
88
109
/* module exports */
89
110
struct module_exports exports = {
90
111
"prometheus" , /* module name */
@@ -93,7 +114,7 @@ struct module_exports exports = {
93
114
DEFAULT_DLFLAGS , /* dlopen flags */
94
115
0 , /* load function */
95
116
& deps , /* OpenSIPS module dependencies */
96
- NULL , /* exported functions */
117
+ cmds , /* exported functions */
97
118
NULL , /* exported async functions */
98
119
mi_params , /* exported parameters */
99
120
NULL , /* exported statistics */
@@ -850,9 +871,17 @@ int prom_answer_to_connection (void *cls, void *connection,
850
871
/* set request route type */
851
872
set_route_type ( REQUEST_ROUTE );
852
873
874
+ prometheus_route_page = page ;
875
+ prometheus_route_page_max = buffer -> len ;
876
+ prometheus_route_page_stat .s = NULL ;
877
+
853
878
/* run given hep route */
854
879
run_top_route ( sroutes -> request [prometheus_route_ref -> idx ], route_msg );
855
880
881
+ prometheus_route_page = NULL ;
882
+ prometheus_route_page_max = 0 ;
883
+ prometheus_route_page_stat .s = NULL ;
884
+
856
885
memset (& val , 0 , sizeof (int_str ));
857
886
if ((script_return_get (& val , 0 ) >= 1 ) && (val .flags & PV_VAL_STR )) {
858
887
if (process_extra_prometheus (val .rs .s ,val .rs .len ,page ,buffer -> len ) < 0 )
@@ -976,3 +1005,105 @@ static int prom_labels_param(modparam_t type, void* val)
976
1005
977
1006
return 0 ;
978
1007
}
1008
+
1009
+ static int w_prom_declare_stat (struct sip_msg * msg , str * name , str * type , str * help )
1010
+ {
1011
+ int len = 0 ;
1012
+ str _type = str_init ("gauge" );
1013
+
1014
+ if (!prometheus_route_ref || !prometheus_route_page ) {
1015
+ LM_ERR ("this function should only be called inside '%s' route\n" ,
1016
+ (!prometheus_route_ref ?"script_route" :prometheus_script_route .s ));
1017
+ return -2 ;
1018
+ }
1019
+ if (!type )
1020
+ type = & _type ;
1021
+ if (help && help -> len )
1022
+ len = 7 /* '# HELP ' */ + name -> len + 1 /* ' ' */ + help -> len + 1 /* '\n' */ ;
1023
+ len += 7 /* '# TYPE ' */ + name -> len + 1 /* ' ' */ + type -> len + 1 /* '\n' */ ;
1024
+ if (prometheus_route_page -> len + len >= prometheus_route_page_max ) {
1025
+ LM_ERR ("declaring statistic overflows\n" );
1026
+ return -1 ;
1027
+ }
1028
+ if (help && help -> len ) {
1029
+ memcpy (prometheus_route_page -> s + prometheus_route_page -> len , "# HELP " , 7 );
1030
+ prometheus_route_page -> len += 7 ;
1031
+ memcpy (prometheus_route_page -> s + prometheus_route_page -> len , name -> s , name -> len );
1032
+ prometheus_route_page -> len += name -> len ;
1033
+ prometheus_route_page -> s [prometheus_route_page -> len ++ ] = ' ' ;
1034
+ memcpy (prometheus_route_page -> s + prometheus_route_page -> len , help -> s , help -> len );
1035
+ prometheus_route_page -> len += help -> len ;
1036
+ prometheus_route_page -> s [prometheus_route_page -> len ++ ] = '\n' ;
1037
+ }
1038
+ memcpy (prometheus_route_page -> s + prometheus_route_page -> len , "# TYPE " , 7 );
1039
+ prometheus_route_page -> len += 7 ;
1040
+ memcpy (prometheus_route_page -> s + prometheus_route_page -> len , name -> s , name -> len );
1041
+ prometheus_route_page_stat .s = prometheus_route_page -> s + prometheus_route_page -> len ;
1042
+ prometheus_route_page_stat .len = name -> len ;
1043
+ prometheus_route_page -> len += name -> len ;
1044
+ prometheus_route_page -> s [prometheus_route_page -> len ++ ] = ' ' ;
1045
+ memcpy (prometheus_route_page -> s + prometheus_route_page -> len , type -> s , type -> len );
1046
+ prometheus_route_page -> len += type -> len ;
1047
+ prometheus_route_page -> s [prometheus_route_page -> len ++ ] = '\n' ;
1048
+ return 1 ;
1049
+ }
1050
+
1051
+ static int w_prom_push_stat (struct sip_msg * msg , int * value , str * labeln , str * labelv )
1052
+ {
1053
+ int len , ret = -1 ;
1054
+ str labels = str_init ("" );
1055
+ str val ;
1056
+
1057
+ if (!prometheus_route_page_stat .s ) {
1058
+ LM_ERR ("can not push stat if not previously declared! "
1059
+ "use prometheus_declare_stat() first\n" );
1060
+ return -2 ;
1061
+ }
1062
+ if (labeln ) {
1063
+ if (labelv ) {
1064
+ /* we have both labels and value - build the string */
1065
+ labels .s = pkg_malloc (5 /* '{="}' */ + labeln -> len + labelv -> len );
1066
+ if (!labels .s ) {
1067
+ LM_ERR ("oom for building labels\n" );
1068
+ return -1 ;
1069
+ }
1070
+ labels .s [0 ] = '{' ;
1071
+ labels .len = 1 ;
1072
+ memcpy (labels .s + labels .len , labeln -> s , labeln -> len );
1073
+ labels .len += labeln -> len ;
1074
+ labels .s [labels .len ++ ] = '=' ;
1075
+ labels .s [labels .len ++ ] = '"' ;
1076
+ memcpy (labels .s + labels .len , labelv -> s , labelv -> len );
1077
+ labels .len += labelv -> len ;
1078
+ labels .s [labels .len ++ ] = '"' ;
1079
+ labels .s [labels .len ++ ] = '}' ;
1080
+ } else {
1081
+ labels = * labeln ;
1082
+ }
1083
+ }
1084
+ len = prometheus_route_page_stat .len + labels .len + 1 /* ' ' */ +
1085
+ INT2STR_MAX_LEN + 1 /* \n' */ ;
1086
+ if (prometheus_route_page -> len + len >= prometheus_route_page_max ) {
1087
+ LM_ERR ("pushing statistic overflows\n" );
1088
+ goto end ;
1089
+ }
1090
+
1091
+ memcpy (prometheus_route_page -> s + prometheus_route_page -> len ,
1092
+ prometheus_route_page_stat .s , prometheus_route_page_stat .len );
1093
+ prometheus_route_page -> len += prometheus_route_page_stat .len ;
1094
+ if (labels .len ) {
1095
+ memcpy (prometheus_route_page -> s + prometheus_route_page -> len ,
1096
+ labels .s , labels .len );
1097
+ prometheus_route_page -> len += labels .len ;
1098
+ }
1099
+ val .s = int2str (* value , & val .len );
1100
+ prometheus_route_page -> s [prometheus_route_page -> len ++ ] = ' ' ;
1101
+ memcpy (prometheus_route_page -> s + prometheus_route_page -> len , val .s , val .len );
1102
+ prometheus_route_page -> len += val .len ;
1103
+ prometheus_route_page -> s [prometheus_route_page -> len ++ ] = '\n' ;
1104
+ ret = 1 ;
1105
+ end :
1106
+ if (labeln && labelv )
1107
+ pkg_free (labels .s );
1108
+ return ret ;
1109
+ }
0 commit comments