@@ -91,10 +91,25 @@ void ElasticsearchWriter::Resume()
9191 /* Setup timer for periodically flushing m_DataBuffer */
9292 m_FlushTimer = Timer::Create ();
9393 m_FlushTimer->SetInterval (GetFlushInterval ());
94- m_FlushTimer->OnTimerExpired .connect ([this ](const Timer * const &) { FlushTimeout (); });
94+ m_FlushTimer->OnTimerExpired .connect ([this ](const Timer* const &) {
95+ m_WorkQueue.Enqueue ([&]() { FlushTimeout (); });
96+ });
9597 m_FlushTimer->Start ();
9698 m_FlushTimer->Reschedule (0 );
9799
100+ Shared<boost::asio::ssl::context>::Ptr sslContext;
101+ if (GetEnableTls ()) {
102+ try {
103+ sslContext = MakeAsioSslContext (GetCertPath (), GetKeyPath (), GetCaPath ());
104+ } catch (const std::exception& ex) {
105+ Log (LogWarning, GetReflectionType ()->GetName ())
106+ << " Unable to create SSL context." ;
107+ throw ;
108+ }
109+ }
110+
111+ m_Connection = new PerfdataWriterConnection{GetHost (), GetPort (), sslContext};
112+
98113 /* Register for new metrics. */
99114 m_HandleCheckResults = Checkable::OnNewCheckResult.connect ([this ](const Checkable::Ptr& checkable,
100115 const CheckResult::Ptr& cr, const MessageOrigin::Ptr&) {
@@ -118,6 +133,10 @@ void ElasticsearchWriter::Pause()
118133 m_HandleStateChanges.disconnect ();
119134 m_HandleNotifications.disconnect ();
120135
136+ m_Connection->StartDisconnectTimeout (
137+ std::chrono::milliseconds{static_cast <unsigned >(GetDisconnectTimeout () * 1000 )}
138+ );
139+
121140 m_FlushTimer->Stop (true );
122141 m_WorkQueue.Join ();
123142
@@ -465,22 +484,6 @@ void ElasticsearchWriter::SendRequest(const String& body)
465484
466485 url->SetPath (path);
467486
468- OptionalTlsStream stream;
469-
470- try {
471- stream = Connect ();
472- } catch (const std::exception& ex) {
473- Log (LogWarning, " ElasticsearchWriter" )
474- << " Flush failed, cannot connect to Elasticsearch: " << DiagnosticInformation (ex, false );
475- return ;
476- }
477-
478- Defer s ([&stream]() {
479- if (stream.first ) {
480- stream.first ->next_layer ().shutdown ();
481- }
482- });
483-
484487 http::request<http::string_body> request (http::verb::post , std::string (url->Format (true )), 10 );
485488
486489 request.set (http::field::user_agent, " Icinga/" + Application::GetAppVersion ());
@@ -510,37 +513,19 @@ void ElasticsearchWriter::SendRequest(const String& body)
510513 << " Sending " << request.method_string () << " request" << ((!username.IsEmpty () && !password.IsEmpty ()) ? " with basic auth" : " " )
511514 << " to '" << url->Format () << " '." ;
512515
516+ decltype (m_Connection->Send (request)) response;
513517 try {
514- if (stream. first ) {
515- http::write (*stream. first , request);
516- stream. first -> flush ( );
517- } else {
518- http::write (*stream. second , request) ;
519- stream. second -> flush () ;
518+ response = m_Connection-> Send (request);
519+ } catch ( const std::exception& ex) {
520+ if ( const auto * se = dynamic_cast < const boost::system::system_error*>(&ex );
521+ se-> code () == boost::system::errc::operation_canceled) {
522+ Log (LogDebug, " ElasticsearchWriter " ) << " Operation Cancelled. " ;
523+ return ;
520524 }
521- } catch (const std::exception&) {
522- Log (LogWarning, " ElasticsearchWriter" )
523- << " Cannot write to HTTP API on host '" << GetHost () << " ' port '" << GetPort () << " '." ;
524- throw ;
525- }
526-
527- http::parser<false , http::string_body> parser;
528- beast::flat_buffer buf;
529525
530- try {
531- if (stream.first ) {
532- http::read (*stream.first , buf, parser);
533- } else {
534- http::read (*stream.second , buf, parser);
535- }
536- } catch (const std::exception& ex) {
537- Log (LogWarning, " ElasticsearchWriter" )
538- << " Failed to parse HTTP response from host '" << GetHost () << " ' port '" << GetPort () << " ': " << DiagnosticInformation (ex, false );
539- throw ;
526+ Log (LogCritical, " ElasticsearchWriter" ) << " Error sending Request: " << ex.what ();
540527 }
541528
542- auto & response (parser.get ());
543-
544529 if (response.result_int () > 299 ) {
545530 if (response.result () == http::status::unauthorized) {
546531 /* More verbose error logging with Elasticsearch is hidden behind a proxy. */
@@ -588,66 +573,6 @@ void ElasticsearchWriter::SendRequest(const String& body)
588573 }
589574}
590575
591- OptionalTlsStream ElasticsearchWriter::Connect ()
592- {
593- Log (LogNotice, " ElasticsearchWriter" )
594- << " Connecting to Elasticsearch on host '" << GetHost () << " ' port '" << GetPort () << " '." ;
595-
596- OptionalTlsStream stream;
597- bool tls = GetEnableTls ();
598-
599- if (tls) {
600- Shared<boost::asio::ssl::context>::Ptr sslContext;
601-
602- try {
603- sslContext = MakeAsioSslContext (GetCertPath (), GetKeyPath (), GetCaPath ());
604- } catch (const std::exception&) {
605- Log (LogWarning, " ElasticsearchWriter" )
606- << " Unable to create SSL context." ;
607- throw ;
608- }
609-
610- stream.first = Shared<AsioTlsStream>::Make (IoEngine::Get ().GetIoContext (), *sslContext, GetHost ());
611-
612- } else {
613- stream.second = Shared<AsioTcpStream>::Make (IoEngine::Get ().GetIoContext ());
614- }
615-
616- try {
617- icinga::Connect (tls ? stream.first ->lowest_layer () : stream.second ->lowest_layer (), GetHost (), GetPort ());
618- } catch (const std::exception&) {
619- Log (LogWarning, " ElasticsearchWriter" )
620- << " Can't connect to Elasticsearch on host '" << GetHost () << " ' port '" << GetPort () << " '." ;
621- throw ;
622- }
623-
624- if (tls) {
625- auto & tlsStream (stream.first ->next_layer ());
626-
627- try {
628- tlsStream.handshake (tlsStream.client );
629- } catch (const std::exception&) {
630- Log (LogWarning, " ElasticsearchWriter" )
631- << " TLS handshake with host '" << GetHost () << " ' on port " << GetPort () << " failed." ;
632- throw ;
633- }
634-
635- if (!GetInsecureNoverify ()) {
636- if (!tlsStream.GetPeerCertificate ()) {
637- BOOST_THROW_EXCEPTION (std::runtime_error (" Elasticsearch didn't present any TLS certificate." ));
638- }
639-
640- if (!tlsStream.IsVerifyOK ()) {
641- BOOST_THROW_EXCEPTION (std::runtime_error (
642- " TLS certificate validation failed: " + std::string (tlsStream.GetVerifyError ())
643- ));
644- }
645- }
646- }
647-
648- return stream;
649- }
650-
651576void ElasticsearchWriter::AssertOnWorkQueue ()
652577{
653578 ASSERT (m_WorkQueue.IsWorkerThread ());
0 commit comments