open-telemetry / opentelemetry-python

OpenTelemetry Python API and SDK
https://opentelemetry.io
Apache License 2.0
1.67k stars 569 forks source link

Inexplicably, opentelemetry-python on Windows is rewriting an OTEL_EXPORTER_OTLP_ENDPOINT env var with backslashes instead of forward slashes #3912

Closed doctorpangloss closed 1 week ago

doctorpangloss commented 1 month ago

Describe your environment

python: 3.11 Windows 2022 Server Windows Containers on Windows

$ pip freeze | grep opentelemetry
opentelemetry-api==1.24.0
opentelemetry-distro==0.45b0
opentelemetry-exporter-otlp==1.24.0
opentelemetry-exporter-otlp-proto-common==1.24.0
opentelemetry-exporter-otlp-proto-grpc==1.24.0
opentelemetry-exporter-otlp-proto-http==1.24.0
opentelemetry-instrumentation==0.45b0
opentelemetry-instrumentation-aio-pika==0.45b0
opentelemetry-instrumentation-aiohttp-client==0.45b0
opentelemetry-instrumentation-asyncio==0.45b0
opentelemetry-instrumentation-aws-lambda==0.45b0
opentelemetry-instrumentation-dbapi==0.45b0
opentelemetry-instrumentation-logging==0.45b0
opentelemetry-instrumentation-sqlite3==0.45b0
opentelemetry-instrumentation-urllib==0.45b0
opentelemetry-instrumentation-wsgi==0.45b0
opentelemetry-propagator-aws-xray==1.0.1
opentelemetry-proto==1.24.0
opentelemetry-sdk==1.24.0
opentelemetry-semantic-conventions==0.45b0
opentelemetry-test-utils==0.45b0
opentelemetry-util-http==0.45b0

Steps to reproduce

  1. On Windows, pip install git+https://github.com/hiddenswitch/ComfyUI.git
  2. Start a local collector.
  3. Run OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 comfyui
  4. Observe that forward slashes are inexplicably replaced with backslashes, breaking automatic configuration.

What is the expected behavior? I should be able to set the endpoint URL in Windows the same way I do in Linux.

What is the actual behavior?

Traceback (most recent call last):
  File "C:\Python311\Lib\site-packages\opentelemetry\sdk\trace\export\__init__.py", line 367, in _export_batch
    self.span_exporter.export(self.spans_list[:idx])  # type: ignore
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Python311\Lib\site-packages\opentelemetry\exporter\otlp\proto\http\trace_exporter\__init__.py", line 145, in export
    resp = self._export(serialized_data)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Python311\Lib\site-packages\opentelemetry\exporter\otlp\proto\http\trace_exporter\__init__.py", line 114, in _export
    return self._session.post(
           ^^^^^^^^^^^^^^^^^^^
  File "C:\Python311\Lib\site-packages\requests\sessions.py", line 637, in post
    return self.request("POST", url, data=data, json=json, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Python311\Lib\site-packages\requests\sessions.py", line 575, in request
    prep = self.prepare_request(req)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Python311\Lib\site-packages\requests\sessions.py", line 486, in prepare_request
    p.prepare(
  File "C:\Python311\Lib\site-packages\requests\models.py", line 368, in prepare
    self.prepare_url(url, params)
  File "C:\Python311\Lib\site-packages\requests\models.py", line 445, in prepare_url
    raise InvalidURL(f"Invalid URL {url!r}: No host supplied")
requests.exceptions.InvalidURL: Invalid URL 'http:\\\\otlp-collector.monitoring.svc.cluster.local:4318/v1/traces': No host supplied

Additional context This is how the tracer is initialized: https://github.com/hiddenswitch/ComfyUI/blob/3a64e04a9339d6797106b1c5f444c76dab2614dc/comfy/cmd/main_pre.py#L48

def _create_tracer():
    resource = Resource.create({
        ResAttrs.SERVICE_NAME: args.otel_service_name,
        ResAttrs.SERVICE_VERSION: args.otel_service_version,
    })

    # omit progress spans from aio pika
    sampler = ProgressSpanSampler()
    provider = TracerProvider(resource=resource, sampler=sampler)

    is_debugging = hasattr(sys, 'gettrace') and sys.gettrace() is not None
    has_endpoint = args.otel_exporter_otlp_endpoint is not None

    if has_endpoint:
        otlp_exporter = OTLPSpanExporter()
    elif is_debugging:
        otlp_exporter = ConsoleSpanExporter()
    else:
        otlp_exporter = SpanExporter()

    processor = BatchSpanProcessor(otlp_exporter)
    provider.add_span_processor(processor)

    trace.set_tracer_provider(provider)

    # enable instrumentation
    patch_spanbuilder_set_channel()
    AioPikaInstrumentor().instrument()
    AioHttpServerInstrumentor().instrument()
    return trace.get_tracer(args.otel_service_name)

tracer = _create_tracer()