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

Unnecessary/noncompliant attributes added via logging instrumentation

Open mx-psi opened this issue 6 months ago • 5 comments

Running the app in https://opentelemetry.io/docs/languages/python/getting-started/ with

export OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED=true
opentelemetry-instrument \
    --traces_exporter console \
    --metrics_exporter console \
    --logs_exporter console \
    --service_name dice-server \
    flask run -p 8080

results in logs like:

{
    "body": "Anonymous player is rolling the dice: 1",
    "severity_number": 13,
    "severity_text": "WARN",
    "attributes": {
        "otelSpanID": "57a328e3a762f95e",
        "otelTraceID": "a794f5ff6f076ca3e8744dd222d27760",
        "otelTraceSampled": true,
        "otelServiceName": "dice-server",
        "code.file.path": "/tmp/tmp.ZHMcsMeRYL/otel-getting-started/app.py",
        "code.function.name": "roll_dice",
        "code.line.number": 17
    },
    "dropped_attributes": 0,
    "timestamp": "2025-07-01T15:07:59.544312Z",
    "observed_timestamp": "2025-07-01T15:07:59.544731Z",
    "trace_id": "0xa794f5ff6f076ca3e8744dd222d27760",
    "span_id": "0x57a328e3a762f95e",
    "trace_flags": 1,
    "resource": {
        "attributes": {
            "telemetry.sdk.language": "python",
            "telemetry.sdk.name": "opentelemetry",
            "telemetry.sdk.version": "1.34.1",
            "service.name": "dice-server",
            "telemetry.auto.version": "0.55b1"
        },
        "schema_url": ""
    }
}

You can see the trace_id, span_id , trace_flags and resource::attributes::service.name are also present as log-level attributes with the names otelSpanID, otelTraceID , otelTraceSampled and otelServiceName respectively. This is mentioned here: https://github.com/open-telemetry/opentelemetry-python-contrib/blob/b1c2c7941b9f5aa4762c648b0e3644de80c1e0a4/instrumentation/opentelemetry-instrumentation-logging/src/opentelemetry/instrumentation/logging/constants.py#L25-L30

I spoke with @xrmx on Slack about this (see https://cloud-native.slack.com/archives/C01PD4HUVBL/p1751382766109069) and this seems to be historical artifact that could be removed. Since this is reported by opentelemetry-demo and it's on our official docs, it has some weight as an 'official' thing when it seems like it is not, so I would suggest removing it.

mx-psi avatar Aug 07 '25 15:08 mx-psi

I'm taking a closer look at this and I think the issue is the following. opentelemetry-instrumentation-logging is injecting otel span context data (otel*) into Python logging records. Then the log shipping in the sdk (OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED=true) is forwarding these attributes into OTel logs too. Now adding these attributes into the Python logs looks legit so maybe we should just filter them out in the log shipping code?

xrmx avatar Nov 13 '25 09:11 xrmx

Now adding these attributes into the Python logs looks legit

My main concern/question is that these attributes seem redundant and feel 'official' since they are coming from one of our official examples. I don't think it is wrong per se that this attributes are there, just potentially confusing

mx-psi avatar Nov 19 '25 11:11 mx-psi

Just found out that the attributes name in non-OTLP logs are documented in https://opentelemetry.io/docs/specs/otel/compatibility/logging_trace_context/ and we should probably make these attributes at least compliant with that.

UPDATE: actually we are already doing that respecting the spec when OTEL_PYTHON_LOG_CORRELATION=true.

xrmx avatar Nov 21 '25 11:11 xrmx

Just found out that the attributes name in non-OTLP logs are documented in https://opentelemetry.io/docs/specs/otel/compatibility/logging_trace_context/ and we should probably make these attributes at least compliant with that.

UPDATE: actually we are already doing that respecting the spec when OTEL_PYTHON_LOG_CORRELATION=true.

So with OTEL_PYTHON_LOG_CORRELATION=true the fields should be added as trace_id rather than otelSpanId etc.? I can't reproduce this with opentelemetry-instrumentation-logging 0.60b1.

msom avatar Dec 17 '25 10:12 msom

Just found out that the attributes name in non-OTLP logs are documented in https://opentelemetry.io/docs/specs/otel/compatibility/logging_trace_context/ and we should probably make these attributes at least compliant with that. UPDATE: actually we are already doing that respecting the spec when OTEL_PYTHON_LOG_CORRELATION=true.

So with OTEL_PYTHON_LOG_CORRELATION=true the fields should be added as trace_id rather than otelSpanId etc.? I can't reproduce this with opentelemetry-instrumentation-logging 0.60b1.

The logs have already the proper trace context, OTEL_PYTHON_LOG_CORRELATION=true IIRC changes the formatting of the message to include them also in the text.

xrmx avatar Dec 17 '25 10:12 xrmx

I think we can workaround this behavior with something like the following: we are injecting these out of spec attributes only if user enabled log correlation or has a log hook configured that is not the out of the box use case or the examples we have in the docs.

diff --git a/instrumentation/opentelemetry-instrumentation-logging/src/opentelemetry/instrumentation/logging/__init__.py b/instrumentation/o
pentelemetry-instrumentation-logging/src/opentelemetry/instrumentation/logging/__init__.py
index 226108325..4e493a69f 100644
--- a/instrumentation/opentelemetry-instrumentation-logging/src/opentelemetry/instrumentation/logging/__init__.py
+++ b/instrumentation/opentelemetry-instrumentation-logging/src/opentelemetry/instrumentation/logging/__init__.py
@@ -130,9 +130,33 @@ class LoggingInstrumentor(BaseInstrumentor):  # pylint: disable=empty-docstring
 
         service_name = None
 
+        set_logging_format = kwargs.get(
+            "set_logging_format",
+            environ.get(OTEL_PYTHON_LOG_CORRELATION, "false").lower()
+            == "true",
+        )
+
+        if set_logging_format:
+            log_format = kwargs.get(
+                "logging_format", environ.get(OTEL_PYTHON_LOG_FORMAT, None)
+            )
+            log_format = log_format or DEFAULT_LOGGING_FORMAT
+
+            log_level = kwargs.get(
+                "log_level", LEVELS.get(environ.get(OTEL_PYTHON_LOG_LEVEL))
+            )
+            log_level = log_level or logging.INFO
+
+            logging.basicConfig(format=log_format, level=log_level)
+
         def record_factory(*args, **kwargs):
             record = old_factory(*args, **kwargs)
 
+            # inject out of spec attributes only if the user is asking to do so or if a
+            # a log hook is configured
+            if not set_logging_format and not callable(LoggingInstrumentor._log_hook):
+                return record
+
             record.otelSpanID = "0"
             record.otelTraceID = "0"
             record.otelTraceSampled = False
@@ -168,25 +192,6 @@ class LoggingInstrumentor(BaseInstrumentor):  # pylint: disable=empty-docstring
 
         logging.setLogRecordFactory(record_factory)
 
-        set_logging_format = kwargs.get(
-            "set_logging_format",
-            environ.get(OTEL_PYTHON_LOG_CORRELATION, "false").lower()
-            == "true",
-        )
-
-        if set_logging_format:
-            log_format = kwargs.get(
-                "logging_format", environ.get(OTEL_PYTHON_LOG_FORMAT, None)
-            )
-            log_format = log_format or DEFAULT_LOGGING_FORMAT
-
-            log_level = kwargs.get(
-                "log_level", LEVELS.get(environ.get(OTEL_PYTHON_LOG_LEVEL))
-            )
-            log_level = log_level or logging.INFO
-
-            logging.basicConfig(format=log_format, level=log_level)
-
     def _uninstrument(self, **kwargs):
         if LoggingInstrumentor._old_factory:
             logging.setLogRecordFactory(LoggingInstrumentor._old_factory)

xrmx avatar Jan 19 '26 09:01 xrmx