open-telemetry / opentelemetry-python-contrib

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

`requests` instrumentation should not modify the custom headers dictionary #1729

Open oavdeev opened 1 year ago

oavdeev commented 1 year ago

Describe your environment Using python 3.10 and

opentelemetry-api==1.16.0
opentelemetry-distro==0.37b0
opentelemetry-exporter-otlp-proto-http==1.15.0
opentelemetry-instrumentation==0.37b0
opentelemetry-instrumentation-botocore==0.37b0
opentelemetry-instrumentation-requests==0.37b0
opentelemetry-proto==1.15.0
opentelemetry-sdk==1.16.0
opentelemetry-semantic-conventions==0.37b0
opentelemetry-util-http==0.37b0
requests==2.28.1

Steps to reproduce When you pass a custom header dictionary to requests, e.g. requests.get("http://example.com", headers=myheaders), opentelemetry instrumentation code injects tracing headers into it. However it should create a copy of the dict instead of modifying it directly. It leads to subtle bugs when the header dictionary is a variable that is long lived and used elsewhere in the user code.

Running the code below illustrates the problem.

# Setup OTEL
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter
from opentelemetry.sdk.resources import SERVICE_NAME, Resource

resource = Resource(attributes={
    SERVICE_NAME: "your-service-name"
})

provider = TracerProvider(resource=resource)
processor = BatchSpanProcessor(ConsoleSpanExporter(out=open('/dev/null', 'w')))
provider.add_span_processor(processor)
trace.set_tracer_provider(provider)

# Set up requests instrumentation
import requests
from opentelemetry.instrumentation.requests import RequestsInstrumentor
RequestsInstrumentor().instrument()

# Try to use requests
HEADERS = {}
print("Headers before", HEADERS)
requests.get('http://example.com', headers=HEADERS)
print("Headers after", HEADERS)

What is the expected behavior? Instrumentation should not modify the dictionary. The code above should print

Headers before {}
Headers after {}

What is the actual behavior? Instead, the dictionary is modified and the code above prints something like

Headers before {}
Headers after {'traceparent': '00-3fa34759485cfd649023710bd9841f85-bf965377dfd3846d-01'}
avzis commented 1 year ago

can you assign this to me? thanks :)

federicobond commented 9 months ago

I was not able to reproduce this, it might have been fixed by the changes in https://github.com/open-telemetry/opentelemetry-python-contrib/pull/1717 inadvertently.

Can you confirm this is working correctly now?