Description:
On latest main, otlploghttp mishandles the global OTEL_EXPORTER_OTLP_ENDPOINT when the base URL ends with a trailing slash
If the endpoint is set to a base URL like http://host/prefix/, log export requests are sent to /prefix//v1/logs instead of /prefix/v1/logs
Steps to Reproduce:
Check out main at 524fc3c25
From PowerShell in the repository root, run:
$repo = ((Get-Location ).Path -replace ' \\' , ' /' )
$root = Join-Path $env: TEMP ' otel-otlploghttp-trailing-slash-repro'
Remove-Item - Recurse - Force $root - ErrorAction SilentlyContinue
New-Item - ItemType Directory - Force - Path $root | Out-Null
@"
module example.com/otlploghttprepro
go 1.25.0
require (
go.opentelemetry.io/otel v0.0.0
go.opentelemetry.io/otel/sdk/log v0.0.0
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.0.0
)
replace go.opentelemetry.io/otel => $repo
replace go.opentelemetry.io/otel/sdk/log => $repo /sdk/log
replace go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp => $repo /exporters/otlp/otlplog/otlploghttp
"@ | Set-Content - Path (Join-Path $root ' go.mod' )
@"
package main
import (
"context"
"fmt"
"net/http"
"net/http/httptest"
"os"
"time"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp"
sdklog "go.opentelemetry.io/otel/sdk/log"
)
func main() {
var gotPath string
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
gotPath = r.URL.Path
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("{}"))
}))
defer srv.Close()
if err := os.Setenv("OTEL_EXPORTER_OTLP_ENDPOINT", srv.URL+"/prefix/"); err != nil {
panic(err)
}
defer os.Unsetenv("OTEL_EXPORTER_OTLP_ENDPOINT")
exp, err := otlploghttp.New(context.Background(), otlploghttp.WithTimeout(time.Second))
if err != nil {
panic(err)
}
var rec sdklog.Record
rec.SetBody(attribute.StringValue("x"))
if err := exp.Export(context.Background(), []sdklog.Record{rec}); err != nil {
panic(err)
}
fmt.Println(gotPath)
}
"@ | Set-Content - Path (Join-Path $root ' main.go' )
Push-Location $root
go mod tidy
go run .
Pop-Location
Actual Behavior:
The repro prints:
So the exporter sends logs to a path with a duplicated slash
Expected Behavior:
The exporter should normalize the global base endpoint path and send logs to:
A trailing slash in the base OTEL_EXPORTER_OTLP_ENDPOINT should not produce a duplicated slash in the final OTLP logs path
Notes:
exporters/otlp/otlplog/otlploghttp/config.go currently returns u.Path + "/v1/logs" in convPath
If u.Path already ends with /, that produces /prefix//v1/logs
The trace and metric OTLP HTTP exporters normalize the global endpoint base path instead of duplicating the slash
This is separate from otlploghttp.WithEndpointURL does not default to "/v1/logs" #8537 , which discussed WithEndpointURL(...) semantics for explicit in-code endpoint URLs
This bug affects only the global OTEL_EXPORTER_OTLP_ENDPOINT base URL path handling
Description:
On latest
main,otlploghttpmishandles the globalOTEL_EXPORTER_OTLP_ENDPOINTwhen the base URL ends with a trailing slashIf the endpoint is set to a base URL like
http://host/prefix/, log export requests are sent to/prefix//v1/logsinstead of/prefix/v1/logsSteps to Reproduce:
mainat524fc3c25Actual Behavior:
The repro prints:
So the exporter sends logs to a path with a duplicated slash
Expected Behavior:
The exporter should normalize the global base endpoint path and send logs to:
A trailing slash in the base
OTEL_EXPORTER_OTLP_ENDPOINTshould not produce a duplicated slash in the final OTLP logs pathNotes:
exporters/otlp/otlplog/otlploghttp/config.gocurrently returnsu.Path + "/v1/logs"inconvPathu.Pathalready ends with/, that produces/prefix//v1/logsWithEndpointURL(...)semantics for explicit in-code endpoint URLsOTEL_EXPORTER_OTLP_ENDPOINTbase URL path handling