原帖 http://gmd20.blog.163.com/blog/static/168439232014274246264/
/*********************************************************************************************************
* Software License Agreement (BSD License) *
* Author: Sebastien Decugis <sdecugis@freediameter.net> *
* *
* Copyright (c) 2013, WIDE Project and NICT *
* All rights reserved. *
* *
* Redistribution and use of this software in source and binary forms, with or without modification,
are *
* permitted provided that the following conditions are met: *
* *
* * Redistributions of source code must retain the above *
* copyright notice, this list of conditions and the *
* following disclaimer. *
* *
* * Redistributions in binary form must reproduce the above *
* copyright notice, this list of conditions and the *
* following disclaimer in the documentation and/or other *
* materials provided with the distribution. *
* *
* * Neither the name of the WIDE Project or NICT nor the *
* names of its contributors may be used to endorse or *
* promote products derived from this software without *
* specific prior written permission of WIDE Project and *
* NICT. *
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
*
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A *
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR *
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
*
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
*
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR *
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
IF *
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
*********************************************************************************************************/
/* Status Monitoring extension:
- periodically display queues and peers information
- recreate and write data into status_monitor.txt once the file was delete
*/
#include
<freeDiameter/extension.h>
#include
<sys/inotify.h>
#include
<unistd.h>
#include
<stdio.h>
#include
<stdlib.h>
#include
<limits.h>
const
char
*kStatusFilename
=
"status_monitor.txt";
static
int
monitor_main(char
*
conffile);
EXTENSION_ENTRY("status_monitor",
monitor_main);
/* Display information about a queue */
static
void
display_info(struct
FILE *
f,
const
char
*
queue_desc,
char
*
peer,
int
current_count,
int
limit_count,
int
highest_count,
long
long
total_count,
struct
timespec *
total,
struct
timespec *
blocking,
struct
timespec *
last)
{
long
long
us =
(total->tv_sec
*
1000000)
+
(total->tv_nsec
/
1000);
long
double
throughput =
(long
double)total_count
*
1000000;
throughput
/=
us;
if
(peer)
{
fprintf(f,
"'%s'@'%s': cur:%d/%d, h:%d, T:%lld in %ld.%06lds (%.2LFitems/s), blocked:%ld.%06lds, last
processing:%ld.%06lds\n",
queue_desc,
peer,
current_count,
limit_count,
highest_count,
total_count,
total->tv_sec,
total->tv_nsec/1000,
throughput,
blocking->tv_sec,
blocking->tv_nsec/1000,
last->tv_sec,
last->tv_nsec/1000);
}
else
{
fprintf(f,
"Global '%s': cur:%d/%d, h:%d, T:%lld in %ld.%06lds (%.2LFitems/s), blocked:%ld.%06lds, last
processing:%ld.%06lds\n",
queue_desc,
current_count,
limit_count,
highest_count,
total_count,
total->tv_sec,
total->tv_nsec/1000,
throughput,
blocking->tv_sec,
blocking->tv_nsec/1000,
last->tv_sec,
last->tv_nsec/1000);
}
}
/* Thread to display periodical debug information */
static
pthread_t
thr;
static
void
*
mn_thr(void
*
arg)
{
int
i =
0;
fd_log_threadname("Status
Monitor thread");
char
*
buf =
NULL;
size_t
len;
int
fd =
-1;
int
wd =
-1;
int
inotify_len =
0;
const
int
kBufferLenOfOneEvent =
sizeof(struct
inotify_event)
+
NAME_MAX +
1;
struct
inotify_event*
event;
event
=
(struct
inotify_event*)
malloc(kBufferLenOfOneEvent);
if
(event
==
NULL)
{
TRACE_DEBUG(INFO,
"Allocate inotify_event failed!");
return
NULL;
}
fd
=
inotify_init();
if
(fd
==
-1)
{
TRACE_DEBUG(INFO,
"inotify_init failed!");
return
NULL;
}
wd
=
inotify_add_watch(fd,
"./",
IN_DELETE);
if
(wd
==
-1)
{
TRACE_DEBUG(INFO,
"inotify_add_watch failed!");
goto
inotify_add_watch_error;
}
/*
Loop */
while
(1)
{
int
current_count,
limit_count,
highest_count;
long
long
total_count;
struct
timespec total,
blocking,
last;
struct
fd_list *
li;
struct
FILE *
f =
NULL;
f
=
fopen(kStatusFilename,
"w");
if
(f
==
NULL)
{
TRACE_DEBUG(INFO,
"Failed to open status monitor file!");
goto
open_file_error;
}
fprintf(f,
"[status_monitor] Dumping queues statistics\n");
CHECK_FCT_DO(
fd_stat_getstats(STAT_G_LOCAL,
NULL,
¤t_count,
&limit_count,
&highest_count,
&total_count,
&total,
&blocking,
&last),
);
display_info(f,
"Local delivery",
NULL,
current_count,
limit_count,
highest_count,
total_count,
&total,
&blocking,
&last);
CHECK_FCT_DO(
fd_stat_getstats(STAT_G_INCOMING,
NULL,
¤t_count,
&limit_count,
&highest_count,
&total_count,
&total,
&blocking,
&last),
);
display_info(f,
"Total received",
NULL,
current_count,
limit_count,
highest_count,
total_count,
&total,
&blocking,
&last);
CHECK_FCT_DO(
fd_stat_getstats(STAT_G_OUTGOING,
NULL,
¤t_count,
&limit_count,
&highest_count,
&total_count,
&total,
&blocking,
&last),
);
display_info(f,
"Total sending",
NULL,
current_count,
limit_count,
highest_count,
total_count,
&total,
&blocking,
&last);
CHECK_FCT_DO(
pthread_rwlock_rdlock(&fd_g_peers_rw),
/* continue */
);
for
(li
=
fd_g_peers.next;
li !=
&fd_g_peers;
li =
li->next)
{
struct
peer_hdr *
p =
(struct
peer_hdr *)li->o;
fprintf(f,
"%s\n",
fd_peer_dump(&buf,
&len,
NULL,
p,
1));
CHECK_FCT_DO(
fd_stat_getstats(STAT_P_PSM,
p,
¤t_count,
&limit_count,
&highest_count,
&total_count,
&total,
&blocking,
&last),
);
display_info(f,
"Events, incl. recept",
p->info.pi_diamid,
current_count,
limit_count,
highest_count,
total_count,
&total,
&blocking,
&last);
CHECK_FCT_DO(
fd_stat_getstats(STAT_P_TOSEND,
p,
¤t_count,
&limit_count,
&highest_count,
&total_count,
&total,
&blocking,
&last),
);
display_info(f,
"Outgoing",
p->info.pi_diamid,
current_count,
limit_count,
highest_count,
total_count,
&total,
&blocking,
&last);
}
CHECK_FCT_DO(
pthread_rwlock_unlock(&fd_g_peers_rw),
/* continue */
);
fprintf(f,
"[status_monitor] Dumping servers information\n");
fprintf(f,
"%s\n",
fd_servers_dump(&buf,
&len,
NULL,
1));
fclose(f);
/*
wait until the status_monitor.txt file was delete */
while
(1)
{
inotify_len
=
read(fd,
event,
kBufferLenOfOneEvent);
if
(inotify_len
==
-1)
{
TRACE_DEBUG(INFO,
"inotify read failed!");
goto
exit_error;
}
if
((event->mask
&
IN_DELETE)
&&
0
==
strcmp(kStatusFilename,
event->name))
{
break;
}
}
sleep(1);
}
exit_error:
free(buf);
open_file_error:
inotify_rm_watch(fd,
wd);
inotify_add_watch_error:
close(fd);
free((char
*)event);
return
NULL;
}
/* Entry point */
static
int
monitor_main(char
*
conffile)
{
TRACE_ENTRY("%p",
conffile);
CHECK_POSIX(
pthread_create(
&thr,
NULL,
mn_thr,
NULL )
);
return
0;
}
/* Cleanup */
void
fd_ext_fini(void)
{
TRACE_ENTRY();
CHECK_FCT_DO(
fd_thr_term(&thr),
/* continue */
);
return
;
}