import os
from prometheus_client import Counter, start_http_server
from prometheus_client import Gauge as PromGauge # avoid collision
try:
    from gauge_pollers import GaugePortStatsPoller
    from valve_of import devid_present
    from valve_util import dpid_log
except ImportError:
    from faucet.gauge_pollers import GaugePortStatsPoller
    from faucet.valve_of import devid_present
    from faucet.valve_util import dpid_log

class GaugePortStatsPrometheusPoller(GaugePortStatsPoller):
    '''Exports port stats to prometheus.

    Note: the prometheus server starts in a separate thread. Whereas Ryu is
    single-threaded and event based.
    '''

    def __init__(self, conf, logger):
        super(GaugePortStatsPrometheusPoller, self).__init__(conf, logger)
        self.bytes_in = PromGauge(
            'bytes_in',
            '',
            ['dp_id', 'port_name'])
        self.bytes_out = PromGauge(
            'bytes_out',
            '',
            ['dp_id', 'port_name'])
        self.dropped_in = PromGauge(
            'dropped_in',
            '',
            ['dp_id', 'port_name'])
        self.dropped_out = PromGauge(
            'dropped_out',
            '',
            ['dp_id', 'port_name'])
        self.errors_in = PromGauge(
            'errors_in',
            '',
            ['dp_id', 'port_name'])
        self.packets_in = PromGauge(
            'packets_in',
            '',
            ['dp_id', 'port_name'])
        self.packets_out = PromGauge(
            'packets_out',
            '',
            ['dp_id', 'port_name'])
        self.port_state_reason = PromGauge(
            'port_state_reason',
            '',
            ['dp_id', 'port_name'])
        try:
            self.logger.debug('Attempting to start Prometheus server')
            start_http_server(
                self.conf.prometheus_port,
                self.conf.prometheus_addr
                )
        except OSError:
            # Prometheus server already started
            self.logger.debug('Prometheus server already running')
            pass

    def update(self, rcv_time, dp_id, msg):
        super(GaugePortStatsPrometheusPoller, self).update(rcv_time, dp_id, msg)
        self.logger.debug('Updating Prometheus Stats')
        for stat in msg.body:
            port_name = self._stat_port_name(msg, stat, dp_id)
            for stat_name, stat_val in self._format_port_stats('_', stat):
                self.__dict__[stat_name].labels(
                    dp_id=hex(dp_id), port_name=port_name).set(stat_val)

@@ -653,232 +653,330 @@
 '''%0A
-%0A
     
-def __init__(self, conf, logger):%0A        super(GaugePortStatsPrometheusPoller, self).__init__(conf, logger)%0A        self.bytes_in = PromGauge(%0A            'bytes_in',%0A            '',%0A            %5B'dp_id', 'port_
+# Ensure only one PromGauge objects are shared across all%0A    # GaugePortStatsPrometheusPollers%0A    # TODO: when we add another prometheus watcher it will probably make sense%0A    # to split this into a superclass that we inherit from%0A    _prom_initialised = False%0A    _counters = %7B%7D%0A%0A    def _init_counter(self, 
 name
-'%5D
 )
+:
 %0A   
@@ -989,19 +989,56 @@
 elf.
-bytes_out =
+__dict__%5Bname%5D = self._counters.setdefault(name,
  Pro
@@ -1061,19 +1061,12 @@
     
-'bytes_out'
+name
 ,%0A  
@@ -1117,33 +1117,96 @@
 me'%5D
-)%0A        self.dropped_in
+%0A            ))%0A        #if name not in self._counters:%0A        #    self.__dict__%5Bname%5D
  = P
@@ -1227,30 +1227,32 @@
     
+#
     
-'dropped_in'
+    name
 ,%0A    
+    #
     
@@ -1258,37 +1258,42 @@
      '',%0A       
+ #
      
+   
 %5B'dp_id', 'port_
@@ -1312,64 +1312,55 @@
     
-self.dropped_out = PromGauge(%0A            'dropped_out',
+#    self._counters%5Bname%5D = self.__dict__%5Bname%5D
 %0A   
@@ -1356,39 +1356,38 @@
 _%5Bname%5D%0A        
-    '',
+#else:
 %0A            %5B'd
@@ -1383,186 +1383,250 @@
     
+#
     
-%5B'dp_id', 'port_name'%5D)%0A        self.errors_in = PromGauge(%0A            'errors_in',%0A            '',%0A            %5B'dp_id', 'port_name'%5D)%0A        self.packets_in = PromGauge(%0A
+self.__dict__%5Bname%5D = self._counters%0A%0A    def __init__(self, conf, logger):%0A        super(GaugePortStatsPrometheusPoller, self).__init__(conf, logger)%0A        for counter in (%0A                'bytes_in',%0A                'bytes_out',%0A    
     
@@ -1634,23 +1634,23 @@
        '
-packets
+dropped
 _in',%0A  
@@ -1663,56 +1663,67 @@
     
-'',%0A            %5B'dp_id', 'port_name'%5D)%0A
+    'dropped_out',%0A                'errors_in',%0A   
         
 self
@@ -1722,21 +1722,22 @@
     
-self.
+     '
 packets_
 out 
@@ -1736,25 +1736,17 @@
 ets_
-out = PromGauge(%0A
+in',%0A    
     
@@ -1784,134 +1784,99 @@
     
-'',%0A            %5B'dp_id', 'port_name'%5D)%0A        self.port_state_reason = PromGauge(%0A            'port_state_reason',%0A 
+    'port_state_reason'%0A                ):%0A            self._init_counter(counter)%0A
         
    '
@@ -1863,38 +1863,36 @@
 ounter)%0A        
-   '',
+try:
 %0A            %5B'd
@@ -1892,45 +1892,43 @@
     
-%5B'dp_id', 'port_name'%5D)%0A        try:%0A
+if not self._prom_initialised:%0A    
     
@@ -2006,16 +2006,20 @@
         
+    
 start_ht
@@ -2029,16 +2029,20 @@
 server(%0A
+    
         
@@ -2076,16 +2076,20 @@
 s_port,%0A
+    
         
@@ -2138,17 +2138,67 @@
         
-)
+    )%0A                self._prom_initialised = True
 %0A       

Fix prometheus for monitoring multiple switches