open-telemetry / opentelemetry-python-contrib

OpenTelemetry instrumentation for Python modules
https://opentelemetry.io
Apache License 2.0
738 stars 609 forks source link

Invalid type WSGIRequest for attribute 'request' value opentelemetry #2808

Open saichander17 opened 2 months ago

saichander17 commented 2 months ago

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

jeremydvoss commented 2 months ago

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)

Okan0 commented 1 month ago

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
lramosduarte commented 1 month ago

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)

alexmarshalldw commented 1 month ago

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