From 3fe169cd7a3b2cc8632edda8e532b7026306b21f Mon Sep 17 00:00:00 2001 From: Michael Friedrich Date: Tue, 1 Apr 2014 20:30:44 +0200 Subject: [PATCH] Graphite/PerfdataWriter: Add host perfdata. Fixes #5908 --- components/perfdata/graphitewriter.cpp | 30 ++++++++++-- components/perfdata/graphitewriter.h | 1 + components/perfdata/perfdatawriter.cpp | 51 +++++++++++++------- components/perfdata/perfdatawriter.h | 5 +- components/perfdata/perfdatawriter.ti | 27 +++++++++-- doc/2.1-setting-up-icinga-2.md | 2 +- doc/3.11-performance-data.md | 28 ++++++----- doc/4.3-object-types.md | 25 ++++++---- doc/8-differences-between-icinga-1x-and-2.md | 6 --- lib/icinga/host.cpp | 9 ++++ 10 files changed, 127 insertions(+), 57 deletions(-) diff --git a/components/perfdata/graphitewriter.cpp b/components/perfdata/graphitewriter.cpp index dabb2386c..a64df7108 100644 --- a/components/perfdata/graphitewriter.cpp +++ b/components/perfdata/graphitewriter.cpp @@ -82,7 +82,7 @@ void GraphiteWriter::ReconnectTimerHandler(void) return; } } catch (const std::exception& ex) { - Log(LogWarning, "perfdata", "GraphiteWriter socket on host '" + GetHost() + "' port '" + GetPort() + "' gone. Attempting to reconnect."); + Log(LogWarning, "perfdata", "GraphiteWriter socket on host '" + GetHost() + "' port '" + GetPort() + "' gone. Attempting to reconnect."); } TcpSocket::Ptr socket = make_shared(); @@ -99,16 +99,17 @@ void GraphiteWriter::CheckResultHandler(const Service::Ptr& service, const Check if (!IcingaApplication::GetInstance()->GetEnablePerfdata() || !service->GetEnablePerfdata()) return; - /* TODO: sanitize host and service names */ - String hostName = service->GetHost()->GetName(); - String serviceName = service->GetShortName(); + Host::Ptr host = service->GetHost(); + + String hostName = host->GetName(); + String serviceName = service->GetShortName(); SanitizeMetric(hostName); SanitizeMetric(serviceName); String prefix = "icinga." + hostName + "." + serviceName; - /* basic metrics */ + /* service metrics */ SendMetric(prefix, "current_attempt", service->GetCheckAttempt()); SendMetric(prefix, "max_check_attempts", service->GetMaxCheckAttempts()); SendMetric(prefix, "state_type", service->GetStateType()); @@ -116,6 +117,25 @@ void GraphiteWriter::CheckResultHandler(const Service::Ptr& service, const Check SendMetric(prefix, "latency", Service::CalculateLatency(cr)); SendMetric(prefix, "execution_time", Service::CalculateExecutionTime(cr)); + SendPerfdata(prefix, cr); + + if (service == host->GetCheckService()) { + prefix = "icinga." + hostName; // TODO works? + + /* host metrics */ + SendMetric(prefix, "current_attempt", service->GetCheckAttempt()); + SendMetric(prefix, "max_check_attempts", service->GetMaxCheckAttempts()); + SendMetric(prefix, "state_type", host->GetStateType()); + SendMetric(prefix, "state", host->GetState()); + SendMetric(prefix, "latency", Service::CalculateLatency(cr)); + SendMetric(prefix, "execution_time", Service::CalculateExecutionTime(cr)); + + SendPerfdata(prefix, cr); + } +} + +void GraphiteWriter::SendPerfdata(const String& prefix, const CheckResult::Ptr& cr) +{ Value pdv = cr->GetPerformanceData(); if (!pdv.IsObjectType()) diff --git a/components/perfdata/graphitewriter.h b/components/perfdata/graphitewriter.h index 9c830f2a3..219bc818f 100644 --- a/components/perfdata/graphitewriter.h +++ b/components/perfdata/graphitewriter.h @@ -53,6 +53,7 @@ private: void CheckResultHandler(const Service::Ptr& service, const CheckResult::Ptr& cr); void SendMetric(const String& prefix, const String& name, double value); + void SendPerfdata(const String& prefix, const CheckResult::Ptr& cr); static void SanitizeMetric(String& str); void ReconnectTimerHandler(void); diff --git a/components/perfdata/perfdatawriter.cpp b/components/perfdata/perfdatawriter.cpp index ca0634f02..68b7e2920 100644 --- a/components/perfdata/perfdatawriter.cpp +++ b/components/perfdata/perfdatawriter.cpp @@ -60,7 +60,8 @@ void PerfdataWriter::Start(void) m_RotationTimer->SetInterval(GetRotationInterval()); m_RotationTimer->Start(); - RotateFile(); + RotateFile(m_ServiceOutputFile, GetServiceTempPath(), GetServicePerfdataPath()); + RotateFile(m_HostOutputFile, GetHostTempPath(), GetHostPerfdataPath()); } void PerfdataWriter::CheckResultHandler(const Service::Ptr& service, const CheckResult::Ptr& cr) @@ -77,36 +78,52 @@ void PerfdataWriter::CheckResultHandler(const Service::Ptr& service, const Check resolvers.push_back(host); resolvers.push_back(IcingaApplication::GetInstance()); - String line = MacroProcessor::ResolveMacros(GetFormatTemplate(), resolvers, cr); + String line = MacroProcessor::ResolveMacros(GetServiceFormatTemplate(), resolvers, cr); - ObjectLock olock(this); - if (!m_OutputFile.good()) - return; + { + ObjectLock olock(this); + if (!m_ServiceOutputFile.good()) + return; + + m_ServiceOutputFile << line << "\n"; + } - m_OutputFile << line << "\n"; + if (service == host->GetCheckService()) { + resolvers.clear(); + resolvers.push_back(host); + resolvers.push_back(IcingaApplication::GetInstance()); + line = MacroProcessor::ResolveMacros(GetHostFormatTemplate(), resolvers, cr); + + { + ObjectLock olock(this); + if (!m_HostOutputFile.good()) + return; + + m_HostOutputFile << line << "\n"; + } + } } -void PerfdataWriter::RotateFile(void) +void PerfdataWriter::RotateFile(std::ofstream& output, const String& temp_path, const String& perfdata_path) { ObjectLock olock(this); - String tempFile = GetTempPath(); - - if (m_OutputFile.good()) { - m_OutputFile.close(); + if (output.good()) { + output.close(); - String finalFile = GetPerfdataPath() + "." + Convert::ToString((long)Utility::GetTime()); - (void) rename(tempFile.CStr(), finalFile.CStr()); + String finalFile = perfdata_path + "." + Convert::ToString((long)Utility::GetTime()); + (void) rename(temp_path.CStr(), finalFile.CStr()); } - m_OutputFile.open(tempFile.CStr()); + output.open(temp_path.CStr()); - if (!m_OutputFile.good()) - Log(LogWarning, "icinga", "Could not open perfdata file '" + tempFile + "' for writing. Perfdata will be lost."); + if (!output.good()) + Log(LogWarning, "icinga", "Could not open perfdata file '" + temp_path + "' for writing. Perfdata will be lost."); } void PerfdataWriter::RotationTimerHandler(void) { - RotateFile(); + RotateFile(m_ServiceOutputFile, GetServiceTempPath(), GetServicePerfdataPath()); + RotateFile(m_HostOutputFile, GetHostTempPath(), GetHostPerfdataPath()); } diff --git a/components/perfdata/perfdatawriter.h b/components/perfdata/perfdatawriter.h index 85edd0d12..2def5b84d 100644 --- a/components/perfdata/perfdatawriter.h +++ b/components/perfdata/perfdatawriter.h @@ -51,8 +51,9 @@ private: Timer::Ptr m_RotationTimer; void RotationTimerHandler(void); - std::ofstream m_OutputFile; - void RotateFile(void); + std::ofstream m_ServiceOutputFile; + std::ofstream m_HostOutputFile; + void RotateFile(std::ofstream& output, const String& temp_path, const String& perfdata_path); }; } diff --git a/components/perfdata/perfdatawriter.ti b/components/perfdata/perfdatawriter.ti index cea802274..400392103 100644 --- a/components/perfdata/perfdatawriter.ti +++ b/components/perfdata/perfdatawriter.ti @@ -6,13 +6,30 @@ namespace icinga class PerfdataWriter : DynamicObject { - [config] String perfdata_path { - default {{{ return Application::GetLocalStateDir() + "/spool/icinga2/perfdata/perfdata"; }}} + [config] String host_perfdata_path { + default {{{ return Application::GetLocalStateDir() + "/spool/icinga2/perfdata/host-perfdata"; }}} }; - [config] String temp_path { - default {{{ return Application::GetLocalStateDir() + "/spool/icinga2/tmp/perfdata"; }}} + [config] String service_perfdata_path { + default {{{ return Application::GetLocalStateDir() + "/spool/icinga2/perfdata/service-perfdata"; }}} }; - [config] String format_template { + [config] String host_temp_path { + default {{{ return Application::GetLocalStateDir() + "/spool/icinga2/tmp/host-perfdata"; }}} + }; + [config] String service_temp_path { + default {{{ return Application::GetLocalStateDir() + "/spool/icinga2/tmp/service-perfdata"; }}} + }; + [config] String host_format_template { + default {{{ + return "DATATYPE::HOSTPERFDATA\t" + "TIMET::$TIMET$\t" + "HOSTNAME::$HOSTNAME$\t" + "HOSTPERFDATA::$HOSTPERFDATA$\t" + "HOSTCHECKCOMMAND::$HOSTCHECKCOMMAND$\t" + "HOSTSTATE::$HOSTSTATE$\t" + "HOSTSTATETYPE::$HOSTSTATETYPE$"; + }}} + }; + [config] String service_format_template { default {{{ return "DATATYPE::SERVICEPERFDATA\t" "TIMET::$TIMET$\t" diff --git a/doc/2.1-setting-up-icinga-2.md b/doc/2.1-setting-up-icinga-2.md index 68b557703..0196c8cf2 100644 --- a/doc/2.1-setting-up-icinga-2.md +++ b/doc/2.1-setting-up-icinga-2.md @@ -57,7 +57,7 @@ By default Icinga 2 uses the following files and directories: /usr/share/icinga2/itl | The Icinga Template Library. /var/run/icinga2 | PID file. /var/run/icinga2/cmd | Command pipe and Livestatus socket. - /var/cache/icinga2 | Performance data files and status.dat/objects.cache. + /var/cache/icinga2 | status.dat/objects.cache. /var/spool/icinga2 | Used for performance data spool files. /var/lib/icinga2 | Icinga 2 state file, cluster feature replay log and configuration files. /var/log/icinga2 | Log file location and compat/ directory for the CompatLogger feature. diff --git a/doc/3.11-performance-data.md b/doc/3.11-performance-data.md index ac71053eb..c8a8cbe57 100644 --- a/doc/3.11-performance-data.md +++ b/doc/3.11-performance-data.md @@ -13,26 +13,29 @@ inGraph and Graphite. > **Note** > -> As there are no real host checks in Icinga 2, there is no performance -> data generated for hosts. +> As there are no real host checks in Icinga 2, the performance data is +> generated from the host check service, if existing. ### Writing Performance Data Files -PNP4Nagios and inGraph use performance data collector daemons to fetch +PNP4Nagios, inGraph and Graphios use performance data collector daemons to fetch the current performance files for their backend updates. Therefore the Icinga 2 `PerfdataWriter` object allows you to define -the output template format backed with Icinga 2 runtime macros. +the output template format for host and services backed with Icinga 2 +runtime macros. - format_template = "DATATYPE::SERVICEPERFDATA\tTIMET::$TIMET$\tHOSTNAME::$HOSTNAME$\tSERVICEDESC::$SERVICEDESC$\tSERVICEPERFDATA::$SERVICEPERFDATA$\tSERVICECHECKCOMMAND::$SERVICECHECKCOMMAND$\tHOSTSTATE::$HOSTSTATE$\tHOSTSTATETYPE::$HOSTSTATETYPE$\tSERVICESTATE::$SERVICESTATE$\tSERVICESTATETYPE::$SERVICESTATETYPE$" - -The default template is already provided with the Icinga 2 feature configuration + host_format_template = "DATATYPE::HOSTPERFDATA\tTIMET::$TIMET$\tHOSTNAME::$HOSTNAME$\tHOSTPERFDATA::$HOSTPERFDATA$\tHOSTCHECKCOMMAND::$HOSTCHECKCOMMAND$\tHOSTSTATE::$HOSTSTATE$\tHOSTSTATETYPE::$HOSTSTATETYPE$" + service_format_template = "DATATYPE::SERVICEPERFDATA\tTIMET::$TIMET$\tHOSTNAME::$HOSTNAME$\tSERVICEDESC::$SERVICEDESC$\tSERVICEPERFDATA::$SERVICEPERFDATA$\tSERVICECHECKCOMMAND::$SERVICECHECKCOMMAND$\tHOSTSTATE::$HOSTSTATE$\tHOSTSTATETYPE::$HOSTSTATETYPE$\tSERVICESTATE::$SERVICESTATE$\tSERVICESTATETYPE::$SERVICESTATETYPE$" + +The default templates are already provided with the Icinga 2 feature configuration which can be enabled using # icinga2-enable-feature perfdata By default all performance data files are rotated in a 15 seconds interval into -the `/var/spool/icinga2/perfdata/` directory as `service-perfdata.`. +the `/var/spool/icinga2/perfdata/` directory as `host-perfdata.` and +`service-perfdata.`. External collectors need to parse the rotated performance data files and then remove the processed files. @@ -46,18 +49,19 @@ remove the processed files. ### Graphite Carbon Cache Writer -While there are some Graphite collector scripts for Icinga 1.x available it's -more reasonable to directly process the check and plugin performance in memory -in Icinga 2. Once there are new metrics available, Icinga 2 will directly +While there are some Graphite collector scripts and daemons like Graphios available for +Icinga 1.x it's more reasonable to directly process the check and plugin performance +in memory in Icinga 2. Once there are new metrics available, Icinga 2 will directly write them to the defined Graphite Carbon daemon tcp socket. You can enable the feature using # icinga2-enable-feature graphite - + The `GraphiteWriter` object expects the Graphite Carbon Cache socket listening at `127.0.0.1` on port `2003` by default. The current naming schema is + icinga.. icinga... diff --git a/doc/4.3-object-types.md b/doc/4.3-object-types.md index 9498b73aa..b3306659c 100644 --- a/doc/4.3-object-types.md +++ b/doc/4.3-object-types.md @@ -523,26 +523,33 @@ Example: library "perfdata" object PerfdataWriter "pnp" { - perfdata_path = "/var/spool/icinga2/perfdata/service-perfdata" + host_perfdata_path = "/var/spool/icinga2/perfdata/host-perfdata" - format_template = "DATATYPE::SERVICEPERFDATA\tTIMET::$TIMET$\tHOSTNAME::$HOSTNAME$\tSERVICEDESC::$SERVICEDESC$\tSERVICEPERFDATA::$SERVICEPERFDATA$\tSERVICECHECKCOMMAND::$SERVICECHECKCOMMAND$\tHOSTSTATE::$HOSTSTATE$\tHOSTSTATETYPE::$HOSTSTATETYPE$\tSERVICESTATE::$SERVICESTATE$\tSERVICESTATETYPE::$SERVICESTATETYPE$" + service_perfdata_path = "/var/spool/icinga2/perfdata/service-perfdata" + + host_format_template = "DATATYPE::HOSTPERFDATA\tTIMET::$TIMET$\tHOSTNAME::$HOSTNAME$\tHOSTPERFDATA::$HOSTPERFDATA$\tHOSTCHECKCOMMAND::$HOSTCHECKCOMMAND$\tHOSTSTATE::$HOSTSTATE$\tHOSTSTATETYPE::$HOSTSTATETYPE$" + + service_format_template = "DATATYPE::SERVICEPERFDATA\tTIMET::$TIMET$\tHOSTNAME::$HOSTNAME$\tSERVICEDESC::$SERVICEDESC$\tSERVICEPERFDATA::$SERVICEPERFDATA$\tSERVICECHECKCOMMAND::$SERVICECHECKCOMMAND$\tHOSTSTATE::$HOSTSTATE$\tHOSTSTATETYPE::$HOSTSTATETYPE$\tSERVICESTATE::$SERVICESTATE$\tSERVICESTATETYPE::$SERVICESTATETYPE$" rotation_interval = 15s } Attributes: - Name |Description - ----------------|---------------- - perfdata\_path |**Optional.** Path to the service performance data file. Defaults to IcingaLocalStateDir + "/spool/icinga2/perfdata/perfdata". - temp\_path |**Optional.** Path to the temporary file. Defaults to IcingaLocalStateDir + "/spool/icinga2/tmp/perfdata". - format\_template|**Optional.** Format template for the performance data file. Defaults to a template that's suitable for use with PNP4Nagios. - rotation\_interval|**Optional.** Rotation interval for the file specified in `perfdata\_path`. Defaults to 30 seconds. + Name |Description + ------------------------|---------------- + host_perfdata\_path |**Optional.** Path to the host performance data file. Defaults to IcingaLocalStateDir + "/spool/icinga2/perfdata/host-perfdata". + service_perfdata\_path |**Optional.** Path to the service performance data file. Defaults to IcingaLocalStateDir + "/spool/icinga2/perfdata/service-perfdata". + host_temp\_path |**Optional.** Path to the temporary host file. Defaults to IcingaLocalStateDir + "/spool/icinga2/tmp/host-perfdata". + service_temp\_path |**Optional.** Path to the temporary service file. Defaults to IcingaLocalStateDir + "/spool/icinga2/tmp/service-perfdata". + host_format\_template |**Optional.** Host Format template for the performance data file. Defaults to a template that's suitable for use with PNP4Nagios. + service_format\_template|**Optional.** Service Format template for the performance data file. Defaults to a template that's suitable for use with PNP4Nagios. + rotation\_interval |**Optional.** Rotation interval for the files specified in `{host,service}\_perfdata\_path`. Defaults to 30 seconds. > **Note** > > When rotating the performance data file the current UNIX timestamp is appended to the path specified -> in `perfdata\_path` to generate a unique filename. +> in `host_perfdata\_path` and `service_perfdata\_path` to generate a unique filename. ### GraphiteWriter diff --git a/doc/8-differences-between-icinga-1x-and-2.md b/doc/8-differences-between-icinga-1x-and-2.md index f12aac8ee..8d14da876 100644 --- a/doc/8-differences-between-icinga-1x-and-2.md +++ b/doc/8-differences-between-icinga-1x-and-2.md @@ -330,12 +330,6 @@ where the initial state checks must have happened. Icinga 2 will use the `retry_interval` setting instead and `check_interval` divided by 5 if `retry_interval` is not defined. -### Performance Data - -There is no host performance data generated in Icinga 2 because there are no -real host checks. Therefore the PerfDataWriter will only write service -performance data files. - ## Commands Unlike in Icinga 1.x there are 3 different command types in Icinga 2: diff --git a/lib/icinga/host.cpp b/lib/icinga/host.cpp index cf40a2a06..486cf4229 100644 --- a/lib/icinga/host.cpp +++ b/lib/icinga/host.cpp @@ -486,6 +486,15 @@ bool Host::ResolveMacro(const String& macro, const CheckResult::Ptr&, String *re return true; } else if (macro == "HOSTPERFDATA") { *result = PluginUtility::FormatPerfdata(hccr->GetPerformanceData()); + return true; + } else if (macro == "HOSTCHECKCOMMAND") { + CheckCommand::Ptr commandObj = hc->GetCheckCommand(); + + if (commandObj) + *result = commandObj->GetName(); + else + *result = ""; + return true; } else if (macro == "LASTHOSTCHECK") { *result = Convert::ToString((long)hccr->GetScheduleStart()); -- 2.40.0