Describe your environment
main at d64b2512, macOS 26.6.2, Apple clang, CMake Debug build with WITH_ELASTICSEARCH=ON, libcurl 8.7.1. The curl client is the only HTTP client in tree.
Steps to reproduce
Point the Elasticsearch log exporter at a socket that accepts the connection and never answers, with a 1 second response timeout.
ElasticsearchExporterOptions options("127.0.0.1", port, "logs", /*response_timeout=*/1);
ElasticsearchLogRecordExporter exporter(options);
auto record = exporter.MakeRecordable();
record->SetBody("probe");
exporter.Export(nostd::span<std::unique_ptr<sdklogs::Recordable>>(&record, 1));
s = socket.socket(); s.bind(("127.0.0.1", port)); s.listen(8)
while True: c, _ = s.accept() # accept, read nothing, answer nothing
What is the expected behavior?
SetTimeoutMs() expires, the session reports SessionState::TimedOut, and the exporter logs [ES Log Exporter] Request timed out from the handler at es_log_record_exporter.cc:178. The doc comment at :114 states this directly: the longest wait is "the timeout of the request, set by SetTimeoutMs(), which arrives here as a TimedOut session event".
What is the actual behavior?
SendFailed, every time. Two runs:
log + 0.4ms [ES Log Exporter] Sending request
log + 1006.4ms [ES Log Exporter] Failed to send request
export 0 result=FAILURE elapsed=1006.4ms
log + 1002.9ms [ES Log Exporter] Failed to send request
export 1 result=FAILURE elapsed=1003.0ms
The timeout is honoured, so this is a classification problem rather than a hang.
Additional context
SessionState::TimedOut is declared at ext/include/opentelemetry/ext/http/client/http_client.h:93 and is never dispatched anywhere under ext/. HttpOperation::PerformCurlMessage (http_operation_curl.cc:1564-1594) maps every non-CURLE_OK code to ConnectFailed when the state is Connecting and to SendFailed when it is Connected or Sending, so CURLE_OPERATION_TIMEDOUT is indistinguishable from a refused connection or a dropped socket.
Four handler branches wait for an event that cannot arrive: es_log_record_exporter.cc:178 and :320, otlp_http_client.cc:200 and :303. A caller cannot currently tell a timeout from a transport failure, which matters because the two usually deserve different retry behaviour.
Two ways out, and I do not want to guess which you prefer. Dispatch TimedOut for CURLE_OPERATION_TIMEDOUT in PerformCurlMessage, which makes the four branches live and could change behaviour for anyone switching on SendFailed today. Or drop the enum value with its four branches and correct the comment at :114. Happy to send a PR either way.
Describe your environment
mainatd64b2512, macOS 26.6.2, Apple clang, CMake Debug build withWITH_ELASTICSEARCH=ON, libcurl 8.7.1. The curl client is the only HTTP client in tree.Steps to reproduce
Point the Elasticsearch log exporter at a socket that accepts the connection and never answers, with a 1 second response timeout.
What is the expected behavior?
SetTimeoutMs()expires, the session reportsSessionState::TimedOut, and the exporter logs[ES Log Exporter] Request timed outfrom the handler ates_log_record_exporter.cc:178. The doc comment at:114states this directly: the longest wait is "the timeout of the request, set bySetTimeoutMs(), which arrives here as a TimedOut session event".What is the actual behavior?
SendFailed, every time. Two runs:The timeout is honoured, so this is a classification problem rather than a hang.
Additional context
SessionState::TimedOutis declared atext/include/opentelemetry/ext/http/client/http_client.h:93and is never dispatched anywhere underext/.HttpOperation::PerformCurlMessage(http_operation_curl.cc:1564-1594) maps every non-CURLE_OKcode toConnectFailedwhen the state isConnectingand toSendFailedwhen it isConnectedorSending, soCURLE_OPERATION_TIMEDOUTis indistinguishable from a refused connection or a dropped socket.Four handler branches wait for an event that cannot arrive:
es_log_record_exporter.cc:178and:320,otlp_http_client.cc:200and:303. A caller cannot currently tell a timeout from a transport failure, which matters because the two usually deserve different retry behaviour.Two ways out, and I do not want to guess which you prefer. Dispatch
TimedOutforCURLE_OPERATION_TIMEDOUTinPerformCurlMessage, which makes the four branches live and could change behaviour for anyone switching onSendFailedtoday. Or drop the enum value with its four branches and correct the comment at:114. Happy to send a PR either way.