We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add dogpile.cache to support libraries
We need to update https://github.com/DataDog/dd-trace-py/blob/master/docs/index.rst after #1123 

--- 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/dogpile_cache/__init__.py`
Content:
```
1 """
2 Instrument dogpile.cache__ to report all cached lookups.
3 
4 This will add spans around the calls to your cache backend (eg. redis, memory,
5 etc). The spans will also include the following tags:
6 
7 - key/keys: The key(s) dogpile passed to your backend. Note that this will be
8   the output of the region's ``function_key_generator``, but before any key
9   mangling is applied (ie. the region's ``key_mangler``).
10 - region: Name of the region.
11 - backend: Name of the backend class.
12 - hit: If the key was found in the cache.
13 - expired: If the key is expired. This is only relevant if the key was found.
14 
15 While cache tracing will generally already have keys in tags, some caching
16 setups will not have useful tag values - such as when you're using consistent
17 hashing with memcached - the key(s) will appear as a mangled hash.
18 ::
19 
20     # Patch before importing dogpile.cache
21     from ddtrace import patch
22     patch(dogpile_cache=True)
23 
24     from dogpile.cache import make_region
25 
26     region = make_region().configure(
27         "dogpile.cache.pylibmc",
28         expiration_time=3600,
29         arguments={"url": ["127.0.0.1"]},
30     )
31 
32     @region.cache_on_arguments()
33     def hello(name):
34         # Some complicated, slow calculation
35         return "Hello, {}".format(name)
36 
37 .. __: https://dogpilecache.sqlalchemy.org/
38 """
39 from ...utils.importlib import require_modules
40 
41 
42 required_modules = ["dogpile.cache"]
43 
44 with require_modules(required_modules) as missing_modules:
45     if not missing_modules:
46         from .patch import patch
47         from .patch import unpatch
48 
49         __all__ = ["patch", "unpatch"]
50
```

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": True,
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     "starlette": True,
62     # Ignore some web framework integrations that might be configured explicitly in code
63     "falcon": False,
64     "pylons": False,
65     "pyramid": False,
66     # Auto-enable logging if the environment variable DD_LOGS_INJECTION is true
67     "logging": config.logs_injection,
68     "pynamodb": True,
69     "pyodbc": True,
70     "fastapi": True,
71 }
72 
73 _LOCK = threading.Lock()
74 _PATCHED_MODULES = set()
75 
76 # Modules which are patched on first use
77 # DEV: These modules are patched when the user first imports them, rather than
78 #      explicitly importing and patching them on application startup `ddtrace.patch_all(module=True)`
79 # DEV: This ensures we do not patch a module until it is needed
80 # DEV: <contrib name> => <list of module names that trigger a patch>
81 _PATCH_ON_IMPORT = {
82     "aiohttp": ("aiohttp",),
83     "aiobotocore": ("aiobotocore",),
84     "celery": ("celery",),
85     "flask": ("flask, "),
86     "gevent": ("gevent",),
87     "requests": ("requests",),
88     "botocore": ("botocore",),
89     "elasticsearch": ("elasticsearch",),
90     "pynamodb": ("pynamodb",),
91 }
92 
93 
94 class PatchException(Exception):
95     """Wraps regular `Exception` class when patching modules"""
96 
97     pass
98 
99 
100 class ModuleNotFoundException(PatchException):
101     pass
102 
103 
104 def _on_import_factory(module, raise_errors=True):
105     """Factory to create an import hook for the provided module name"""
106 
107     def on_import(hook):
108         # Import and patch module
109         path = "ddtrace.contrib.%s" % module
110         imported_module = importlib.import_module(path)
111         imported_module.patch()
112 
113     return on_import
114 
115 
116 def patch_all(**patch_modules):
117     """Automatically patches all available modules.
118 
119     In addition to ``patch_modules``, an override can be specified via an
120     environment variable, ``DD_TRACE_<module>_ENABLED`` for each module.
121 
122     ``patch_modules`` have the highest precedence for overriding.
123 
124     :param dict patch_modules: Override whether particular modules are patched or not.
125 
126         >>> patch_all(redis=False, cassandra=False)
127     """
128     modules = PATCH_MODULES.copy()
129 
130     # The enabled setting can be overridden by environment variables
131     for module, enabled in modules.items():
132         env_var = "DD_TRACE_%s_ENABLED" % module.upper()
133         if env_var not in os.environ:
134             continue
135 
136         override_enabled = formats.asbool(os.environ[env_var])
137         modules[module] = override_enabled
138 
139     # Arguments take precedence over the environment and the defaults.
140     modules.update(patch_modules)
141 
142     patch(raise_errors=False, **modules)
143 
144 
145 def patch(raise_errors=True, **patch_modules):
146     """Patch only a set of given modules.
147 
148     :param bool raise_errors: Raise error if one patch fail.
149     :param dict patch_modules: List of modules to patch.
150 
151         >>> patch(psycopg=True, elasticsearch=True)
152     """
153     modules = [m for (m, should_patch) in patch_modules.items() if should_patch]
154     for module in modules:
155         if module in _PATCH_ON_IMPORT:
156             # If the module has already been imported then patch immediately
157             if module in sys.modules:
158                 patch_module(module, raise_errors=raise_errors)
159 
160             # Otherwise, add a hook to patch when it is imported for the first time
161             else:
162                 # Use factory to create handler to close over `module` and `raise_errors` values from this loop
163                 when_imported(module)(_on_import_factory(module, raise_errors))
164 
165                 # manually add module to patched modules
166                 with _LOCK:
167                     _PATCHED_MODULES.add(module)
168         else:
169             patch_module(module, raise_errors=raise_errors)
170 
171     patched_modules = get_patched_modules()
172     log.info(
173         "patched %s/%s modules (%s)",
174         len(patched_modules),
175         len(modules),
176         ",".join(patched_modules),
177     )
178 
179 
180 def patch_module(module, raise_errors=True):
181     """Patch a single module
182 
183     Returns if the module got properly patched.
184     """
185     try:
186         return _patch_module(module)
187     except ModuleNotFoundException:
188         if raise_errors:
189             raise
190         return False
191     except Exception:
192         if raise_errors:
193             raise
194         log.debug("failed to patch %s", module, exc_info=True)
195         return False
196 
197 
198 def get_patched_modules():
199     """Get the list of patched modules"""
200     with _LOCK:
201         return sorted(_PATCHED_MODULES)
202 
203 
204 def _patch_module(module):
205     """_patch_module will attempt to monkey patch the module.
206 
207     Returns if the module got patched.
208     Can also raise errors if it fails.
209     """
210     path = "ddtrace.contrib.%s" % module
211     with _LOCK:
212         if module in _PATCHED_MODULES and module not in _PATCH_ON_IMPORT:
213             log.debug("already patched: %s", path)
214             return False
215 
216         try:
217             imported_module = importlib.import_module(path)
218         except ImportError:
219             # if the import fails, the integration is not available
220             raise PatchException("integration '%s' not available" % path)
221         else:
222             # if patch() is not available in the module, it means
223             # that the library is not installed in the environment
224             if not hasattr(imported_module, "patch"):
225                 raise ModuleNotFoundException("module '%s' not installed" % module)
226 
227             imported_module.patch()
228             _PATCHED_MODULES.add(module)
229             return True
230
```
--- 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/dogpile_cache/__init__.py b/ddtrace/contrib/dogpile_cache/__init__.py
--- a/ddtrace/contrib/dogpile_cache/__init__.py
+++ b/ddtrace/contrib/dogpile_cache/__init__.py
@@ -1,12 +1,12 @@
 """
 Instrument dogpile.cache__ to report all cached lookups.
 
-This will add spans around the calls to your cache backend (eg. redis, memory,
+This will add spans around the calls to your cache backend (e.g. redis, memory,
 etc). The spans will also include the following tags:
 
 - key/keys: The key(s) dogpile passed to your backend. Note that this will be
   the output of the region's ``function_key_generator``, but before any key
-  mangling is applied (ie. the region's ``key_mangler``).
+  mangling is applied (i.e. the region's ``key_mangler``).
 - region: Name of the region.
 - backend: Name of the backend class.
 - hit: If the key was found in the cache.
diff --git a/ddtrace/monkey.py b/ddtrace/monkey.py
--- a/ddtrace/monkey.py
+++ b/ddtrace/monkey.py
@@ -68,6 +68,7 @@
     "pynamodb": True,
     "pyodbc": True,
     "fastapi": True,
+    "dogpile_cache": True,
 }
 
 _LOCK = threading.Lock()

{"golden_diff": "diff --git a/ddtrace/contrib/dogpile_cache/__init__.py b/ddtrace/contrib/dogpile_cache/__init__.py\n--- a/ddtrace/contrib/dogpile_cache/__init__.py\n+++ b/ddtrace/contrib/dogpile_cache/__init__.py\n@@ -1,12 +1,12 @@\n \"\"\"\n Instrument dogpile.cache__ to report all cached lookups.\n \n-This will add spans around the calls to your cache backend (eg. redis, memory,\n+This will add spans around the calls to your cache backend (e.g. redis, memory,\n etc). The spans will also include the following tags:\n \n - key/keys: The key(s) dogpile passed to your backend. Note that this will be\n   the output of the region's ``function_key_generator``, but before any key\n-  mangling is applied (ie. the region's ``key_mangler``).\n+  mangling is applied (i.e. the region's ``key_mangler``).\n - region: Name of the region.\n - backend: Name of the backend class.\n - hit: If the key was found in the cache.\ndiff --git a/ddtrace/monkey.py b/ddtrace/monkey.py\n--- a/ddtrace/monkey.py\n+++ b/ddtrace/monkey.py\n@@ -68,6 +68,7 @@\n     \"pynamodb\": True,\n     \"pyodbc\": True,\n     \"fastapi\": True,\n+    \"dogpile_cache\": True,\n }\n \n _LOCK = threading.Lock()\n", "issue": "Add dogpile.cache to support libraries\nWe need to update https://github.com/DataDog/dd-trace-py/blob/master/docs/index.rst after #1123 \n", "before_files": [{"content": "\"\"\"\nInstrument dogpile.cache__ to report all cached lookups.\n\nThis will add spans around the calls to your cache backend (eg. redis, memory,\netc). The spans will also include the following tags:\n\n- key/keys: The key(s) dogpile passed to your backend. Note that this will be\n  the output of the region's ``function_key_generator``, but before any key\n  mangling is applied (ie. the region's ``key_mangler``).\n- region: Name of the region.\n- backend: Name of the backend class.\n- hit: If the key was found in the cache.\n- expired: If the key is expired. This is only relevant if the key was found.\n\nWhile cache tracing will generally already have keys in tags, some caching\nsetups will not have useful tag values - such as when you're using consistent\nhashing with memcached - the key(s) will appear as a mangled hash.\n::\n\n    # Patch before importing dogpile.cache\n    from ddtrace import patch\n    patch(dogpile_cache=True)\n\n    from dogpile.cache import make_region\n\n    region = make_region().configure(\n        \"dogpile.cache.pylibmc\",\n        expiration_time=3600,\n        arguments={\"url\": [\"127.0.0.1\"]},\n    )\n\n    @region.cache_on_arguments()\n    def hello(name):\n        # Some complicated, slow calculation\n        return \"Hello, {}\".format(name)\n\n.. __: https://dogpilecache.sqlalchemy.org/\n\"\"\"\nfrom ...utils.importlib import require_modules\n\n\nrequired_modules = [\"dogpile.cache\"]\n\nwith require_modules(required_modules) as missing_modules:\n    if not missing_modules:\n        from .patch import patch\n        from .patch import unpatch\n\n        __all__ = [\"patch\", \"unpatch\"]\n", "path": "ddtrace/contrib/dogpile_cache/__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\": True,\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    \"starlette\": True,\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    \"pynamodb\": True,\n    \"pyodbc\": True,\n    \"fastapi\": True,\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    \"pynamodb\": (\"pynamodb\",),\n}\n\n\nclass PatchException(Exception):\n    \"\"\"Wraps regular `Exception` class when patching modules\"\"\"\n\n    pass\n\n\nclass ModuleNotFoundException(PatchException):\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)\",\n        len(patched_modules),\n        len(modules),\n        \",\".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 ModuleNotFoundException:\n        if raise_errors:\n            raise\n        return False\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        except ImportError:\n            # if the import fails, the integration is not available\n            raise PatchException(\"integration '%s' not available\" % path)\n        else:\n            # if patch() is not available in the module, it means\n            # that the library is not installed in the environment\n            if not hasattr(imported_module, \"patch\"):\n                raise ModuleNotFoundException(\"module '%s' not installed\" % module)\n\n            imported_module.patch()\n            _PATCHED_MODULES.add(module)\n            return True\n", "path": "ddtrace/monkey.py"}], "after_files": [{"content": "\"\"\"\nInstrument dogpile.cache__ to report all cached lookups.\n\nThis will add spans around the calls to your cache backend (e.g. redis, memory,\netc). The spans will also include the following tags:\n\n- key/keys: The key(s) dogpile passed to your backend. Note that this will be\n  the output of the region's ``function_key_generator``, but before any key\n  mangling is applied (i.e. the region's ``key_mangler``).\n- region: Name of the region.\n- backend: Name of the backend class.\n- hit: If the key was found in the cache.\n- expired: If the key is expired. This is only relevant if the key was found.\n\nWhile cache tracing will generally already have keys in tags, some caching\nsetups will not have useful tag values - such as when you're using consistent\nhashing with memcached - the key(s) will appear as a mangled hash.\n::\n\n    # Patch before importing dogpile.cache\n    from ddtrace import patch\n    patch(dogpile_cache=True)\n\n    from dogpile.cache import make_region\n\n    region = make_region().configure(\n        \"dogpile.cache.pylibmc\",\n        expiration_time=3600,\n        arguments={\"url\": [\"127.0.0.1\"]},\n    )\n\n    @region.cache_on_arguments()\n    def hello(name):\n        # Some complicated, slow calculation\n        return \"Hello, {}\".format(name)\n\n.. __: https://dogpilecache.sqlalchemy.org/\n\"\"\"\nfrom ...utils.importlib import require_modules\n\n\nrequired_modules = [\"dogpile.cache\"]\n\nwith require_modules(required_modules) as missing_modules:\n    if not missing_modules:\n        from .patch import patch\n        from .patch import unpatch\n\n        __all__ = [\"patch\", \"unpatch\"]\n", "path": "ddtrace/contrib/dogpile_cache/__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\": True,\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    \"starlette\": True,\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    \"pynamodb\": True,\n    \"pyodbc\": True,\n    \"fastapi\": True,\n    \"dogpile_cache\": True,\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    \"pynamodb\": (\"pynamodb\",),\n}\n\n\nclass PatchException(Exception):\n    \"\"\"Wraps regular `Exception` class when patching modules\"\"\"\n\n    pass\n\n\nclass ModuleNotFoundException(PatchException):\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)\",\n        len(patched_modules),\n        len(modules),\n        \",\".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 ModuleNotFoundException:\n        if raise_errors:\n            raise\n        return False\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        except ImportError:\n            # if the import fails, the integration is not available\n            raise PatchException(\"integration '%s' not available\" % path)\n        else:\n            # if patch() is not available in the module, it means\n            # that the library is not installed in the environment\n            if not hasattr(imported_module, \"patch\"):\n                raise ModuleNotFoundException(\"module '%s' not installed\" % module)\n\n            imported_module.patch()\n            _PATCHED_MODULES.add(module)\n            return True\n", "path": "ddtrace/monkey.py"}]}