Cleanup config.nodes_of
[check_mk.git] / checks / size_trend.include
blob0a3178519cdee332d0d732da6bad3bf9623ef48d
1 #!/usr/bin/python
2 # -*- encoding: utf-8; py-indent-offset: 4 -*-
3 # +------------------------------------------------------------------+
4 # | ____ _ _ __ __ _ __ |
5 # | / ___| |__ ___ ___| | __ | \/ | |/ / |
6 # | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
7 # | | |___| | | | __/ (__| < | | | | . \ |
8 # | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
9 # | |
10 # | Copyright Mathias Kettner 2017 mk@mathias-kettner.de |
11 # +------------------------------------------------------------------+
13 # This file is part of Check_MK.
14 # The official homepage is at http://mathias-kettner.de/check_mk.
16 # check_mk is free software; you can redistribute it and/or modify it
17 # under the terms of the GNU General Public License as published by
18 # the Free Software Foundation in version 2. check_mk is distributed
19 # in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
20 # out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
21 # PARTICULAR PURPOSE. See the GNU General Public License for more de-
22 # tails. You should have received a copy of the GNU General Public
23 # License along with GNU Make; see the file COPYING. If not, write
24 # to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
25 # Boston, MA 02110-1301 USA.
28 def size_trend(check, item, resource, levels, used_mb, size_mb, timestamp=None): # pylint: disable=function-redefined
29 """Trend computation for size related checks of disks, ram, etc.
30 Trends are computed in two steps. In the first step the delta to
31 the last check is computed, using a normal check_mk counter.
32 In the second step an average over that counter is computed to
33 make a long-term prediction.
35 Note:
36 This function is experimental and may change in future releases.
37 Use at your own risk!
39 Args:
40 check (str): The name of the check, e.g. "df".
41 item (str): The name of the item, e.g. the mountpoint "/" for df.
42 resource (str): The resource in question, e.g. "disk", "ram", "swap".
43 levels (dict): Level parameters for the trend computation. Items:
44 "trend_range" : 24, # interval for the trend in hours
45 "trend_perfdata : True # generate perfomance data for trends
46 "trend_mb" : (10, 20), # MB of change during trend_range
47 "trend_perc" : (1, 2), # percent change during trend_range
48 "trend_timeleft" : (72, 48) # time left in hours until full
49 "trend_showtimeleft: True # display time left in infotext
50 The item "trend_range" is required. All other items are optional.
51 timestamp (float, optional): Time in secs used to calculate the rate
52 and average. Defaults to "None".
53 used_mb (float): Used space in MB.
54 size_mb (float): Max. available space in MB.
56 Returns:
57 A tuple of (state, infotext, perfdata) for the trend computation.
58 If a MKCounterWrapped occurs (i.e. there is not enough data
59 present for the trend computation) the tuple (0, '', []) is
60 returned.
61 """
63 state, infotext, perfdata, problems = 0, '', [], []
65 MB = 1024.0 * 1024.0
66 H24 = 60 * 60 * 24
68 range_hours = levels["trend_range"]
69 range_sec = range_hours * 3600.0
70 if not timestamp:
71 timestamp = time.time()
73 # compute current rate in MB/s by computing delta since last check
74 try:
75 rate = get_rate(
76 "%s.%s.delta" % (check, item), timestamp, used_mb, allow_negative=True, onwrap=ZERO)
77 except MKCounterWrapped:
78 # need more data for computing a trend
79 return 0, '', []
81 if levels.get("trend_perfdata"):
82 perfdata.append(("growth", rate * H24))
84 # average trend in MB/s, initialized with zero
85 rate_avg = get_average("%s.%s.trend" % (check, item), timestamp, rate, range_sec / 60.0, True)
87 trend = rate_avg * range_sec
88 sign = '+' if trend > 0 else ""
89 infotext += ", trend: %s%s / %g hours" % \
90 (sign, get_bytes_human_readable(trend * MB), range_hours)
92 # levels for performance data
93 warn_perf, crit_perf = None, None
95 # apply levels for absolute growth in MB / interval
96 trend_mb = levels.get("trend_mb")
97 if trend_mb:
98 wa, cr = trend_mb
99 warn_perf, crit_perf = wa, cr
100 if trend >= wa:
101 problems.append("growing too fast (warn/crit at %s/%s per %.1f h)(!" % (
102 get_bytes_human_readable(wa * MB),
103 get_bytes_human_readable(cr * MB),
104 range_hours,
106 state = max(1, state)
107 if trend >= cr:
108 state = 2
109 problems[-1] += "!"
110 problems[-1] += ")"
112 # apply levels for growth relative to filesystem size
113 trend_perc = levels.get("trend_perc")
114 if trend_perc:
115 wa_perc, cr_perc = trend_perc
116 wa = wa_perc / 100.0 * size_mb
117 cr = cr_perc / 100.0 * size_mb
118 if warn_perf is not None:
119 warn_perf = min(warn_perf, wa)
120 crit_perf = min(crit_perf, cr)
121 else:
122 warn_perf, crit_perf = wa, cr
123 if trend >= wa:
124 problems.append("growing too fast (warn/crit at %.3f%%/%.3f%% per %.1f h)(!" %
125 (wa_perc, cr_perc, range_hours))
126 state = max(1, state)
127 if trend >= cr:
128 state = 2
129 problems[-1] += "!"
130 problems[-1] += ")"
132 # compute time until filesystem is full (only for positive trend, of course)
134 # The start value of hours_left is negative. The pnp graph and the perfometer
135 # will interpret this as inifinite -> not growing
136 hours_left = -1
137 if trend > 0:
139 def format_hours(hours):
140 if hours > 365 * 24:
141 return "more than a year"
142 elif hours > 90 * 24:
143 return "%0d months" % (hours / (30 * 24))
144 elif hours > 4 * 7 * 24: # 4 weeks
145 return "%0d weeks" % (hours / (7 * 24))
146 elif hours > 7 * 24: # 1 week
147 return "%0.1f weeks" % (hours / (7 * 24))
148 elif hours > 2 * 24: # 2 days
149 return "%0.1f days" % (hours / 24)
150 return "%d hours" % hours
152 hours_left = (size_mb - used_mb) / trend * range_hours
153 hours_txt = format_hours(hours_left)
155 timeleft = levels.get("trend_timeleft")
156 if timeleft:
157 wa, cr = timeleft
158 if hours_left <= cr:
159 state = 2
160 problems.append("only %s until %s full(!!)" % (hours_txt, resource))
161 elif hours_left <= wa:
162 state = max(state, 1)
163 problems.append("only %s until %s full(!)" % (hours_txt, resource))
164 elif hours_left <= wa * 2 or levels.get("trend_showtimeleft"):
165 problems.append("time left until %s full: %s" % (resource, hours_txt))
166 elif levels.get("trend_showtimeleft"):
167 problems.append("time left until %s full: %s" % (resource, hours_txt))
169 if levels.get("trend_perfdata"):
170 perfdata.append((
171 "trend",
172 rate_avg * H24,
173 (warn_perf / range_sec * H24) if warn_perf is not None else None,
174 (crit_perf / range_sec * H24) if crit_perf is not None else None,
176 size_mb / range_hours,
179 if levels.get("trend_showtimeleft"):
180 perfdata.append(("trend_hoursleft", hours_left))
182 if problems:
183 infotext += " - %s" % ", ".join(problems)
185 return state, infotext, perfdata