From 9885c351e57dd9070c0f93c1b0e9ec8d94f5d547 Mon Sep 17 00:00:00 2001 From: Victor LABORIE Date: Fri, 2 Jun 2017 14:25:13 +0200 Subject: [PATCH] redis: add munin config --- redis/files/munin_redis | 290 ++++++++++++++++++++++++++++++++++++++++ redis/tasks/main.yml | 2 + redis/tasks/munin.yml | 62 +++++++++ 3 files changed, 354 insertions(+) create mode 100644 redis/files/munin_redis create mode 100644 redis/tasks/munin.yml diff --git a/redis/files/munin_redis b/redis/files/munin_redis new file mode 100644 index 00000000..55474435 --- /dev/null +++ b/redis/files/munin_redis @@ -0,0 +1,290 @@ +#!/usr/bin/perl -w + +# +## Copyright (C) 2009 Gleb Voronich +## +## 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; version 2 dated June, +## 1991. +## +## 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. +## +## You should have received a copy of the GNU General Public License +## along with this program; if not, write to the Free Software +## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +## +## +## $Log$ +## +## Based on Redis module code v0.08 2009/from http://svn.rot13.org/index.cgi/Redis +## +## Installation process: +## +## 1. Download the plugin to your plugins directory (e.g. /usr/share/munin/plugins) +## 2. Create 3 symlinks at the directory that us used by munin for plugins detection (e.g. /etc/munin/plugins): redis_connected_clients, redis_per_sec and and redis_used_memory +## 3. Edit plugin-conf.d/munin-node if it is needed (env.host and env.port variables are accepted; set env.password for password protected Redis server) +## 4. Restart munin-node service +## +## Magic Markers +#%# family=auto +#%# capabilities=autoconf suggest + +use strict; +use IO::Socket::INET; +use IO::Socket::UNIX; +use Switch; + +my $HOST = exists $ENV{'host'} ? $ENV{'host'} : "127.0.0.1"; +my $UNIX_SOCKET = exists $ENV{'unixsocket'} ? $ENV{'unixsocket'} : ''; # path to Redis Unix sock file +my $PORT = exists $ENV{'port'} ? $ENV{'port'} : 6379; +my $PASSWORD = exists $ENV{'password'} ? $ENV{'password'} : undef; +my $TITLE_PREFIX = exists $ENV{'title_prefix'} ? $ENV{'title_prefix'} . ": " : ""; + +my $sock = &get_conn(); +my $config = ( defined $ARGV[0] and $ARGV[0] eq "config" ); +my $autoconf = ( defined $ARGV[0] and $ARGV[0] eq "autoconf" ); +if ( $autoconf ) { + if ( defined( $sock ) ) { + print "yes\n"; + exit 0; + } else { + print "no (unable to connect to $HOST\[:$PORT\])\n"; + exit 0; + } +} +my $suggest = ( defined $ARGV[0] and $ARGV[0] eq "suggest" ); +if ( $suggest ) { + if ( defined( $sock ) ) { + my @plugins = ('connected_clients', 'key_ratio', 'keys_per_sec', 'per_sec', 'used_keys', 'used_memory'); + foreach my $plugin (@plugins) { + print "$plugin\n"; + } + exit 0; + } else { + print "no (unable to connect to $HOST\[:$PORT\])\n"; + exit 0; + } +} + +my $hash=&get_info(); + +$0 =~ s/(.+)redis_//g; + +switch ($0) { + case "connected_clients" { + if ( $config ) { + my $maxclients= get_config("maxclients")->{"maxclients"}; + print "graph_title ${TITLE_PREFIX}Connected clients\n"; + print "graph_vlabel Connected clients\n"; + print "graph_category search\n"; + print "graph_args -l 0\n"; + print "connected_clients.line $maxclients:ff0000:Limit\n"; + print "connected_clients.label connected clients\n"; + exit 0; + } + + print "connected_clients.value " . $hash->{'connected_clients'} . "\n"; + } + + + case "keys_per_sec" { + if ( $config ) { + print "graph_title ${TITLE_PREFIX}Keys Per Second\n"; + print "graph_vlabel per \${graph_period}\n"; + print "graph_category search\n"; + print "graph_args -l 0\n"; + print "hits.label hits\n"; + print "hits.type COUNTER\n"; + print "misses.label misses\n"; + print "misses.type COUNTER\n"; + print "expired.label expirations\n"; + print "expired.type COUNTER\n"; + print "evictions.label evictions\n"; + print "evictions.type COUNTER\n"; + exit 0; + } + + print "hits.value " . $hash->{'keyspace_hits'} . "\n"; + print "misses.value " . $hash->{'keyspace_misses'} . "\n"; + print "expired.value " . $hash->{'expired_keys'} . "\n"; + print "evictions.value " . $hash->{'evicted_keys'} . "\n"; + } + + case "key_ratio" { + if ( $config ) { + print "graph_title ${TITLE_PREFIX}Key Hit vs Miss Ratio\n"; + print "graph_vlabel per \${graph_period}\n"; + print "graph_category search\n"; + print "graph_args -u 100 -l 0 -r --base 1000\n"; + print "hitratio.label hit ratio\n"; + print "hitratio.type GAUGE\n"; + print "hitratio.draw AREA\n"; + print "missratio.label miss ratio\n"; + print "missratio.type GAUGE\n"; + print "missratio.draw STACK\n"; + exit 0; + } + + my $total = $hash->{'keyspace_hits'} + $hash->{'keyspace_misses'}; + my $hitratio = 0; + my $missratio = 0; + if ($total > 0) { + $hitratio = $hash->{'keyspace_hits'} / $total * 100; + $missratio = $hash->{'keyspace_misses'} / $total * 100; + } + printf("hitratio.value %.2f\n", $hitratio); + printf("missratio.value %.2f\n", $missratio); + } + + + case "per_sec" { + if ( $config ) { + print "graph_title ${TITLE_PREFIX}Per second\n"; + print "graph_vlabel per \${graph_period}\n"; + print "graph_category search\n"; + print "graph_args -l 0\n"; + print "requests.label requests\n"; + print "requests.type COUNTER\n"; + print "connections.label connections\n"; + print "connections.type COUNTER\n"; + exit 0; + } + + print "requests.value ". $hash->{'total_commands_processed'} ."\n"; + print "connections.value ". $hash->{'total_connections_received'} ."\n"; + } + + + case "used_memory" { + if ( $config ) { + my $maxmemory = get_config("maxmemory")->{"maxmemory"}; + print "graph_title ${TITLE_PREFIX}Used memory\n"; + print "graph_vlabel Used memory\n"; + print "graph_category search\n"; + print "graph_args -l 0 --base 1024\n"; + print "used_memory.line $maxmemory:ff0000:Limit\n"; + print "used_memory.label used memory\n"; + print "used_memory_peak.label used memory in peak\n"; + print "used_memory_rss.label Resident set size memory usage\n"; + exit 0; + } + + print "used_memory.value ". $hash->{'used_memory'} ."\n"; + print "used_memory_rss.value ". $hash->{'used_memory_rss'} ."\n"; + print "used_memory_peak.value ". $hash->{'used_memory_peak'} ."\n"; + } + + case "used_keys" { + my $dbs; + foreach my $key (keys %{$hash}) { + if ( $key =~ /^db\d+$/ && $hash->{$key} =~ /keys=(\d+),expires=(\d+)/ ) { + $dbs->{$key} = [ $1, $2 ]; + } + } + + if ( $config ) { + print "graph_title ${TITLE_PREFIX}Used keys\n"; + print "graph_vlabel Used keys\n"; + print "graph_category search\n"; + print "graph_args -l 0\n"; + + foreach my $db (keys %{$dbs}) { + printf "%s_keys.label %s keys\n", $db, $db; + printf "%s_expires.label %s expires\n", $db, $db; + } + + exit 0; + } + + foreach my $db (keys %{$dbs}) { + printf "%s_keys.value %d\n", $db, $dbs->{$db}[0]; + printf "%s_expires.value %d\n", $db, $dbs->{$db}[1]; + } + } +} + +close ($sock); + +sub get_conn { + + my $sock; + + if( $UNIX_SOCKET && -S $UNIX_SOCKET ){ + + $sock = IO::Socket::UNIX->new( + Type => SOCK_STREAM(), + Peer => $UNIX_SOCKET, + ); + + }else{ + + $sock = IO::Socket::INET->new( + PeerAddr => $HOST, + PeerPort => $PORT, + Timeout => 10, + Proto => 'tcp' + ); + } + + if ( defined( $PASSWORD ) ) { + print $sock "AUTH ", $PASSWORD, "\r\n"; + my $result = <$sock> || die "can't read socket: $!"; + } + return $sock; +} + +sub get_info{ + print $sock "INFO\r\n"; + my $result = <$sock> || die "can't read socket: $!"; + + my $rep; + # +2 characters for \r\n at end of the data block + read($sock, $rep, substr($result,1)+2) || die "can't read from socket: $!"; + + my $hash; + foreach (split(/\r\n/, substr($rep, 0, -2))) { + my ($key,$val) = split(/:/, $_, 2); + if (defined($key)) { + $hash->{$key} = $val; + } + } + return $hash; +} + +# This subroutine returns configuration matched to supplied as object +sub get_config{ + + print $sock "*3\r\n\$6\r\nCONFIG\r\n\$3\r\nGET\r\n\$".length($_[0])."\r\n".$_[0]."\r\n"; + # Response will look like like + # *2\r\n$9\r\nmaxmemory\r\n$10\r\n3221225472\r\n + + my $type = <$sock> || die "can't read socket: $!"; + + my $conf; + if( substr($type,0,1) ne "*" ) { + return $conf; + } + + my $count=substr($type,1); + + my ( $namesize, $name, $valuesize, $value ); + while ( $count > 1 ){ + $count=$count-2; + + $namesize=<$sock>; + read($sock, $name, substr($namesize,1)+2) || die "can't read from socket: $!"; + + $valuesize=<$sock>; + read($sock, $value, substr($valuesize,1)+2) || die "can't read from socket: $!"; + + $conf->{substr($name, 0, -2)}=substr($value, 0, -2); + } + + return $conf; +} + +# vim: ft=perl ai ts=4 sw=4 et: diff --git a/redis/tasks/main.yml b/redis/tasks/main.yml index b492b22c..1483a245 100644 --- a/redis/tasks/main.yml +++ b/redis/tasks/main.yml @@ -23,3 +23,5 @@ state: started tags: - redis + +- include: munin.yml diff --git a/redis/tasks/munin.yml b/redis/tasks/munin.yml new file mode 100644 index 00000000..c55e4f63 --- /dev/null +++ b/redis/tasks/munin.yml @@ -0,0 +1,62 @@ +--- +- name: Install munin check dependencies + apt: + name: libswitch-perl + state: present + tags: + - redis + +- name: Check if /usr is a partition + shell: "mount | grep 'on /usr type'" + args: + warn: no + changed_when: False + failed_when: False + check_mode: no + register: usr_partition + tags: redis + +- name: Mount /usr in rw + command: mount -o remount,rw /usr + args: + warn: no + changed_when: False + when: usr_partition.rc == 0 + tags: redis + +- name: Create plugin directory + file: + name: /usr/local/share/munin/ + state: directory + mode: "0755" + tags: redis + +- name: Create plugin directory + file: + name: /usr/local/share/munin/plugins/ + state: directory + mode: "0755" + tags: redis + +- name: Copy redis munin plugin + copy: + src: munin_redis + dest: /usr/local/share/munin/plugins/redis_ + mode: "0755" + notify: restart munin-node + tags: redis + +- name: Enable redis munin plugin + file: + src: /usr/local/share/munin/plugins/redis_ + dest: "/etc/munin/plugins/redis_{{item}}" + state: link + with_items: + - connected_clients + - key_ratio + - keys_per_sec + - per_sec + - used_keys + - used_memory + notify: restart munin-node + tags: redis