Repository: open-telemetry/opentelemetry-python-contrib

Issue:
Add error handling for uninstallable packages to `opentelemetry-bootstrap -a install`
Right now we are doing this error handling [here](https://github.com/open-telemetry/opentelemetry-python-contrib/blob/46d2ce6acea9a1a6cb1a4d4c863077002f5f7d21/scripts/otel_packaging.py#L46). It should be [here](https://github.com/open-telemetry/opentelemetry-python-contrib/blob/46d2ce6acea9a1a6cb1a4d4c863077002f5f7d21/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap.py#L51).

The situation we are right now is that if we add a new instrumentation that does not have a third-party package as a dependency (like `threading`), then it won't be added to the [`default_instrumentations`](https://github.com/open-telemetry/opentelemetry-python-contrib/blob/46d2ce6acea9a1a6cb1a4d4c863077002f5f7d21/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py#L184) as it should. This happens because the [script that gets all instrumentations](https://github.com/open-telemetry/opentelemetry-python-contrib/blob/46d2ce6acea9a1a6cb1a4d4c863077002f5f7d21/scripts/otel_packaging.py#L46) won't get this instrumentation because it first checks if it is in Pypi (it is obviously not because we are just adding it to the repo).


Discussion:

Resolving patch:
diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap.py
--- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap.py
+++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap.py
@@ -14,8 +14,14 @@
 
 import argparse
 import logging
-import subprocess
 import sys
+from subprocess import (
+    PIPE,
+    CalledProcessError,
+    Popen,
+    SubprocessError,
+    check_call,
+)
 
 import pkg_resources
 
@@ -34,7 +40,7 @@ def wrapper(package=None):
             if package:
                 return func(package)
             return func()
-        except subprocess.SubprocessError as exp:
+        except SubprocessError as exp:
             cmd = getattr(exp, "cmd", None)
             if cmd:
                 msg = f'Error calling system command "{" ".join(cmd)}"'
@@ -48,18 +54,21 @@ def wrapper(package=None):
 @_syscall
 def _sys_pip_install(package):
     # explicit upgrade strategy to override potential pip config
-    subprocess.check_call(
-        [
-            sys.executable,
-            "-m",
-            "pip",
-            "install",
-            "-U",
-            "--upgrade-strategy",
-            "only-if-needed",
-            package,
-        ]
-    )
+    try:
+        check_call(
+            [
+                sys.executable,
+                "-m",
+                "pip",
+                "install",
+                "-U",
+                "--upgrade-strategy",
+                "only-if-needed",
+                package,
+            ]
+        )
+    except CalledProcessError as error:
+        print(error)
 
 
 def _pip_check():
@@ -70,8 +79,8 @@ def _pip_check():
     'opentelemetry-instrumentation-flask 1.0.1 has requirement opentelemetry-sdk<2.0,>=1.0, but you have opentelemetry-sdk 0.5.'
     To not be too restrictive, we'll only check for relevant packages.
     """
-    with subprocess.Popen(
-        [sys.executable, "-m", "pip", "check"], stdout=subprocess.PIPE
+    with Popen(
+        [sys.executable, "-m", "pip", "check"], stdout=PIPE
     ) as check_pipe:
         pip_check = check_pipe.communicate()[0].decode()
         pip_check_lower = pip_check.lower()
diff --git a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py
--- a/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py
+++ b/opentelemetry-instrumentation/src/opentelemetry/instrumentation/bootstrap_gen.py
@@ -24,6 +24,10 @@
         "library": "aiohttp ~= 3.0",
         "instrumentation": "opentelemetry-instrumentation-aiohttp-client==0.46b0.dev",
     },
+    {
+        "library": "aiohttp ~= 3.0",
+        "instrumentation": "opentelemetry-instrumentation-aiohttp-server==0.46b0.dev",
+    },
     {
         "library": "aiopg >= 0.13.0, < 2.0.0",
         "instrumentation": "opentelemetry-instrumentation-aiopg==0.46b0.dev",
@@ -187,6 +191,7 @@
     "opentelemetry-instrumentation-dbapi==0.46b0.dev",
     "opentelemetry-instrumentation-logging==0.46b0.dev",
     "opentelemetry-instrumentation-sqlite3==0.46b0.dev",
+    "opentelemetry-instrumentation-threading==0.46b0.dev",
     "opentelemetry-instrumentation-urllib==0.46b0.dev",
     "opentelemetry-instrumentation-wsgi==0.46b0.dev",
 ]
diff --git a/scripts/otel_packaging.py b/scripts/otel_packaging.py
--- a/scripts/otel_packaging.py
+++ b/scripts/otel_packaging.py
@@ -12,55 +12,43 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-from tomli import load
-from os import path, listdir
-from subprocess import check_output, CalledProcessError
-from requests import get
+import os
+import subprocess
+from subprocess import CalledProcessError
 
-scripts_path = path.dirname(path.abspath(__file__))
-root_path = path.dirname(scripts_path)
-instrumentations_path = path.join(root_path, "instrumentation")
+import tomli
+
+scripts_path = os.path.dirname(os.path.abspath(__file__))
+root_path = os.path.dirname(scripts_path)
+instrumentations_path = os.path.join(root_path, "instrumentation")
 
 
 def get_instrumentation_packages():
-    for pkg in sorted(listdir(instrumentations_path)):
-        pkg_path = path.join(instrumentations_path, pkg)
-        if not path.isdir(pkg_path):
+    for pkg in sorted(os.listdir(instrumentations_path)):
+        pkg_path = os.path.join(instrumentations_path, pkg)
+        if not os.path.isdir(pkg_path):
             continue
 
-        error = f"Could not get version for package {pkg}"
-
         try:
-            hatch_version = check_output(
+            version = subprocess.check_output(
                 "hatch version",
                 shell=True,
                 cwd=pkg_path,
-                universal_newlines=True
+                universal_newlines=True,
             )
-
         except CalledProcessError as exc:
             print(f"Could not get hatch version from path {pkg_path}")
             print(exc.output)
+            raise exc
 
-        try:
-            response = get(f"https://pypi.org/pypi/{pkg}/json", timeout=10)
-
-        except Exception:
-            print(error)
-            continue
-
-        if response.status_code != 200:
-            print(error)
-            continue
-
-        pyproject_toml_path = path.join(pkg_path, "pyproject.toml")
+        pyproject_toml_path = os.path.join(pkg_path, "pyproject.toml")
 
         with open(pyproject_toml_path, "rb") as file:
-            pyproject_toml = load(file)
+            pyproject_toml = tomli.load(file)
 
         instrumentation = {
             "name": pyproject_toml["project"]["name"],
-            "version": hatch_version.strip(),
+            "version": version.strip(),
             "instruments": pyproject_toml["project"]["optional-dependencies"][
                 "instruments"
             ],


Test patch: