opentelemetry-python-contrib icon indicating copy to clipboard operation
opentelemetry-python-contrib copied to clipboard

Invalid type WSGIRequest for attribute 'request' value opentelemetry

Open saichander17 opened this issue 1 year ago • 7 comments

Describe your environment

OS: (Alpine Docker) Python version: (Python 3.8) SDK version: (e.g., 1.22.0) API version: (e.g., 1.22.0)

What happened?

Invalid type WSGIRequest for attribute 'request' value. Expected one of ['bool', 'str', 'bytes', 'int', 'float'] or a sequence of those types

I'm getting this warning when I integrated opentelemetry in my Django application. I don't know if it's a bug or I'm doing something wrong. Has anyone encountered this previously?

Steps to Reproduce

Added these to my requirements

opentelemetry-distro==0.43b0
opentelemetry-exporter-otlp==1.22.0

Added the following to my Dockerfile

RUN opentelemetry-bootstrap --action=install
ENV DJANGO_SETTINGS_MODULE myapp.settings
CMD OTEL_RESOURCE_ATTRIBUTES=service.name=testing_app OTEL_EXPORTER_OTLP_ENDPOINT="http://<IP>:4317" OTEL_EXPORTER_OTLP_PROTOCOL=grpc opentelemetry-instrument gunicorn myapp.wsgi:application -c gunicorn.conf.py

Expected Result

I shouldn't get that warning? I'm not sure here!

Actual Result

I'm getting the warning Invalid type WSGIRequest for attribute 'request' value. Expected one of ['bool', 'str', 'bytes', 'int', 'float'] or a sequence of those types

Additional context

I raised the issue first in opentelemtry-python but was suggested that I raise it here.

Would you like to implement a fix?

None

saichander17 avatar Aug 21 '24 05:08 saichander17

I have not been able to reproduce this. Could you provide a greater list of dependency versions for the docker container. For instance: opentelemetry-instrumentation-django gunicorn

Consider providing a full repro (Dockerfile + dependencies)

jeremydvoss avatar Aug 23 '24 16:08 jeremydvoss

The problem is reproducable if the opentelemetry Logger is used as the root logger in Django:

LOGGING = {
    "version": 1,
    "disable_existing_loggers": False,
    "formatters": {
        "verbose": {
            "format": (
                f"%(levelname)s [trace_id=%(otelTraceID)s span_id=%(otelSpanID)s] "
                "%(asctime)s %(pathname)s %(process)d %(thread)d %(message)s"
            )
        },
        "simple": {
            "format": (f"%(levelname)s [trace_id=%(otelTraceID)s span_id=%(otelSpanID)s]" "%(asctime)s %(message)s")
        },
    },
    "handlers": {
        # [...]
        "opentelemetry": {
            "class": "opentelemetry.sdk._logs.LoggingHandler"
        },
    },
    "loggers": {
        #  [...]
    },
    "root": {
        "handlers": [
            #[...]
            "opentelemetry",
        ],
        "level": "INFO",
    },
}

I fixed it by defining a subclass of the original LoggingHandler and use that class for the otlp handler instead:

from logging import LogRecord

from opentelemetry.sdk._logs import LoggingHandler as OpenTelemetryLoggingHandler


class LoggingHandler(OpenTelemetryLoggingHandler):
    @staticmethod
    def _get_attributes(record: LogRecord):
        attributes = OpenTelemetryLoggingHandler._get_attributes(record)
        if "request" in attributes:
            attributes["request"] = f'{attributes["request"].method} {attributes["request"].path}'
        return attributes

Okan0 avatar Sep 19 '24 10:09 Okan0

Same here:

deps:

gunicorn==23.0.0
opentelemetry-sdk==1.27.0
opentelemetry-exporter-otlp==1.27.0
opentelemetry-instrumentation-django==0.48b0
opentelemetry-instrumentation-logging==0.48b0
opentelemetry-instrumentation-httpx==0.48b0
Django==4.2.16

Instrumentation

from opentelemetry.instrumentation import django as django_otel
from opentelemetry.instrumentation import httpx as httpx_otel
from opentelemetry.instrumentation import logging as logging_otel

...
    logging_otel.LoggingInstrumentor().instrument()
    django_otel.DjangoInstrumentor().instrument()
    httpx_otel.HTTPXClientInstrumentor().instrument()
...

I have not been able to reproduce this. Could you provide a greater list of dependency versions for the docker container. For instance: opentelemetry-instrumentation-django gunicorn

Consider providing a full repro (Dockerfile + dependencies)

lramosduarte avatar Oct 01 '24 17:10 lramosduarte

I fixed it by defining a subclass of the original LoggingHandler and use that class for the otlp handler instead:

from logging import LogRecord

from opentelemetry.sdk._logs import LoggingHandler as OpenTelemetryLoggingHandler


class LoggingHandler(OpenTelemetryLoggingHandler):
    @staticmethod
    def _get_attributes(record: LogRecord):
        attributes = OpenTelemetryLoggingHandler._get_attributes(record)
        if "request" in attributes:
            attributes["request"] = f'{attributes["request"].method} {attributes["request"].path}'
        return attributes

Confirmed, I was able to fix the issue with this approach as well. Many thanks @Okan0

alexmarshalldw avatar Oct 17 '24 02:10 alexmarshalldw

I've started to receive this error, too. Looking into possible solutions

jeremydvoss avatar Feb 05 '25 22:02 jeremydvoss

It appears to only happen during exceptions at least for me.

jeremydvoss avatar Feb 05 '25 22:02 jeremydvoss

The following attached (minimal) Django server illustrates the problem

uvlog.zip

To reproduce:

  • unzip uvlog.zip
  • cd uvlog
  • run with
OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED=true OTEL_RESOURCE_ATTRIBUTES="service.name=s1" DJANGO_SETTINGS_MODULE=core.settings OTEL_TRACES_EXPORTER=console OTEL_METRICS_EXPORTER=console OTEL_LOGS_EXPORTER=console uv run opentelemetry-instrument gunicorn core.wsgi
  • send an HTTP request to base http :8000 - this logs correctly since the django request logger django.request only logs errors
  • send an HTTP request to unhandled endpoint http :8000/xxx - The offending line appears
...
"body": "Invalid type WSGIRequest for attribute 'request' value. Expected one of ['bool', 'str', 'bytes', 'int', 'float'] or a sequence of those types",
...
  • run with FIX_LOG=1 to apply the work-around from @Okan0 above

The main issue seems to be that in django/utils/log.py Django adds request to the map of extras. Somehow, this needs to be filtered within the django instrumentor

bettiah avatar Feb 11 '25 18:02 bettiah

I will be investigating this. Could I please be assigned this issue.

rads-1996 avatar Jun 18 '25 22:06 rads-1996