Repository: open-telemetry/opentelemetry-python-contrib

Issue:
error with logging instrumentation - AttributeError: 'ProxyTracerProvider' object has no attribute 'resource'
**Describe your environment** 

LoggingInstrumentor().instrument() is throwing an error
```
Traceback (most recent call last):
  File "manage.py", line 30, in <module>
    main()
  File "manage.py", line 14, in main
    LoggingInstrumentor().instrument(set_logging_format=True)
  File "/home/vamsikrishnam/otel/lib/python3.8/site-packages/opentelemetry/instrumentation/instrumentor.py", line 109, in instrument
    result = self._instrument(  # pylint: disable=assignment-from-no-return
  File "/home/vamsikrishnam/otel/lib/python3.8/site-packages/opentelemetry/instrumentation/logging/__init__.py", line 81, in _instrument
    resource = provider.resource if provider else None
AttributeError: 'ProxyTracerProvider' object has no attribute 'resource'
```

**Steps to reproduce**
Below packages installed and trying to instrument with below two lines:

>  LoggingInstrumentor().instrument(set_logging_format=True)
>  DjangoInstrumentor().instrument()

```
(otel) vamsikrishnam@NHHYDL-00217:~/django$ pip list | grep opentele
opentelemetry-api                      1.7.1
opentelemetry-exporter-otlp            1.7.1
opentelemetry-exporter-otlp-proto-grpc 1.7.1
opentelemetry-exporter-otlp-proto-http 1.7.1
opentelemetry-instrumentation          0.26b1
opentelemetry-instrumentation-django   0.26b1
opentelemetry-instrumentation-logging  0.26b1
opentelemetry-instrumentation-wsgi     0.26b1
opentelemetry-propagator-b3            1.7.1
opentelemetry-proto                    1.7.1
opentelemetry-sdk                      1.7.1
opentelemetry-semantic-conventions     0.26b1
opentelemetry-util-http                0.26b1
```

**What is the expected behavior?**
What did you expect to see?
logging should be instrumented properly.

**What is the actual behavior?**
What did you see instead?
logging should be instrumented properly and populate the otelTraceID and otelSpanID in the logs.

**Additional context**
Add any other context about the problem here.

$ python3 --version
Python 3.8.10

manage.py:

```
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
import logging
from opentelemetry.instrumentation.django import DjangoInstrumentor
from opentelemetry.instrumentation.logging import LoggingInstrumentor


def main():
    """Run administrative tasks."""
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_project.settings')
    logging.basicConfig(level = logging.DEBUG)
    LoggingInstrumentor().instrument(set_logging_format=True)
    DjangoInstrumentor().instrument()
    # LoggingInstrumentor().instrument(set_logging_format=True,log_level=logging.DEBUG)

    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
        raise ImportError(
            "Couldn't import Django. Are you sure it's installed and "
            "available on your PYTHONPATH environment variable? Did you "
            "forget to activate a virtual environment?"
        ) from exc
    execute_from_command_line(sys.argv)


if __name__ == '__main__':
    main()
```




Discussion:
You need to set up the SDK and tracing pipeline before you can use any instrumentors. Please refer to this: https://opentelemetry-python.readthedocs.io/en/latest/getting-started.html
```
provider = TracerProvider()
processor = BatchSpanProcessor(ConsoleSpanExporter())
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)
```
> You need to set up the SDK and tracing pipeline before you can use any instrumentors. Please refer to this: https://opentelemetry-python.readthedocs.io/en/latest/getting-started.html

This is right, but we should not fail like this (with an attribute error) if SDK or tracing has not yet been set.
We shouldn't. I meant to bring it up in weekly SIG this Thursday.
@owais I'm seeing a similar thing in #821, I believe that I've set things up properly, if I use the ConsoleSpanExporter then I get the traces output to the CLI, but as soon as I switch to OTLPHTTP my TraceID's are *always* `0` in the logs.

Could there be a bigger issue here? 
@proffalken 
Is your issue related to this issue's topic? As well, have you looked at the [explanation](https://github.com/open-telemetry/opentelemetry-python-contrib/issues/821#issuecomment-988220469) for the linked issue? Perhaps it may solve your use case.
@lzchen - apologies, I'd forgotten that I'd commented here, the linked issue resolved my particular problem.
> > You need to set up the SDK and tracing pipeline before you can use any instrumentors. Please refer to this: https://opentelemetry-python.readthedocs.io/en/latest/getting-started.html
> 
> This is right, but we should not fail like this (with an attribute error) if SDK or tracing has not yet been set.

Imo, the instrumentation shouldn't make any assumptions about the SDK at all since it does not define a dependency to it. Furtheremore, there might be 3rd party SDKs in the wild that might handle things like resources differently.

Hello all,
QQ related to the same topic.

Is the logging instrumentation supposed to  work with the auto-instrumentation?

I'm asking because when I use the `opentelemetry-instrument` in my sample I get this exact same error.
Just checking if maybe I'm doing something wrong, or if that's a limitation.

I have this sample with the logging instrumentation commented out, just in case someone wants to reproduce the issue.
https://github.com/julianocosta89/microservices-demo/tree/main/src/emailservice

Resolving patch:
diff --git a/instrumentation/opentelemetry-instrumentation-logging/src/opentelemetry/instrumentation/logging/__init__.py b/instrumentation/opentelemetry-instrumentation-logging/src/opentelemetry/instrumentation/logging/__init__.py
--- a/instrumentation/opentelemetry-instrumentation-logging/src/opentelemetry/instrumentation/logging/__init__.py
+++ b/instrumentation/opentelemetry-instrumentation-logging/src/opentelemetry/instrumentation/logging/__init__.py
@@ -76,20 +76,29 @@ def instrumentation_dependencies(self) -> Collection[str]:
         return _instruments
 
     def _instrument(self, **kwargs):
-        service_name = ""
-        provider = kwargs.get("tracer_provider", None) or get_tracer_provider()
-        resource = provider.resource if provider else None
-        if resource:
-            service_name = resource.attributes.get("service.name")
 
+        provider = kwargs.get("tracer_provider", None) or get_tracer_provider()
         old_factory = logging.getLogRecordFactory()
         LoggingInstrumentor._old_factory = old_factory
 
+        service_name = None
+
         def record_factory(*args, **kwargs):
             record = old_factory(*args, **kwargs)
 
             record.otelSpanID = "0"
             record.otelTraceID = "0"
+
+            nonlocal service_name
+            if service_name is None:
+                resource = getattr(provider, "resource", None)
+                if resource:
+                    service_name = (
+                        resource.attributes.get("service.name") or ""
+                    )
+                else:
+                    service_name = ""
+
             record.otelServiceName = service_name
 
             span = get_current_span()


Test patch:
diff --git a/instrumentation/opentelemetry-instrumentation-logging/tests/test_logging.py b/instrumentation/opentelemetry-instrumentation-logging/tests/test_logging.py
--- a/instrumentation/opentelemetry-instrumentation-logging/tests/test_logging.py
+++ b/instrumentation/opentelemetry-instrumentation-logging/tests/test_logging.py
@@ -13,6 +13,7 @@
 # limitations under the License.
 
 import logging
+from typing import Optional
 from unittest import mock
 
 import pytest
@@ -22,7 +23,45 @@
     LoggingInstrumentor,
 )
 from opentelemetry.test.test_base import TestBase
-from opentelemetry.trace import get_tracer
+from opentelemetry.trace import ProxyTracer, get_tracer
+
+
+class FakeTracerProvider:
+    def get_tracer(  # pylint: disable=no-self-use
+        self,
+        instrumenting_module_name: str,
+        instrumenting_library_version: Optional[str] = None,
+        schema_url: Optional[str] = None,
+    ) -> ProxyTracer:
+        return ProxyTracer(
+            instrumenting_module_name,
+            instrumenting_library_version,
+            schema_url,
+        )
+
+
+class TestLoggingInstrumentorProxyTracerProvider(TestBase):
+    @pytest.fixture(autouse=True)
+    def inject_fixtures(self, caplog):
+        self.caplog = caplog  # pylint: disable=attribute-defined-outside-init
+
+    def setUp(self):
+        super().setUp()
+        LoggingInstrumentor().instrument(tracer_provider=FakeTracerProvider())
+
+    def tearDown(self):
+        super().tearDown()
+        LoggingInstrumentor().uninstrument()
+
+    def test_trace_context_injection(self):
+        with self.caplog.at_level(level=logging.INFO):
+            logger = logging.getLogger("test logger")
+            logger.info("hello")
+            self.assertEqual(len(self.caplog.records), 1)
+            record = self.caplog.records[0]
+            self.assertEqual(record.otelSpanID, "0")
+            self.assertEqual(record.otelTraceID, "0")
+            self.assertEqual(record.otelServiceName, "")
 
 
 class TestLoggingInstrumentor(TestBase):