We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Distros are coupled with instrumentations
As mentioned [here](https://github.com/open-telemetry/opentelemetry-python/discussions/2005#discussion-3489738).

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py`
Content:
```
1 # Copyright The OpenTelemetry Authors
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #     http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 
15 import sys
16 from logging import getLogger
17 from os import environ, path
18 from os.path import abspath, dirname, pathsep
19 from re import sub
20 
21 from pkg_resources import iter_entry_points
22 
23 from opentelemetry.environment_variables import (
24     OTEL_PYTHON_DISABLED_INSTRUMENTATIONS,
25 )
26 from opentelemetry.instrumentation.dependencies import (
27     get_dist_dependency_conflicts,
28 )
29 from opentelemetry.instrumentation.distro import BaseDistro, DefaultDistro
30 
31 logger = getLogger(__file__)
32 
33 
34 def _load_distros() -> BaseDistro:
35     for entry_point in iter_entry_points("opentelemetry_distro"):
36         try:
37             distro = entry_point.load()()
38             if not isinstance(distro, BaseDistro):
39                 logger.debug(
40                     "%s is not an OpenTelemetry Distro. Skipping",
41                     entry_point.name,
42                 )
43                 continue
44             logger.debug(
45                 "Distribution %s will be configured", entry_point.name
46             )
47             return distro
48         except Exception as exc:  # pylint: disable=broad-except
49             logger.exception(
50                 "Distribution %s configuration failed", entry_point.name
51             )
52             raise exc
53     return DefaultDistro()
54 
55 
56 def _load_instrumentors(distro):
57     package_to_exclude = environ.get(OTEL_PYTHON_DISABLED_INSTRUMENTATIONS, [])
58     if isinstance(package_to_exclude, str):
59         package_to_exclude = package_to_exclude.split(",")
60         # to handle users entering "requests , flask" or "requests, flask" with spaces
61         package_to_exclude = [x.strip() for x in package_to_exclude]
62 
63     for entry_point in iter_entry_points("opentelemetry_instrumentor"):
64         if entry_point.name in package_to_exclude:
65             logger.debug(
66                 "Instrumentation skipped for library %s", entry_point.name
67             )
68             continue
69 
70         try:
71             conflict = get_dist_dependency_conflicts(entry_point.dist)
72             if conflict:
73                 logger.debug(
74                     "Skipping instrumentation %s: %s",
75                     entry_point.name,
76                     conflict,
77                 )
78                 continue
79 
80             # tell instrumentation to not run dep checks again as we already did it above
81             distro.load_instrumentor(entry_point, skip_dep_check=True)
82             logger.debug("Instrumented %s", entry_point.name)
83         except Exception as exc:  # pylint: disable=broad-except
84             logger.exception("Instrumenting of %s failed", entry_point.name)
85             raise exc
86 
87 
88 def _load_configurators():
89     configured = None
90     for entry_point in iter_entry_points("opentelemetry_configurator"):
91         if configured is not None:
92             logger.warning(
93                 "Configuration of %s not loaded, %s already loaded",
94                 entry_point.name,
95                 configured,
96             )
97             continue
98         try:
99             entry_point.load()().configure()  # type: ignore
100             configured = entry_point.name
101         except Exception as exc:  # pylint: disable=broad-except
102             logger.exception("Configuration of %s failed", entry_point.name)
103             raise exc
104 
105 
106 def initialize():
107     try:
108         distro = _load_distros()
109         distro.configure()
110         _load_configurators()
111         _load_instrumentors(distro)
112     except Exception:  # pylint: disable=broad-except
113         logger.exception("Failed to auto initialize opentelemetry")
114     finally:
115         environ["PYTHONPATH"] = sub(
116             r"{}{}?".format(dirname(abspath(__file__)), pathsep),
117             "",
118             environ["PYTHONPATH"],
119         )
120 
121 
122 if (
123     hasattr(sys, "argv")
124     and sys.argv[0].split(path.sep)[-1] == "celery"
125     and "worker" in sys.argv[1:]
126 ):
127     from celery.signals import worker_process_init  # pylint:disable=E0401
128 
129     @worker_process_init.connect(weak=False)
130     def init_celery(*args, **kwargs):
131         initialize()
132 
133 
134 else:
135     initialize()
136
```
--- 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/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py
--- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py
+++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py
@@ -60,6 +60,9 @@
         # to handle users entering "requests , flask" or "requests, flask" with spaces
         package_to_exclude = [x.strip() for x in package_to_exclude]
 
+    for entry_point in iter_entry_points("opentelemetry_pre_instrument"):
+        entry_point.load()()
+
     for entry_point in iter_entry_points("opentelemetry_instrumentor"):
         if entry_point.name in package_to_exclude:
             logger.debug(
@@ -84,6 +87,9 @@
             logger.exception("Instrumenting of %s failed", entry_point.name)
             raise exc
 
+    for entry_point in iter_entry_points("opentelemetry_post_instrument"):
+        entry_point.load()()
+
 
 def _load_configurators():
     configured = None

{"golden_diff": "diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py\n--- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py\n+++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py\n@@ -60,6 +60,9 @@\n         # to handle users entering \"requests , flask\" or \"requests, flask\" with spaces\n         package_to_exclude = [x.strip() for x in package_to_exclude]\n \n+    for entry_point in iter_entry_points(\"opentelemetry_pre_instrument\"):\n+        entry_point.load()()\n+\n     for entry_point in iter_entry_points(\"opentelemetry_instrumentor\"):\n         if entry_point.name in package_to_exclude:\n             logger.debug(\n@@ -84,6 +87,9 @@\n             logger.exception(\"Instrumenting of %s failed\", entry_point.name)\n             raise exc\n \n+    for entry_point in iter_entry_points(\"opentelemetry_post_instrument\"):\n+        entry_point.load()()\n+\n \n def _load_configurators():\n     configured = None\n", "issue": "Distros are coupled with instrumentations\nAs mentioned [here](https://github.com/open-telemetry/opentelemetry-python/discussions/2005#discussion-3489738).\n", "before_files": [{"content": "# Copyright The OpenTelemetry Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport sys\nfrom logging import getLogger\nfrom os import environ, path\nfrom os.path import abspath, dirname, pathsep\nfrom re import sub\n\nfrom pkg_resources import iter_entry_points\n\nfrom opentelemetry.environment_variables import (\n    OTEL_PYTHON_DISABLED_INSTRUMENTATIONS,\n)\nfrom opentelemetry.instrumentation.dependencies import (\n    get_dist_dependency_conflicts,\n)\nfrom opentelemetry.instrumentation.distro import BaseDistro, DefaultDistro\n\nlogger = getLogger(__file__)\n\n\ndef _load_distros() -> BaseDistro:\n    for entry_point in iter_entry_points(\"opentelemetry_distro\"):\n        try:\n            distro = entry_point.load()()\n            if not isinstance(distro, BaseDistro):\n                logger.debug(\n                    \"%s is not an OpenTelemetry Distro. Skipping\",\n                    entry_point.name,\n                )\n                continue\n            logger.debug(\n                \"Distribution %s will be configured\", entry_point.name\n            )\n            return distro\n        except Exception as exc:  # pylint: disable=broad-except\n            logger.exception(\n                \"Distribution %s configuration failed\", entry_point.name\n            )\n            raise exc\n    return DefaultDistro()\n\n\ndef _load_instrumentors(distro):\n    package_to_exclude = environ.get(OTEL_PYTHON_DISABLED_INSTRUMENTATIONS, [])\n    if isinstance(package_to_exclude, str):\n        package_to_exclude = package_to_exclude.split(\",\")\n        # to handle users entering \"requests , flask\" or \"requests, flask\" with spaces\n        package_to_exclude = [x.strip() for x in package_to_exclude]\n\n    for entry_point in iter_entry_points(\"opentelemetry_instrumentor\"):\n        if entry_point.name in package_to_exclude:\n            logger.debug(\n                \"Instrumentation skipped for library %s\", entry_point.name\n            )\n            continue\n\n        try:\n            conflict = get_dist_dependency_conflicts(entry_point.dist)\n            if conflict:\n                logger.debug(\n                    \"Skipping instrumentation %s: %s\",\n                    entry_point.name,\n                    conflict,\n                )\n                continue\n\n            # tell instrumentation to not run dep checks again as we already did it above\n            distro.load_instrumentor(entry_point, skip_dep_check=True)\n            logger.debug(\"Instrumented %s\", entry_point.name)\n        except Exception as exc:  # pylint: disable=broad-except\n            logger.exception(\"Instrumenting of %s failed\", entry_point.name)\n            raise exc\n\n\ndef _load_configurators():\n    configured = None\n    for entry_point in iter_entry_points(\"opentelemetry_configurator\"):\n        if configured is not None:\n            logger.warning(\n                \"Configuration of %s not loaded, %s already loaded\",\n                entry_point.name,\n                configured,\n            )\n            continue\n        try:\n            entry_point.load()().configure()  # type: ignore\n            configured = entry_point.name\n        except Exception as exc:  # pylint: disable=broad-except\n            logger.exception(\"Configuration of %s failed\", entry_point.name)\n            raise exc\n\n\ndef initialize():\n    try:\n        distro = _load_distros()\n        distro.configure()\n        _load_configurators()\n        _load_instrumentors(distro)\n    except Exception:  # pylint: disable=broad-except\n        logger.exception(\"Failed to auto initialize opentelemetry\")\n    finally:\n        environ[\"PYTHONPATH\"] = sub(\n            r\"{}{}?\".format(dirname(abspath(__file__)), pathsep),\n            \"\",\n            environ[\"PYTHONPATH\"],\n        )\n\n\nif (\n    hasattr(sys, \"argv\")\n    and sys.argv[0].split(path.sep)[-1] == \"celery\"\n    and \"worker\" in sys.argv[1:]\n):\n    from celery.signals import worker_process_init  # pylint:disable=E0401\n\n    @worker_process_init.connect(weak=False)\n    def init_celery(*args, **kwargs):\n        initialize()\n\n\nelse:\n    initialize()\n", "path": "opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py"}], "after_files": [{"content": "# Copyright The OpenTelemetry Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#     http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport sys\nfrom logging import getLogger\nfrom os import environ, path\nfrom os.path import abspath, dirname, pathsep\nfrom re import sub\n\nfrom pkg_resources import iter_entry_points\n\nfrom opentelemetry.environment_variables import (\n    OTEL_PYTHON_DISABLED_INSTRUMENTATIONS,\n)\nfrom opentelemetry.instrumentation.dependencies import (\n    get_dist_dependency_conflicts,\n)\nfrom opentelemetry.instrumentation.distro import BaseDistro, DefaultDistro\n\nlogger = getLogger(__file__)\n\n\ndef _load_distros() -> BaseDistro:\n    for entry_point in iter_entry_points(\"opentelemetry_distro\"):\n        try:\n            distro = entry_point.load()()\n            if not isinstance(distro, BaseDistro):\n                logger.debug(\n                    \"%s is not an OpenTelemetry Distro. Skipping\",\n                    entry_point.name,\n                )\n                continue\n            logger.debug(\n                \"Distribution %s will be configured\", entry_point.name\n            )\n            return distro\n        except Exception as exc:  # pylint: disable=broad-except\n            logger.exception(\n                \"Distribution %s configuration failed\", entry_point.name\n            )\n            raise exc\n    return DefaultDistro()\n\n\ndef _load_instrumentors(distro):\n    package_to_exclude = environ.get(OTEL_PYTHON_DISABLED_INSTRUMENTATIONS, [])\n    if isinstance(package_to_exclude, str):\n        package_to_exclude = package_to_exclude.split(\",\")\n        # to handle users entering \"requests , flask\" or \"requests, flask\" with spaces\n        package_to_exclude = [x.strip() for x in package_to_exclude]\n\n    for entry_point in iter_entry_points(\"opentelemetry_pre_instrument\"):\n        entry_point.load()()\n\n    for entry_point in iter_entry_points(\"opentelemetry_instrumentor\"):\n        if entry_point.name in package_to_exclude:\n            logger.debug(\n                \"Instrumentation skipped for library %s\", entry_point.name\n            )\n            continue\n\n        try:\n            conflict = get_dist_dependency_conflicts(entry_point.dist)\n            if conflict:\n                logger.debug(\n                    \"Skipping instrumentation %s: %s\",\n                    entry_point.name,\n                    conflict,\n                )\n                continue\n\n            # tell instrumentation to not run dep checks again as we already did it above\n            distro.load_instrumentor(entry_point, skip_dep_check=True)\n            logger.debug(\"Instrumented %s\", entry_point.name)\n        except Exception as exc:  # pylint: disable=broad-except\n            logger.exception(\"Instrumenting of %s failed\", entry_point.name)\n            raise exc\n\n    for entry_point in iter_entry_points(\"opentelemetry_post_instrument\"):\n        entry_point.load()()\n\n\ndef _load_configurators():\n    configured = None\n    for entry_point in iter_entry_points(\"opentelemetry_configurator\"):\n        if configured is not None:\n            logger.warning(\n                \"Configuration of %s not loaded, %s already loaded\",\n                entry_point.name,\n                configured,\n            )\n            continue\n        try:\n            entry_point.load()().configure()  # type: ignore\n            configured = entry_point.name\n        except Exception as exc:  # pylint: disable=broad-except\n            logger.exception(\"Configuration of %s failed\", entry_point.name)\n            raise exc\n\n\ndef initialize():\n    try:\n        distro = _load_distros()\n        distro.configure()\n        _load_configurators()\n        _load_instrumentors(distro)\n    except Exception:  # pylint: disable=broad-except\n        logger.exception(\"Failed to auto initialize opentelemetry\")\n    finally:\n        environ[\"PYTHONPATH\"] = sub(\n            r\"{}{}?\".format(dirname(abspath(__file__)), pathsep),\n            \"\",\n            environ[\"PYTHONPATH\"],\n        )\n\n\nif (\n    hasattr(sys, \"argv\")\n    and sys.argv[0].split(path.sep)[-1] == \"celery\"\n    and \"worker\" in sys.argv[1:]\n):\n    from celery.signals import worker_process_init  # pylint:disable=E0401\n\n    @worker_process_init.connect(weak=False)\n    def init_celery(*args, **kwargs):\n        initialize()\n\n\nelse:\n    initialize()\n", "path": "opentelemetry-instrumentation/src/opentelemetry/instrumentation/auto_instrumentation/sitecustomize.py"}]}