# coding=utf-8

"""
The DockerCollector uses the docker stats api to
collect data about docker and the containers.

#### Dependencies

* docker -- Install via `pip install docker-py`
  Source https://github.com/docker/docker-py
"""

import json
import diamond.collector

try:
    import docker
except ImportError:
    docker = None


class DockerCollector(diamond.collector.Collector):

    METRICS = {
        # memory stats
        "memory_stats.stats.total_rss": "RSS_byte",
        "memory_stats.stats.total_cache": "cache_byte",
        "memory_stats.stats.total_swap": "swap_byte",
        "memory_stats.stats.total_pgpgin": "pagein_count",
        "memory_stats.stats.total_pgpgout": "pageout_count",

        # cpu stats
        "cpu_stats.cpu_usage.total_usage": "cpu.total",
        "cpu_stats.cpu_usage.usage_in_kernelmode": "cpu.kernelmode",
        "cpu_stats.cpu_usage.usage_in_usermode": "cpu.usermode",
        "cpu_stats.system_cpu_usage": "cpu.system",
    }

    def get_default_config_help(self):
        return super(DockerCollector, self).get_default_config_help()

    def get_default_config(self):
        config = super(DockerCollector, self).get_default_config()
        config.update({
            'path': 'docker'
        })
        return config

    def get_value(self, path, dictionary):
        keys = path.split(".")
        cur = dictionary
        for key in keys:
            if not isinstance(cur, dict):
                raise Exception("metric '{0}' does not exist".format(path))
            cur = cur.get(key)
            if cur is None:
                break
        return cur

    def collect(self):
        if docker is None:
            self.log.error('Unable to import docker')

        try:
            # Collect info
            results = {}
            client = docker.Client(version='auto')

            # Top level stats
            running_containers = client.containers()
            results['containers_running_count'] = (
                len(running_containers), 'GAUGE')

            all_containers = client.containers(all=True)
            results['containers_stopped_count'] = (
                len(all_containers) - len(running_containers), 'GAUGE')

            images_count = len(set(client.images(quiet=True)))
            results['images_count'] = (images_count, 'GAUGE')

            dangling_images_count = len(set(client.images(
                quiet=True, all=True, filters={'dangling': True})))
            results['images_dangling_count'] = (dangling_images_count, 'GAUGE')

            # Collect memory and cpu stats
            for container in running_containers:
                name = "containers." + "".join(container['Names'][0][1:])
                s = client.stats(container["Id"])
                stat = json.loads(s.next())
                for path in self.METRICS:
                    val = self.get_value(path, stat)
                    if val is not None:
                        metric_key = ".".join([name, self.METRICS.get(path)])
                        results[metric_key] = (val, 'GAUGE')
                s.close()

            for name in sorted(results.keys()):
                (value, metric_type) = results[name]
                self.publish(name, value, metric_type=metric_type)

        except Exception, e:
            self.log.error(e, exc_info=True)

@@ -1721,25 +1721,8 @@
 ')%0A%0A
-        try:%0A    
     
@@ -1744,28 +1744,24 @@
 nfo%0A        
-   
- 
 results = %7B%7D
@@ -1761,20 +1761,16 @@
 ts = %7B%7D%0A
-    
         
@@ -1817,20 +1817,16 @@
         
- 
-   
 # Top le
@@ -1831,28 +1831,24 @@
 level stats%0A
-    
         runn
@@ -1884,36 +1884,32 @@
 iners()%0A        
-    
 results%5B'contain
@@ -1940,28 +1940,24 @@
             
-  
-  
 len(running_
@@ -1971,36 +1971,32 @@
 ers), 'GAUGE')%0A%0A
-    
         all_cont
@@ -2032,36 +2032,32 @@
 l=True)%0A        
-    
 results%5B'contain
@@ -2088,28 +2088,24 @@
             
-  
-  
 len(all_cont
@@ -2157,20 +2157,16 @@
         
-    
 images_c
@@ -2208,36 +2208,32 @@
 True)))%0A        
- 
-   
 results%5B'images_
@@ -2275,20 +2275,16 @@
         
-   
- 
 dangling
@@ -2322,20 +2322,16 @@
 images(%0A
-    
         
@@ -2386,36 +2386,32 @@
 rue%7D)))%0A        
-  
-  
 results%5B'images_
@@ -2459,28 +2459,24 @@
 , 'GAUGE')%0A%0A
-    
         # Co
@@ -2506,28 +2506,24 @@
 ats%0A        
-    
 for containe
@@ -2559,20 +2559,16 @@
         
-   
- 
 name = %22
@@ -2629,20 +2629,16 @@
         
-    
 s = clie
@@ -2675,20 +2675,16 @@
         
- 
-   
 stat = j
@@ -2711,28 +2711,24 @@
             
-   
- 
 for path in 
@@ -2741,20 +2741,16 @@
 ETRICS:%0A
-    
         
@@ -2806,20 +2806,16 @@
         
- 
-   
 if val i
@@ -2822,28 +2822,24 @@
 s not None:%0A
-    
             
@@ -2916,28 +2916,24 @@
             
-    
 results%5Bmetr
@@ -2969,20 +2969,16 @@
         
-  
-  
 s.close(
@@ -2980,20 +2980,16 @@
 lose()%0A%0A
-    
         
@@ -3036,20 +3036,16 @@
         
- 
-   
 (value, 
@@ -3081,28 +3081,24 @@
             
-   
- 
 self.publish
@@ -3140,79 +3140,4 @@
 pe)%0A
-%0A        except Exception, e:%0A            self.log.error(e, exc_info=True)%0A

Fix docker collector exception handling