# Path: kingpin/kazoo_utils/utils.py
# def _escape_path_for_stats_name(path):
#     def __init__(self, *args, **kwargs):
#     def increment(self, stats, sample_rate=1, tags={}):
#     def gauge(self, stats, value, sample_rate=1, tags={}):
# class DummyStatsdClient:
# 
# Path: kingpin/kazoo_utils/utils.py
# def _escape_path_for_stats_name(path):
#     def __init__(self, *args, **kwargs):
#     def increment(self, stats, sample_rate=1, tags={}):
#     def gauge(self, stats, value, sample_rate=1, tags={}):
# class DummyStatsdClient:
# 
# Path: kingpin/kazoo_utils/utils.py
# def _escape_path_for_stats_name(path):
#     # Do some formatting the file path.
#     if path is None:
#         return None
#     if path.startswith("/"):
#         path = path[1:]
#     return path.replace("/", "_")
# 
# Path: kingpin/kazoo_utils/decorators.py
# class SingletonMetaclass(type):
#     """Singleton class that ensures there is only one instance of the object.
# 
#     Instead of using ``singleton`` decorator use this metaclass. This ensures
#     that classes remain classes as opposed to
#     functions that return classes, as that is the approach the decorator takes.
# 
#     For more details consult
#     http://stackoverflow.com/questions/8563130/python-singleton-class.
# 
#     To make your class singleton add ``__metaclass__``::
# 
#         class Highlander(object)
#             '''There can be only one!'''
# 
#             __metaclass__ = SingletonMetaclass
# 
#             def __init__(self):
#                 self.x = 1
# 
#     """
#     def __init__(cls, *args, **kwargs):
#         super(SingletonMetaclass, cls).__init__(*args, **kwargs)
#         cls.__instance = None
#         cls.__lock = threading.RLock()
# 
#     def __call__(cls, *args, **kwargs):
#         # Make this thread safe.
#         with cls.__lock:
#             if cls.__instance is None:
#                 cls.__instance = super(SingletonMetaclass, cls).__call__(
#                     *args, **kwargs)
#         return cls.__instance
# 
# Path: kingpin/thrift_utils/periodical.py
# class Periodical(object):
#     def __init__(self, name, interval_secs, start_after_secs,
#                  f, *args, **kwargs):
#         """Constructor.
# 
#         Args:
#             name: name of the periodical for bookkeeping.
#             interval_secs: frequency to run.
#             start_after_secs: first run starts after start_after_secs.
#             f: function to run.
#             args: args passed to f
#             kwargs: kwargs passed to f
# 
#         """
#         self.name = name
#         self.interval_secs = interval_secs
# 
#         self.f = f
#         self.args = args
#         self.kwargs = kwargs
# 
#         self.last_timestamp = time.time() + start_after_secs - interval_secs
#         self.greenlet = gevent.spawn(self._run)
# 
#     def _run(self):
#         """Run the wrapped function periodically"""
#         try:
#             while True:
#                 ts = time.time()
#                 if self.last_timestamp + self.interval_secs <= ts:
#                     self.last_timestamp = ts
#                     try:
#                         self.f(*self.args, **self.kwargs)
#                     except gevent.GreenletExit:
#                         # We are notified to exit.
#                         raise
#                     except BaseException as e:
#                         # We ignore other exceptions.
#                         log.error("Exception %s caught in Periodical %s " % (
#                             repr(e), self.name))
# 
#                 # sleep until the time for the next run.
#                 sleep_secs = self.last_timestamp + self.interval_secs \
#                     - time.time()
# 
#                 if sleep_secs < 0:
#                     sleep_secs = 0
# 
#                 gevent.sleep(sleep_secs)
# 
#         except gevent.GreenletExit:
#             log.info("Periodical %s stopped." % self.name)
# 
#     def stop(self):
#         """Stop the periodical.
# 
#         It must be called in order to garbage collect this object.
# 
#         """
#         self.greenlet.kill(block=True)


from collections import namedtuple
from functools import wraps
from .utils import dummy_statsd
from .utils import hostname
from .utils import _escape_path_for_stats_name
from .decorators import SingletonMetaclass
from ..thrift_utils.periodical import Periodical
import datetime
import gevent
import hashlib
import logging
import os
                    watch_type, file_path))
                break
            except Exception, gevent.Timeout:
                log.exception("failed to add file watch of type %s, on %s" % (
                    watch_type, file_path))
                self._sc.increment(
                    "errors.file.{}watch.failure.{}.{}".format(
                        watch_type, file_path_stat_name, hostname),
                    sample_rate=1)
                if keep_retrying:
                    # exponential backoff
                    gevent.sleep(self._calculate_backoff_time(
                        num_tries, backoff_in_secs, max_wait_in_secs))
                    num_tries += 1
                else:
                    raise

    @timeout_after(30)
    def _check_file_updates(self):
        start_time = datetime.datetime.now()
        for key, value in self._watched_file_map.iteritems():
            (file_path, watch_type) = key
            (update_time, hash, callbacks) = value
            try:
                new_update_time = os.path.getmtime(file_path)
                if new_update_time != update_time:
                    with open(file_path, 'r') as f:
                        file_content = f.read()
                    new_hash = self._compute_md5_hash(file_content)
                    if new_hash != hash:

# Path: kingpin/kazoo_utils/utils.py
# def _escape_path_for_stats_name(path):
#     def __init__(self, *args, **kwargs):
#     def increment(self, stats, sample_rate=1, tags={}):
#     def gauge(self, stats, value, sample_rate=1, tags={}):
# class DummyStatsdClient:
# 
# Path: kingpin/kazoo_utils/utils.py
# def _escape_path_for_stats_name(path):
#     def __init__(self, *args, **kwargs):
#     def increment(self, stats, sample_rate=1, tags={}):
#     def gauge(self, stats, value, sample_rate=1, tags={}):
# class DummyStatsdClient:
# 
# Path: kingpin/kazoo_utils/utils.py
# def _escape_path_for_stats_name(path):
#     # Do some formatting the file path.
#     if path is None:
#         return None
#     if path.startswith("/"):
#         path = path[1:]
#     return path.replace("/", "_")
# 
# Path: kingpin/kazoo_utils/decorators.py
# class SingletonMetaclass(type):
#     """Singleton class that ensures there is only one instance of the object.
# 
#     Instead of using ``singleton`` decorator use this metaclass. This ensures
#     that classes remain classes as opposed to
#     functions that return classes, as that is the approach the decorator takes.
# 
#     For more details consult
#     http://stackoverflow.com/questions/8563130/python-singleton-class.
# 
#     To make your class singleton add ``__metaclass__``::
# 
#         class Highlander(object)
#             '''There can be only one!'''
# 
#             __metaclass__ = SingletonMetaclass
# 
#             def __init__(self):
#                 self.x = 1
# 
#     """
#     def __init__(cls, *args, **kwargs):
#         super(SingletonMetaclass, cls).__init__(*args, **kwargs)
#         cls.__instance = None
#         cls.__lock = threading.RLock()
# 
#     def __call__(cls, *args, **kwargs):
#         # Make this thread safe.
#         with cls.__lock:
#             if cls.__instance is None:
#                 cls.__instance = super(SingletonMetaclass, cls).__call__(
#                     *args, **kwargs)
#         return cls.__instance
# 
# Path: kingpin/thrift_utils/periodical.py
# class Periodical(object):
#     def __init__(self, name, interval_secs, start_after_secs,
#                  f, *args, **kwargs):
#         """Constructor.
# 
#         Args:
#             name: name of the periodical for bookkeeping.
#             interval_secs: frequency to run.
#             start_after_secs: first run starts after start_after_secs.
#             f: function to run.
#             args: args passed to f
#             kwargs: kwargs passed to f
# 
#         """
#         self.name = name
#         self.interval_secs = interval_secs
# 
#         self.f = f
#         self.args = args
#         self.kwargs = kwargs
# 
#         self.last_timestamp = time.time() + start_after_secs - interval_secs
#         self.greenlet = gevent.spawn(self._run)
# 
#     def _run(self):
#         """Run the wrapped function periodically"""
#         try:
#             while True:
#                 ts = time.time()
#                 if self.last_timestamp + self.interval_secs <= ts:
#                     self.last_timestamp = ts
#                     try:
#                         self.f(*self.args, **self.kwargs)
#                     except gevent.GreenletExit:
#                         # We are notified to exit.
#                         raise
#                     except BaseException as e:
#                         # We ignore other exceptions.
#                         log.error("Exception %s caught in Periodical %s " % (
#                             repr(e), self.name))
# 
#                 # sleep until the time for the next run.
#                 sleep_secs = self.last_timestamp + self.interval_secs \
#                     - time.time()
# 
#                 if sleep_secs < 0:
#                     sleep_secs = 0
# 
#                 gevent.sleep(sleep_secs)
# 
#         except gevent.GreenletExit:
#             log.info("Periodical %s stopped." % self.name)
# 
#     def stop(self):
#         """Stop the periodical.
# 
#         It must be called in order to garbage collect this object.
# 
#         """
#         self.greenlet.kill(block=True)


# Path: kingpin/kazoo_utils/file_watch.py
from collections import namedtuple
from functools import wraps
from .utils import dummy_statsd
from .utils import hostname
from .utils import _escape_path_for_stats_name
from .decorators import SingletonMetaclass
from ..thrift_utils.periodical import Periodical
import datetime
import gevent
import hashlib
import logging
import os

                    watch_type, file_path))
                break
            except Exception, gevent.Timeout:
                log.exception("failed to add file watch of type %s, on %s" % (
                    watch_type, file_path))
                self._sc.increment(
                    "errors.file.{}watch.failure.{}.{}".format(
                        watch_type, file_path_stat_name, hostname),
                    sample_rate=1)
                if keep_retrying:
                    # exponential backoff
                    gevent.sleep(self._calculate_backoff_time(
                        num_tries, backoff_in_secs, max_wait_in_secs))
                    num_tries += 1
                else:
                    raise

    @timeout_after(30)
    def _check_file_updates(self):
        start_time = datetime.datetime.now()
        for key, value in self._watched_file_map.iteritems():
            (file_path, watch_type) = key
            (update_time, hash, callbacks) = value
            try:
                new_update_time = os.path.getmtime(file_path)
                if new_update_time != update_time:
                    with open(file_path, 'r') as f:
                        file_content = f.read()
                    new_hash = self._compute_md5_hash(file_content)
                    if new_hash != hash:

                        self._sc.gauge('file_watch.{}'.format(_escape_path_for_stats_name(file_path)),