22
33#include  < boost/algorithm/string.hpp> 
44#include  < boost/asio/ssl/context.hpp> 
5+ #include  < boost/asio/ssl/stream.hpp> 
56#include  < boost/beast/core/flat_buffer.hpp> 
67#include  < boost/beast/http/field.hpp> 
78#include  < boost/beast/http/message.hpp> 
@@ -43,6 +44,11 @@ using namespace icinga;
4344namespace  beast  =  boost::beast;
4445namespace  http  =  beast::http;
4546
47+ static  void  ExceptionHandler (const  boost::exception_ptr& exp);
48+ static  Array::Ptr ExtractTemplateTags (const  MacroProcessor::ResolverList& resolvers, const  Array::Ptr& tags_tmpl,
49+ 	const  Checkable::Ptr& checkable, const  CheckResult::Ptr& cr);
50+ static  Dictionary::Ptr ExtractTemplateLabels (const  MacroProcessor::ResolverList& resolvers, const  Dictionary::Ptr& labels_tmpl,
51+ 	const  Checkable::Ptr& checkable, const  CheckResult::Ptr& cr);
4652
4753REGISTER_TYPE (ElasticsearchDatastreamWriter);
4854
@@ -87,7 +93,7 @@ void ElasticsearchDatastreamWriter::Resume()
8793	Log (LogInformation, " ElasticsearchDatastreamWriter"  )
8894		<< " '"   << GetName () << " ' resumed."  ;
8995	m_Paused = false ;
90- 	m_WorkQueue.SetExceptionCallback ([this ](boost::exception_ptr exp) { ExceptionHandler (std::move ( exp) ); });
96+ 	m_WorkQueue.SetExceptionCallback ([](boost::exception_ptr exp) { ExceptionHandler (exp); });
9197
9298	if  (GetManageIndexTemplate ()) {
9399		//  Ensure index template exists/is updated as the first item on the work queue.
@@ -167,9 +173,9 @@ void ElasticsearchDatastreamWriter::ManageIndexTemplate() {
167173			Dictionary::Ptr jsonResponse = TrySend (component_template_url, " {\" template\" :{}}"  );
168174			Log (LogInformation, " ElasticsearchDatastreamWriter"  )
169175				<< " Successfully installed component template 'icinga2@custom'."  ;
170- 		} catch  (const  StatusCodeException es) {
176+ 		} catch  (const  StatusCodeException&  es) {
171177		  int  status_code = es.GetStatusCode ();
172- 		  if  (status_code == 400 ) {
178+ 		  if  (status_code == static_cast < int >(http::status::bad_request) ) {
173179			Log (LogInformation, " ElasticsearchDatastreamWriter"  )
174180				<< " Component template 'metrics-icinga2@custom' already exists, skipping creation."  ;
175181			//  Continue to install/update index template
@@ -207,7 +213,7 @@ void ElasticsearchDatastreamWriter::ManageIndexTemplate() {
207213	}
208214}
209215
210- Dictionary::Ptr ElasticsearchDatastreamWriter::ExtractPerfData (const  Checkable::Ptr checkable, const  Array::Ptr& perfdata) {
216+ Dictionary::Ptr ElasticsearchDatastreamWriter::ExtractPerfData (const  Checkable::Ptr&  checkable, const  Array::Ptr& perfdata) {
211217	Dictionary::Ptr pd_fields = new  Dictionary ();
212218	if  (!perfdata)
213219		return  pd_fields;
@@ -231,7 +237,7 @@ Dictionary::Ptr ElasticsearchDatastreamWriter::ExtractPerfData(const Checkable::
231237
232238		Dictionary::Ptr metric = new  Dictionary ();
233239		metric->Set (" value"  , pdv->GetValue ());
234- 		metric->Set (" counter"  , pdv->GetCounter ());
240+ 		if  (pdv-> GetCounter ())  metric->Set (" counter"  , pdv->GetCounter ());
235241
236242		if  (!pdv->GetMin ().IsEmpty ()) metric->Set (" min"  , pdv->GetMin ());
237243		if  (!pdv->GetMax ().IsEmpty ()) metric->Set (" max"  , pdv->GetMax ());
@@ -249,8 +255,8 @@ Dictionary::Ptr ElasticsearchDatastreamWriter::ExtractPerfData(const Checkable::
249255}
250256
251257//  user-defined tags, as specified in the ECS specification: https://www.elastic.co/docs/reference/ecs/ecs-base#field-tags
252- Array::Ptr ElasticsearchDatastreamWriter:: ExtractTemplateTags (const  MacroProcessor::ResolverList resolvers,
253- 	const  Array::Ptr tag_tmpl, const  Checkable::Ptr& checkable, const  CheckResult::Ptr& cr)
258+ static   Array::Ptr ExtractTemplateTags (const  MacroProcessor::ResolverList&  resolvers,
259+ 	const  Array::Ptr&  tag_tmpl, const  Checkable::Ptr& checkable, const  CheckResult::Ptr& cr)
254260{
255261	if  (tag_tmpl == nullptr ) {
256262		return  nullptr ;
@@ -275,8 +281,8 @@ Array::Ptr ElasticsearchDatastreamWriter::ExtractTemplateTags(const MacroProcess
275281}
276282
277283//  user-defined labels, as specified in the ECS specification: https://www.elastic.co/docs/reference/ecs/ecs-base#field-labels
278- Dictionary::Ptr ElasticsearchDatastreamWriter:: ExtractTemplateLabels (const  MacroProcessor::ResolverList resolvers,
279- 	const  Dictionary::Ptr labels_tmpl, const  Checkable::Ptr& checkable, const  CheckResult::Ptr& cr)
284+ static   Dictionary::Ptr ExtractTemplateLabels (const  MacroProcessor::ResolverList&  resolvers,
285+ 	const  Dictionary::Ptr&  labels_tmpl, const  Checkable::Ptr& checkable, const  CheckResult::Ptr& cr)
280286{
281287	if  (labels_tmpl == nullptr ) {
282288		return  nullptr ;
@@ -301,7 +307,7 @@ Dictionary::Ptr ElasticsearchDatastreamWriter::ExtractTemplateLabels(const Macro
301307	return  labels;
302308}
303309
304- String ElasticsearchDatastreamWriter::ExtractDatastreamNamespace (MacroProcessor::ResolverList resolvers,
310+ String ElasticsearchDatastreamWriter::ExtractDatastreamNamespace (const   MacroProcessor::ResolverList&  resolvers,
305311	const  Checkable::Ptr& checkable, const  CheckResult::Ptr& cr)
306312{
307313	String namespace_tmpl = GetDatastreamNamespace ();
@@ -365,20 +371,21 @@ void ElasticsearchDatastreamWriter::CheckResultHandler(const Checkable::Ptr& che
365371		{ " version"  , " 8.0.0"   }
366372	});
367373
368- 	String datastream_name = " metrics-icinga2."   + checkable->GetCheckCommandRaw () + " -"   + GetDatastreamNamespace ();
374+ 	String datastream_namespace = ExtractDatastreamNamespace (resolvers, checkable, cr);
375+ 	String datastream_name = " metrics-icinga2."   + checkable->GetCheckCommandRaw () + " -"   + datastream_namespace;
369376	Dictionary::Ptr data_stream = new  Dictionary ({
370377		{" type"  , " metrics"  },
371378		{" dataset"  , " icinga2."   + checkable->GetCheckCommandRaw ()},
372- 		{" namespace"  , ExtractDatastreamNamespace (resolvers, checkable, cr) }
379+ 		{" namespace"  , datastream_namespace }
373380	});
374381
375382	Dictionary::Ptr ecs_host = new  Dictionary ({
376383		{" name"  , host->GetDisplayName ()},
377384		{" hostname"  , host->GetName ()},
378- 		{" zone"  , host->GetZone ()->GetZoneName ()},
379385		{" soft_state"  , host->GetState ()},
380386		{" hard_state"  , host->GetLastHardState ()}
381387	});
388+ 	if  (!host->GetZoneName ().IsEmpty ()) ecs_host->Set (" zone"  , host->GetZoneName ());
382389
383390	char  _addr[16 ];
384391	if  (!host->GetAddress ().IsEmpty () && inet_pton (AF_INET, host->GetAddress ().CStr (), _addr) == 1 ) {
@@ -394,10 +401,10 @@ void ElasticsearchDatastreamWriter::CheckResultHandler(const Checkable::Ptr& che
394401	   	ecs_service = new  Dictionary ({
395402	   		{" name"  , service->GetName ()},
396403			{" display_name"  , service->GetDisplayName ()},
397- 			{" zone"  , host->GetZone ()->GetZoneName ()},
398404			{" soft_state"  , service->GetState ()},
399405			{" hard_state"  , service->GetLastHardState ()}
400406		});
407+ 		if  (!service->GetZoneName ().IsEmpty ()) ecs_service->Set (" zone"  , service->GetZoneName ());
401408	}
402409
403410	Dictionary::Ptr ecs_agent = new  Dictionary ({
@@ -407,10 +414,10 @@ void ElasticsearchDatastreamWriter::CheckResultHandler(const Checkable::Ptr& che
407414	Endpoint::Ptr endpoint = checkable->GetCommandEndpoint ();
408415	if  (endpoint) {
409416		ecs_agent->Set (" id"  , endpoint->GetName ());
410- 		ecs_agent->Set (" version"  , FormatIcingaVersion ( endpoint->GetIcingaVersion () ));
417+ 		ecs_agent->Set (" version"  , endpoint->GetIcingaVersionString ( ));
411418	} else  {
412419		ecs_agent->Set (" id"  , IcingaApplication::GetInstance ()->GetName ());
413- 		ecs_agent->Set (" version"  , FormatIcingaVersion (( unsigned   long )  IcingaApplication::GetInstance  ()-> GetVersion () ));
420+ 		ecs_agent->Set (" version"  , IcingaApplication::GetAppSpecVersion  ( ));
414421	}
415422
416423	Dictionary::Ptr ecs_event = new  Dictionary ({
@@ -432,25 +439,38 @@ void ElasticsearchDatastreamWriter::CheckResultHandler(const Checkable::Ptr& che
432439		{" active"  , cr->GetActive ()}
433440	});
434441
435- 	Dictionary::Ptr perf_data = ExtractPerfData (checkable, cr->GetPerformanceData ());
436- 
437442	Dictionary::Ptr document = new  Dictionary ({
438443		{" @timestamp"  , FormatTimestamp (cr->GetScheduleEnd ())},
439444		{ " ecs"  , ecs_metadata },
440445		{ " data_stream"  , data_stream },
441446		{ " host"  , ecs_host },
442- 		{ " service"  , ecs_service },
443447		{ " agent"  , ecs_agent },
444448		{ " event"  , ecs_event },
445449		{ " check"  , check_result },
446450		{ " message"  , cr->GetOutput () },
447- 		{ " perf_data"  , perf_data },
448- 		{ " tags"  , ExtractTemplateTags (
449- 			resolvers, service ? GetServiceTagsTemplate () : GetHostTagsTemplate (),  checkable, cr) },
450- 		{ " labels"  , ExtractTemplateLabels (
451- 			resolvers, service ? GetServiceLabelsTemplate () : GetHostLabelsTemplate (), checkable, cr) }
452451	});
453452
453+ 	Dictionary::Ptr perfdata = ExtractPerfData (checkable, cr->GetPerformanceData ());
454+ 	if  (perfdata->GetLength () != 0 ) {
455+         document->Set (" perfdata"  , perfdata);
456+     }
457+ 
458+ 	Array::Ptr ecs_tags = ExtractTemplateTags (
459+ 	    resolvers, service ? GetServiceTagsTemplate () : GetHostTagsTemplate (),  checkable, cr);
460+ 	if  (ecs_tags && ecs_tags->GetLength () != 0  ) {
461+         document->Set (" tags"  , ecs_tags);
462+     }
463+ 
464+ 	Dictionary::Ptr ecs_labels = ExtractTemplateLabels (
465+         resolvers, service ? GetServiceLabelsTemplate () : GetHostLabelsTemplate (), checkable, cr);
466+ 	if  (ecs_labels && ecs_labels->GetLength () != 0  ) {
467+ 	        document->Set (" labels"  , ecs_labels);
468+     }
469+ 
470+ 	if  (ecs_service && ecs_service->GetLength () != 0  ) {
471+ 	        document->Set (" service"  , ecs_service);
472+     }
473+ 
454474	EcsDocument::Ptr workqueue_document = new  EcsDocument (
455475		datastream_name,
456476		document
@@ -550,7 +570,7 @@ Value ElasticsearchDatastreamWriter::TrySend(Url::Ptr url, String body) {
550570	m_FlushTimer->Reschedule (-1 );
551571
552572	http::request<http::string_body> request  (http::verb::post , std::string (url->Format (true )), 10 );
553- 	request.set (http::field::user_agent, " Icinga/"   + Application::GetAppVersion  ());
573+ 	request.set (http::field::user_agent, " Icinga/"   + Application::GetAppSpecVersion  ());
554574	request.set (http::field::host, url->GetHost () + " :"   + url->GetPort ());
555575
556576	/*  Specify required headers by Elasticsearch. */ 
@@ -676,7 +696,7 @@ OptionalTlsStream ElasticsearchDatastreamWriter::Connect()
676696		auto & tlsStream  (stream.first ->next_layer ());
677697
678698		try  {
679- 			tlsStream.handshake (tlsStream. client );
699+ 			tlsStream.handshake (boost::asio::ssl::stream_base:: client);
680700		} catch  (const  std::exception&) {
681701			Log (LogWarning, " ElasticsearchDatastreamWriter"  )
682702				<< " TLS handshake with host '"   << GetHost () << " ' on port "   << GetPort () << "  failed."  ;
@@ -705,12 +725,12 @@ void ElasticsearchDatastreamWriter::AssertOnWorkQueue()
705725	ASSERT (m_WorkQueue.IsWorkerThread ());
706726}
707727
708- void  ElasticsearchDatastreamWriter:: ExceptionHandler (boost::exception_ptr exp)
728+ static   void  ExceptionHandler (const   boost::exception_ptr&  exp)
709729{
710730	Log (LogCritical, " ElasticsearchDatastreamWriter"  , " Exception during Elastic operation: Verify that your backend is operational!"  );
711731
712732	Log (LogDebug, " ElasticsearchDatastreamWriter"  )
713- 		<< " Exception during Elasticsearch operation: "   << DiagnosticInformation (std::move ( exp) );
733+ 		<< " Exception during Elasticsearch operation: "   << DiagnosticInformation (exp);
714734}
715735
716736String ElasticsearchDatastreamWriter::FormatTimestamp (double  ts)
@@ -731,16 +751,7 @@ String ElasticsearchDatastreamWriter::FormatTimestamp(double ts)
731751	return  Utility::FormatDateTime (" %Y-%m-%dT%H:%M:%S"  , ts) + " ."   + Convert::ToString (milliSeconds) + Utility::FormatDateTime (" %z"  , ts);
732752}
733753
734- String ElasticsearchDatastreamWriter::FormatIcingaVersion (unsigned  long  version) {
735- 	auto  bugfix = version % 100 ;
736- 	version /= 100 ;
737- 	auto  minor = version % 100 ;
738- 	auto  major = version / 100 ;
739- 	return  String () + std::to_string (major) + " ."   + std::to_string (minor) + " ."   + std::to_string (bugfix);
740- }
741- 
742- 
743- void  ElasticsearchDatastreamWriter::ValidateTagsTemplate (Array::Ptr tags) {
754+ void  ElasticsearchDatastreamWriter::ValidateTagsTemplate (const  Array::Ptr& tags) {
744755	ObjectLock olock (tags);
745756	for  (const  Value& tag : tags) {
746757		if  (!MacroProcessor::ValidateMacroString (tag)) {
@@ -752,7 +763,7 @@ void ElasticsearchDatastreamWriter::ValidateTagsTemplate(Array::Ptr tags) {
752763void  ElasticsearchDatastreamWriter::ValidateHostTagsTemplate (const  Lazy<Array::Ptr>& lvalue, const  ValidationUtils& utils)
753764{
754765	ObjectImpl<ElasticsearchDatastreamWriter>::ValidateHostTagsTemplate (lvalue, utils);
755- 	Array::Ptr  tags = lvalue ();
766+ 	auto &  tags = lvalue ();
756767	if  (tags) {
757768		ValidateTagsTemplate (tags);
758769	}
@@ -761,13 +772,13 @@ void ElasticsearchDatastreamWriter::ValidateHostTagsTemplate(const Lazy<Array::P
761772void  ElasticsearchDatastreamWriter::ValidateServiceTagsTemplate (const  Lazy<Array::Ptr>& lvalue, const  ValidationUtils& utils)
762773{
763774	ObjectImpl<ElasticsearchDatastreamWriter>::ValidateServiceTagsTemplate (lvalue, utils);
764- 	Array::Ptr  tags = lvalue ();
775+ 	auto &  tags = lvalue ();
765776	if  (tags) {
766777		ValidateTagsTemplate (tags);
767778	}
768779}
769780
770- void  ElasticsearchDatastreamWriter::ValidateLabelsTemplate (Dictionary::Ptr labels) {
781+ void  ElasticsearchDatastreamWriter::ValidateLabelsTemplate (const   Dictionary::Ptr&  labels) {
771782	ObjectLock olock (labels);
772783	for  (const  Dictionary::Pair& kv : labels) {
773784		if  (!MacroProcessor::ValidateMacroString (kv.second )) {
@@ -779,7 +790,7 @@ void ElasticsearchDatastreamWriter::ValidateLabelsTemplate(Dictionary::Ptr label
779790void  ElasticsearchDatastreamWriter::ValidateHostLabelsTemplate (const  Lazy<Dictionary::Ptr>& lvalue, const  ValidationUtils& utils)
780791{
781792	ObjectImpl<ElasticsearchDatastreamWriter>::ValidateHostLabelsTemplate (lvalue, utils);
782- 	Dictionary::Ptr  labels = lvalue ();
793+ 	auto &  labels = lvalue ();
783794	if  (labels) {
784795		ValidateLabelsTemplate (labels);
785796	}
@@ -788,7 +799,7 @@ void ElasticsearchDatastreamWriter::ValidateHostLabelsTemplate(const Lazy<Dictio
788799void  ElasticsearchDatastreamWriter::ValidateServiceLabelsTemplate (const  Lazy<Dictionary::Ptr>& lvalue, const  ValidationUtils& utils)
789800{
790801	ObjectImpl<ElasticsearchDatastreamWriter>::ValidateServiceLabelsTemplate (lvalue, utils);
791- 	Dictionary::Ptr  labels = lvalue ();
802+ 	auto &  labels = lvalue ();
792803	if  (labels) {
793804		ValidateLabelsTemplate (labels);
794805	}
@@ -816,7 +827,6 @@ void ElasticsearchDatastreamWriter::ValidateFilter(const Lazy<Value> &lvalue, co
816827	m_CompiledFilter = std::move (fexpr);
817828}
818829
819- EcsDocument::EcsDocument (String index, Dictionary::Ptr document) {
820- 	SetIndex (index, true );
821- 	SetDocument (document, true );
830+ EcsDocument::EcsDocument (String index, Dictionary::Ptr document)
831+ 	: m_Index(std::move(index)), m_Document(std::move(document)) {
822832}
0 commit comments