Repository: open-telemetry/opentelemetry-python

Issue:
Resource Detectors produce blank Exception() after 5 seconds
**Describe your environment**
Resource Detector only get [5 seconds by default](https://github.com/open-telemetry/opentelemetry-python/blob/main/opentelemetry-sdk/src/opentelemetry/sdk/resources/__init__.py#L375) to run. However, instead of ending the process after 5 seconds, a blank "Exception()" is creating resulting in the follow warning:
`Exception  in detector <opentelemetry.resource.detector.<RESOURCE DETECTOR CLASS> object at 0x000002B955D43D60>, ignoring`
Note that the Exception string is blank resulting in 2 whitespaces: `Exception__in...`
This blank exception is causing [confusion ](https://github.com/Azure/azure-sdk-for-python/issues/33253) among Azure customers. And perhaps more importantly, the process still hangs.

 
**Steps to reproduce**
1. Create a resource detector that sleeps for more than 5 seconds (try 10-20):
```
from opentelemetry.sdk.resources import Resource, ResourceDetector

from time import sleep

class SleepingResourceDetector(ResourceDetector):
    # pylint: disable=no-self-use
    def detect(self) -> "Resource":
        sleep(20)
        attributes = {}
        return Resource(attributes)
```
2. Set resource detector entry point in pyproject.toml
```
[project.entry-points.opentelemetry_resource_detector]
sleeping = "opentelemetry.resource.detector.sleeping:SleepingResourceDetector"
```
3. Install package to install entry point
4. Point sdk to resource detector: `export OTEL_EXPERIMENTAL_RESOURCE_DETECTORS=sleeping`
5. Create a Resource: `Resource.create()` This will eventually call [get_aggregated_resources](https://github.com/open-telemetry/opentelemetry-python/blob/main/opentelemetry-sdk/src/opentelemetry/sdk/resources/__init__.py#L372)


**What is the expected behavior?**
The "concurrent future" setup should gracefully exit the process and not print out a confusing blank warning.

**What is the actual behavior?**
Process hangs and confusing warning message with blank error.

**Additional context**
Add any other context about the problem here.



Discussion:

Resolving patch:
diff --git a/opentelemetry-sdk/src/opentelemetry/sdk/resources/__init__.py b/opentelemetry-sdk/src/opentelemetry/sdk/resources/__init__.py
--- a/opentelemetry-sdk/src/opentelemetry/sdk/resources/__init__.py
+++ b/opentelemetry-sdk/src/opentelemetry/sdk/resources/__init__.py
@@ -390,6 +390,14 @@ def get_aggregated_resources(
             detected_resource: Resource = _EMPTY_RESOURCE
             try:
                 detected_resource = future.result(timeout=timeout)
+            except concurrent.futures.TimeoutError as ex:
+                if detector.raise_on_error:
+                    raise ex
+                logger.warning(
+                    "Detector %s took longer than %s seconds, skipping",
+                    detector,
+                    timeout,
+                )
             # pylint: disable=broad-except
             except Exception as ex:
                 if detector.raise_on_error:


Test patch:
diff --git a/opentelemetry-sdk/tests/resources/test_resources.py b/opentelemetry-sdk/tests/resources/test_resources.py
--- a/opentelemetry-sdk/tests/resources/test_resources.py
+++ b/opentelemetry-sdk/tests/resources/test_resources.py
@@ -15,6 +15,7 @@
 import sys
 import unittest
 import uuid
+from concurrent.futures import TimeoutError
 from logging import ERROR, WARNING
 from os import environ
 from unittest.mock import Mock, patch
@@ -420,6 +421,23 @@ def test_resource_detector_raise_error(self):
             Exception, get_aggregated_resources, [resource_detector]
         )
 
+    @patch("opentelemetry.sdk.resources.logger")
+    def test_resource_detector_timeout(self, mock_logger):
+        resource_detector = Mock(spec=ResourceDetector)
+        resource_detector.detect.side_effect = TimeoutError()
+        resource_detector.raise_on_error = False
+        self.assertEqual(
+            get_aggregated_resources([resource_detector]),
+            _DEFAULT_RESOURCE.merge(
+                Resource({SERVICE_NAME: "unknown_service"}, "")
+            ),
+        )
+        mock_logger.warning.assert_called_with(
+            "Detector %s took longer than %s seconds, skipping",
+            resource_detector,
+            5,
+        )
+
     @patch.dict(
         environ,
         {"OTEL_RESOURCE_ATTRIBUTES": "key1=env_value1,key2=env_value2"},