MCPcopy Create free account
hub / github.com/Icinga/icinga2 / ExportImpl

Method ExportImpl

lib/otel/otel.cpp:366–421  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

364}
365
366void OTel::ExportImpl(boost::asio::yield_context& yc) const
367{
368 AsioProtobufOutStream outputS{*m_Stream, m_ConnInfo, yc};
369 [[maybe_unused]] auto serialized = m_Request->SerializeToZeroCopyStream(&outputS);
370 ASSERT(serialized);
371 // Must have completed chunk writing successfully, otherwise reading the response will hang forever.
372 if (!outputS.WriterDone()) {
373 BOOST_THROW_EXCEPTION(std::runtime_error("BUG: Protobuf output stream writer did not complete successfully."));
374 }
375
376 IncomingHttpResponse responseMsg{*m_Stream};
377 responseMsg.Parse(yc);
378
379 if (auto ct = responseMsg[http::field::content_type]; ct != "application/x-protobuf") {
380 if (responseMsg.result() == http::status::ok) {
381 // Some OpenTelemetry Collector compatible backends (e.g., Prometheus OTLP Receiver) respond with 200 OK
382 // but without the expected Protobuf content type. So, don't do anything here since the request succeeded.
383 return;
384 }
385 Log(LogWarning, "OTelExporter")
386 << "Unexpected Content-Type from OpenTelemetry backend '" << ct << "' (" << responseMsg.reason() << "):\n"
387 << responseMsg.body();
388 } else if (responseMsg.result_int() >= 200 && responseMsg.result_int() <= 299) {
389 // We've got a valid Protobuf response, so we've to deserialize the body to check for partial success.
390 // See https://opentelemetry.io/docs/specs/otlp/#partial-success-1.
391 google::protobuf::Arena arena;
392 auto* response = MetricsResponse::default_instance().New(&arena);
393 [[maybe_unused]] auto deserialized = response->ParseFromString(responseMsg.body());
394 ASSERT(deserialized);
395
396 if (response->has_partial_success()) {
397 const auto& ps = response->partial_success();
398 const auto& msg = ps.error_message();
399 if (ps.rejected_data_points() > 0 || !msg.empty()) {
400 Log(LogWarning, "OTelExporter")
401 << "OpenTelemetry backend reported partial success: " << (msg.empty() ? "<none>" : msg)
402 << " (" << ps.rejected_data_points() << " metric data points rejected).";
403 }
404 }
405 } else if (IsRetryableExportError(responseMsg.result())) {
406 uint64_t throttleSeconds = 0;
407 if (auto throttle = responseMsg[http::field::retry_after]; !throttle.empty()) {
408 try {
409 throttleSeconds = boost::lexical_cast<uint64_t>(throttle);
410 } catch (const std::exception& ex) {
411 Log(LogWarning, "OTelExporter")
412 << "Failed to parse 'Retry-After' header from OpenTelemetry backend response: " << ex.what();
413 }
414 }
415 BOOST_THROW_EXCEPTION(RetryableExportError{throttleSeconds});
416 } else {
417 Log(LogWarning, "OTelExporter")
418 << "OpenTelemetry backend responded with non-success and non-retryable status code "
419 << responseMsg.result_int() << " (" << responseMsg.reason() << ").\n" << responseMsg.body();
420 }
421}
422
423/**

Callers

nothing calls this directly

Calls 5

LogClass · 0.85
WriterDoneMethod · 0.80
ParseMethod · 0.45
emptyMethod · 0.45
whatMethod · 0.45

Tested by

no test coverage detected