4 * Class that provides API/helpers for generating the state of a report based on
7 abstract class StateCalculator
10 * For hysterical reasons, we expect every single report type to return
11 * the report data in a brand new way. Jay.
15 abstract public function get_data();
17 * Given an event (a database row), add it to the current report
19 abstract public function add_event($row);
21 protected $st_text = array(); /**< Mapping between state integers and state text */
23 protected $st_source = false; /**< The source object. Can be object array, can be host_name, can be host_name;service_description, can drive you mad. */
24 protected $host_name = false; /**< The source object's host name, if it's just one. Set for services. */
25 protected $service_description = false; /**< The source object's service description, if it's just one. Only description for services */
27 /** The state template for hosts */
28 protected $state_tpl_host = array(
30 'TIME_UP_SCHEDULED' => 0,
31 'TIME_UP_UNSCHEDULED' => 0,
32 'TIME_DOWN_SCHEDULED' => 0,
33 'TIME_DOWN_UNSCHEDULED' => 0,
34 'TIME_UNREACHABLE_SCHEDULED' => 0,
35 'TIME_UNREACHABLE_UNSCHEDULED' => 0,
36 'TIME_UNDETERMINED_NOT_RUNNING' => 0,
37 'TIME_UNDETERMINED_NO_DATA' => 0,
40 /** The state template for services */
41 protected $state_tpl_svc = array(
43 'SERVICE_DESCRIPTION' => '',
44 'TIME_OK_SCHEDULED' => 0,
45 'TIME_OK_UNSCHEDULED' => 0,
46 'TIME_WARNING_SCHEDULED' => 0,
47 'TIME_WARNING_UNSCHEDULED' => 0,
48 'TIME_UNKNOWN_SCHEDULED' => 0,
49 'TIME_UNKNOWN_UNSCHEDULED' => 0,
50 'TIME_CRITICAL_SCHEDULED' => 0,
51 'TIME_CRITICAL_UNSCHEDULED' => 0,
52 'TIME_UNDETERMINED_NOT_RUNNING' => 0,
53 'TIME_UNDETERMINED_NO_DATA' => 0,
56 protected $st_is_service = false; /**< Whether this is a service */
57 protected $st_running = false; /**< Is nagios running? */
58 protected $st_inactive = 0; /**< Time we have no information about */
59 protected $st_dt_depth = 0; /**< The downtime depth */
61 * The calculated state of the object, taking such things
62 * as scheduled downtime counted as uptime into consideration
64 protected $st_obj_state = false;
65 protected $st_raw = array(); /**< Mapping between the raw states and the time spent there */
66 protected $prev_row; /**< The last db row, so we can get duration */
68 protected $options; /**< A Report_options object for this report */
71 * Create a new state calculator
72 * @param $options A report_options object that describes the report
73 * @param $timeperiod A (resolved) timeperiod to use throughout calculations
75 public function __construct(Report_options
$options, $timeperiod)
77 $this->options
= $options;
78 $this->timeperiod
= $timeperiod;
82 * Prepare a state calculator for action
83 * Takes a number of initialization arguments, simply because they can be
84 * more efficiently retrieved in bulk somewhere else.
85 * @param $initial_state The state for the object when the report starts
86 * @param $initial_depth The downtime depth when the report starts - in practice a boolean
87 * @param $is_running Is nagios itself running when the report starts?
89 public function initialize($initial_state, $initial_depth, $is_running)
91 $this->st_running
= $is_running;
92 $this->st_obj_state
= $initial_state;
93 $this->st_dt_depth
= $initial_depth;
95 if ($this->options
['report_type'] == 'services' ||
$this->options
['report_type'] == 'servicegroups') {
96 $this->st_is_service
= true;
99 # we need at least a service or a host
100 if ($this->options
['report_type'] !== 'hosts' && $this->options
['report_type'] !== 'hostgroups')
104 $this->st_text
= $this->st_is_service ? Reports_Model
::$service_states : Reports_Model
::$host_states;
105 $this->st_text
= array_map('strtoupper', $this->st_text
);
108 if (!$this->st_running
)
109 $fevent_type = Reports_Model
::PROCESS_SHUTDOWN
;
111 if ($this->st_is_service
)
112 $fevent_type = Reports_Model
::SERVICECHECK
;
114 $fevent_type = Reports_Model
::HOSTCHECK
;
116 $state = ($this->st_running ||
$this->options
['assumestatesduringnotrunning']) ?
$this->st_obj_state
: -1;
117 $this->prev_row
= array
119 'the_time' => $this->options
['start_time'],
120 'event_type' => $fevent_type,
121 'downtime_depth' => $this->st_dt_depth
);
123 # if we're actually going to use the log, we'll need
124 # to generate a faked initial message for it.
125 if ($this->options
['include_trends']) {
126 $fout = sprintf("Report period start. Daemon is%s running, " .
127 "we're%s in scheduled downtime, state is %s (%d)",
128 $this->st_running ?
'' : ' not',
129 $this->st_dt_depth ?
'' : ' not',
130 $this->st_text
[$state], $state);
131 $this->prev_row
['output'] = $fout;
133 if (!empty($hostname) && is_string($hostname))
134 $this->prev_row
['host_name'] = $hostname;
136 if (!empty($servicename) && is_string($servicename))
137 $this->prev_row
['service_description'] = $servicename;
142 * Update the raw uptime array
144 * @param $end_time When the event ends - start time is taken from prev_row
146 public function st_update($end_time)
148 $prev_time = $this->prev_row
['the_time'];
149 $duration = $end_time - $prev_time;
150 $active = intval($this->timeperiod
->active_time($prev_time, $end_time));
151 $this->st_inactive +
= ($end_time - $prev_time) - $active;
153 $st = "$this->st_running:$this->st_dt_depth:$this->st_obj_state";
155 if (!isset($this->st_raw
[$st]))
156 $this->st_raw
[$st] = $active;
158 $this->st_raw
[$st] +
= $active;
163 * Calculate the time spent in different states as total and percentage.
165 * @param $state State times. Has the format:<br>
166 * array("X:Y:Z" => seconds, ...). Where X, Y and Z are numeric states and rhs argument is the number of seconds in that state
167 * @param $conv State translation table. E.g. for hostgroups:<br> array(0 => 'UP', '1' => 'DOWN', '2' => 'UNREACHABLE', '-1' => 'PENDING')
168 * @return array A huge array with all possible states and time spent in that state. States called PERCENT_* contains percentages rather than a number of seconds.
170 public function convert_state_table($state, $conv)
173 $cstate['TIME_UNDETERMINED_NO_DATA'] = 0;
174 $cstate['TIME_UNDETERMINED_NOT_RUNNING'] = 0;
175 $cstate['TIME_DOWN_COUNTED_AS_UP'] = 0;
176 $cstate['TOTAL_TIME_UNSCHEDULED'] = 0;
177 $cstate['TOTAL_TIME_SCHEDULED'] = 0;
178 $cstate['TOTAL_TIME_UNDETERMINED'] = 0;
179 $cstate['TOTAL_TIME_KNOWN'] = 0;
180 $cstate['TOTAL_TIME_ACTIVE'] = 0;
181 foreach ($state as $s => $duration) {
183 $cstate['TOTAL_TIME_ACTIVE'] +
= $duration;
184 $ary = explode(':', $s);
185 $is_running = intval($ary[0]);
186 $current_state = intval($ary[2]);
187 $in_dt = $ary[1] != 0;
188 $p3 = $in_dt ?
'' : 'UN';
192 $cstate['TIME_UNDETERMINED_NOT_RUNNING'] +
= $duration;
194 $p1 = $is_running ?
'_' : '_UNKNOWN_';
196 # this is where we hack in scheduled downtime as uptime
197 if ($in_dt && $this->options
['scheduleddowntimeasuptime']) {
198 $real_state = $conv[$current_state];
200 if ($real_state !== 'UP' && $real_state !== 'OK')
201 $cstate['TIME_DOWN_COUNTED_AS_UP'] +
= $duration;
203 elseif (isset($conv[$current_state])) {
204 $p2 = $conv[$current_state];
206 if ($p2 === 'PENDING')
207 $cstate['TIME_UNDETERMINED_NO_DATA'] +
= $duration;
210 $p2 = "BAD_BUG_ERROR";
213 if (!$is_running ||
$p2 === 'PENDING') {
215 $cstate['TOTAL_TIME_UNDETERMINED'] +
= $duration;
218 $cstate['TOTAL_TIME_KNOWN'] +
= $duration;
222 $tot_state = "TOTAL_TIME_$p2";
223 if (!isset($cstate[$tot_state]))
224 $cstate[$tot_state] = $duration;
226 $cstate[$tot_state] +
= $duration;
229 $kstate = "KNOWN_TIME_$p2";
230 if (!isset($cstate[$kstate]))
231 $cstate[$kstate] = $duration;
233 $cstate[$kstate] +
= $duration;
236 # scheduled/unscheduled totals
237 $cstate['TOTAL_TIME_' . $p3] +
= $duration;
239 $cname = 'TIME' . $p1 . $p2 . '_' . $p3;
240 if (!isset($cstate[$cname]))
241 $cstate[$cname] = $duration;
243 $cstate[$cname] +
= $duration;
246 $cname = 'KNOWN_' . $cname;
247 if (!isset($cstate[$cname]))
248 $cstate[$cname] = $duration;
250 $cstate[$cname] +
= $duration;
254 $sched_junk = array('_SCHEDULED', '_UNSCHEDULED');
255 foreach (array('KNOWN_', '') as $known) {
256 foreach ($conv as $s) {
257 foreach ($sched_junk as $dt_str) {
258 $entry = $known . "TIME_$s" . $dt_str;
259 if (!isset($cstate[$entry]))
261 $entry = "KNOWN_TIME_$s" . $dt_str;
266 # For each $state, we need to calculate
267 # PERCENT_TOTAL_TIME_$state,
268 # PERCENT_TIME_$state_SCHEDULED,
269 # PERCENT_TIME_$state_UNSCHEDULED,
270 # PERCENT_KNOWN_TIME_$state,
271 # PERCENT_KNOWN_TIME_$state_SCHEDULED,
272 # PERCENT_KNOWN_TIME_$state_UNSCHEDULED
273 $conv['UNDETERMINED'] = 'UNDETERMINED';
274 $div = $cstate['TOTAL_TIME_ACTIVE'];
275 foreach ($conv as $state) {
276 $str = 'TIME_' . $state;
277 foreach (array('TOTAL_', 'KNOWN_') as $prefix) {
278 $full_str = $prefix . $str;
280 if (!isset($cstate[$full_str]))
281 $cstate[$full_str] = 0;
282 $cstate['PERCENT_' . $full_str] =
283 reports
::percent($cstate[$full_str], $div);
286 foreach (array('', 'KNOWN_') as $known) {
287 foreach ($sched_junk as $dt_str) {
288 $perc_str = 'PERCENT_' . $known . $str . $dt_str;
290 reports
::percent(arr
::search($cstate, $str . $dt_str), $div);
294 $str = 'PERCENT_KNOWN_TIME_' . $state;
296 $cstate[$str . '_SCHEDULED'] +
$cstate[$str . '_UNSCHEDULED'];
299 # mop up the oddballs and special cases
300 $cstate['PERCENT_TIME_UNDETERMINED_NOT_RUNNING'] =
301 reports
::percent($cstate['TIME_UNDETERMINED_NOT_RUNNING'], $div);
302 $cstate['PERCENT_TIME_UNDETERMINED_NO_DATA'] =
303 reports
::percent($cstate['TIME_UNDETERMINED_NO_DATA'], $div);
304 $cstate['PERCENT_TIME_DOWN_COUNTED_AS_UP'] =
305 reports
::percent($cstate['TIME_DOWN_COUNTED_AS_UP'], $div);
311 * Finalize the report, calculating real uptime from our internal
314 public function finalize()
316 // gather remaining time. If they match, it'll be 0
317 $this->st_update($this->options
['end_time']);