Django OpenTelemetry Logging Error: 'ProxyLogger' object has no attribute 'resource' Azure application insights
I am integrating OpenTelemetry logging into my Django application to send logs to Azure Application Insights, but I am encountering the following error:
AttributeError: 'ProxyLogger' object has no attribute 'resource'
The settings has following logger setup copilot/settings.py
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'standard': {
'format': '%(asctime)s [%(levelname)s] %(name)s: %(message)s'
},
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'formatter': 'standard',
},
},
'root': {
'handlers': ['console'],
'level': 'INFO',
},
'loggers': {
'django': {
'handlers': ['console'],
'level': 'INFO',
'propagate': True,
},
'copilot': { # Parent logger for your app
'handlers': ['console'],
'level': 'INFO',
'propagate': True, # Allows child loggers to inherit handlers
},
},
}
This is the copilot/otel_config.py
# otel_config.py
import os
from django.conf import settings
import logging
from dotenv import load_dotenv
from opentelemetry import trace
from opentelemetry._logs import set_logger_provider
from opentelemetry.sdk._logs import (
LoggerProvider,
LoggingHandler,
)
from opentelemetry.sdk._logs.export import BatchLogRecordProcessor
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from azure.monitor.opentelemetry.exporter import AzureMonitorTraceExporter, AzureMonitorLogExporter
from opentelemetry.instrumentation.django import DjangoInstrumentor
from opentelemetry.instrumentation.logging import LoggingInstrumentor
def setup_opentelemetry():
# Set up the tracer provider with resource attributes
resource = Resource(attributes={
"service.name": "copilot",
})
tracer_provider = TracerProvider()
trace.set_tracer_provider(tracer_provider)
connection_string = settings.APPLICATIONINSIGHTS_CONNECTION_STRING
trace_exporter = AzureMonitorTraceExporter(
connection_string = connection_string
)
span_processor = BatchSpanProcessor(trace_exporter)
tracer_provider.add_span_processor(span_processor)
# Initialize LoggerProvider
logger_provider = LoggerProvider(resource=resource)
set_logger_provider(logger_provider)
log_exporter = AzureMonitorLogExporter(
connection_string = connection_string
)
logger_provider.add_log_record_processor(BatchLogRecordProcessor(log_exporter))
LoggingInstrumentor().instrument(set_logging_format=True)
\
DjangoInstrumentor().instrument()
logging.basicConfig(level=logging.INFO) # Set to INFO or DEBUG as needed
root_logger = logging.getLogger()
root_logger.setLevel(logging.INFO) # Ensure the root logger captures INFO level logs
# Remove existing handlers to avoid duplication
# for handler in root_logger.handlers[:]:
# root_logger.removeHandler(handler)
# Add Azure Monitor Log Exporter as a handler
azure_log_handler = LoggingHandler(level=logging.INFO)
root_logger.addHandler(azure_log_handler)
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG)
formatter = logging.Formatter(
'%(asctime)s [%(levelname)s] %(name)s: %(message)s'
)
console_handler.setFormatter(formatter)
root_logger.addHandler(console_handler)
# Log a test warning to verify setup
root_logger.warning("OpenTelemetry setup complete")
This is the logger_utils utils/logger_utils.py
import logging
from opentelemetry.sdk._logs import LoggingHandler
from django.conf import settings
def get_logger(name: str):
logger = logging.getLogger(name)
# if settings.DJANGO_ENV == 'development':
# return logger
handler = LoggingHandler(level=logging.DEBUG)
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)
return logger
I am calling the logger as shown as below in the code in the views and services
from utils.logger_utils import get_logger
logger = get_logger(__name__)
logger.info("Test")
When accessing in the files in most of the cases this works and also logs on azure app insights but in some cases it fails and give me a error
Exception in thread django-main-thread:
Traceback (most recent call last):
File "/.pyenv/versions/3.10.12/lib/python3.10/threading.py", line 1016, in _bootstrap_inner
self.run()
File "/.pyenv/versions/3.10.12/lib/python3.10/threading.py", line 953, in run
self._target(*self._args, **self._kwargs)
File "/Desktop/workspace/odin/venv/lib/python3.10/site-packages/django/utils/autoreload.py", line 64, in wrapper
fn(*args, **kwargs)
File "/Desktop/workspace/odin/venv/lib/python3.10/site-packages/django/core/management/commands/runserver.py", line 133, in inner_run
self.check(display_num_errors=True)
File "/Desktop/workspace/odin/venv/lib/python3.10/site-packages/django/core/management/base.py", line 486, in check
all_issues = checks.run_checks(
File "/Desktop/workspace/odin/venv/lib/python3.10/site-packages/django/core/checks/registry.py", line 88, in run_checks
new_errors = check(app_configs=app_configs, databases=databases)
File "/Desktop/workspace/odin/venv/lib/python3.10/site-packages/django/core/checks/urls.py", line 14, in check_url_config
return check_resolver(resolver)
File "/Desktop/workspace/odin/venv/lib/python3.10/site-packages/django/core/checks/urls.py", line 24, in check_resolver
return check_method()
File "/Desktop/workspace/odin/venv/lib/python3.10/site-packages/django/urls/resolvers.py", line 519, in check
for pattern in self.url_patterns:
File "/Desktop/workspace/odin/venv/lib/python3.10/site-packages/django/utils/functional.py", line 47, in __get__
res = instance.__dict__[self.name] = self.func(instance)
File "/Desktop/workspace/odin/venv/lib/python3.10/site-packages/django/urls/resolvers.py", line 738, in url_patterns
patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
File "/Desktop/workspace/odin/venv/lib/python3.10/site-packages/django/utils/functional.py", line 47, in __get__
res = instance.__dict__[self.name] = self.func(instance)
File "/Desktop/workspace/odin/venv/lib/python3.10/site-packages/django/urls/resolvers.py", line 731, in urlconf_module
return import_module(self.urlconf_name)
File "/.pyenv/versions/3.10.12/lib/python3.10/importlib/__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 883, in exec_module
File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
File "/copilot/urls.py", line 13, in <module>
import purchase_app.urls
File "/purchase_app/urls.py", line 2, in <module>
from purchase_app.views import user_views, admin_views
File "/purchase_app/views/user_views.py", line 106, in <module>
class ApplicationDetailView(APIView):
File "/purchase_app/views/user_views.py", line 108, in ApplicationDetailView
logger.info("This is the application detail view")
File "/.pyenv/versions/3.10.12/lib/python3.10/logging/__init__.py", line 1477, in info
self._log(INFO, msg, args, **kwargs)
File "/.pyenv/versions/3.10.12/lib/python3.10/logging/__init__.py", line 1624, in _log
self.handle(record)
File "/.pyenv/versions/3.10.12/lib/python3.10/logging/__init__.py", line 1634, in handle
self.callHandlers(record)
File "/.pyenv/versions/3.10.12/lib/python3.10/logging/__init__.py", line 1696, in callHandlers
hdlr.handle(record)
File "/.pyenv/versions/3.10.12/lib/python3.10/logging/__init__.py", line 968, in handle
self.emit(record)
File "/Desktop/workspace/odin/venv/lib/python3.10/site-packages/opentelemetry/sdk/_logs/_internal/__init__.py", line 580, in emit
logger.emit(self._translate(record))
File "/Desktop/workspace/odin/venv/lib/python3.10/site-packages/opentelemetry/sdk/_logs/_internal/__init__.py", line 568, in _translate
resource=logger.resource,
AttributeError: 'ProxyLogger' object has no attribute 'resource'