Repository: open-telemetry/opentelemetry-python

Issue:
Setting built-in sampler with auto-instrumentation fails with `Failed to initialize custom sampler` due to it missing from entry points
Previously also reported in https://github.com/open-telemetry/opentelemetry-operator/issues/1468, but I believe this needs to be fixed in the SDK.

**Describe your environment**
Python 3.9
MacOS 12.6.2
OTEL version latest release (`1.15.0`/`0.36b0`)

**Steps to reproduce**
- Set env var `OTEL_TRACES_SAMPLER` to one of the built-in sampler values, e.g. `OTEL_TRACES_SAMPLER=always_off`
- Run any application with auto-instrumentation as instructed in https://opentelemetry.io/docs/instrumentation/python/automatic/agent-config/
- Observe the warning message, e.g. `Using default sampler. Failed to initialize custom sampler, always_off: Requested component 'always_off' not found in entry points for 'opentelemetry_traces_sampler'`

**What is the expected behavior?**
The agent should use the built-in sampler.

**What is the actual behavior?**
The agent complains about the sampler missing from entry points and falls back to using the default sampler.

**Additional context**
I believe this should be fixed by adding the samplers to entry points in `opentelemetry-sdk`. Some additional code change might be necessary as well, e.g. the sampler arg does not seem to be handled correctly (should be `float` not `str`), there is a mix between `Callable` and `Sampler` objects in the list of built-in samplers.



Discussion:
Ran into this one myself today. Hopefully that PR can go in soon. 🚀 

Resolving patch:
diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py
--- a/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py
+++ b/opentelemetry-sdk/src/opentelemetry/sdk/_configuration/__init__.py
@@ -295,8 +295,20 @@ def _import_sampler(sampler_name: str) -> Optional[Sampler]:
         return None
     try:
         sampler_factory = _import_sampler_factory(sampler_name)
-        sampler_arg = os.getenv(OTEL_TRACES_SAMPLER_ARG, "")
-        sampler = sampler_factory(sampler_arg)
+        arg = None
+        if sampler_name in ("traceidratio", "parentbased_traceidratio"):
+            try:
+                rate = float(os.getenv(OTEL_TRACES_SAMPLER_ARG))
+            except (ValueError, TypeError):
+                _logger.warning(
+                    "Could not convert TRACES_SAMPLER_ARG to float. Using default value 1.0."
+                )
+                rate = 1.0
+            arg = rate
+        else:
+            arg = os.getenv(OTEL_TRACES_SAMPLER_ARG)
+
+        sampler = sampler_factory(arg)
         if not isinstance(sampler, Sampler):
             message = f"Sampler factory, {sampler_factory}, produced output, {sampler}, which is not a Sampler."
             _logger.warning(message)
@@ -304,7 +316,7 @@ def _import_sampler(sampler_name: str) -> Optional[Sampler]:
         return sampler
     except Exception as exc:  # pylint: disable=broad-except
         _logger.warning(
-            "Using default sampler. Failed to initialize custom sampler, %s: %s",
+            "Using default sampler. Failed to initialize sampler, %s: %s",
             sampler_name,
             exc,
         )
diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/trace/sampling.py b/opentelemetry-sdk/src/opentelemetry/sdk/trace/sampling.py
--- a/opentelemetry-sdk/src/opentelemetry/sdk/trace/sampling.py
+++ b/opentelemetry-sdk/src/opentelemetry/sdk/trace/sampling.py
@@ -394,6 +394,26 @@ def __init__(self, rate: float):
         super().__init__(root=root)
 
 
+class _AlwaysOff(StaticSampler):
+    def __init__(self, _):
+        super().__init__(Decision.DROP)
+
+
+class _AlwaysOn(StaticSampler):
+    def __init__(self, _):
+        super().__init__(Decision.RECORD_AND_SAMPLE)
+
+
+class _ParentBasedAlwaysOff(ParentBased):
+    def __init__(self, _):
+        super().__init__(ALWAYS_OFF)
+
+
+class _ParentBasedAlwaysOn(ParentBased):
+    def __init__(self, _):
+        super().__init__(ALWAYS_ON)
+
+
 _KNOWN_SAMPLERS = {
     "always_on": ALWAYS_ON,
     "always_off": ALWAYS_OFF,
@@ -415,7 +435,7 @@ def _get_from_env_or_default() -> Sampler:
     if trace_sampler in ("traceidratio", "parentbased_traceidratio"):
         try:
             rate = float(os.getenv(OTEL_TRACES_SAMPLER_ARG))
-        except ValueError:
+        except (ValueError, TypeError):
             _logger.warning("Could not convert TRACES_SAMPLER_ARG to float.")
             rate = 1.0
         return _KNOWN_SAMPLERS[trace_sampler](rate)


Test patch: