summaryrefslogtreecommitdiff
path: root/src/pmdas/memcache/pmdamemcache.pl
diff options
context:
space:
mode:
Diffstat (limited to 'src/pmdas/memcache/pmdamemcache.pl')
-rw-r--r--src/pmdas/memcache/pmdamemcache.pl307
1 files changed, 307 insertions, 0 deletions
diff --git a/src/pmdas/memcache/pmdamemcache.pl b/src/pmdas/memcache/pmdamemcache.pl
new file mode 100644
index 0000000..de232b2
--- /dev/null
+++ b/src/pmdas/memcache/pmdamemcache.pl
@@ -0,0 +1,307 @@
+#
+# Copyright (c) 2012 Red Hat.
+# Copyright (c) 2008 Aconex. All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 2 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# for more details.
+#
+# The memcached PMDA
+# NOTE: Not all metrics are exported at the moment, in particular,
+# the per-slab and per-item statistics are not. It may be better to
+# manage instances differently as these values are dynamic - perhaps
+# have the monitored memcaches (the current indom) in the namespace,
+# like the old DBMS PMDAs.
+#
+use strict;
+use warnings;
+use PCP::PMDA;
+use vars qw( $pmda $id $n %caches );
+
+my $memcache_delay = 5; # refresh rate in seconds
+my @memcache_instances = ( 0 => '127.0.0.1:11211',
+ # 1 => '127.0.0.1:11212',
+ # 2 => '192.168.5.76:11211',
+ );
+# Configuration files for overriding the above settings
+for my $file ( pmda_config('PCP_PMDAS_DIR') . '/memcache/memcache.conf',
+ './memcache.conf' ) {
+ eval `cat $file` unless ! -f $file;
+}
+
+my $memcache_indom = 0; # one for each memcached
+my $query = "stats\r\nstats slabs\r\nstats items\r\n"; # sent to memcached
+
+sub memcache_stats_callback
+{
+ ( $id, $_ ) = @_;
+ # $pmda->log("memcache_stats_callback: id $id");
+
+ if (/^STAT items:(\d+):(\w+) (\d+)/) { # stats items
+ # $caches{$id}{"item$1"}{$2} = $3;
+ }
+ elsif (/^STAT (\d+):(\w+) (\d+)/) { # stats slabs
+ # $caches{$id}{"slab$1"}{$2} = $3;
+ }
+ elsif (/^STAT (\w+) (\d+)/) { # stats
+ $caches{$id}{$1} = $2;
+ }
+ elsif (!(/^END/)) { # unknown
+ $pmda->log("Eh?: $_");
+ }
+}
+
+sub memcache_connect
+{
+ # $pmda->log("memcache_connect: $#memcache_instances");
+
+ for ($id = 0; $id < $#memcache_instances; $id += 2) {
+ my ($host, $port) = split(/:/, $memcache_instances[$id+1]);
+ $pmda->add_sock($host, $port, \&memcache_stats_callback, $id);
+ }
+}
+
+sub memcache_timer_callback
+{
+ # $pmda->log("memcache_timer_callback");
+
+ for ($id = 0; $id < $#memcache_instances; $id += 2) {
+ $pmda->put_sock($id, $query);
+ }
+}
+
+sub memcache_fetch_callback
+{
+ my ($cluster, $item, $inst) = @_;
+
+ # $pmda->log("memcache_fetch_callback: $cluster:$item ($inst)");
+
+ return (PM_ERR_INST, 0) unless ($inst != PM_IN_NULL);
+ return (PM_ERR_INST, 0) unless ($inst < $#memcache_instances);
+ $id = $memcache_instances[$inst];
+ return (PM_ERR_AGAIN, 0) unless defined($caches{$id});
+
+ if ($cluster == 0) {
+ if ($item == 0) { return ($caches{$id}{'pid'}, 1); }
+ elsif ($item == 1) { return ($caches{$id}{'uptime'}, 1); }
+ elsif ($item == 2) { return ($caches{$id}{'curr_items'}, 1); }
+ elsif ($item == 3) { return ($caches{$id}{'total_items'}, 1); }
+ elsif ($item == 4) { return ($caches{$id}{'bytes'}, 1); }
+ elsif ($item == 5) { return ($caches{$id}{'curr_connections'}, 1); }
+ elsif ($item == 6) { return ($caches{$id}{'total_connections'}, 1); }
+ elsif ($item == 7) { return ($caches{$id}{'connection_structures'}, 1); }
+ elsif ($item == 8) { return ($caches{$id}{'cmd_get'}, 1); }
+ elsif ($item == 9) { return ($caches{$id}{'cmd_set'}, 1); }
+ elsif ($item == 10) { return ($caches{$id}{'get_hits'}, 1); }
+ elsif ($item == 11) { return ($caches{$id}{'get_misses'}, 1); }
+ elsif ($item == 12) { return ($caches{$id}{'bytes_read'}, 1); }
+ elsif ($item == 13) { return ($caches{$id}{'bytes_written'}, 1); }
+ elsif ($item == 14) { return ($caches{$id}{'limit_maxbytes'}, 1); }
+ }
+# elsif ($cluster == 1) {
+# # many different slabs (X..Y), and 7 metrics in this cluster
+# if ($item > 7 * 11) { return (PM_ERR_PMID, 0); }
+# $id = int($item / 7) + 6;
+# $item %= 7;
+# my $slab = "slab$id";
+#
+# return (PM_ERR_AGAIN, 0) unless defined($caches{$id}{$slab});
+# if ($item == 0) { return ($caches{$id}{$slab}{'chunk_size'}, 1); }
+# elsif ($item == 1) { return ($caches{$id}{$slab}{'chunks_per_page'}, 1); }
+# elsif ($item == 2) { return ($caches{$id}{$slab}{'total_pages'}, 1); }
+# elsif ($item == 3) { return ($caches{$id}{$slab}{'total_chunks'}, 1); }
+# elsif ($item == 4) { return ($caches{$id}{$slab}{'used_chunks'}, 1); }
+# elsif ($item == 5) { return ($caches{$id}{$slab}{'free_chunks'}, 1); }
+# elsif ($item == 6) { return ($caches{$id}{$slab}{'free_chunks_end'}, 1); }
+# }
+ elsif ($cluster == 2) {
+ if ($item == 0) { return ($caches{$id}{'active_slabs'}, 1); }
+ elsif ($item == 1) { return ($caches{$id}{'total_malloced'}, 1); }
+ }
+# elsif ($cluster == 3) {
+# # many different slabs (X..Y), and 2 metrics in this cluster
+# if ($item > 2 * [Y]) { return (PM_ERR_PMID, 0); }
+# $id = int($item / 2) + [X];
+# $item %= 2;
+# my $itemid = "item$id";
+#
+# return (PM_ERR_AGAIN, 0) unless defined($caches{$id}{$itemid});
+# if ($item == 0) { return ($caches{$id}{$itemid}{'count'}, 1); }
+# elsif ($item == 1) { return ($caches{$id}{$itemid}{'age'}, 1); }
+# }
+ return (PM_ERR_PMID, 0);
+}
+
+$pmda = PCP::PMDA->new('memcache', 89);
+
+$pmda->add_metric(pmda_pmid(0,0), PM_TYPE_U32, $memcache_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'memcache.pid', '', '');
+$pmda->add_metric(pmda_pmid(0,1), PM_TYPE_U32, $memcache_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'memcache.uptime', '', '');
+$pmda->add_metric(pmda_pmid(0,2), PM_TYPE_U32, $memcache_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'memcache.current_items', '', '');
+$pmda->add_metric(pmda_pmid(0,3), PM_TYPE_U32, $memcache_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'memcache.total_items', '', '');
+$pmda->add_metric(pmda_pmid(0,4), PM_TYPE_U64, $memcache_indom,
+ PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0),
+ 'memcache.bytes', '', '');
+$pmda->add_metric(pmda_pmid(0,5), PM_TYPE_U32, $memcache_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'memcache.current_connections', '', '');
+$pmda->add_metric(pmda_pmid(0,6), PM_TYPE_U32, $memcache_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'memcache.total_connections', '', '');
+$pmda->add_metric(pmda_pmid(0,7), PM_TYPE_U32, $memcache_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'memcache.connection_structures', '', '');
+$pmda->add_metric(pmda_pmid(0,8), PM_TYPE_U32, $memcache_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'memcache.gets', '', '');
+$pmda->add_metric(pmda_pmid(0,9), PM_TYPE_U32, $memcache_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'memcache.sets', '', '');
+$pmda->add_metric(pmda_pmid(0,10), PM_TYPE_U32, $memcache_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'memcache.hits', '', '');
+$pmda->add_metric(pmda_pmid(0,11), PM_TYPE_U32, $memcache_indom,
+ PM_SEM_COUNTER, pmda_units(0,0,1,0,0,PM_COUNT_ONE),
+ 'memcache.misses', '', '');
+$pmda->add_metric(pmda_pmid(0,12), PM_TYPE_U64, $memcache_indom,
+ PM_SEM_COUNTER, pmda_units(1,0,0,PM_SPACE_BYTE,0,0),
+ 'memcache.bytes_read', '', '');
+$pmda->add_metric(pmda_pmid(0,13), PM_TYPE_U64, $memcache_indom,
+ PM_SEM_COUNTER, pmda_units(1,0,0,PM_SPACE_BYTE,0,0),
+ 'memcache.bytes_written', '', '');
+$pmda->add_metric(pmda_pmid(0,14), PM_TYPE_U32, $memcache_indom,
+ PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0),
+ 'memcache.limit_maxbytes', '', '');
+# $id = 0;
+# foreach $n (6 .. 17) { # stats slabs (N=6-17)
+# $pmda->add_metric(pmda_pmid(1,$id++), PM_TYPE_U32, $memcache_indom,
+# PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0),
+# "memcache.slabs.slab$n.chunk_size", '', '');
+# $pmda->add_metric(pmda_pmid(1,$id++), PM_TYPE_U32, $memcache_indom,
+# PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+# "memcache.slabs.slab$n.chunks_per_page", '', '');
+# $pmda->add_metric(pmda_pmid(1,$id++), PM_TYPE_U32, $memcache_indom,
+# PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+# "memcache.slabs.slab$n.total_pages", '', '');
+# $pmda->add_metric(pmda_pmid(1,$id++), PM_TYPE_U32, $memcache_indom,
+# PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+# "memcache.slabs.slab$n.total_chunks", '', '');
+# $pmda->add_metric(pmda_pmid(1,$id++), PM_TYPE_U32, $memcache_indom,
+# PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+# "memcache.slabs.slab$n.used_chunks", '', '');
+# $pmda->add_metric(pmda_pmid(1,$id++), PM_TYPE_U32, $memcache_indom,
+# PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+# "memcache.slabs.slab$n.free_chunks", '', '');
+# $pmda->add_metric(pmda_pmid(1,$id++), PM_TYPE_U32, $memcache_indom,
+# PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+# "memcache.slabs.slab$n.free_chunks_end", '', '');
+# }
+
+$pmda->add_metric(pmda_pmid(2,0), PM_TYPE_U32, $memcache_indom,
+ PM_SEM_INSTANT, pmda_units(0,0,0,0,0,0),
+ 'memcache.active_slabs', '', '');
+$pmda->add_metric(pmda_pmid(2,1), PM_TYPE_U32, $memcache_indom,
+ PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0),
+ 'memcache.total_malloced', '', '');
+
+# $id = 0;
+# foreach $n (6 .. 17) { # stats items (N=6-17)
+# $pmda->add_metric(pmda_pmid(3,$id++), PM_TYPE_U32, $memcache_indom,
+# PM_SEM_INSTANT, pmda_units(1,0,0,PM_SPACE_BYTE,0,0),
+# "memcache.items.item$n.count", '', '');
+# $pmda->add_metric(pmda_pmid(3,$id++), PM_TYPE_U32, $memcache_indom,
+# PM_SEM_INSTANT, pmda_units(0,1,0,0,PM_TIME_SEC,0),
+# "memcache.items.item$n.age", '', '');
+# }
+
+$pmda->add_indom($memcache_indom, \@memcache_instances,
+ 'Instance domain exporting each memcache daemon', '');
+
+$pmda->add_timer($memcache_delay, \&memcache_timer_callback, 0);
+$pmda->set_fetch_callback(\&memcache_fetch_callback);
+
+&memcache_connect;
+&memcache_timer_callback;
+
+$pmda->set_user('pcp');
+$pmda->run;
+
+=pod
+
+=head1 NAME
+
+pmdamemcache - memcache performance metrics domain agent (PMDA)
+
+=head1 DESCRIPTION
+
+This PMDA extracts performance data from memcached, a distributed memory
+caching daemon commonly used to improve web serving performance. A farm
+of memcached processes over multiple servers can be utilised by a single
+web application, increasing the total available object cache size, and
+decreasing the database load associated with smaller cache sizes. This
+system is described in detail at http://www.danga.com/memcached.
+
+=head1 INSTALLATION
+
+Configure B<pmdamemcache> to extract the values from set of hosts
+used in the memcache farm. These hosts can be listed in the
+$PCP_PMDAS_DIR/memcache/memcache.conf file, in the format (i.e.
+Perl array) described at the top of pmdamemcache.pl. A custom
+refresh rate can also be configured using this mechanism.
+
+ # cd $PCP_PMDAS_DIR/memcache
+ # [ edit memcache.conf ]
+
+Once this is setup, you can access the names and values for the
+memcache performance metrics by doing the following as root:
+
+ # cd $PCP_PMDAS_DIR/memcache
+ # ./Install
+
+If you want to undo the installation, do the following as root:
+
+ # cd $PCP_PMDAS_DIR/memcache
+ # ./Remove
+
+B<pmdamemcache> is launched by pmcd(1) and should never be executed
+directly. The Install and Remove scripts notify pmcd(1) when
+the agent is installed or removed.
+
+=head1 FILES
+
+=over
+
+=item $PCP_PMDAS_DIR/memcache/memcache.conf
+
+configuration file listing monitored memcache instances
+
+=item $PCP_PMDAS_DIR/memcache/Install
+
+installation script for the B<pmdamemcache> agent
+
+=item $PCP_PMDAS_DIR/memcache/Remove
+
+undo installation script for the B<pmdamemcache> agent
+
+=item $PCP_LOG_DIR/pmcd/memcache.log
+
+default log file for error messages from B<pmdamemcache>
+
+=back
+
+=head1 SEE ALSO
+
+pmcd(1) and memcached(1).