From: Michael Friedrich Date: Fri, 19 Jun 2015 16:11:55 +0000 (+0200) Subject: Implement a better Graphite tree schema X-Git-Tag: v2.4.0~335 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=b10cb8a2e7acccc285377f72fef533ab277f2ad1;p=icinga2 Implement a better Graphite tree schema This changes the entire tree, but with the prefix "icinga2" not to conflict with existing installations. Includes enable_legacy_mode and detailed documentation. fixes #9461 fixes #8149 --- diff --git a/doc/5-advanced-topics.md b/doc/5-advanced-topics.md index 36c36d727..0ad250128 100644 --- a/doc/5-advanced-topics.md +++ b/doc/5-advanced-topics.md @@ -612,7 +612,104 @@ You can enable the feature using By default the `GraphiteWriter` object expects the Graphite Carbon Cache to listen at `127.0.0.1` on TCP port `2003`. -The current naming schema is +#### Current Graphite Schema + +The current naming schema is defined as follows. The official Icinga Web 2 Graphite +module will use that schema too. + +The default prefix for hosts and services is configured using +[runtime macros](3-monitoring-basics.md#runtime-macros)like this: + + icinga2.$host.name$.host.$host.check_command$ + icinga2.$host.name$.services.$service.name$.$service.check_command$ + +You can customize the prefix name by using the `host_name_template` and +`service_name_template` configuration attributes. + +The additional levels will allow fine granular filters and also template +capabilities, e.g. by using the check command `disk` for specific +graph templates in web applications rendering the Graphite data. + +The following characters are escaped in prefix labels: + + Character | Escaped character + --------------|-------------------------- + whitespace | _ + . | _ + \ | _ + / | _ + +Metric values are stored like this: + + .perfdata..value + +The following characters are escaped in perfdata labels: + + Character | Escaped character + --------------|-------------------------- + whitespace | _ + \ | _ + / | _ + :: | . + +Note that perfdata labels may contain dots (`.`) allowing to +add more subsequent levels inside the Graphite tree. +`::` adds support for [multi performance labels](http://my-plugin.de/wiki/projects/check_multi/configuration/performance) +and is therefore replaced by `.`. + +By enabling `enable_send_thresholds` Icinga 2 automatically adds the following threshold metrics: + + .perfdata..min + .perfdata..max + .perfdata..warn + .perfdata..crit + +By enabling `enable_send_metadata` Icinga 2 automatically adds the following metadata metrics: + + .metadata.current_attempt + .metadata.downtime_depth + .metadata.execution_time + .metadata.latency + .metadata.max_check_attempts + .metadata.reachable + .metadata.state + .metadata.state_type + +Metadata metric overview: + + metric | description + -------------------|------------------------------------------ + current_attempt | current check attempt + max_check_attempts | maximum check attempts until the hard state is reached + reachable | checked object is reachable + downtime_depth | number of downtimes this object is in + execution_time | check execution time + latency | check latency + state | current state of the checked object + state_type | 0=SOFT, 1=HARD state + +The following example illustrates how to configure the storage schemas for Graphite Carbon +Cache. + + [icinga2_default] + # intervals like PNP4Nagios uses them per default + pattern = ^icinga2\. + retentions = 1m:2d,5m:10d,30m:90d,360m:4y + +#### Graphite Schema < 2.4 + +In order to restore the old legacy schema, you'll need to adopt the `GraphiteWriter` +configuration: + + object GraphiteWriter "graphite" { + + enable_legacy_mode = true + + host_name_template = "icinga.$host.name$" + service_name_template = "icinga.$host.name$.$service.name$" + } + +The old legacy naming schema is icinga.. icinga... diff --git a/doc/6-object-types.md b/doc/6-object-types.md index 3a6d634b0..cbf1c87e9 100644 --- a/doc/6-object-types.md +++ b/doc/6-object-types.md @@ -446,17 +446,13 @@ Configuration Attributes: ----------------------|---------------------- host |**Optional.** Graphite Carbon host address. Defaults to '127.0.0.1'. port |**Optional.** Graphite Carbon port. Defaults to 2003. - host_name_template |**Optional.** Metric prefix for host name. Defaults to "icinga.$host.name$". - service_name_template |**Optional.** Metric prefix for service name. Defaults to "icinga.$host.name$.$service.name$". + host_name_template |**Optional.** Metric prefix for host name. Defaults to "icinga2.$host.name$.host.$host.check_command$". + service_name_template |**Optional.** Metric prefix for service name. Defaults to "icinga2.$host.name$.services.$service.name$.$service.check_command$". + enable_send_thresholds | **Optional.** Send additional threshold metrics. Defaults to `false`. + enable_send_metadata | **Optional.** Send additional metadata metrics. Defaults to `false`. + enable_legacy_mode | **Optional.** Enable legacy mode for schema < 2.4. **Note**: This will be removed in future versions. -Metric prefix names can be modified using [runtime macros](3-monitoring-basics.md#runtime-macros). - -Example with your custom [global constant](20-language-reference.md#constants) `GraphiteEnv`: - - const GraphiteEnv = "icinga.env1" - - host_name_template = GraphiteEnv + ".$host.name$" - service_name_template = GraphiteEnv + ".$host.name$.$service.name$" +Additional usage examples can be found [here](5-advanced-topics.md#graphite-carbon-cache-writer). diff --git a/lib/perfdata/graphitewriter.cpp b/lib/perfdata/graphitewriter.cpp index dd36104e7..4bd3291cd 100644 --- a/lib/perfdata/graphitewriter.cpp +++ b/lib/perfdata/graphitewriter.cpp @@ -117,24 +117,53 @@ void GraphiteWriter::CheckResultHandler(const Checkable::Ptr& checkable, const C double ts = cr->GetExecutionEnd(); - if (service) { - prefix = MacroProcessor::ResolveMacros(GetServiceNameTemplate(), resolvers, cr, NULL, &GraphiteWriter::EscapeMacroMetric); + /* new mode below. old mode in else tree with 2.4, deprecate it in 2.6 */ + if (!GetEnableLegacyMode()) { + if (service) { + prefix = MacroProcessor::ResolveMacros(GetServiceNameTemplate(), resolvers, cr, NULL, boost::bind(&GraphiteWriter::EscapeMacroMetric, _1, false)); + } else { + prefix = MacroProcessor::ResolveMacros(GetHostNameTemplate(), resolvers, cr, NULL, boost::bind(&GraphiteWriter::EscapeMacroMetric, _1, false)); + } + + String prefix_perfdata = prefix + ".perfdata"; + String prefix_metadata = prefix + ".metadata"; + + if (GetEnableSendMetadata()) { + + if (service) { + SendMetric(prefix_metadata, "state", service->GetState(), ts); + } else { + SendMetric(prefix_metadata, "state", host->GetState(), ts); + } + + SendMetric(prefix_metadata, "current_attempt", checkable->GetCheckAttempt(), ts); + SendMetric(prefix_metadata, "max_check_attempts", checkable->GetMaxCheckAttempts(), ts); + SendMetric(prefix_metadata, "state_type", checkable->GetStateType(), ts); + SendMetric(prefix_metadata, "reachable", checkable->IsReachable(), ts); + SendMetric(prefix_metadata, "downtime_depth", checkable->GetDowntimeDepth(), ts); + SendMetric(prefix_metadata, "latency", Service::CalculateLatency(cr), ts); + SendMetric(prefix_metadata, "execution_time", Service::CalculateExecutionTime(cr), ts); + } - SendMetric(prefix, "state", service->GetState(), ts); + SendPerfdata(prefix_perfdata, cr, ts); } else { - prefix = MacroProcessor::ResolveMacros(GetHostNameTemplate(), resolvers, cr, NULL, &GraphiteWriter::EscapeMacroMetric); + if (service) { + prefix = MacroProcessor::ResolveMacros(GetServiceNameTemplate(), resolvers, cr, NULL, boost::bind(&GraphiteWriter::EscapeMacroMetric, _1, true)); + SendMetric(prefix, "state", service->GetState(), ts); + } else { + prefix = MacroProcessor::ResolveMacros(GetHostNameTemplate(), resolvers, cr, NULL, boost::bind(&GraphiteWriter::EscapeMacroMetric, _1, true)); + SendMetric(prefix, "state", host->GetState(), ts); + } - SendMetric(prefix, "state", host->GetState(), ts); + SendMetric(prefix, "current_attempt", checkable->GetCheckAttempt(), ts); + SendMetric(prefix, "max_check_attempts", checkable->GetMaxCheckAttempts(), ts); + SendMetric(prefix, "state_type", checkable->GetStateType(), ts); + SendMetric(prefix, "reachable", checkable->IsReachable(), ts); + SendMetric(prefix, "downtime_depth", checkable->GetDowntimeDepth(), ts); + SendMetric(prefix, "latency", Service::CalculateLatency(cr), ts); + SendMetric(prefix, "execution_time", Service::CalculateExecutionTime(cr), ts); + SendPerfdata(prefix, cr, ts); } - - SendMetric(prefix, "current_attempt", checkable->GetCheckAttempt(), ts); - SendMetric(prefix, "max_check_attempts", checkable->GetMaxCheckAttempts(), ts); - SendMetric(prefix, "state_type", checkable->GetStateType(), ts); - SendMetric(prefix, "reachable", checkable->IsReachable(), ts); - SendMetric(prefix, "downtime_depth", checkable->GetDowntimeDepth(), ts); - SendMetric(prefix, "latency", Service::CalculateLatency(cr), ts); - SendMetric(prefix, "execution_time", Service::CalculateExecutionTime(cr), ts); - SendPerfdata(prefix, cr, ts); } void GraphiteWriter::SendPerfdata(const String& prefix, const CheckResult::Ptr& cr, double ts) @@ -160,19 +189,36 @@ void GraphiteWriter::SendPerfdata(const String& prefix, const CheckResult::Ptr& } } - String escaped_key = EscapeMetric(pdv->GetLabel()); - boost::algorithm::replace_all(escaped_key, "::", "."); - - SendMetric(prefix, escaped_key, pdv->GetValue(), ts); - - if (pdv->GetCrit()) - SendMetric(prefix, escaped_key + "_crit", pdv->GetCrit(), ts); - if (pdv->GetWarn()) - SendMetric(prefix, escaped_key + "_warn", pdv->GetWarn(), ts); - if (pdv->GetMin()) - SendMetric(prefix, escaped_key + "_min", pdv->GetMin(), ts); - if (pdv->GetMax()) - SendMetric(prefix, escaped_key + "_max", pdv->GetMax(), ts); + /* new mode below. old mode in else tree with 2.4, deprecate it in 2.6 */ + if (!GetEnableLegacyMode()) { + String escaped_key = EscapeMetricLabel(pdv->GetLabel()); + + SendMetric(prefix, escaped_key + ".value", pdv->GetValue(), ts); + + if (GetEnableSendThresholds()) { + if (pdv->GetCrit()) + SendMetric(prefix, escaped_key + ".crit", pdv->GetCrit(), ts); + if (pdv->GetWarn()) + SendMetric(prefix, escaped_key + ".warn", pdv->GetWarn(), ts); + if (pdv->GetMin()) + SendMetric(prefix, escaped_key + ".min", pdv->GetMin(), ts); + if (pdv->GetMax()) + SendMetric(prefix, escaped_key + ".max", pdv->GetMax(), ts); + } + } else { + String escaped_key = EscapeMetric(pdv->GetLabel()); + boost::algorithm::replace_all(escaped_key, "::", "."); + SendMetric(prefix, escaped_key, pdv->GetValue(), ts); + + if (pdv->GetCrit()) + SendMetric(prefix, escaped_key + "_crit", pdv->GetCrit(), ts); + if (pdv->GetWarn()) + SendMetric(prefix, escaped_key + "_warn", pdv->GetWarn(), ts); + if (pdv->GetMin()) + SendMetric(prefix, escaped_key + "_min", pdv->GetMin(), ts); + if (pdv->GetMax()) + SendMetric(prefix, escaped_key + "_max", pdv->GetMax(), ts); + } } } @@ -203,20 +249,36 @@ void GraphiteWriter::SendMetric(const String& prefix, const String& name, double } } -String GraphiteWriter::EscapeMetric(const String& str) +String GraphiteWriter::EscapeMetric(const String& str, bool legacyMode) { String result = str; + //don't allow '.' in metric prefixes boost::replace_all(result, " ", "_"); boost::replace_all(result, ".", "_"); - boost::replace_all(result, "-", "_"); boost::replace_all(result, "\\", "_"); boost::replace_all(result, "/", "_"); + if (legacyMode) + boost::replace_all(result, "-", "_"); + + return result; +} + +String GraphiteWriter::EscapeMetricLabel(const String& str) +{ + String result = str; + + //allow to pass '.' in perfdata labels + boost::replace_all(result, " ", "_"); + boost::replace_all(result, "\\", "_"); + boost::replace_all(result, "/", "_"); + boost::replace_all(result, "::", "."); + return result; } -Value GraphiteWriter::EscapeMacroMetric(const Value& value) +Value GraphiteWriter::EscapeMacroMetric(const Value& value, bool legacyMode) { if (value.IsObjectType()) { Array::Ptr arr = value; @@ -224,12 +286,12 @@ Value GraphiteWriter::EscapeMacroMetric(const Value& value) ObjectLock olock(arr); BOOST_FOREACH(const Value& arg, arr) { - result->Add(EscapeMetric(arg)); + result->Add(EscapeMetric(arg, legacyMode)); } return Utility::Join(result, '.'); } else - return EscapeMetric(value); + return EscapeMetric(value, legacyMode); } void GraphiteWriter::ValidateHostNameTemplate(const String& value, const ValidationUtils& utils) diff --git a/lib/perfdata/graphitewriter.hpp b/lib/perfdata/graphitewriter.hpp index 2e06b01e7..e3dd6eede 100644 --- a/lib/perfdata/graphitewriter.hpp +++ b/lib/perfdata/graphitewriter.hpp @@ -57,8 +57,9 @@ private: void CheckResultHandler(const Checkable::Ptr& checkable, const CheckResult::Ptr& cr); void SendMetric(const String& prefix, const String& name, double value, double ts); void SendPerfdata(const String& prefix, const CheckResult::Ptr& cr, double ts); - static String EscapeMetric(const String& str); - static Value EscapeMacroMetric(const Value& value); + static String EscapeMetric(const String& str, bool legacyMode = false); + static String EscapeMetricLabel(const String& str); + static Value EscapeMacroMetric(const Value& value, bool legacyMode = false); void ReconnectTimerHandler(void); }; diff --git a/lib/perfdata/graphitewriter.ti b/lib/perfdata/graphitewriter.ti index 3863d4f3b..5d0685a2d 100644 --- a/lib/perfdata/graphitewriter.ti +++ b/lib/perfdata/graphitewriter.ti @@ -33,11 +33,21 @@ class GraphiteWriter : ConfigObject default {{{ return "2003"; }}} }; [config] String host_name_template { - default {{{ return "icinga.$host.name$"; }}} + default {{{ return "icinga2.$host.name$.host.$host.check_command$"; }}} }; [config] String service_name_template { - default {{{ return "icinga.$host.name$.$service.name$"; }}} + default {{{ return "icinga2.$host.name$.services.$service.name$.$service.check_command$"; }}} }; + [config] bool enable_send_thresholds { + default {{{ return false; }}} + }; + [config] bool enable_send_metadata { + default {{{ return false; }}} + }; + [config] bool enable_legacy_mode { + default {{{ return false; }}} + }; + }; }