core_stats.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006 Voice Sistem SRL
00003  *
00004  * This file is part of Kamailio, a free SIP server.
00005  *
00006  * Kamailio is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * Kamailio is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00019  *
00020  * History:
00021  * ---------
00022  *  2006-01-23  first version (bogdan)
00023  *  2006-11-28  Added statistics for the number of bad URI's, methods, and 
00024  *              proxy requests (Jeffrey Magder - SOMA Networks)
00025  */
00026 
00034 #include <string.h>
00035 
00036 #include "../../lib/kcore/statistics.h"
00037 #include "../../lib/kmi/mi.h"
00038 #include "../../events.h"
00039 #include "../../dprint.h"
00040 #include "../../timer.h"
00041 #include "../../parser/msg_parser.h"
00042 #include "../../script_cb.h"
00043 #include "../../mem/meminfo.h"
00044 #include "../../mem/shm_mem.h"
00045 
00046 
00047 #ifdef STATISTICS
00048 
00049 stat_var* rcv_reqs;                             
00050 stat_var* rcv_rpls;                             
00051 stat_var* fwd_reqs;                             
00052 stat_var* fwd_rpls;                             
00053 stat_var* drp_reqs;                             
00054 stat_var* drp_rpls;                             
00055 stat_var* err_reqs;                             
00056 stat_var* err_rpls;                             
00057 stat_var* bad_URIs;                             
00058 stat_var* unsupported_methods;                  
00059 stat_var* bad_msg_hdr;                          
00063 stat_export_t core_stats[] = {
00064         {"rcv_requests" ,         0,  &rcv_reqs              },
00065         {"rcv_replies" ,          0,  &rcv_rpls              },
00066         {"fwd_requests" ,         0,  &fwd_reqs              },
00067         {"fwd_replies" ,          0,  &fwd_rpls              },
00068         {"drop_requests" ,        0,  &drp_reqs              },
00069         {"drop_replies" ,         0,  &drp_rpls              },
00070         {"err_requests" ,         0,  &err_reqs              },
00071         {"err_replies" ,          0,  &err_rpls              },
00072         {"bad_URIs_rcvd",         0,  &bad_URIs              },
00073         {"unsupported_methods",   0,  &unsupported_methods   },
00074         {"bad_msg_hdr",           0,  &bad_msg_hdr           },
00075         {0,0,0}
00076 };
00077 
00078 unsigned long shm_stats_get_size(void);
00079 unsigned long shm_stats_get_used(void);
00080 unsigned long shm_stats_get_rused(void);
00081 unsigned long shm_stats_get_mused(void);
00082 unsigned long shm_stats_get_free(void);
00083 unsigned long shm_stats_get_frags(void);
00084 
00085 stat_export_t shm_stats[] = {
00086         {"total_size" ,     STAT_IS_FUNC,    (stat_var**)shm_stats_get_size     },
00087         {"used_size" ,      STAT_IS_FUNC,    (stat_var**)shm_stats_get_used     },
00088         {"real_used_size" , STAT_IS_FUNC,    (stat_var**)shm_stats_get_rused    },
00089         {"max_used_size" ,  STAT_IS_FUNC,    (stat_var**)shm_stats_get_mused    },
00090         {"free_size" ,      STAT_IS_FUNC,    (stat_var**)shm_stats_get_free     },
00091         {"fragments" ,      STAT_IS_FUNC,    (stat_var**)shm_stats_get_frags    },
00092         {0,0,0}
00093 };
00094 
00095 static struct mi_root *mi_get_stats(struct mi_root *cmd, void *param);
00096 static struct mi_root *mi_reset_stats(struct mi_root *cmd, void *param);
00097 static struct mi_root *mi_clear_stats(struct mi_root *cmd, void *param);
00098 
00099 static mi_export_t mi_stat_cmds[] = {
00100         { "get_statistics",    mi_get_stats,    0  ,  0,  0 },
00101         { "reset_statistics",  mi_reset_stats,  0  ,  0,  0 },
00102         { "clear_statistics",  mi_clear_stats,  0  ,  0,  0 },
00103         { 0, 0, 0, 0, 0}
00104 };
00105 
00106 int register_mi_stats(void)
00107 {
00108         /* register MI commands */
00109         if (register_mi_mod("core", mi_stat_cmds)<0) {
00110                 LM_ERR("unable to register MI cmds\n");
00111                 return -1;
00112         }
00113         return 0;
00114 }
00115 
00116 static int km_cb_req_stats(struct sip_msg *msg,
00117                 unsigned int flags, void *param)
00118 {
00119         update_stat(rcv_reqs, 1);
00120         if(msg->first_line.u.request.method_value==METHOD_OTHER)
00121                 update_stat(unsupported_methods, 1);
00122         return 1;
00123 }
00124 
00125 static int km_cb_rpl_stats(struct sip_msg *msg,
00126                 unsigned int flags, void *param)
00127 {
00128         update_stat(rcv_rpls, 1);
00129         return 1;
00130 }
00131 
00132 
00133 static int sts_update_core_stats(void *data)
00134 {
00135         int type;
00136 
00137         type = (int)(long)data;
00138         switch(type) {
00139                 case 1:
00140                         /* fwd_requests */
00141                         update_stat(fwd_reqs, 1);
00142                 break;
00143                 case 2:
00144                         /* fwd_replies */
00145                         update_stat(fwd_rpls, 1);
00146                 break;
00147                 case 3:
00148                         /* drop_requests */
00149                         update_stat(drp_reqs, 1);
00150                 break;
00151                 case 4:
00152                         /* drop_replies */
00153                         update_stat(drp_rpls, 1);
00154                 break;
00155                 case 5:
00156                         /* err_requests */
00157                         update_stat(err_reqs, 1);
00158                 break;
00159                 case 6:
00160                         /* err_replies */
00161                         update_stat(err_rpls, 1);
00162                 break;
00163                 case 7:
00164                         /* bad_URIs_rcvd */
00165                         update_stat(bad_URIs, 1);
00166                 break;
00167                 case 8:
00168                         /* bad_msg_hdr */
00169                         update_stat(bad_msg_hdr, 1);
00170                 break;
00171         }
00172         return 0;
00173 }
00174 
00175 int register_core_stats(void)
00176 {
00177         /* register core statistics */
00178         if (register_module_stats( "core", core_stats)!=0 ) {
00179                 LM_ERR("failed to register core statistics\n");
00180                 return -1;
00181         }
00182         /* register sh_mem statistics */
00183         if (register_module_stats( "shmem", shm_stats)!=0 ) {
00184                 LM_ERR("failed to register sh_mem statistics\n");
00185                 return -1;
00186         }
00187         if (register_script_cb(km_cb_req_stats, PRE_SCRIPT_CB|REQUEST_CB, 0)<0 ) {
00188                 LM_ERR("failed to register PRE request callback\n");
00189                 return -1;
00190         }
00191         if (register_script_cb(km_cb_rpl_stats, PRE_SCRIPT_CB|ONREPLY_CB, 0)<0 ) {
00192                 LM_ERR("failed to register PRE request callback\n");
00193                 return -1;
00194         }
00195         sr_event_register_cb(SREV_CORE_STATS, sts_update_core_stats);
00196 
00197         return 0;
00198 }
00199 
00200 /***************************** MI STUFF ********************************/
00201 
00202 inline static int mi_add_stat(struct mi_node *rpl, stat_var *stat)
00203 {
00204         struct mi_node *node;
00205 
00206         if (stats_support()==0) return -1;
00207 
00208         node = addf_mi_node_child(rpl, 0, 0, 0, "%s:%s = %lu",
00209                 ZSW(get_stat_module(stat)),
00210                 ZSW(get_stat_name(stat)),
00211                 get_stat_val(stat) );
00212 
00213         if (node==0)
00214                 return -1;
00215         return 0;
00216 }
00217 
00218 
00219 
00220 /* callback for counter_iterate_grp_vars. */
00221 static void mi_add_grp_vars_cbk(void* r, str* g, str* n, counter_handle_t h)
00222 {
00223         struct mi_node *rpl;
00224         
00225         rpl = r;
00226         addf_mi_node_child(rpl, 0, 0, 0, "%.*s:%.*s = %lu",
00227                                                         g->len, g->s, n->len, n->s, counter_get_val(h));
00228 }
00229 
00230 
00231 /* callback for counter_iterate_grp_names */
00232 static void mi_add_all_grps_cbk(void* p, str* g)
00233 {
00234         counter_iterate_grp_vars(g->s, mi_add_grp_vars_cbk, p);
00235 }
00236 
00237 static struct mi_root *mi_get_stats(struct mi_root *cmd, void *param)
00238 {
00239         struct mi_root *rpl_tree;
00240         struct mi_node *rpl;
00241         struct mi_node *arg;
00242         stat_var       *stat;
00243         str val;
00244 
00245 
00246         if(stats_support()==0)
00247                 return init_mi_tree( 404, "Statistics Not Found", 20);
00248 
00249         if (cmd->node.kids==NULL)
00250                 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00251 
00252         rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00253         if (rpl_tree==0)
00254                 return 0;
00255         rpl = &rpl_tree->node;
00256 
00257         for( arg=cmd->node.kids ; arg ; arg=arg->next) {
00258                 if (arg->value.len==0)
00259                         continue;
00260 
00261                 val = arg->value;
00262 
00263                 if ( val.len==3 && memcmp(val.s,"all",3)==0) {
00264                         /* add all statistic variables */
00265                         /* use direct counters access for that */
00266                         counter_iterate_grp_names(mi_add_all_grps_cbk, rpl);
00267                 } else if ( val.len>1 && val.s[val.len-1]==':') {
00268                         /* add module statistics */
00269                         val.len--;
00270                         val.s[val.len]=0; /* zero term. */
00271                         /* use direct counters access for that */
00272                         counter_iterate_grp_vars(val.s, mi_add_grp_vars_cbk, rpl);
00273                         val.s[val.len]=':' /* restore */;
00274                 } else {
00275                         /* add only one statistic */
00276                         stat = get_stat( &val );
00277                         if (stat==0)
00278                                 continue;
00279                         if (mi_add_stat(rpl,stat)!=0)
00280                                 goto error;
00281                 }
00282         }
00283 
00284         if (rpl->kids==0) {
00285                 free_mi_tree(rpl_tree);
00286                 return init_mi_tree( 404, "Statistics Not Found", 20);
00287         }
00288 
00289         return rpl_tree;
00290 error:
00291         free_mi_tree(rpl_tree);
00292         return 0;
00293 }
00294 
00295 
00296 
00297 static struct mi_root *mi_reset_stats(struct mi_root *cmd, void *param)
00298 {
00299         struct mi_root *rpl_tree;
00300         struct mi_node *arg;
00301         stat_var       *stat;
00302         int found;
00303 
00304         if (cmd->node.kids==NULL)
00305                 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00306 
00307         rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00308         if (rpl_tree==0)
00309                 return 0;
00310         found = 0;
00311 
00312         for( arg=cmd->node.kids ; arg ; arg=arg->next) {
00313                 if (arg->value.len==0)
00314                         continue;
00315 
00316                 stat = get_stat( &arg->value );
00317                 if (stat==0)
00318                         continue;
00319 
00320                 reset_stat( stat );
00321                 found = 1;
00322         }
00323 
00324         if (!found) {
00325                 free_mi_tree(rpl_tree);
00326                 return init_mi_tree( 404, "Statistics Not Found", 20);
00327         }
00328 
00329         return rpl_tree;
00330 }
00331 
00332 
00333 inline static int mi_reset_and_add_stat(struct mi_node *rpl, stat_var *stat)
00334 {
00335         struct mi_node *node;
00336         long old_val, new_val;
00337 
00338         if (stats_support()==0) return -1;
00339 
00340         old_val=get_stat_val(stat);
00341         reset_stat(stat);
00342         new_val=get_stat_val(stat);
00343 
00344         if (old_val==new_val)
00345         {
00346                 node = addf_mi_node_child(rpl, 0, 0, 0, "%s:%s = %lu",
00347                                 ZSW(get_stat_module(stat)),
00348                                 ZSW(get_stat_name(stat)),
00349                                 new_val);
00350         } else {
00351                 node = addf_mi_node_child(rpl, 0, 0, 0, "%s:%s = %lu (%lu)",
00352                                 ZSW(get_stat_module(stat)),
00353                                 ZSW(get_stat_name(stat)),
00354                                 new_val, old_val );
00355         }
00356 
00357         if (node==0)
00358                 return -1;
00359         return 0;
00360 }
00361 
00362 
00363 /* callback for counter_iterate_grp_vars to reset counters */
00364 static void mi_add_grp_vars_cbk2(void* r, str* g, str* n, counter_handle_t h)
00365 {
00366         struct mi_node *rpl;
00367         counter_val_t old_val, new_val;
00368 
00369         rpl = r;
00370         old_val = counter_get_val(h);
00371         counter_reset(h);
00372         new_val = counter_get_val(h);
00373 
00374         if (old_val==new_val)
00375         {
00376                 addf_mi_node_child(rpl, 0, 0, 0, "%.*s:%.*s = %lu",
00377                                         g->len, g->s, n->len, n->s, new_val);
00378         } else {
00379                 addf_mi_node_child(rpl, 0, 0, 0, "%.*s:%.*s = %lu (%lu)",
00380                                         g->len, g->s, n->len, n->s, new_val, old_val);
00381         }
00382 }
00383 
00384 
00385 /* callback for counter_iterate_grp_names to reset counters */
00386 static void mi_add_all_grps_cbk2(void* p, str* g)
00387 {
00388         counter_iterate_grp_vars(g->s, mi_add_grp_vars_cbk2, p);
00389 }
00390 
00391 
00392 static struct mi_root *mi_clear_stats(struct mi_root *cmd, void *param)
00393 {
00394         struct mi_root *rpl_tree;
00395         struct mi_node *rpl;
00396         struct mi_node *arg;
00397         stat_var       *stat;
00398         str val;
00399 
00400         if(stats_support()==0)
00401                 return init_mi_tree( 404, "Statistics Not Found", 20);
00402 
00403         if (cmd->node.kids==NULL)
00404         return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00405 
00406         rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00407         if (rpl_tree==0)
00408                 return 0;
00409         rpl = &rpl_tree->node;
00410 
00411         for( arg=cmd->node.kids ; arg ; arg=arg->next)
00412         {
00413                 if (arg->value.len==0)
00414                         continue;
00415 
00416                 val = arg->value;
00417 
00418                 if ( val.len==3 && memcmp(val.s,"all",3)==0) {
00419                         /* add all statistic variables */
00420                         /* use direct counters access for that */
00421                         counter_iterate_grp_names(mi_add_all_grps_cbk2, rpl);
00422                 } else if ( val.len>1 && val.s[val.len-1]==':') {
00423                         /* add module statistics */
00424                         val.len--;
00425                         val.s[val.len]=0; /* zero term. */
00426                         /* use direct counters access for that */
00427                         counter_iterate_grp_vars(val.s, mi_add_grp_vars_cbk2, rpl);
00428                         val.s[val.len]=':' /* restore */;
00429                 } else {
00430                         /* reset & return only one statistic */
00431                         stat = get_stat( &val );
00432 
00433                         if (stat==0)
00434                                 continue;
00435                         if (mi_reset_and_add_stat(rpl,stat)!=0)
00436                                 goto error;
00437                 }
00438         }
00439 
00440         if (rpl->kids==0) {
00441                 free_mi_tree(rpl_tree);
00442                 return init_mi_tree( 404, "Statistics Not Found", 20);
00443         }
00444 
00445         return rpl_tree;
00446 error:
00447         free_mi_tree(rpl_tree);
00448         return 0;
00449 }
00450 
00451 /*** shm stats ***/
00452 
00453 static struct mem_info _stats_shm_mi;
00454 static ticks_t _stats_shm_tm = 0;
00455 void stats_shm_update(void)
00456 {
00457         ticks_t t;
00458         t = get_ticks();
00459         if(t!=_stats_shm_tm) {
00460                 shm_info(&_stats_shm_mi);
00461                 _stats_shm_tm = t;
00462         }
00463 }
00464 unsigned long shm_stats_get_size(void)
00465 {
00466         stats_shm_update();
00467         return _stats_shm_mi.total_size;
00468 }
00469 
00470 unsigned long shm_stats_get_used(void)
00471 {
00472         stats_shm_update();
00473         return _stats_shm_mi.used;
00474 }
00475 
00476 unsigned long shm_stats_get_rused(void)
00477 {
00478         stats_shm_update();
00479         return _stats_shm_mi.real_used;
00480 }
00481 
00482 unsigned long shm_stats_get_mused(void)
00483 {
00484         stats_shm_update();
00485         return _stats_shm_mi.max_used;
00486 }
00487 
00488 unsigned long shm_stats_get_free(void)
00489 {
00490         stats_shm_update();
00491         return _stats_shm_mi.free;
00492 }
00493 
00494 unsigned long shm_stats_get_frags(void)
00495 {
00496         stats_shm_update();
00497         return _stats_shm_mi.total_frags;
00498 }
00499 
00500 #endif