We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Missing info on fixing: Using events for service checks is deprecated in favor of monitors
It seems that you deprecated a feature without putting any information regarding how to fix it. I even googled and the only reference is the source code where you added this warning.

Please provide some information regarding what changes we are supposed to implement in order not to get these warnings. 

These warnings are showing in the UI:
https://www.dropbox.com/s/xpjpmgqtk71hqze/Screenshot%202014-09-24%2015.43.22.png?dl=0


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `checks/network_checks.py`
Content:
```
1 # (C) Datadog, Inc. 2010-2016
2 # All rights reserved
3 # Licensed under Simplified BSD License (see LICENSE)
4 
5 # stdlib
6 from collections import defaultdict
7 from Queue import Empty, Queue
8 import threading
9 import time
10 
11 # project
12 from checks import AgentCheck
13 from checks.libs.thread_pool import Pool
14 from config import _is_affirmative
15 
16 TIMEOUT = 180
17 DEFAULT_SIZE_POOL = 6
18 MAX_LOOP_ITERATIONS = 1000
19 FAILURE = "FAILURE"
20 
21 class Status:
22     DOWN = "DOWN"
23     WARNING = "WARNING"
24     CRITICAL = "CRITICAL"
25     UP = "UP"
26 
27 
28 class EventType:
29     DOWN = "servicecheck.state_change.down"
30     UP = "servicecheck.state_change.up"
31 
32 
33 class NetworkCheck(AgentCheck):
34     SOURCE_TYPE_NAME = 'servicecheck'
35     SERVICE_CHECK_PREFIX = 'network_check'
36     _global_current_pool_size = 0
37 
38     STATUS_TO_SERVICE_CHECK = {
39         Status.UP : AgentCheck.OK,
40         Status.WARNING : AgentCheck.WARNING,
41         Status.CRITICAL : AgentCheck.CRITICAL,
42         Status.DOWN : AgentCheck.CRITICAL,
43     }
44 
45     """
46     Services checks inherits from this class.
47     This class should never be directly instanciated.
48 
49     Work flow:
50         The main agent loop will call the check function for each instance for
51         each iteration of the loop.
52         The check method will make an asynchronous call to the _process method in
53         one of the thread initiated in the thread pool created in this class constructor.
54         The _process method will call the _check method of the inherited class
55         which will perform the actual check.
56 
57         The _check method must return a tuple which first element is either
58             Status.UP or Status.DOWN.
59             The second element is a short error message that will be displayed
60             when the service turns down.
61 
62     """
63 
64     def __init__(self, name, init_config, agentConfig, instances):
65         AgentCheck.__init__(self, name, init_config, agentConfig, instances)
66 
67         # A dictionary to keep track of service statuses
68         self.statuses = {}
69         self.notified = {}
70         self.nb_failures = 0
71         self.pool_size = 0
72         self.pool_started = False
73 
74         # Make sure every instance has a name that we use as a unique key
75         # to keep track of statuses
76         names = []
77         for inst in instances:
78             inst_name = inst.get('name', None)
79             if not inst_name:
80                 raise Exception("All instances should have a 'name' parameter,"
81                                 " error on instance: {0}".format(inst))
82             if inst_name in names:
83                 raise Exception("Duplicate names for instances with name {0}"
84                                 .format(inst_name))
85             names.append(inst_name)
86 
87     def stop(self):
88         self.stop_pool()
89         self.pool_started = False
90 
91     def start_pool(self):
92         # The pool size should be the minimum between the number of instances
93         # and the DEFAULT_SIZE_POOL. It can also be overridden by the 'threads_count'
94         # parameter in the init_config of the check
95         self.log.info("Starting Thread Pool")
96         default_size = min(self.instance_count(), DEFAULT_SIZE_POOL)
97         self.pool_size = int(self.init_config.get('threads_count', default_size))
98 
99         # To keep track on the total number of threads we should have running
100         NetworkCheck._global_current_pool_size += self.pool_size
101 
102         self.pool = Pool(self.pool_size)
103 
104         self.resultsq = Queue()
105         self.jobs_status = {}
106         self.jobs_results = {}
107         self.pool_started = True
108 
109     def stop_pool(self):
110         self.log.info("Stopping Thread Pool")
111 
112         # To keep track on the total number of threads we should have running
113         NetworkCheck._global_current_pool_size -= self.pool_size
114 
115         if self.pool_started:
116             self.pool.terminate()
117             self.pool.join()
118             self.jobs_status.clear()
119             assert self.pool.get_nworkers() == 0
120 
121     def restart_pool(self):
122         self.stop_pool()
123         self.start_pool()
124 
125     def check(self, instance):
126         if not self.pool_started:
127             self.start_pool()
128         if threading.activeCount() > 5 * NetworkCheck._global_current_pool_size + 6:
129             # On Windows the agent runs on multiple threads because of WMI so we need an offset of 6
130             raise Exception("Thread number (%s) is exploding. Skipping this check" % threading.activeCount())
131         self._process_results()
132         self._clean()
133         name = instance.get('name', None)
134         if name is None:
135             self.log.error('Each service check must have a name')
136             return
137 
138         if name not in self.jobs_status:
139             # A given instance should be processed one at a time
140             self.jobs_status[name] = time.time()
141             self.jobs_results[name] = self.pool.apply_async(self._process, args=(instance,))
142         else:
143             self.log.error("Instance: %s skipped because it's already running." % name)
144 
145     def _process(self, instance):
146         try:
147             statuses = self._check(instance)
148 
149             if isinstance(statuses, tuple):
150                 # Assume the check only returns one service check
151                 status, msg = statuses
152                 self.resultsq.put((status, msg, None, instance))
153 
154             elif isinstance(statuses, list):
155                 for status in statuses:
156                     sc_name, status, msg = status
157                     self.resultsq.put((status, msg, sc_name, instance))
158 
159         except Exception:
160             self.log.exception(
161                 u"Failed to process instance '%s'.", instance.get('name', u"")
162             )
163             result = (FAILURE, FAILURE, FAILURE, instance)
164             self.resultsq.put(result)
165 
166     def _process_results(self):
167         for i in xrange(MAX_LOOP_ITERATIONS):
168             try:
169                 # We want to fetch the result in a non blocking way
170                 status, msg, sc_name, instance = self.resultsq.get_nowait()
171             except Empty:
172                 break
173 
174             instance_name = instance['name']
175             if status == FAILURE:
176                 self.nb_failures += 1
177                 if self.nb_failures >= self.pool_size - 1:
178                     self.nb_failures = 0
179                     self.restart_pool()
180 
181                 # clean failed job
182                 self._clean_job(instance_name)
183                 continue
184 
185             self.report_as_service_check(sc_name, status, instance, msg)
186 
187             # FIXME: 5.3, this has been deprecated before, get rid of events
188             # Don't create any event to avoid duplicates with server side
189             # service_checks
190             skip_event = _is_affirmative(instance.get('skip_event', False))
191             if not skip_event:
192                 self.warning("Using events for service checks is deprecated in favor of monitors and will be removed in future versions of the Datadog Agent.")
193                 event = None
194 
195                 if instance_name not in self.statuses:
196                     self.statuses[instance_name] = defaultdict(list)
197 
198                 self.statuses[instance_name][sc_name].append(status)
199 
200                 window = int(instance.get('window', 1))
201 
202                 if window > 256:
203                     self.log.warning("Maximum window size (256) exceeded, defaulting it to 256")
204                     window = 256
205 
206                 threshold = instance.get('threshold', 1)
207 
208                 if len(self.statuses[instance_name][sc_name]) > window:
209                     self.statuses[instance_name][sc_name].pop(0)
210 
211                 nb_failures = self.statuses[instance_name][sc_name].count(Status.DOWN)
212 
213                 if nb_failures >= threshold:
214                     if self.notified.get((instance_name, sc_name), Status.UP) != Status.DOWN:
215                         event = self._create_status_event(sc_name, status, msg, instance)
216                         self.notified[(instance_name, sc_name)] = Status.DOWN
217                 else:
218                     if self.notified.get((instance_name, sc_name), Status.UP) != Status.UP:
219                         event = self._create_status_event(sc_name, status, msg, instance)
220                         self.notified[(instance_name, sc_name)] = Status.UP
221 
222                 if event is not None:
223                     self.events.append(event)
224 
225             self._clean_job(instance_name)
226 
227     def _clean_job(self, instance_name):
228         # The job is finished here, this instance can be re processed
229         if instance_name in self.jobs_status:
230             self.log.debug("Instance: %s cleaned from jobs status." % instance_name)
231             del self.jobs_status[instance_name]
232 
233         # if an exception happened, log it
234         if instance_name in self.jobs_results:
235             self.log.debug("Instance: %s cleaned from jobs results." % instance_name)
236             ret = self.jobs_results[instance_name].get()
237             if isinstance(ret, Exception):
238                 self.log.exception("Exception in worker thread: {0}".format(ret))
239             del self.jobs_results[instance_name]
240 
241 
242     def _check(self, instance):
243         """This function should be implemented by inherited classes"""
244         raise NotImplementedError
245 
246 
247     def _clean(self):
248         now = time.time()
249         for name, start_time in self.jobs_status.iteritems():
250             if now - start_time > TIMEOUT:
251                 self.log.critical("Restarting Pool. One check is stuck: %s" % name)
252                 self.restart_pool()
253                 break
254
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/checks/network_checks.py b/checks/network_checks.py
--- a/checks/network_checks.py
+++ b/checks/network_checks.py
@@ -3,7 +3,6 @@
 # Licensed under Simplified BSD License (see LICENSE)
 
 # stdlib
-from collections import defaultdict
 from Queue import Empty, Queue
 import threading
 import time
@@ -11,7 +10,6 @@
 # project
 from checks import AgentCheck
 from checks.libs.thread_pool import Pool
-from config import _is_affirmative
 
 TIMEOUT = 180
 DEFAULT_SIZE_POOL = 6
@@ -183,45 +181,6 @@
                 continue
 
             self.report_as_service_check(sc_name, status, instance, msg)
-
-            # FIXME: 5.3, this has been deprecated before, get rid of events
-            # Don't create any event to avoid duplicates with server side
-            # service_checks
-            skip_event = _is_affirmative(instance.get('skip_event', False))
-            if not skip_event:
-                self.warning("Using events for service checks is deprecated in favor of monitors and will be removed in future versions of the Datadog Agent.")
-                event = None
-
-                if instance_name not in self.statuses:
-                    self.statuses[instance_name] = defaultdict(list)
-
-                self.statuses[instance_name][sc_name].append(status)
-
-                window = int(instance.get('window', 1))
-
-                if window > 256:
-                    self.log.warning("Maximum window size (256) exceeded, defaulting it to 256")
-                    window = 256
-
-                threshold = instance.get('threshold', 1)
-
-                if len(self.statuses[instance_name][sc_name]) > window:
-                    self.statuses[instance_name][sc_name].pop(0)
-
-                nb_failures = self.statuses[instance_name][sc_name].count(Status.DOWN)
-
-                if nb_failures >= threshold:
-                    if self.notified.get((instance_name, sc_name), Status.UP) != Status.DOWN:
-                        event = self._create_status_event(sc_name, status, msg, instance)
-                        self.notified[(instance_name, sc_name)] = Status.DOWN
-                else:
-                    if self.notified.get((instance_name, sc_name), Status.UP) != Status.UP:
-                        event = self._create_status_event(sc_name, status, msg, instance)
-                        self.notified[(instance_name, sc_name)] = Status.UP
-
-                if event is not None:
-                    self.events.append(event)
-
             self._clean_job(instance_name)
 
     def _clean_job(self, instance_name):

{"golden_diff": "diff --git a/checks/network_checks.py b/checks/network_checks.py\n--- a/checks/network_checks.py\n+++ b/checks/network_checks.py\n@@ -3,7 +3,6 @@\n # Licensed under Simplified BSD License (see LICENSE)\n \n # stdlib\n-from collections import defaultdict\n from Queue import Empty, Queue\n import threading\n import time\n@@ -11,7 +10,6 @@\n # project\n from checks import AgentCheck\n from checks.libs.thread_pool import Pool\n-from config import _is_affirmative\n \n TIMEOUT = 180\n DEFAULT_SIZE_POOL = 6\n@@ -183,45 +181,6 @@\n                 continue\n \n             self.report_as_service_check(sc_name, status, instance, msg)\n-\n-            # FIXME: 5.3, this has been deprecated before, get rid of events\n-            # Don't create any event to avoid duplicates with server side\n-            # service_checks\n-            skip_event = _is_affirmative(instance.get('skip_event', False))\n-            if not skip_event:\n-                self.warning(\"Using events for service checks is deprecated in favor of monitors and will be removed in future versions of the Datadog Agent.\")\n-                event = None\n-\n-                if instance_name not in self.statuses:\n-                    self.statuses[instance_name] = defaultdict(list)\n-\n-                self.statuses[instance_name][sc_name].append(status)\n-\n-                window = int(instance.get('window', 1))\n-\n-                if window > 256:\n-                    self.log.warning(\"Maximum window size (256) exceeded, defaulting it to 256\")\n-                    window = 256\n-\n-                threshold = instance.get('threshold', 1)\n-\n-                if len(self.statuses[instance_name][sc_name]) > window:\n-                    self.statuses[instance_name][sc_name].pop(0)\n-\n-                nb_failures = self.statuses[instance_name][sc_name].count(Status.DOWN)\n-\n-                if nb_failures >= threshold:\n-                    if self.notified.get((instance_name, sc_name), Status.UP) != Status.DOWN:\n-                        event = self._create_status_event(sc_name, status, msg, instance)\n-                        self.notified[(instance_name, sc_name)] = Status.DOWN\n-                else:\n-                    if self.notified.get((instance_name, sc_name), Status.UP) != Status.UP:\n-                        event = self._create_status_event(sc_name, status, msg, instance)\n-                        self.notified[(instance_name, sc_name)] = Status.UP\n-\n-                if event is not None:\n-                    self.events.append(event)\n-\n             self._clean_job(instance_name)\n \n     def _clean_job(self, instance_name):\n", "issue": "Missing info on fixing: Using events for service checks is deprecated in favor of monitors\nIt seems that you deprecated a feature without putting any information regarding how to fix it. I even googled and the only reference is the source code where you added this warning.\n\nPlease provide some information regarding what changes we are supposed to implement in order not to get these warnings. \n\nThese warnings are showing in the UI:\nhttps://www.dropbox.com/s/xpjpmgqtk71hqze/Screenshot%202014-09-24%2015.43.22.png?dl=0\n\n", "before_files": [{"content": "# (C) Datadog, Inc. 2010-2016\n# All rights reserved\n# Licensed under Simplified BSD License (see LICENSE)\n\n# stdlib\nfrom collections import defaultdict\nfrom Queue import Empty, Queue\nimport threading\nimport time\n\n# project\nfrom checks import AgentCheck\nfrom checks.libs.thread_pool import Pool\nfrom config import _is_affirmative\n\nTIMEOUT = 180\nDEFAULT_SIZE_POOL = 6\nMAX_LOOP_ITERATIONS = 1000\nFAILURE = \"FAILURE\"\n\nclass Status:\n    DOWN = \"DOWN\"\n    WARNING = \"WARNING\"\n    CRITICAL = \"CRITICAL\"\n    UP = \"UP\"\n\n\nclass EventType:\n    DOWN = \"servicecheck.state_change.down\"\n    UP = \"servicecheck.state_change.up\"\n\n\nclass NetworkCheck(AgentCheck):\n    SOURCE_TYPE_NAME = 'servicecheck'\n    SERVICE_CHECK_PREFIX = 'network_check'\n    _global_current_pool_size = 0\n\n    STATUS_TO_SERVICE_CHECK = {\n        Status.UP : AgentCheck.OK,\n        Status.WARNING : AgentCheck.WARNING,\n        Status.CRITICAL : AgentCheck.CRITICAL,\n        Status.DOWN : AgentCheck.CRITICAL,\n    }\n\n    \"\"\"\n    Services checks inherits from this class.\n    This class should never be directly instanciated.\n\n    Work flow:\n        The main agent loop will call the check function for each instance for\n        each iteration of the loop.\n        The check method will make an asynchronous call to the _process method in\n        one of the thread initiated in the thread pool created in this class constructor.\n        The _process method will call the _check method of the inherited class\n        which will perform the actual check.\n\n        The _check method must return a tuple which first element is either\n            Status.UP or Status.DOWN.\n            The second element is a short error message that will be displayed\n            when the service turns down.\n\n    \"\"\"\n\n    def __init__(self, name, init_config, agentConfig, instances):\n        AgentCheck.__init__(self, name, init_config, agentConfig, instances)\n\n        # A dictionary to keep track of service statuses\n        self.statuses = {}\n        self.notified = {}\n        self.nb_failures = 0\n        self.pool_size = 0\n        self.pool_started = False\n\n        # Make sure every instance has a name that we use as a unique key\n        # to keep track of statuses\n        names = []\n        for inst in instances:\n            inst_name = inst.get('name', None)\n            if not inst_name:\n                raise Exception(\"All instances should have a 'name' parameter,\"\n                                \" error on instance: {0}\".format(inst))\n            if inst_name in names:\n                raise Exception(\"Duplicate names for instances with name {0}\"\n                                .format(inst_name))\n            names.append(inst_name)\n\n    def stop(self):\n        self.stop_pool()\n        self.pool_started = False\n\n    def start_pool(self):\n        # The pool size should be the minimum between the number of instances\n        # and the DEFAULT_SIZE_POOL. It can also be overridden by the 'threads_count'\n        # parameter in the init_config of the check\n        self.log.info(\"Starting Thread Pool\")\n        default_size = min(self.instance_count(), DEFAULT_SIZE_POOL)\n        self.pool_size = int(self.init_config.get('threads_count', default_size))\n\n        # To keep track on the total number of threads we should have running\n        NetworkCheck._global_current_pool_size += self.pool_size\n\n        self.pool = Pool(self.pool_size)\n\n        self.resultsq = Queue()\n        self.jobs_status = {}\n        self.jobs_results = {}\n        self.pool_started = True\n\n    def stop_pool(self):\n        self.log.info(\"Stopping Thread Pool\")\n\n        # To keep track on the total number of threads we should have running\n        NetworkCheck._global_current_pool_size -= self.pool_size\n\n        if self.pool_started:\n            self.pool.terminate()\n            self.pool.join()\n            self.jobs_status.clear()\n            assert self.pool.get_nworkers() == 0\n\n    def restart_pool(self):\n        self.stop_pool()\n        self.start_pool()\n\n    def check(self, instance):\n        if not self.pool_started:\n            self.start_pool()\n        if threading.activeCount() > 5 * NetworkCheck._global_current_pool_size + 6:\n            # On Windows the agent runs on multiple threads because of WMI so we need an offset of 6\n            raise Exception(\"Thread number (%s) is exploding. Skipping this check\" % threading.activeCount())\n        self._process_results()\n        self._clean()\n        name = instance.get('name', None)\n        if name is None:\n            self.log.error('Each service check must have a name')\n            return\n\n        if name not in self.jobs_status:\n            # A given instance should be processed one at a time\n            self.jobs_status[name] = time.time()\n            self.jobs_results[name] = self.pool.apply_async(self._process, args=(instance,))\n        else:\n            self.log.error(\"Instance: %s skipped because it's already running.\" % name)\n\n    def _process(self, instance):\n        try:\n            statuses = self._check(instance)\n\n            if isinstance(statuses, tuple):\n                # Assume the check only returns one service check\n                status, msg = statuses\n                self.resultsq.put((status, msg, None, instance))\n\n            elif isinstance(statuses, list):\n                for status in statuses:\n                    sc_name, status, msg = status\n                    self.resultsq.put((status, msg, sc_name, instance))\n\n        except Exception:\n            self.log.exception(\n                u\"Failed to process instance '%s'.\", instance.get('name', u\"\")\n            )\n            result = (FAILURE, FAILURE, FAILURE, instance)\n            self.resultsq.put(result)\n\n    def _process_results(self):\n        for i in xrange(MAX_LOOP_ITERATIONS):\n            try:\n                # We want to fetch the result in a non blocking way\n                status, msg, sc_name, instance = self.resultsq.get_nowait()\n            except Empty:\n                break\n\n            instance_name = instance['name']\n            if status == FAILURE:\n                self.nb_failures += 1\n                if self.nb_failures >= self.pool_size - 1:\n                    self.nb_failures = 0\n                    self.restart_pool()\n\n                # clean failed job\n                self._clean_job(instance_name)\n                continue\n\n            self.report_as_service_check(sc_name, status, instance, msg)\n\n            # FIXME: 5.3, this has been deprecated before, get rid of events\n            # Don't create any event to avoid duplicates with server side\n            # service_checks\n            skip_event = _is_affirmative(instance.get('skip_event', False))\n            if not skip_event:\n                self.warning(\"Using events for service checks is deprecated in favor of monitors and will be removed in future versions of the Datadog Agent.\")\n                event = None\n\n                if instance_name not in self.statuses:\n                    self.statuses[instance_name] = defaultdict(list)\n\n                self.statuses[instance_name][sc_name].append(status)\n\n                window = int(instance.get('window', 1))\n\n                if window > 256:\n                    self.log.warning(\"Maximum window size (256) exceeded, defaulting it to 256\")\n                    window = 256\n\n                threshold = instance.get('threshold', 1)\n\n                if len(self.statuses[instance_name][sc_name]) > window:\n                    self.statuses[instance_name][sc_name].pop(0)\n\n                nb_failures = self.statuses[instance_name][sc_name].count(Status.DOWN)\n\n                if nb_failures >= threshold:\n                    if self.notified.get((instance_name, sc_name), Status.UP) != Status.DOWN:\n                        event = self._create_status_event(sc_name, status, msg, instance)\n                        self.notified[(instance_name, sc_name)] = Status.DOWN\n                else:\n                    if self.notified.get((instance_name, sc_name), Status.UP) != Status.UP:\n                        event = self._create_status_event(sc_name, status, msg, instance)\n                        self.notified[(instance_name, sc_name)] = Status.UP\n\n                if event is not None:\n                    self.events.append(event)\n\n            self._clean_job(instance_name)\n\n    def _clean_job(self, instance_name):\n        # The job is finished here, this instance can be re processed\n        if instance_name in self.jobs_status:\n            self.log.debug(\"Instance: %s cleaned from jobs status.\" % instance_name)\n            del self.jobs_status[instance_name]\n\n        # if an exception happened, log it\n        if instance_name in self.jobs_results:\n            self.log.debug(\"Instance: %s cleaned from jobs results.\" % instance_name)\n            ret = self.jobs_results[instance_name].get()\n            if isinstance(ret, Exception):\n                self.log.exception(\"Exception in worker thread: {0}\".format(ret))\n            del self.jobs_results[instance_name]\n\n\n    def _check(self, instance):\n        \"\"\"This function should be implemented by inherited classes\"\"\"\n        raise NotImplementedError\n\n\n    def _clean(self):\n        now = time.time()\n        for name, start_time in self.jobs_status.iteritems():\n            if now - start_time > TIMEOUT:\n                self.log.critical(\"Restarting Pool. One check is stuck: %s\" % name)\n                self.restart_pool()\n                break\n", "path": "checks/network_checks.py"}], "after_files": [{"content": "# (C) Datadog, Inc. 2010-2016\n# All rights reserved\n# Licensed under Simplified BSD License (see LICENSE)\n\n# stdlib\nfrom Queue import Empty, Queue\nimport threading\nimport time\n\n# project\nfrom checks import AgentCheck\nfrom checks.libs.thread_pool import Pool\n\nTIMEOUT = 180\nDEFAULT_SIZE_POOL = 6\nMAX_LOOP_ITERATIONS = 1000\nFAILURE = \"FAILURE\"\n\nclass Status:\n    DOWN = \"DOWN\"\n    WARNING = \"WARNING\"\n    CRITICAL = \"CRITICAL\"\n    UP = \"UP\"\n\n\nclass EventType:\n    DOWN = \"servicecheck.state_change.down\"\n    UP = \"servicecheck.state_change.up\"\n\n\nclass NetworkCheck(AgentCheck):\n    SOURCE_TYPE_NAME = 'servicecheck'\n    SERVICE_CHECK_PREFIX = 'network_check'\n    _global_current_pool_size = 0\n\n    STATUS_TO_SERVICE_CHECK = {\n        Status.UP : AgentCheck.OK,\n        Status.WARNING : AgentCheck.WARNING,\n        Status.CRITICAL : AgentCheck.CRITICAL,\n        Status.DOWN : AgentCheck.CRITICAL,\n    }\n\n    \"\"\"\n    Services checks inherits from this class.\n    This class should never be directly instanciated.\n\n    Work flow:\n        The main agent loop will call the check function for each instance for\n        each iteration of the loop.\n        The check method will make an asynchronous call to the _process method in\n        one of the thread initiated in the thread pool created in this class constructor.\n        The _process method will call the _check method of the inherited class\n        which will perform the actual check.\n\n        The _check method must return a tuple which first element is either\n            Status.UP or Status.DOWN.\n            The second element is a short error message that will be displayed\n            when the service turns down.\n\n    \"\"\"\n\n    def __init__(self, name, init_config, agentConfig, instances):\n        AgentCheck.__init__(self, name, init_config, agentConfig, instances)\n\n        # A dictionary to keep track of service statuses\n        self.statuses = {}\n        self.notified = {}\n        self.nb_failures = 0\n        self.pool_size = 0\n        self.pool_started = False\n\n        # Make sure every instance has a name that we use as a unique key\n        # to keep track of statuses\n        names = []\n        for inst in instances:\n            inst_name = inst.get('name', None)\n            if not inst_name:\n                raise Exception(\"All instances should have a 'name' parameter,\"\n                                \" error on instance: {0}\".format(inst))\n            if inst_name in names:\n                raise Exception(\"Duplicate names for instances with name {0}\"\n                                .format(inst_name))\n            names.append(inst_name)\n\n    def stop(self):\n        self.stop_pool()\n        self.pool_started = False\n\n    def start_pool(self):\n        # The pool size should be the minimum between the number of instances\n        # and the DEFAULT_SIZE_POOL. It can also be overridden by the 'threads_count'\n        # parameter in the init_config of the check\n        self.log.info(\"Starting Thread Pool\")\n        default_size = min(self.instance_count(), DEFAULT_SIZE_POOL)\n        self.pool_size = int(self.init_config.get('threads_count', default_size))\n\n        # To keep track on the total number of threads we should have running\n        NetworkCheck._global_current_pool_size += self.pool_size\n\n        self.pool = Pool(self.pool_size)\n\n        self.resultsq = Queue()\n        self.jobs_status = {}\n        self.jobs_results = {}\n        self.pool_started = True\n\n    def stop_pool(self):\n        self.log.info(\"Stopping Thread Pool\")\n\n        # To keep track on the total number of threads we should have running\n        NetworkCheck._global_current_pool_size -= self.pool_size\n\n        if self.pool_started:\n            self.pool.terminate()\n            self.pool.join()\n            self.jobs_status.clear()\n            assert self.pool.get_nworkers() == 0\n\n    def restart_pool(self):\n        self.stop_pool()\n        self.start_pool()\n\n    def check(self, instance):\n        if not self.pool_started:\n            self.start_pool()\n        if threading.activeCount() > 5 * NetworkCheck._global_current_pool_size + 6:\n            # On Windows the agent runs on multiple threads because of WMI so we need an offset of 6\n            raise Exception(\"Thread number (%s) is exploding. Skipping this check\" % threading.activeCount())\n        self._process_results()\n        self._clean()\n        name = instance.get('name', None)\n        if name is None:\n            self.log.error('Each service check must have a name')\n            return\n\n        if name not in self.jobs_status:\n            # A given instance should be processed one at a time\n            self.jobs_status[name] = time.time()\n            self.jobs_results[name] = self.pool.apply_async(self._process, args=(instance,))\n        else:\n            self.log.error(\"Instance: %s skipped because it's already running.\" % name)\n\n    def _process(self, instance):\n        try:\n            statuses = self._check(instance)\n\n            if isinstance(statuses, tuple):\n                # Assume the check only returns one service check\n                status, msg = statuses\n                self.resultsq.put((status, msg, None, instance))\n\n            elif isinstance(statuses, list):\n                for status in statuses:\n                    sc_name, status, msg = status\n                    self.resultsq.put((status, msg, sc_name, instance))\n\n        except Exception:\n            self.log.exception(\n                u\"Failed to process instance '%s'.\", instance.get('name', u\"\")\n            )\n            result = (FAILURE, FAILURE, FAILURE, instance)\n            self.resultsq.put(result)\n\n    def _process_results(self):\n        for i in xrange(MAX_LOOP_ITERATIONS):\n            try:\n                # We want to fetch the result in a non blocking way\n                status, msg, sc_name, instance = self.resultsq.get_nowait()\n            except Empty:\n                break\n\n            instance_name = instance['name']\n            if status == FAILURE:\n                self.nb_failures += 1\n                if self.nb_failures >= self.pool_size - 1:\n                    self.nb_failures = 0\n                    self.restart_pool()\n\n                # clean failed job\n                self._clean_job(instance_name)\n                continue\n\n            self.report_as_service_check(sc_name, status, instance, msg)\n            self._clean_job(instance_name)\n\n    def _clean_job(self, instance_name):\n        # The job is finished here, this instance can be re processed\n        if instance_name in self.jobs_status:\n            self.log.debug(\"Instance: %s cleaned from jobs status.\" % instance_name)\n            del self.jobs_status[instance_name]\n\n        # if an exception happened, log it\n        if instance_name in self.jobs_results:\n            self.log.debug(\"Instance: %s cleaned from jobs results.\" % instance_name)\n            ret = self.jobs_results[instance_name].get()\n            if isinstance(ret, Exception):\n                self.log.exception(\"Exception in worker thread: {0}\".format(ret))\n            del self.jobs_results[instance_name]\n\n\n    def _check(self, instance):\n        \"\"\"This function should be implemented by inherited classes\"\"\"\n        raise NotImplementedError\n\n\n    def _clean(self):\n        now = time.time()\n        for name, start_time in self.jobs_status.iteritems():\n            if now - start_time > TIMEOUT:\n                self.log.critical(\"Restarting Pool. One check is stuck: %s\" % name)\n                self.restart_pool()\n                break\n", "path": "checks/network_checks.py"}]}