# coding=utf-8

"""
Collects data from a Redis Server

#### Dependencies

 * redis

"""

import diamond.collector
import time

try:
    import redis
except ImportError:
    redis = None


class RedisCollector(diamond.collector.Collector):

    _DATABASE_COUNT = 16
    _DEFAULT_DB = 0
    _DEFAULT_HOST = 'localhost'
    _DEFAULT_PORT = 6379
    _KEYS = {'clients.blocked': 'blocked_clients',
             'clients.connected': 'connected_clients',
             'clients.longest_output_list': 'client_longest_output_list',
             'cpu.parent.sys': 'used_cpu_sys',
             'cpu.children.sys': 'used_cpu_sys_childrens',
             'cpu.parent.user': 'used_cpu_user',
             'cpu.children.user': 'used_cpu_user_childrens',
             'hash_max_zipmap.entries': 'hash_max_zipmap_entries',
             'hash_max_zipmap.value': 'hash_max_zipmap_value',
             'keys.evicted': 'evicted_keys',
             'keys.expired': 'expired_keys',
             'keyspace.hits': 'keyspace_hits',
             'keyspace.misses': 'keyspace_misses',
             'last_save.changes_since': 'changes_since_last_save',
             'last_save.time': 'last_save_time',
             'memory.internal_view': 'used_memory',
             'memory.external_view': 'used_memory_rss',
             'memory.fragmentation_ratio': 'mem_fragmentation_ratio',
             'process.commands_processed': 'total_commands_processed',
             'process.connections_received': 'total_connections_received',
             'process.uptime': 'uptime_in_seconds',
             'pubsub.channels': 'pubsub_channels',
             'pubsub.patterns': 'pubsub_patterns',
             'slaves.connected': 'connected_slaves'}

    def get_default_config_help(self):
        config_help = super(RedisCollector, self).get_default_config_help()
        config_help.update({
            'host': 'Hostname to collect from',
            'port': 'Port number to collect from',
            'db': '',
            'databases': '',
        })
        return config_help

    def get_default_config(self):
        """
        Return default config

:rtype: dict

        """
        config = super(RedisCollector, self).get_default_config()
        config.update({
            'host': self._DEFAULT_HOST,
            'port': self._DEFAULT_PORT,
            'db': self._DEFAULT_DB,
            'databases': self._DATABASE_COUNT})
        return config

    def _client(self):
        """Return a redis client for the configuration.

:rtype: redis.Redis

        """
        return redis.Redis(host=self.config.get('host',
                                                self._DEFAULT_HOST),
                           port=int(self.config.get('port',
                                                    self._DEFAULT_PORT)),
                           db=int(self.config.get('db',
                                                  self._DEFAULT_DB)))

    def _precision(self, value):
        """Return the precision of the number

:param str value: The value to find the precision of
:rtype: int

        """
        value = str(value)
        decimal = value.rfind('.')
        if decimal == -1:
            return 0
        return len(value) - decimal - 1

    def _publish_key(self, key):
        """Return the full key for the partial key. Prefix the redis port
        in case there are multiple running on one machine.

:param str key: The key name
:rtype: str

        """
        return '%s.%s' % (self.config.get('port', self._DEFAULT_PORT), key)

    def collect(self):
        """Collect the stats from the redis instance and publish them.

        """
        if redis is None:
            self.log.error('Unable to import module redis')
            return {}

        # Connect to redis
        client = self._client()
        info = client.info()
        del client

        # The structure should include the port for multiple instances per
        # server
        data = dict()

        # Iterate over the top level keys
        for key in self._KEYS:
            if self._KEYS[key] in info:
                data[key] = info[self._KEYS[key]]

        # Look for databaase speific stats
        for dbnum in range(0, self.config.get('databases',
                                              self._DATABASE_COUNT)):
            db = 'db%i' % dbnum
            if db in info:
                for key in info[db]:
                    data['%s.%s' % (db, key)] = info[db][key]

        # Time since last save
        data['last_save.time_since'] = int(time.time()) - info['last_save_time']

        # Publish the data to graphite
        for key in data:
            self.publish(self._publish_key(key),
                         data[key],
                         self._precision(data[key]))

@@ -1695,16 +1695,148 @@
 slaves'%7D
+%0A    _RENAMED_KEYS = %7B'last_save.changes_since': 'rdb_changes_since_last_save',%0A             'last_save.time': 'rdb_last_save_time'%7D
 %0A%0A    de
@@ -4250,16 +4250,214 @@
 %5Bkey%5D%5D%0A%0A
+        # Iterate over renamed keys for 2.6 support%0A        for key in self._RENAMED_KEYS:%0A            if self._RENAMED_KEYS%5Bkey%5D in info:%0A                data%5Bkey%5D = info%5Bself._RENAMED_KEYS%5Bkey%5D%5D%0A%0A
         
@@ -4810,16 +4810,113 @@
 st save%0A
+        for key in %5B'last_save_time', 'rdb_last_save_time'%5D:%0A            if key in info:%0A        
         
@@ -4970,32 +4970,19 @@
  - info%5B
-'last_save_time'
+key
 %5D%0A%0A     

Support renamed keys in 2.6