2
2
This file is the for the Flex code-generator: http://flex.sourceforge.net/
3
3
It also requires libmemcached: http://libmemcached.org/libMemcached.html
5
For yum based distributions, eg Red Hat/Fedora/SuSE/Mageia
6
yum install gcc flex glibc-devel libmemcached-devel
8
For apt based distributions, eg Debian/Ubuntu
9
apt-get install gcc make flex libc6-dev libmemcached-dev
6
12
make LDFLAGS=-lmemcached check_memcached
14
make LDFLAGS="-lmemcached -lpthread" check_memcached
15
(depending on your Linux distro)
8
17
This program was initially developed by Lonely Planet for internal use
9
18
and has kindly been made available to the Open Source community for
53
62
static int max_n_stats = 30;
54
63
static int min_stats_interval = 30; /* Compare stats at least 30 minutes old, at least */
55
64
static int verbose=0;
65
static int perfstats_for_rrdtool=0;
56
66
static double min_hit_miss = 2.0;
57
67
static uint64_t max_evictions = 10;
58
68
static double timeout=1.0;
85
95
/* --------------------------- functions() ------------------------------ */
87
97
int check_memcached();
88
char * get_new_stats(memcached_st*);
98
char * get_current_stats(memcached_st*);
89
99
char * update_stats_obj(char *, size_t , char *);
91
101
/* ===================================================================================== */
157
167
int arg_error = 0;
159
while ( ( opt_c = getopt(argc, argv, "hvH:p:w:c:t:T:n:E:k:K:") ) != -1 ) {
169
while ( ( opt_c = getopt(argc, argv, "hvrH:p:w:c:t:T:n:E:k:K:") ) != -1 ) {
160
170
switch( opt_c ) {
162
172
/* Hostname or IP address - support for comma-separated list */
282
295
/* ----------------------------------------------------------------------------------------- */
283
296
/* Get the stats from this server */
284
new_item = get_new_stats(my_memcached);
297
current_stats_str = get_current_stats(my_memcached);
286
299
/* ----------------------------------------------------------------------------------------- */
287
300
/* Get our data (if it's there) */
305
318
print_debug("Found %d items in stats history\n",obj_n_stats);
306
319
print_debug("Best stats:\ntime=%llu cmd_get=%llu cmd_set=%llu get_hits=%llu get_misses=%llu evictions=%llu\n",
307
320
obj_time,obj_cmd_get,obj_cmd_set,obj_get_hits,obj_get_misses,obj_evictions);
308
print_debug("New stats\n%s\n",new_item);
321
print_debug("New stats\n%s\n",current_stats_str);
310
new_object = update_stats_obj(object, object_size, new_item);
323
new_object = update_stats_obj(object, object_size, current_stats_str);
312
325
/* ----------------------------------------------------------------------------------------- */
313
326
/* Store new data if it's at least 1 minute newer */
370
383
free ( nagios_service_tmp );
373
385
str_bytes = asprintf(&nagios_service_output,
374
"%shit/miss: %1.1f; ",
386
"%shit/miss=%1.1f; ",
375
387
nagios_service_tmp,
382
str_bytes = asprintf(&nagios_service_output,"%shit/miss: %llu/0; ",
393
str_bytes = asprintf(&nagios_service_output,"%shit/miss=%llu/0; ",
383
394
nagios_service_tmp,
384
395
stats.get_hits - obj_get_hits
397
free ( nagios_service_tmp );
389
400
nagios_service_tmp = nagios_service_output;
398
409
free ( nagios_service_tmp );
400
411
/* Add the performance data */
401
/* Remove trailing newline from new_item */
402
n = strlen(new_item);
403
if ( n > 1 && *(new_item+n-1) == '\n' ) {
404
*(new_item+n-1) = '\0';
412
/* Remove trailing newline from current_stats_str */
413
n = strlen(current_stats_str);
414
if ( n > 1 && *(current_stats_str+n-1) == '\n' ) {
415
*(current_stats_str+n-1) = '\0';
406
417
if ( str_bytes == -1 ) {
407
418
puts(memory_error_message);
411
422
/* Delta times may not apply if no suitable object found. Also, if NO object exists yet, there is nothing to calculate */
412
if ( obj_time == 0 ) {
413
nagios_perfdata = new_item;
423
if ( perfstats_for_rrdtool == 1 ) {
424
if ( obj_time == 0 ) {
425
/* No performance stats available (yet) */
426
nagios_perfdata = "";
429
str_bytes = asprintf(&nagios_perfdata,
430
"%s delta_time_s=%lu gets_per_min=%llu sets_per_min=%llu hits_per_min=%llu misses_per_min=%llu evictions_per_min=%llu",
432
(uint32_t) ( stats.time - obj_time ),
433
60 * ( stats.cmd_get - obj_cmd_get) / ( stats.time - obj_time ),
434
60 * ( stats.cmd_set - obj_cmd_set )/ ( stats.time - obj_time ),
435
60 * ( stats.get_hits - obj_get_hits ) / ( stats.time - obj_time ),
436
60 * ( stats.get_misses - obj_get_misses ) / ( stats.time - obj_time ),
437
60 * ( stats.evictions - obj_evictions ) / ( stats.time - obj_time )
440
str_bytes = asprintf(&nagios_perfdata,
441
"gets_per_min=%.2f sets_per_min=%.2f hits_per_min=%.2f misses_per_min=%.2f evictions_per_min=%.2f hit_miss_ratio=%.2f",
442
60.0 * ( stats.cmd_get - obj_cmd_get) / ( stats.time - obj_time ),
443
60.0 * ( stats.cmd_set - obj_cmd_set )/ ( stats.time - obj_time ),
444
60.0 * ( stats.get_hits - obj_get_hits ) / ( stats.time - obj_time ),
445
60.0 * ( stats.get_misses - obj_get_misses ) / ( stats.time - obj_time ),
446
60.0 * ( stats.evictions - obj_evictions ) / ( stats.time - obj_time ),
452
} else if ( obj_time == 0 ) {
453
nagios_perfdata = "";
415
455
str_bytes = asprintf(&nagios_perfdata,
416
456
"%s delta_time=%lu delta_cmd_get=%llu delta_cmd_set=%llu delta_get_hits=%llu delta_get_misses=%llu delta_evictions=%llu",
418
458
(uint32_t) ( stats.time - obj_time ),
419
459
stats.cmd_get - obj_cmd_get,
420
460
stats.cmd_set - obj_cmd_set,
446
486
print_v("\nNo misses - very good\n");
449
print_v("\nHistory object '%s':\n%s\nNew stats:\n%s (%sstored)\n",memcached_key,object,new_item,
489
print_v("\nHistory object '%s':\n%s\nNew stats:\n%s (%sstored)\n",memcached_key,object,current_stats_str,
450
490
new_object== NULL? "not ":"");
452
492
memcached_free(my_memcached);
457
497
/* ==================================================================================================== */
458
char *get_new_stats(memcached_st *my_memcached) {
498
char *get_current_stats(memcached_st *my_memcached) {
459
499
memcached_return error;
461
char * new_item_format;
501
char * current_stats_str_format;
502
char * current_stats_str;
463
503
memcached_stat_st *stats_array;
465
505
/* error = memcached_stat_servername(&stats, NULL, hostname, port); - cannot set timeout, but gives better error responses :-( */
474
514
stats = stats_array[0];
475
515
free(stats_array);
477
new_item_format = "time=%lu cmd_get=%llu cmd_set=%llu get_hits=%llu get_misses=%llu evictions=%llu\n";
517
current_stats_str_format = "time=%lu cmd_get=%llu cmd_set=%llu get_hits=%llu get_misses=%llu evictions=%llu\n";
479
str_bytes = asprintf(&new_item,new_item_format,
519
str_bytes = asprintf(¤t_stats_str,current_stats_str_format,
480
520
stats.time,stats.cmd_get,stats.cmd_set,stats.get_hits,stats.get_misses,stats.evictions);
482
522
obj_time_oldest = stats.time;
529
return(current_stats_str);
492
532
/* ==================================================================================================== */
493
char * update_stats_obj(char *object, size_t object_size, char *new_item) {
533
char * update_stats_obj(char *object, size_t object_size, char *current_stats_str) {
495
535
char *new_object;
496
536
size_t new_object_size;
497
537
size_t graft_offset;
500
if ( stats.time < obj_time_last + 60 ) {
540
if ( stats.time < obj_time_last + 30 ) {
501
541
/* Only store new stats if at least 1 minute has passed since the last stats were stored */
502
print_debug("New stats are less than minute newer than last entry - not stored\n");
542
print_v("New stats are less than 30s newer than last entry - not stored\n");
505
545
/* Prune stats from the start of the object */
519
559
print_debug("Prune %d items / %d chars from start of object\nNew:\n%s\n",obj_n_prune,obj_offset,object+obj_offset);
521
561
/* Add extra 2 chars for trailing \n\0 */
522
new_object_size = object_size - obj_offset + (size_t) ( (strlen(new_item)+ 2) * sizeof(char));
562
new_object_size = object_size - obj_offset + (size_t) ( (strlen(current_stats_str)+ 2) * sizeof(char));
523
563
new_object = malloc(new_object_size * sizeof(char) );
524
564
if (new_object == NULL ) {
525
565
puts(memory_error_message);
543
583
/* Add \n\0 to end of buffer */
544
584
strcpy(++s,"\n");
586
strcat(s,current_stats_str);
547
587
return(new_object);
548
588
print_debug("New Object is:\n%s\nNew size: %d\nReal size: %d\n",new_object, new_object_size, (strlen(new_object)+1));
549
589
return(new_object);
556
printf("\t%s -H hostname[:port] [-v] [-p port] [-t time_out] [-w min_hit_miss] [-n max_stats] [-T min_stats_interval] [-E max_evictions] [-k key] [-K key_expiry_time]\n", argv0);
596
printf("\t%s -H hostname[:port] [-v] [-p port] [-t time_out] [-w min_hit_miss] [-n max_stats] [-T min_stats_interval] [-E max_evictions] [-k key] [-K key_expiry_time] [-r]\n", argv0);
557
597
printf("\t-H ... Hostname or IP address (required)\n\t optional \":port\" overrides -p\n");
558
598
printf("\t-p ... Port number (default: %u)\n",default_port);
559
599
printf("\t-v ... verbose messages\n");
564
604
printf("\t-t ... timeout in seconds (default: %1.1f)\n",timeout);
565
605
printf("\t-k ... key name for history object (default: %s)\n",memcached_key);
566
606
printf("\t-K ... expiry time in seconds for history object (default: %u)\n",memcache_stats_object_expiry_time);
607
printf("\t-r ... output performance statistics as rate-per-minute figures (better suited to pnp4nagios)\n");
567
608
printf("\nExample:\n");
568
609
printf("\t%s -H 192.168.1.1 -p 11212 -w 10 -E 5 -t 0.3 -T 10 -n 10\n",argv0);
569
printf("\nNote: the history object \"%s\" will not be updated if the new stats are less than a minute old\n",memcached_key);
610
printf("\nNote: the history object \"%s\" will not be updated if the new stats are less than 30 seconds old\n",memcached_key);
570
611
printf( " compared to the most recent stats in the \"%s\" object\n",memcached_key);