We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[boto] [botocore] importing boto/botocore before gevent patching raises exception
Reported in https://github.com/DataDog/dd-trace-py/issues/506#issuecomment-431692318

This is a similar problem as #632 


To reproduce:

```python
# app.py
import gevent.monkey
gevent.monkey.patch_all()
```

```
$ ddtrace-run python app.py
app.py:2: MonkeyPatchWarning: Monkey-patching ssl after ssl has already been imported may lead to errors, including RecursionError on Python 3.6. It may also silently lead to incorrect behaviour on Python 3.7. Please monkey-patch earlier. See https://github.com/gevent/gevent/issues/1016. Modules that had direct imports (NOT patched): ['botocore.httpsession (/Users/brett.langdon/.env/issue-662/lib/python3.7/site-packages/botocore/httpsession.py)', 'botocore.vendored.requests.packages.urllib3.util.ssl_ (/Users/brett.langdon/.env/issue-662/lib/python3.7/site-packages/botocore/vendored/requests/packages/urllib3/util/ssl_.py)', 'botocore.vendored.requests.packages.urllib3.util (/Users/brett.langdon/.env/issue-662/lib/python3.7/site-packages/botocore/vendored/requests/packages/urllib3/util/__init__.py)', 'urllib3.util (/Users/brett.langdon/.env/issue-662/lib/python3.7/site-packages/urllib3/util/__init__.py)', 'urllib3.util.ssl_ (/Users/brett.langdon/.env/issue-662/lib/python3.7/site-packages/urllib3/util/ssl_.py)'].
  gevent.monkey.patch_all()
```


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `ddtrace/contrib/gevent/__init__.py`
Content:
```
1 """
2 To trace a request in a ``gevent`` environment, configure the tracer to use the greenlet
3 context provider, rather than the default one that relies on a thread-local storaging.
4 
5 This allows the tracer to pick up a transaction exactly where it left off as greenlets
6 yield the context to another one.
7 
8 The simplest way to trace a ``gevent`` application is to configure the tracer and
9 patch ``gevent`` **before importing** the library::
10 
11     # patch before importing gevent
12     from ddtrace import patch, tracer
13     patch(gevent=True)
14 
15     # use gevent as usual with or without the monkey module
16     from gevent import monkey; monkey.patch_thread()
17 
18     def my_parent_function():
19         with tracer.trace("web.request") as span:
20             span.service = "web"
21             gevent.spawn(worker_function)
22 
23     def worker_function():
24         # then trace its child
25         with tracer.trace("greenlet.call") as span:
26             span.service = "greenlet"
27             ...
28 
29             with tracer.trace("greenlet.child_call") as child:
30                 ...
31 """
32 from ...utils.importlib import require_modules
33 
34 
35 required_modules = ['gevent']
36 
37 with require_modules(required_modules) as missing_modules:
38     if not missing_modules:
39         from .provider import GeventContextProvider
40         from .patch import patch, unpatch
41 
42         context_provider = GeventContextProvider()
43 
44         __all__ = [
45             'patch',
46             'unpatch',
47             'context_provider',
48         ]
49
```

Path: `ddtrace/monkey.py`
Content:
```
1 """Patch libraries to be automatically instrumented.
2 
3 It can monkey patch supported standard libraries and third party modules.
4 A patched module will automatically report spans with its default configuration.
5 
6 A library instrumentation can be configured (for instance, to report as another service)
7 using Pin. For that, check its documentation.
8 """
9 import importlib
10 import os
11 import sys
12 import threading
13 
14 from ddtrace.vendor.wrapt.importer import when_imported
15 
16 from .internal.logger import get_logger
17 from .settings import config
18 from .utils import formats
19 
20 
21 log = get_logger(__name__)
22 
23 # Default set of modules to automatically patch or not
24 PATCH_MODULES = {
25     "asyncio": False,
26     "boto": True,
27     "botocore": True,
28     "bottle": False,
29     "cassandra": True,
30     "celery": True,
31     "consul": True,
32     "django": True,
33     "elasticsearch": True,
34     "algoliasearch": True,
35     "futures": False,  # experimental propagation
36     "grpc": True,
37     "mongoengine": True,
38     "mysql": True,
39     "mysqldb": True,
40     "pymysql": True,
41     "psycopg": True,
42     "pylibmc": True,
43     "pymemcache": True,
44     "pymongo": True,
45     "redis": True,
46     "rediscluster": True,
47     "requests": True,
48     "sanic": True,
49     "sqlalchemy": False,  # Prefer DB client instrumentation
50     "sqlite3": True,
51     "aiohttp": True,  # requires asyncio (Python 3.4+)
52     "aiopg": True,
53     "aiobotocore": False,
54     "httplib": False,
55     "vertica": True,
56     "molten": True,
57     "jinja2": True,
58     "mako": True,
59     "flask": True,
60     "kombu": False,
61     # Ignore some web framework integrations that might be configured explicitly in code
62     "falcon": False,
63     "pylons": False,
64     "pyramid": False,
65     # Auto-enable logging if the environment variable DD_LOGS_INJECTION is true
66     "logging": config.logs_injection,
67 }
68 
69 _LOCK = threading.Lock()
70 _PATCHED_MODULES = set()
71 
72 # Modules which are patched on first use
73 # DEV: These modules are patched when the user first imports them, rather than
74 #      explicitly importing and patching them on application startup `ddtrace.patch_all(module=True)`
75 # DEV: This ensures we do not patch a module until it is needed
76 # DEV: <contrib name> => <list of module names that trigger a patch>
77 _PATCH_ON_IMPORT = {
78     "celery": ("celery",),
79     "flask": ("flask, "),
80     "gevent": ("gevent",),
81     "requests": ("requests",),
82 }
83 
84 
85 class PatchException(Exception):
86     """Wraps regular `Exception` class when patching modules"""
87 
88     pass
89 
90 
91 def _on_import_factory(module, raise_errors=True):
92     """Factory to create an import hook for the provided module name"""
93 
94     def on_import(hook):
95         # Import and patch module
96         path = "ddtrace.contrib.%s" % module
97         imported_module = importlib.import_module(path)
98         imported_module.patch()
99 
100     return on_import
101 
102 
103 def patch_all(**patch_modules):
104     """Automatically patches all available modules.
105 
106     In addition to ``patch_modules``, an override can be specified via an
107     environment variable, ``DD_TRACE_<module>_ENABLED`` for each module.
108 
109     ``patch_modules`` have the highest precedence for overriding.
110 
111     :param dict patch_modules: Override whether particular modules are patched or not.
112 
113         >>> patch_all(redis=False, cassandra=False)
114     """
115     modules = PATCH_MODULES.copy()
116 
117     # The enabled setting can be overridden by environment variables
118     for module, enabled in modules.items():
119         env_var = "DD_TRACE_%s_ENABLED" % module.upper()
120         if env_var not in os.environ:
121             continue
122 
123         override_enabled = formats.asbool(os.environ[env_var])
124         modules[module] = override_enabled
125 
126     # Arguments take precedence over the environment and the defaults.
127     modules.update(patch_modules)
128 
129     patch(raise_errors=False, **modules)
130 
131 
132 def patch(raise_errors=True, **patch_modules):
133     """Patch only a set of given modules.
134 
135     :param bool raise_errors: Raise error if one patch fail.
136     :param dict patch_modules: List of modules to patch.
137 
138         >>> patch(psycopg=True, elasticsearch=True)
139     """
140     modules = [m for (m, should_patch) in patch_modules.items() if should_patch]
141     for module in modules:
142         if module in _PATCH_ON_IMPORT:
143             # If the module has already been imported then patch immediately
144             if module in sys.modules:
145                 patch_module(module, raise_errors=raise_errors)
146 
147             # Otherwise, add a hook to patch when it is imported for the first time
148             else:
149                 # Use factory to create handler to close over `module` and `raise_errors` values from this loop
150                 when_imported(module)(_on_import_factory(module, raise_errors))
151 
152                 # manually add module to patched modules
153                 with _LOCK:
154                     _PATCHED_MODULES.add(module)
155         else:
156             patch_module(module, raise_errors=raise_errors)
157 
158     patched_modules = get_patched_modules()
159     log.info(
160         "patched %s/%s modules (%s)", len(patched_modules), len(modules), ",".join(patched_modules),
161     )
162 
163 
164 def patch_module(module, raise_errors=True):
165     """Patch a single module
166 
167     Returns if the module got properly patched.
168     """
169     try:
170         return _patch_module(module)
171     except Exception:
172         if raise_errors:
173             raise
174         log.debug("failed to patch %s", module, exc_info=True)
175         return False
176 
177 
178 def get_patched_modules():
179     """Get the list of patched modules"""
180     with _LOCK:
181         return sorted(_PATCHED_MODULES)
182 
183 
184 def _patch_module(module):
185     """_patch_module will attempt to monkey patch the module.
186 
187     Returns if the module got patched.
188     Can also raise errors if it fails.
189     """
190     path = "ddtrace.contrib.%s" % module
191     with _LOCK:
192         if module in _PATCHED_MODULES and module not in _PATCH_ON_IMPORT:
193             log.debug("already patched: %s", path)
194             return False
195 
196         try:
197             imported_module = importlib.import_module(path)
198             imported_module.patch()
199         except ImportError:
200             # if the import fails, the integration is not available
201             raise PatchException("integration '%s' not available" % path)
202         except AttributeError:
203             # if patch() is not available in the module, it means
204             # that the library is not installed in the environment
205             raise PatchException("module '%s' not installed" % module)
206 
207         _PATCHED_MODULES.add(module)
208         return True
209
```
--- 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/ddtrace/contrib/gevent/__init__.py b/ddtrace/contrib/gevent/__init__.py
--- a/ddtrace/contrib/gevent/__init__.py
+++ b/ddtrace/contrib/gevent/__init__.py
@@ -1,25 +1,40 @@
 """
-To trace a request in a ``gevent`` environment, configure the tracer to use the greenlet
-context provider, rather than the default one that relies on a thread-local storaging.
+The gevent integration adds support for tracing across greenlets.
 
-This allows the tracer to pick up a transaction exactly where it left off as greenlets
-yield the context to another one.
+The integration patches the gevent internals to add context management logic.
+It also configures the global tracer instance to use a gevent context
+provider to utilize the context management logic.
 
-The simplest way to trace a ``gevent`` application is to configure the tracer and
-patch ``gevent`` **before importing** the library::
+If custom tracer instances are being used in a gevent application, then
+configure it with::
 
-    # patch before importing gevent
-    from ddtrace import patch, tracer
+    from ddtrace.contrib.gevent import context_provider
+
+    tracer.configure(context_provider=context_provider)
+
+
+Enabling
+~~~~~~~~
+
+The integration is enabled automatically when using
+:ref:`ddtrace-run<ddtracerun>` or :ref:`patch_all()<patch_all>`.
+
+Or use :ref:`patch()<patch>` to manually enable the integration::
+
+    from ddtrace import patch
     patch(gevent=True)
 
-    # use gevent as usual with or without the monkey module
-    from gevent import monkey; monkey.patch_thread()
+
+**Note:** these calls need to be performed before calling the gevent patching.
+
+Example of the context propagation::
 
     def my_parent_function():
         with tracer.trace("web.request") as span:
             span.service = "web"
             gevent.spawn(worker_function)
 
+
     def worker_function():
         # then trace its child
         with tracer.trace("greenlet.call") as span:
@@ -32,7 +47,7 @@
 from ...utils.importlib import require_modules
 
 
-required_modules = ['gevent']
+required_modules = ["gevent"]
 
 with require_modules(required_modules) as missing_modules:
     if not missing_modules:
@@ -42,7 +57,7 @@
         context_provider = GeventContextProvider()
 
         __all__ = [
-            'patch',
-            'unpatch',
-            'context_provider',
+            "patch",
+            "unpatch",
+            "context_provider",
         ]
diff --git a/ddtrace/monkey.py b/ddtrace/monkey.py
--- a/ddtrace/monkey.py
+++ b/ddtrace/monkey.py
@@ -75,10 +75,14 @@
 # DEV: This ensures we do not patch a module until it is needed
 # DEV: <contrib name> => <list of module names that trigger a patch>
 _PATCH_ON_IMPORT = {
+    "aiohttp": ("aiohttp",),
+    "aiobotocore": ("aiobotocore",),
     "celery": ("celery",),
     "flask": ("flask, "),
     "gevent": ("gevent",),
     "requests": ("requests",),
+    "botocore": ("botocore",),
+    "elasticsearch": ("elasticsearch",),
 }

{"golden_diff": "diff --git a/ddtrace/contrib/gevent/__init__.py b/ddtrace/contrib/gevent/__init__.py\n--- a/ddtrace/contrib/gevent/__init__.py\n+++ b/ddtrace/contrib/gevent/__init__.py\n@@ -1,25 +1,40 @@\n \"\"\"\n-To trace a request in a ``gevent`` environment, configure the tracer to use the greenlet\n-context provider, rather than the default one that relies on a thread-local storaging.\n+The gevent integration adds support for tracing across greenlets.\n \n-This allows the tracer to pick up a transaction exactly where it left off as greenlets\n-yield the context to another one.\n+The integration patches the gevent internals to add context management logic.\n+It also configures the global tracer instance to use a gevent context\n+provider to utilize the context management logic.\n \n-The simplest way to trace a ``gevent`` application is to configure the tracer and\n-patch ``gevent`` **before importing** the library::\n+If custom tracer instances are being used in a gevent application, then\n+configure it with::\n \n-    # patch before importing gevent\n-    from ddtrace import patch, tracer\n+    from ddtrace.contrib.gevent import context_provider\n+\n+    tracer.configure(context_provider=context_provider)\n+\n+\n+Enabling\n+~~~~~~~~\n+\n+The integration is enabled automatically when using\n+:ref:`ddtrace-run<ddtracerun>` or :ref:`patch_all()<patch_all>`.\n+\n+Or use :ref:`patch()<patch>` to manually enable the integration::\n+\n+    from ddtrace import patch\n     patch(gevent=True)\n \n-    # use gevent as usual with or without the monkey module\n-    from gevent import monkey; monkey.patch_thread()\n+\n+**Note:** these calls need to be performed before calling the gevent patching.\n+\n+Example of the context propagation::\n \n     def my_parent_function():\n         with tracer.trace(\"web.request\") as span:\n             span.service = \"web\"\n             gevent.spawn(worker_function)\n \n+\n     def worker_function():\n         # then trace its child\n         with tracer.trace(\"greenlet.call\") as span:\n@@ -32,7 +47,7 @@\n from ...utils.importlib import require_modules\n \n \n-required_modules = ['gevent']\n+required_modules = [\"gevent\"]\n \n with require_modules(required_modules) as missing_modules:\n     if not missing_modules:\n@@ -42,7 +57,7 @@\n         context_provider = GeventContextProvider()\n \n         __all__ = [\n-            'patch',\n-            'unpatch',\n-            'context_provider',\n+            \"patch\",\n+            \"unpatch\",\n+            \"context_provider\",\n         ]\ndiff --git a/ddtrace/monkey.py b/ddtrace/monkey.py\n--- a/ddtrace/monkey.py\n+++ b/ddtrace/monkey.py\n@@ -75,10 +75,14 @@\n # DEV: This ensures we do not patch a module until it is needed\n # DEV: <contrib name> => <list of module names that trigger a patch>\n _PATCH_ON_IMPORT = {\n+    \"aiohttp\": (\"aiohttp\",),\n+    \"aiobotocore\": (\"aiobotocore\",),\n     \"celery\": (\"celery\",),\n     \"flask\": (\"flask, \"),\n     \"gevent\": (\"gevent\",),\n     \"requests\": (\"requests\",),\n+    \"botocore\": (\"botocore\",),\n+    \"elasticsearch\": (\"elasticsearch\",),\n }\n", "issue": "[boto] [botocore] importing boto/botocore before gevent patching raises exception\nReported in https://github.com/DataDog/dd-trace-py/issues/506#issuecomment-431692318\r\n\r\nThis is a similar problem as #632 \r\n\r\n\r\nTo reproduce:\r\n\r\n```python\r\n# app.py\r\nimport gevent.monkey\r\ngevent.monkey.patch_all()\r\n```\r\n\r\n```\r\n$ ddtrace-run python app.py\r\napp.py:2: MonkeyPatchWarning: Monkey-patching ssl after ssl has already been imported may lead to errors, including RecursionError on Python 3.6. It may also silently lead to incorrect behaviour on Python 3.7. Please monkey-patch earlier. See https://github.com/gevent/gevent/issues/1016. Modules that had direct imports (NOT patched): ['botocore.httpsession (/Users/brett.langdon/.env/issue-662/lib/python3.7/site-packages/botocore/httpsession.py)', 'botocore.vendored.requests.packages.urllib3.util.ssl_ (/Users/brett.langdon/.env/issue-662/lib/python3.7/site-packages/botocore/vendored/requests/packages/urllib3/util/ssl_.py)', 'botocore.vendored.requests.packages.urllib3.util (/Users/brett.langdon/.env/issue-662/lib/python3.7/site-packages/botocore/vendored/requests/packages/urllib3/util/__init__.py)', 'urllib3.util (/Users/brett.langdon/.env/issue-662/lib/python3.7/site-packages/urllib3/util/__init__.py)', 'urllib3.util.ssl_ (/Users/brett.langdon/.env/issue-662/lib/python3.7/site-packages/urllib3/util/ssl_.py)'].\r\n  gevent.monkey.patch_all()\r\n```\r\n\n", "before_files": [{"content": "\"\"\"\nTo trace a request in a ``gevent`` environment, configure the tracer to use the greenlet\ncontext provider, rather than the default one that relies on a thread-local storaging.\n\nThis allows the tracer to pick up a transaction exactly where it left off as greenlets\nyield the context to another one.\n\nThe simplest way to trace a ``gevent`` application is to configure the tracer and\npatch ``gevent`` **before importing** the library::\n\n    # patch before importing gevent\n    from ddtrace import patch, tracer\n    patch(gevent=True)\n\n    # use gevent as usual with or without the monkey module\n    from gevent import monkey; monkey.patch_thread()\n\n    def my_parent_function():\n        with tracer.trace(\"web.request\") as span:\n            span.service = \"web\"\n            gevent.spawn(worker_function)\n\n    def worker_function():\n        # then trace its child\n        with tracer.trace(\"greenlet.call\") as span:\n            span.service = \"greenlet\"\n            ...\n\n            with tracer.trace(\"greenlet.child_call\") as child:\n                ...\n\"\"\"\nfrom ...utils.importlib import require_modules\n\n\nrequired_modules = ['gevent']\n\nwith require_modules(required_modules) as missing_modules:\n    if not missing_modules:\n        from .provider import GeventContextProvider\n        from .patch import patch, unpatch\n\n        context_provider = GeventContextProvider()\n\n        __all__ = [\n            'patch',\n            'unpatch',\n            'context_provider',\n        ]\n", "path": "ddtrace/contrib/gevent/__init__.py"}, {"content": "\"\"\"Patch libraries to be automatically instrumented.\n\nIt can monkey patch supported standard libraries and third party modules.\nA patched module will automatically report spans with its default configuration.\n\nA library instrumentation can be configured (for instance, to report as another service)\nusing Pin. For that, check its documentation.\n\"\"\"\nimport importlib\nimport os\nimport sys\nimport threading\n\nfrom ddtrace.vendor.wrapt.importer import when_imported\n\nfrom .internal.logger import get_logger\nfrom .settings import config\nfrom .utils import formats\n\n\nlog = get_logger(__name__)\n\n# Default set of modules to automatically patch or not\nPATCH_MODULES = {\n    \"asyncio\": False,\n    \"boto\": True,\n    \"botocore\": True,\n    \"bottle\": False,\n    \"cassandra\": True,\n    \"celery\": True,\n    \"consul\": True,\n    \"django\": True,\n    \"elasticsearch\": True,\n    \"algoliasearch\": True,\n    \"futures\": False,  # experimental propagation\n    \"grpc\": True,\n    \"mongoengine\": True,\n    \"mysql\": True,\n    \"mysqldb\": True,\n    \"pymysql\": True,\n    \"psycopg\": True,\n    \"pylibmc\": True,\n    \"pymemcache\": True,\n    \"pymongo\": True,\n    \"redis\": True,\n    \"rediscluster\": True,\n    \"requests\": True,\n    \"sanic\": True,\n    \"sqlalchemy\": False,  # Prefer DB client instrumentation\n    \"sqlite3\": True,\n    \"aiohttp\": True,  # requires asyncio (Python 3.4+)\n    \"aiopg\": True,\n    \"aiobotocore\": False,\n    \"httplib\": False,\n    \"vertica\": True,\n    \"molten\": True,\n    \"jinja2\": True,\n    \"mako\": True,\n    \"flask\": True,\n    \"kombu\": False,\n    # Ignore some web framework integrations that might be configured explicitly in code\n    \"falcon\": False,\n    \"pylons\": False,\n    \"pyramid\": False,\n    # Auto-enable logging if the environment variable DD_LOGS_INJECTION is true\n    \"logging\": config.logs_injection,\n}\n\n_LOCK = threading.Lock()\n_PATCHED_MODULES = set()\n\n# Modules which are patched on first use\n# DEV: These modules are patched when the user first imports them, rather than\n#      explicitly importing and patching them on application startup `ddtrace.patch_all(module=True)`\n# DEV: This ensures we do not patch a module until it is needed\n# DEV: <contrib name> => <list of module names that trigger a patch>\n_PATCH_ON_IMPORT = {\n    \"celery\": (\"celery\",),\n    \"flask\": (\"flask, \"),\n    \"gevent\": (\"gevent\",),\n    \"requests\": (\"requests\",),\n}\n\n\nclass PatchException(Exception):\n    \"\"\"Wraps regular `Exception` class when patching modules\"\"\"\n\n    pass\n\n\ndef _on_import_factory(module, raise_errors=True):\n    \"\"\"Factory to create an import hook for the provided module name\"\"\"\n\n    def on_import(hook):\n        # Import and patch module\n        path = \"ddtrace.contrib.%s\" % module\n        imported_module = importlib.import_module(path)\n        imported_module.patch()\n\n    return on_import\n\n\ndef patch_all(**patch_modules):\n    \"\"\"Automatically patches all available modules.\n\n    In addition to ``patch_modules``, an override can be specified via an\n    environment variable, ``DD_TRACE_<module>_ENABLED`` for each module.\n\n    ``patch_modules`` have the highest precedence for overriding.\n\n    :param dict patch_modules: Override whether particular modules are patched or not.\n\n        >>> patch_all(redis=False, cassandra=False)\n    \"\"\"\n    modules = PATCH_MODULES.copy()\n\n    # The enabled setting can be overridden by environment variables\n    for module, enabled in modules.items():\n        env_var = \"DD_TRACE_%s_ENABLED\" % module.upper()\n        if env_var not in os.environ:\n            continue\n\n        override_enabled = formats.asbool(os.environ[env_var])\n        modules[module] = override_enabled\n\n    # Arguments take precedence over the environment and the defaults.\n    modules.update(patch_modules)\n\n    patch(raise_errors=False, **modules)\n\n\ndef patch(raise_errors=True, **patch_modules):\n    \"\"\"Patch only a set of given modules.\n\n    :param bool raise_errors: Raise error if one patch fail.\n    :param dict patch_modules: List of modules to patch.\n\n        >>> patch(psycopg=True, elasticsearch=True)\n    \"\"\"\n    modules = [m for (m, should_patch) in patch_modules.items() if should_patch]\n    for module in modules:\n        if module in _PATCH_ON_IMPORT:\n            # If the module has already been imported then patch immediately\n            if module in sys.modules:\n                patch_module(module, raise_errors=raise_errors)\n\n            # Otherwise, add a hook to patch when it is imported for the first time\n            else:\n                # Use factory to create handler to close over `module` and `raise_errors` values from this loop\n                when_imported(module)(_on_import_factory(module, raise_errors))\n\n                # manually add module to patched modules\n                with _LOCK:\n                    _PATCHED_MODULES.add(module)\n        else:\n            patch_module(module, raise_errors=raise_errors)\n\n    patched_modules = get_patched_modules()\n    log.info(\n        \"patched %s/%s modules (%s)\", len(patched_modules), len(modules), \",\".join(patched_modules),\n    )\n\n\ndef patch_module(module, raise_errors=True):\n    \"\"\"Patch a single module\n\n    Returns if the module got properly patched.\n    \"\"\"\n    try:\n        return _patch_module(module)\n    except Exception:\n        if raise_errors:\n            raise\n        log.debug(\"failed to patch %s\", module, exc_info=True)\n        return False\n\n\ndef get_patched_modules():\n    \"\"\"Get the list of patched modules\"\"\"\n    with _LOCK:\n        return sorted(_PATCHED_MODULES)\n\n\ndef _patch_module(module):\n    \"\"\"_patch_module will attempt to monkey patch the module.\n\n    Returns if the module got patched.\n    Can also raise errors if it fails.\n    \"\"\"\n    path = \"ddtrace.contrib.%s\" % module\n    with _LOCK:\n        if module in _PATCHED_MODULES and module not in _PATCH_ON_IMPORT:\n            log.debug(\"already patched: %s\", path)\n            return False\n\n        try:\n            imported_module = importlib.import_module(path)\n            imported_module.patch()\n        except ImportError:\n            # if the import fails, the integration is not available\n            raise PatchException(\"integration '%s' not available\" % path)\n        except AttributeError:\n            # if patch() is not available in the module, it means\n            # that the library is not installed in the environment\n            raise PatchException(\"module '%s' not installed\" % module)\n\n        _PATCHED_MODULES.add(module)\n        return True\n", "path": "ddtrace/monkey.py"}], "after_files": [{"content": "\"\"\"\nThe gevent integration adds support for tracing across greenlets.\n\nThe integration patches the gevent internals to add context management logic.\nIt also configures the global tracer instance to use a gevent context\nprovider to utilize the context management logic.\n\nIf custom tracer instances are being used in a gevent application, then\nconfigure it with::\n\n    from ddtrace.contrib.gevent import context_provider\n\n    tracer.configure(context_provider=context_provider)\n\n\nEnabling\n~~~~~~~~\n\nThe integration is enabled automatically when using\n:ref:`ddtrace-run<ddtracerun>` or :ref:`patch_all()<patch_all>`.\n\nOr use :ref:`patch()<patch>` to manually enable the integration::\n\n    from ddtrace import patch\n    patch(gevent=True)\n\n\n**Note:** these calls need to be performed before calling the gevent patching.\n\nExample of the context propagation::\n\n    def my_parent_function():\n        with tracer.trace(\"web.request\") as span:\n            span.service = \"web\"\n            gevent.spawn(worker_function)\n\n\n    def worker_function():\n        # then trace its child\n        with tracer.trace(\"greenlet.call\") as span:\n            span.service = \"greenlet\"\n            ...\n\n            with tracer.trace(\"greenlet.child_call\") as child:\n                ...\n\"\"\"\nfrom ...utils.importlib import require_modules\n\n\nrequired_modules = [\"gevent\"]\n\nwith require_modules(required_modules) as missing_modules:\n    if not missing_modules:\n        from .provider import GeventContextProvider\n        from .patch import patch, unpatch\n\n        context_provider = GeventContextProvider()\n\n        __all__ = [\n            \"patch\",\n            \"unpatch\",\n            \"context_provider\",\n        ]\n", "path": "ddtrace/contrib/gevent/__init__.py"}, {"content": "\"\"\"Patch libraries to be automatically instrumented.\n\nIt can monkey patch supported standard libraries and third party modules.\nA patched module will automatically report spans with its default configuration.\n\nA library instrumentation can be configured (for instance, to report as another service)\nusing Pin. For that, check its documentation.\n\"\"\"\nimport importlib\nimport os\nimport sys\nimport threading\n\nfrom ddtrace.vendor.wrapt.importer import when_imported\n\nfrom .internal.logger import get_logger\nfrom .settings import config\nfrom .utils import formats\n\n\nlog = get_logger(__name__)\n\n# Default set of modules to automatically patch or not\nPATCH_MODULES = {\n    \"asyncio\": False,\n    \"boto\": True,\n    \"botocore\": True,\n    \"bottle\": False,\n    \"cassandra\": True,\n    \"celery\": True,\n    \"consul\": True,\n    \"django\": True,\n    \"elasticsearch\": True,\n    \"algoliasearch\": True,\n    \"futures\": False,  # experimental propagation\n    \"grpc\": True,\n    \"mongoengine\": True,\n    \"mysql\": True,\n    \"mysqldb\": True,\n    \"pymysql\": True,\n    \"psycopg\": True,\n    \"pylibmc\": True,\n    \"pymemcache\": True,\n    \"pymongo\": True,\n    \"redis\": True,\n    \"rediscluster\": True,\n    \"requests\": True,\n    \"sanic\": True,\n    \"sqlalchemy\": False,  # Prefer DB client instrumentation\n    \"sqlite3\": True,\n    \"aiohttp\": True,  # requires asyncio (Python 3.4+)\n    \"aiopg\": True,\n    \"aiobotocore\": False,\n    \"httplib\": False,\n    \"vertica\": True,\n    \"molten\": True,\n    \"jinja2\": True,\n    \"mako\": True,\n    \"flask\": True,\n    \"kombu\": False,\n    # Ignore some web framework integrations that might be configured explicitly in code\n    \"falcon\": False,\n    \"pylons\": False,\n    \"pyramid\": False,\n    # Auto-enable logging if the environment variable DD_LOGS_INJECTION is true\n    \"logging\": config.logs_injection,\n}\n\n_LOCK = threading.Lock()\n_PATCHED_MODULES = set()\n\n# Modules which are patched on first use\n# DEV: These modules are patched when the user first imports them, rather than\n#      explicitly importing and patching them on application startup `ddtrace.patch_all(module=True)`\n# DEV: This ensures we do not patch a module until it is needed\n# DEV: <contrib name> => <list of module names that trigger a patch>\n_PATCH_ON_IMPORT = {\n    \"aiohttp\": (\"aiohttp\",),\n    \"aiobotocore\": (\"aiobotocore\",),\n    \"celery\": (\"celery\",),\n    \"flask\": (\"flask, \"),\n    \"gevent\": (\"gevent\",),\n    \"requests\": (\"requests\",),\n    \"botocore\": (\"botocore\",),\n    \"elasticsearch\": (\"elasticsearch\",),\n}\n\n\nclass PatchException(Exception):\n    \"\"\"Wraps regular `Exception` class when patching modules\"\"\"\n\n    pass\n\n\ndef _on_import_factory(module, raise_errors=True):\n    \"\"\"Factory to create an import hook for the provided module name\"\"\"\n\n    def on_import(hook):\n        # Import and patch module\n        path = \"ddtrace.contrib.%s\" % module\n        imported_module = importlib.import_module(path)\n        imported_module.patch()\n\n    return on_import\n\n\ndef patch_all(**patch_modules):\n    \"\"\"Automatically patches all available modules.\n\n    In addition to ``patch_modules``, an override can be specified via an\n    environment variable, ``DD_TRACE_<module>_ENABLED`` for each module.\n\n    ``patch_modules`` have the highest precedence for overriding.\n\n    :param dict patch_modules: Override whether particular modules are patched or not.\n\n        >>> patch_all(redis=False, cassandra=False)\n    \"\"\"\n    modules = PATCH_MODULES.copy()\n\n    # The enabled setting can be overridden by environment variables\n    for module, enabled in modules.items():\n        env_var = \"DD_TRACE_%s_ENABLED\" % module.upper()\n        if env_var not in os.environ:\n            continue\n\n        override_enabled = formats.asbool(os.environ[env_var])\n        modules[module] = override_enabled\n\n    # Arguments take precedence over the environment and the defaults.\n    modules.update(patch_modules)\n\n    patch(raise_errors=False, **modules)\n\n\ndef patch(raise_errors=True, **patch_modules):\n    \"\"\"Patch only a set of given modules.\n\n    :param bool raise_errors: Raise error if one patch fail.\n    :param dict patch_modules: List of modules to patch.\n\n        >>> patch(psycopg=True, elasticsearch=True)\n    \"\"\"\n    modules = [m for (m, should_patch) in patch_modules.items() if should_patch]\n    for module in modules:\n        if module in _PATCH_ON_IMPORT:\n            # If the module has already been imported then patch immediately\n            if module in sys.modules:\n                patch_module(module, raise_errors=raise_errors)\n\n            # Otherwise, add a hook to patch when it is imported for the first time\n            else:\n                # Use factory to create handler to close over `module` and `raise_errors` values from this loop\n                when_imported(module)(_on_import_factory(module, raise_errors))\n\n                # manually add module to patched modules\n                with _LOCK:\n                    _PATCHED_MODULES.add(module)\n        else:\n            patch_module(module, raise_errors=raise_errors)\n\n    patched_modules = get_patched_modules()\n    log.info(\n        \"patched %s/%s modules (%s)\", len(patched_modules), len(modules), \",\".join(patched_modules),\n    )\n\n\ndef patch_module(module, raise_errors=True):\n    \"\"\"Patch a single module\n\n    Returns if the module got properly patched.\n    \"\"\"\n    try:\n        return _patch_module(module)\n    except Exception:\n        if raise_errors:\n            raise\n        log.debug(\"failed to patch %s\", module, exc_info=True)\n        return False\n\n\ndef get_patched_modules():\n    \"\"\"Get the list of patched modules\"\"\"\n    with _LOCK:\n        return sorted(_PATCHED_MODULES)\n\n\ndef _patch_module(module):\n    \"\"\"_patch_module will attempt to monkey patch the module.\n\n    Returns if the module got patched.\n    Can also raise errors if it fails.\n    \"\"\"\n    path = \"ddtrace.contrib.%s\" % module\n    with _LOCK:\n        if module in _PATCHED_MODULES and module not in _PATCH_ON_IMPORT:\n            log.debug(\"already patched: %s\", path)\n            return False\n\n        try:\n            imported_module = importlib.import_module(path)\n            imported_module.patch()\n        except ImportError:\n            # if the import fails, the integration is not available\n            raise PatchException(\"integration '%s' not available\" % path)\n        except AttributeError:\n            # if patch() is not available in the module, it means\n            # that the library is not installed in the environment\n            raise PatchException(\"module '%s' not installed\" % module)\n\n        _PATCHED_MODULES.add(module)\n        return True\n", "path": "ddtrace/monkey.py"}]}