Avail feature updated
[ninja.git] / application / libraries / Livestatus.php
blob14a9509dbf97e76c65ac65ad09116c532089801e
1 <?php
3 /*
4 * Livestatus Class
6 * usage:
8 * access nagios data by various get<Table> methods.
10 * options is an hash array which provides filtering and other query options:
12 * example:
13 * $ls = Livestatus::instance();
14 * $hosts = getHosts($options)
16 * options = array(
17 * 'auth' => <bool>, # authentication is enabled by default.
18 * # use this switch to disable it
20 * 'limit' => <nr of records>, # limit result set
22 * 'paging' => $this, # use paging. $this is a reference to
23 * # a kohana object to access the input
24 * # and template reference
26 * 'order' => $order, # sorting / order by structure, ex.:
27 * # array('name' => 'DESC')
28 * # array('host_name' => 'DESC', 'description' => 'DESC')
29 * 'order_mappings' => $map, # Makes it possible to map a fictive column name to a real
30 * # column name for sorting. Useful when using 'callback' columns.
32 * 'filter' => $filter, # filter structure used to filter the
33 * # resulting objects
34 * # simple filter:
35 * # array('name' => 'value')
36 * # simple filter with operator:
37 * # array('name' => array('!=' => 'value'))
38 * # logical operator:
39 * # array('-or' => array('name' => 'value', 'address' => 'othervalue'))
40 * # nested filter:
41 * # array('-or' => array('name' => 'value', 'address' => array('~~' => 'othervalue')))
42 * #
43 * # filter can also be a string containing an expression with livestatus operations,
44 * # grouped with logical operators. Example:
45 * #
46 * # 'host_name ~~ "name regexp" and (status = 1 or status = 2)'
47 * #
48 * # see livestatus docs for details about available operators
49 * 'extra_header' => # A raw livestatus header block, useful for example to raw filters.
50 * );
53 require_once("op5/livestatus.php");
55 class Livestatus {
56 private static $instance = false;
58 /* singleton */
59 public static function instance($config = null) {
60 if (self::$instance !== false) {
61 return self::$instance;
63 return self::$instance = new self($config);
66 private $program_start = false;
67 private $backend = false;
69 public function __construct($config = null) {
70 $this->backend = new LiveStatusBackend($config);
73 public function getBackend() {
74 return $this->backend;
77 public function calc_duration($row) {
78 $now = time();
79 return $row['last_state_change'] ? ($now - $row['last_state_change']) : ($now - $this->program_start);
82 /**
83 * Fugly but the right place to .. place it.
84 * Originally intended for config listing.
86 * @todo this only suits string columns, not lists, not ints
88 * @return array
90 function filterable_columns() {
91 return array(
92 'services' => array(
93 'host_name',
94 'description'
96 'hosts' => array(
97 'name'
99 'hostgroups' => array(
100 'name'
102 'servicegroups' => array(
103 'name'
105 'contacts' => array(
106 'name'
108 'contactgroups' => array(
109 'name'
111 'commands' => array(
112 'name'
117 public function handle_passive_as_active($row) {
118 static $passive_as_active = null;
119 if ($passive_as_active === null)
120 $passive_as_active = config::get('checks.show_passive_as_active', '*');
122 if ($passive_as_active)
123 return $row['active_checks_enabled'] || $row['accept_passive_checks'];
124 else
125 return $row['active_checks_enabled'];
128 public function handle_host_passive_as_active($row) {
129 static $passive_as_active = null;
130 if ($passive_as_active === null)
131 $passive_as_active = config::get('checks.show_passive_as_active', '*');
133 if ($passive_as_active)
134 return $row['host_active_checks_enabled'] || $row['host_accept_passive_checks'];
135 else
136 return $row['host_active_checks_enabled'];
139 /* getHosts */
140 public function getHosts($options = null) {
141 if(!isset($options['columns'])) {
142 $options['columns'] = array(
143 'accept_passive_checks', 'acknowledged', 'action_url', 'action_url_expanded',
144 'active_checks_enabled', 'address', 'alias', 'check_command', 'check_freshness', 'check_interval',
145 'check_options', 'check_period', 'check_type', 'checks_enabled', 'childs', 'comments', 'current_attempt',
146 'current_notification_number', 'display_name', 'event_handler_enabled', 'execution_time',
147 'custom_variable_names', 'custom_variable_values', 'hourly_value',
148 'first_notification_delay', 'flap_detection_enabled', 'groups', 'has_been_checked',
149 'high_flap_threshold', 'icon_image', 'icon_image_alt', 'icon_image_expanded',
150 'is_executing', 'is_flapping', 'last_check', 'last_notification', 'last_state_change',
151 'latency', 'long_plugin_output', 'low_flap_threshold', 'max_check_attempts', 'name',
152 'next_check', 'notes', 'notes_expanded', 'notes_url', 'notes_url_expanded', 'notification_interval',
153 'notification_period', 'notifications_enabled', 'num_services_crit', 'num_services_ok',
154 'num_services_pending', 'num_services_unknown', 'num_services_warn', 'num_services', 'obsess',
155 'parents', 'percent_state_change', 'perf_data', 'plugin_output', 'process_performance_data',
156 'retry_interval', 'scheduled_downtime_depth', 'state', 'state_type', 'modified_attributes_list',
157 'pnpgraph_present'
159 $options['callbacks'] = array(
160 'duration' => array($this, 'calc_duration'),
161 'checks_enabled' => array($this, 'handle_passive_as_active')
164 $options['order_mappings'] = array(
165 'duration' => array( '!last_state_change' ),
167 /* This is not actually correct... But isn't possible to do better in LS*/
168 'checks_enabled' => array( 'active_checks_enabled', 'accept_passive_checks' )
171 return $this->backend->getTable('hosts', $options);
174 /* getHostgroups */
175 public function getHostgroups($options = null) {
176 if(!isset($options['columns'])) {
177 $options['columns'] = array(
178 'name', 'alias', /*'members',*/ 'action_url', 'notes', 'notes_url',
180 /* Slow, skip by default
181 'members_with_state',
182 'worst_host_state',
183 'num_hosts',
184 'num_hosts_pending',
185 'num_hosts_up',
186 'num_hosts_down',
187 'num_hosts_unreach',
188 'num_services',
189 'worst_service_state',
190 'num_services_pending',
191 'num_services_ok',
192 'num_services_warn',
193 'num_services_crit',
194 'num_services_unknown',
195 'worst_service_hard_state',
196 'num_services_hard_ok',
197 'num_services_hard_warn',
198 'num_services_hard_crit',
199 'num_services_hard_unknown'
204 return $this->backend->getTable('hostgroups', $options);
207 /* getHostsByGroup */
208 public function getHostsByGroup($options = null) {
209 if(!isset($options['columns'])) {
210 $options['columns'] = array(
211 'icon_image', 'icon_image_alt', 'name', 'services_with_state', 'action_url',
212 'action_url', 'notes_url','pnpgraph_present'
215 return $this->backend->getTable('hostsbygroup', $options);
218 /* getServices */
219 public function getServices($options = null) {
220 if(!isset($options['columns'])) {
221 $options['columns'] = array(
222 'accept_passive_checks', 'acknowledged', 'action_url', 'action_url_expanded',
223 'active_checks_enabled', 'check_command', 'check_interval', 'check_options',
224 'check_period', 'check_type', 'checks_enabled', 'comments', 'current_attempt',
225 'current_notification_number', 'description', 'event_handler', 'event_handler_enabled',
226 'custom_variable_names', 'custom_variable_values', 'display_name',
227 'execution_time', 'first_notification_delay', 'flap_detection_enabled', 'groups',
228 'has_been_checked', 'high_flap_threshold', 'host_acknowledged', 'host_action_url_expanded',
229 'host_active_checks_enabled', 'host_address', 'host_alias', 'host_checks_enabled', 'host_check_type',
230 'host_comments', 'host_groups', 'host_has_been_checked', 'host_icon_image_expanded', 'host_icon_image_alt',
231 'host_is_executing', 'host_is_flapping', 'host_name', 'host_notes_url_expanded',
232 'host_notifications_enabled', 'host_scheduled_downtime_depth', 'host_state', 'host_state_type',
233 'host_accept_passive_checks', 'host_current_attempt', 'host_max_check_attempts',
234 'host_display_name',
235 'icon_image', 'icon_image_alt', 'icon_image_expanded', 'is_executing', 'is_flapping',
236 'last_check', 'last_notification', 'last_state_change', 'latency', 'long_plugin_output',
237 'low_flap_threshold', 'max_check_attempts', 'next_check', 'notes', 'notes_expanded',
238 'notes_url', 'notes_url_expanded', 'notification_interval', 'notification_period',
239 'notifications_enabled', 'obsess', 'percent_state_change', 'perf_data',
240 'plugin_output', 'process_performance_data', 'retry_interval', 'scheduled_downtime_depth',
241 'state', 'state_type', 'modified_attributes_list', 'pnpgraph_present'
243 $options['callbacks'] = array(
244 'duration' => array($this, 'calc_duration'),
245 'checks_enabled' => array($this, 'handle_passive_as_active'),
246 'host_checks_enabled' => array($this, 'handle_host_passive_as_active')
249 $options['order_mappings'] = array(
250 'duration' => array( '!last_state_change' ),
252 /* This is not actually correct... But isn't possible to do better in LS*/
253 'checks_enabled' => array( 'active_checks_enabled', 'accept_passive_checks' )
256 return $this->backend->getTable('services', $options);
259 /* getServicegroups */
260 public function getServicegroups($options = null) {
261 if(!isset($options['columns'])) {
262 $options['columns'] = array(
263 'name', 'alias', /*'members',*/ 'action_url', 'notes', 'notes_url',
264 /* Slow, skip by default
265 'members_with_state',
266 'worst_service_state',
267 'num_services',
268 'num_services_ok',
269 'num_services_warn',
270 'num_services_crit',
271 'num_services_unknown',
272 'num_services_pending',
273 'num_services_hard_ok',
274 'num_services_hard_warn',
275 'num_services_hard_crit',
276 'num_services_hard_unknown'
280 return $this->backend->getTable('servicegroups', $options);
283 /* getContacts */
284 public function getContacts($options = null) {
285 if(!isset($options['columns'])) {
286 $options['columns'] = array(
287 'name',
288 'alias',
289 'email',
290 'pager',
291 'service_notification_period',
292 'host_notification_period',
293 'can_submit_commands'
296 return $this->backend->getTable('contacts', $options);
299 /* getContactgroups */
300 public function getContactgroups($options = null) {
301 if(!isset($options['columns'])) {
302 $options['columns'] = array(
303 'name', 'alias', /*'members',*/
306 return $this->backend->getTable('contactgroups', $options);
309 /* getCommands */
310 public function getCommands($options = null) {
311 if(!isset($options['columns'])) {
312 $options['columns'] = array(
313 'name', 'line',
316 return $this->backend->getTable('commands', $options);
319 /* getTimeperiods */
320 public function getTimeperiods($options = null) {
321 if(!isset($options['columns'])) {
322 $options['columns'] = array(
323 'name', 'alias',
326 return $this->backend->getTable('timeperiods', $options);
329 /* getLogs */
330 public function getLogs($options = null) {
331 if(!isset($options['columns'])) {
332 $options['columns'] = array(
333 'class', 'time', 'type', 'state', 'host_name', 'service_description', 'plugin_output',
334 'message', 'options', 'contact_name', 'command_name', 'state_type', 'current_host_groups',
335 'current_service_groups',
338 return $this->backend->getTable('log', $options);
341 /* getComments */
342 public function getComments($options = null) {
343 if(!isset($options['columns'])) {
344 $options['columns'] = array(
345 'author', 'comment', 'entry_time', 'entry_type', 'expires',
346 'expire_time', 'host_name', 'id', 'persistent', 'service_description',
347 'source', 'type',
350 return $this->backend->getTable('comments', $options);
353 /* getDowntimes */
354 public function getDowntimes($options = null) {
355 if(!isset($options['columns'])) {
356 $options['columns'] = array(
357 'author', 'comment', 'end_time', 'entry_time', 'duration', 'fixed', 'host_name',
358 'id', 'start_time', 'service_description', 'triggered_by', 'type'
361 return $this->backend->getTable('downtimes', $options);
364 /* getProcessInfo */
365 public function getProcessInfo($options = null) {
366 if(!isset($options['columns'])) {
367 $options['columns'] = array(
368 'accept_passive_host_checks', 'accept_passive_service_checks', 'check_external_commands',
369 'check_host_freshness', 'check_service_freshness', 'enable_event_handlers', 'enable_flap_detection',
370 'enable_notifications', 'execute_host_checks', 'execute_service_checks',
371 'last_log_rotation', 'livestatus_version', 'nagios_pid', 'obsess_over_hosts', 'obsess_over_services',
372 'process_performance_data', 'program_start', 'program_version', 'interval_length',
373 'cached_log_messages', 'connections', 'connections_rate', 'host_checks',
374 'host_checks_rate', 'requests', 'requests_rate', 'service_checks',
375 'service_checks_rate', 'neb_callbacks', 'neb_callbacks_rate',
378 $objects = $this->backend->getTable('status', $options);
379 if(count($objects) == 0) return null;
380 $this->program_start = $objects[0]['program_start'];
381 return (object) $objects[0];
385 /* getHostTotals */
386 public function getHostTotals($options = null) {
387 if (config::get('checks.show_passive_as_active', '*')) {
388 $active_checks_condition = array('-or' => array('active_checks_enabled' => 1, 'accept_passive_checks' => 1));
389 $disabled_checks_condition = array('active_checks_enabled' => 0, 'accept_passive_checks' => 0);
390 } else {
391 $active_checks_condition = array('active_checks_enabled' => 1);
392 $disabled_checks_condition = array('active_checks_enabled' => 0);
394 $stats = array(
395 'total' => array( 'state' => array( '!=' => 999 )),
396 'total_active' => array( 'check_type' => 0 ),
397 'total_passive' => array( 'check_type' => 1 ),
398 'pending' => array( 'has_been_checked' => 0 ),
399 'pending_and_disabled' => array_merge(array('has_been_checked' => 0), $disabled_checks_condition),
400 'pending_and_scheduled' => array( 'has_been_checked' => 0, 'scheduled_downtime_depth' => array('>' => 0 )),
401 'up' => array( 'has_been_checked' => 1, 'state' => 0 ),
402 'up_and_disabled_active' => array_merge(array('check_type' => 0, 'has_been_checked' => 1, 'state' => 0), $disabled_checks_condition),
403 'up_and_disabled_passive' => array_merge(array('check_type' => 1, 'has_been_checked' => 1, 'state' => 0), $disabled_checks_condition),
404 'up_and_scheduled' => array( 'has_been_checked' => 1, 'state' => 0, 'scheduled_downtime_depth' => array( '>' => 0 )),
405 'down' => array( 'has_been_checked' => 1, 'state' => 1 ),
406 'down_and_ack' => array( 'has_been_checked' => 1, 'state' => 1, 'acknowledged' => 1 ),
407 'down_and_scheduled' => array( 'has_been_checked' => 1, 'state' => 1, 'scheduled_downtime_depth' => array( '>' => 0 )),
408 'down_and_disabled_active' => array_merge(array('check_type' => 0, 'has_been_checked' => 1, 'state' => 1), $disabled_checks_condition),
409 'down_and_disabled_passive' => array_merge(array('check_type' => 1, 'has_been_checked' => 1, 'state' => 1), $disabled_checks_condition),
410 'down_and_unhandled' => array_merge(array('has_been_checked' => 1, 'state' => 1, 'acknowledged' => 0, 'scheduled_downtime_depth' => 0), $active_checks_condition),
411 'unreachable' => array( 'has_been_checked' => 1, 'state' => 2 ),
412 'unreachable_and_ack' => array( 'has_been_checked' => 1, 'state' => 2, 'acknowledged' => 1 ),
413 'unreachable_and_scheduled' => array( 'has_been_checked' => 1, 'state' => 2, 'scheduled_downtime_depth' => array( '>' => 0 ) ),
414 'unreachable_and_disabled_active' => array_merge(array('check_type' => 0, 'has_been_checked' => 1, 'state' => 2), $disabled_checks_condition),
415 'unreachable_and_disabled_passive' => array_merge(array('check_type' => 1, 'has_been_checked' => 1, 'state' => 2), $disabled_checks_condition),
416 'unreachable_and_unhandled' => array_merge(array('has_been_checked' => 1, 'state' => 2, 'acknowledged' => 0, 'scheduled_downtime_depth' => 0), $active_checks_condition),
417 'flapping' => array( 'is_flapping' => 1 ),
418 'flapping_disabled' => array( 'flap_detection_enabled' => 0 ),
419 'notifications_disabled' => array( 'notifications_enabled' => 0 ),
420 'eventhandler_disabled' => array( 'event_handler_enabled' => 0 ),
421 'active_checks_disabled_active' => array( 'check_type' => 0, 'active_checks_enabled' => 0 ),
422 'active_checks_disabled_passive' => array( 'check_type' => 1, 'active_checks_enabled' => 0 ),
423 'passive_checks_disabled' => array( 'accept_passive_checks' => 0 ),
424 'outages' => array( 'state' => 1, 'childs' => array( '!=' => '' ) ),
426 if (is_array($options) && isset($options['stats']) && is_array($options['stats'])) {
427 $newstats = array();
428 foreach( $options['stats'] as $statcol ) {
429 $newstats[$statcol] = $stats[$statcol];
431 $stats = $newstats;
433 $data = $this->backend->getStats('hosts', $stats, $options);
434 return (object) $data[0];
438 /* getServiceTotals */
439 public function getServiceTotals($options = null) {
440 if (config::get('checks.show_passive_as_active', '*')) {
441 $active_checks_condition = array('-or' => array('active_checks_enabled' => 1, 'accept_passive_checks' => 1));
442 $disabled_checks_condition = array('active_checks_enabled' => 0, 'accept_passive_checks' => 0);
443 } else {
444 $active_checks_condition = array('active_checks_enabled' => 1);
445 $disabled_checks_condition = array('active_checks_enabled' => 0);
447 $stats = array(
448 'total' => array( 'description' => array( '!=' => '' ) ),
449 'total_active' => array( 'check_type' => 0 ),
450 'total_passive' => array( 'check_type' => 1 ),
451 'pending' => array( 'has_been_checked' => 0 ),
452 'pending_and_disabled' => array_merge(array('has_been_checked' => 0), $disabled_checks_condition),
453 'pending_and_scheduled' => array( 'has_been_checked' => 0, 'scheduled_downtime_depth' => array( '>' => 0 ) ),
454 'ok' => array( 'has_been_checked' => 1, 'state' => 0 ),
455 'ok_and_scheduled' => array( 'has_been_checked' => 1, 'state' => 0, 'scheduled_downtime_depth' => array( '>' => 0 ) ),
456 'ok_and_disabled_active' => array_merge(array('check_type' => 0, 'has_been_checked' => 1, 'state' => 0), $disabled_checks_condition),
457 'ok_and_disabled_passive' => array_merge(array('check_type' => 1, 'has_been_checked' => 1, 'state' => 0), $disabled_checks_condition),
458 'warning' => array( 'has_been_checked' => 1, 'state' => 1 ),
459 'warning_and_scheduled' => array( 'has_been_checked' => 1, 'state' => 1, 'scheduled_downtime_depth' => array( '>' => 0 ) ),
460 'warning_and_disabled_active' => array_merge(array('check_type' => 0, 'has_been_checked' => 1, 'state' => 1), $disabled_checks_condition),
461 'warning_and_disabled_passive' => array_merge(array('check_type' => 1, 'has_been_checked' => 1, 'state' => 1), $disabled_checks_condition),
462 'warning_and_ack' => array( 'has_been_checked' => 1, 'state' => 1, 'acknowledged' => 1 ),
463 'warning_on_down_host' => array( 'has_been_checked' => 1, 'state' => 1, 'host_state' => array( '!=' => 0 ) ),
464 'warning_and_unhandled' => array_merge(array('has_been_checked' => 1, 'state' => 1, 'host_state' => 0, 'acknowledged' => 0, 'scheduled_downtime_depth' => 0), $active_checks_condition),
465 'critical' => array( 'has_been_checked' => 1, 'state' => 2 ),
466 'critical_and_scheduled' => array( 'has_been_checked' => 1, 'state' => 2, 'scheduled_downtime_depth' => array( '>' => 0 ) ),
467 'critical_and_disabled_active' => array_merge(array('check_type' => 0, 'has_been_checked' => 1, 'state' => 2), $disabled_checks_condition),
468 'critical_and_disabled_passive' => array_merge(array('check_type' => 1, 'has_been_checked' => 1, 'state' => 2), $disabled_checks_condition),
469 'critical_and_ack' => array( 'has_been_checked' => 1, 'state' => 2, 'acknowledged' => 1 ),
470 'critical_on_down_host' => array( 'has_been_checked' => 1, 'state' => 2, 'host_state' => array( '!=' => 0 ) ),
471 'critical_and_unhandled' => array_merge(array('has_been_checked' => 1, 'state' => 2, 'host_state' => 0, 'acknowledged' => 0, 'scheduled_downtime_depth' => 0), $active_checks_condition),
472 'unknown' => array( 'has_been_checked' => 1, 'state' => 3 ),
473 'unknown_and_scheduled' => array( 'has_been_checked' => 1, 'state' => 3, 'scheduled_downtime_depth' => array( '>' => 0 ) ),
474 'unknown_and_disabled_active' => array_merge(array('check_type' => 0, 'has_been_checked' => 1, 'state' => 3), $disabled_checks_condition),
475 'unknown_and_disabled_passive' => array_merge(array('check_type' => 1, 'has_been_checked' => 1, 'state' => 3), $disabled_checks_condition),
476 'unknown_and_ack' => array( 'has_been_checked' => 1, 'state' => 3, 'acknowledged' => 1 ),
477 'unknown_on_down_host' => array( 'has_been_checked' => 1, 'state' => 3, 'host_state' => array( '!=' => 0 ) ),
478 'unknown_and_unhandled' => array_merge(array('has_been_checked' => 1, 'state' => 3, 'host_state' => 0, 'acknowledged' => 0, 'scheduled_downtime_depth' => 0), $active_checks_condition),
479 'flapping' => array( 'is_flapping' => 1 ),
480 'flapping_disabled' => array( 'flap_detection_enabled' => 0 ),
481 'notifications_disabled' => array( 'notifications_enabled' => 0 ),
482 'eventhandler_disabled' => array( 'event_handler_enabled' => 0 ),
483 'active_checks_disabled_active' => array( 'check_type' => 0, 'active_checks_enabled' => 0 ),
484 'active_checks_disabled_passive' => array( 'check_type' => 1, 'active_checks_enabled' => 0 ),
485 'passive_checks_disabled' => array( 'accept_passive_checks' => 0 ),
487 if (is_array($options) && isset($options['stats']) && is_array($options['stats'])) {
488 $newstats = array();
489 foreach( $options['stats'] as $statcol ) {
490 $newstats[$statcol] = $stats[$statcol];
492 $stats = $newstats;
494 $data = $this->backend->getStats('services', $stats, $options);
495 return (object) $data[0];
498 /* getHostPerformance */
499 public function getHostPerformance($last_program_start, $options = null) {
500 return $this->getPerformanceStats('hosts', $last_program_start, $options);
503 /* getServicePerformance */
504 public function getServicePerformance($last_program_start, $options = null) {
505 $stats = $this->getPerformanceStats('services', $last_program_start, $options);
506 return $stats;
509 public function getSchedulingQueue($last_program_start, $options = null) {
510 $stats = $this->getPerformanceStats('services', $last_program_start, $options);
511 return $stats;
514 /* getPerformanceStats */
515 public function getPerformanceStats($type, $last_program_start, $options = null) {
516 $result = array();
517 $now = time();
518 $min1 = $now - 60;
519 $min5 = $now - 300;
520 $min15 = $now - 900;
521 $min60 = $now - 3600;
522 $minall = $last_program_start;
524 $stats = array(
525 'active_sum' => array( 'check_type' => 0 ),
526 'active_1_sum' => array( 'check_type' => 0, 'has_been_checked' => 1, 'last_check' => array( '>=' => $min1 ) ),
527 'active_5_sum' => array( 'check_type' => 0, 'has_been_checked' => 1, 'last_check' => array( '>=' => $min5 ) ),
528 'active_15_sum' => array( 'check_type' => 0, 'has_been_checked' => 1, 'last_check' => array( '>=' => $min15 ) ),
529 'active_60_sum' => array( 'check_type' => 0, 'has_been_checked' => 1, 'last_check' => array( '>=' => $min60 ) ),
530 'active_all_sum' => array( 'check_type' => 0, 'has_been_checked' => 1, 'last_check' => array( '>=' => $minall ) ),
532 'passive_sum' => array( 'check_type' => 1 ),
533 'passive_1_sum' => array( 'check_type' => 1, 'has_been_checked' => 1, 'last_check' => array( '>=' => $min1 ) ),
534 'passive_5_sum' => array( 'check_type' => 1, 'has_been_checked' => 1, 'last_check' => array( '>=' => $min5 ) ),
535 'passive_15_sum' => array( 'check_type' => 1, 'has_been_checked' => 1, 'last_check' => array( '>=' => $min15 ) ),
536 'passive_60_sum' => array( 'check_type' => 1, 'has_been_checked' => 1, 'last_check' => array( '>=' => $min60 ) ),
537 'passive_all_sum' => array( 'check_type' => 1, 'has_been_checked' => 1, 'last_check' => array( '>=' => $minall ) ),
540 $data = $this->backend->getStats($type, $stats);
541 $result = array_merge($result, $data[0]);
543 /* add stats for active checks */
544 $stats = array(
545 'execution_time_sum' => array( '-sum' => 'execution_time' ),
546 'latency_sum' => array( '-sum' => 'latency' ),
547 'active_state_change_sum' => array( '-sum' => 'percent_state_change' ),
548 'execution_time_min' => array( '-min' => 'execution_time' ),
549 'latency_min' => array( '-min' => 'latency' ),
550 'active_state_change_min' => array( '-min' => 'percent_state_change' ),
551 'execution_time_max' => array( '-max' => 'execution_time' ),
552 'latency_max' => array( '-max' => 'latency' ),
553 'active_state_change_max' => array( '-max' => 'percent_state_change' ),
554 'execution_time_avg' => array( '-avg' => 'execution_time' ),
555 'latency_avg' => array( '-avg' => 'latency' ),
556 'active_state_change_avg' => array( '-avg' => 'percent_state_change' ),
559 $data = $this->backend->getStats($type, $stats, array('filter' => array('has_been_checked' => 1, 'check_type' => 0)));
560 $result = array_merge($result, $data[0]);
562 /* add stats for passive checks */
563 $stats = array(
564 'passive_state_change_sum' => array( '-sum' => 'percent_state_change' ),
565 'passive_state_change_min' => array( '-min' => 'percent_state_change' ),
566 'passive_state_change_max' => array( '-max' => 'percent_state_change' ),
567 'passive_state_change_avg' => array( '-avg' => 'percent_state_change' ),
569 $data = $this->backend->getStats($type, $stats, array('filter' => array('has_been_checked' => 1, 'check_type' => 1)));
570 $result = array_merge($result, $data[0]);
572 return (object) $result;
577 * Livetatus interaface.
579 class LivestatusBackend {
580 private $connection = null;
582 /* constructor */
583 public function __construct() {
586 /* combineFilter */
587 public static function combineFilter($operator, $filter) {
589 if(!isset($operator) and $operator != '-or' and $operator != '-and') {
590 throw new op5LivestatusException("unknown operator in combine_filter(): ".$operator);
593 if(!isset($filter)) {
594 return "";
597 if(!is_array($filter)) {
598 throw new op5LivestatusException("expected array in combine_filter(): ");
601 if(count($filter) == 0) {
602 return "";
605 if(count($filter) == 1) {
606 return($filter[0]);
609 return array($operator => $filter );
613 /********************************************************
614 * INTERNAL FUNCTIONS
615 *******************************************************/
616 public function getTable($table, $options = null) {
617 return $this->getStats($table, false, $options);
620 public function getStats($table, $stats, $options = null) {
621 $query = "";
622 if(isset($options['filter'])) {
623 $query .= $this->getQueryFilter($options['filter'], false);
625 if(isset($options['extra_header'])) {
626 $query .= trim( $options['extra_header'] ) . "\n";
628 if( isset( $options['extra_columns'] ) ) {
629 if( !isset( $options['columns'] ) )
630 $options['columns'] = array();
631 $options['columns'] = array_unique( array_merge( $options['columns'], $options['extra_columns'] ) );
634 $columns = isset($options['columns'])?$options['columns']:array();
636 $output_columns = $columns;
637 if( $stats !== false ) {
638 foreach($stats as $key => $filter) {
639 if( is_string( $filter ) ) {
640 $query .= "Stats: $filter\n";
641 } else {
642 $query .= $this->getQueryFilter($filter, true);
644 array_push($output_columns, $key);
648 $this->prepare_pagination($options);
649 list($objects,$count) = $this->query($table, $query, $columns, $options);
650 $this->postprocess_pagination($options, $count);
652 return $this->objects2Assoc($objects, $output_columns, isset($options['callbacks']) ? $options['callbacks'] : null);
655 private function prepare_pagination(&$options) {
656 if(isset($options['paging'])) {
657 $page = $options['paging'];
658 $items_per_page = $page->input->get('items_per_page', config::get('pagination.default.items_per_page', '*'));
659 $items_per_page = $page->input->get('custom_pagination_field', $items_per_page);
661 elseif(isset($options['paginggroup'])) {
662 $page = $options['paginggroup'];
663 $items_per_page = $page->input->get('items_per_page', config::get('pagination.group_items_per_page', '*'));
664 $items_per_page = $page->input->get('custom_pagination_field', $items_per_page);
665 } else {
666 return;
668 $current_page = $page->input->get('page',1);
669 if(!is_numeric($current_page)) { $current_page = 1; }
671 /* Set parameters to query */
672 $options['offset'] = ($current_page-1) * $items_per_page;
673 $options['limit'] = $items_per_page;
675 /* Store to postprocess method */
676 $options['page_enabled'] = true;
677 $options['page_items_per_page'] = $items_per_page;
678 $options['page_current_page'] = $current_page;
679 $options['page_obj'] = $page;
682 private function postprocess_pagination($options, $count) {
683 if( !isset($options['page_enabled']) || !$options['page_enabled'] )
684 return;
686 $page = $options['page_obj'];
687 $items_per_page = $options['page_items_per_page'];
688 $current_page = $options['page_current_page'];
690 $pagination = new Pagination(array(
691 'total_items' => $count,
692 'items_per_page' => $items_per_page,
694 $page->template->content->pagination = $pagination;
695 $page->template->content->total_items = $count;
696 $page->template->content->items_per_page = $items_per_page;
697 $page->template->content->page = $current_page;
700 private function query($table, $filter, $columns, $options) {
701 $ls = op5livestatus::instance();
703 if( isset( $options['order'] ) ) {
704 $order_mappings = !empty($options['order_mappings'])?$options['order_mappings']:array();
705 foreach( $options['order'] as $column => $direction ) {
706 if( isset($order_mappings[$column]) ) {
707 foreach( $order_mappings[$column] as $mapping ) {
708 $column = $mapping;
709 if( $column[0] == '!' ) {
710 $column = substr($column,1);
711 $direction = strtolower($direction)=='asc'?'desc':'asc';
713 $filter .= "Sort: $column $direction\n";
715 } else {
716 $filter .= "Sort: $column $direction\n";
720 if( isset( $options['offset'] ) ) {
721 $filter .= "Offset: ".$options['offset']."\n";
723 if( isset( $options['limit'] ) && $options['limit'] !== false ) {
724 $filter .= "Limit: ".$options['limit']."\n";
727 list($columns, $objects, $count) = $ls->query($table, $filter, $columns, $options);
728 return array($objects,$count);
731 /* Public, just to make it testable */
732 public function getQueryFilter($filter, $stats = false ) {
733 if( empty( $filter ) ) {
734 return "";
736 return $this->parseQueryFilterArray($stats, $filter, null, null, $stats?'And':null);
739 private function parseQueryFilterArray($stats = false, $filter = null, $op = null, $name = null, $listop = null) {
740 if($filter === null) {
741 return "";
743 /* TODO: implement proper escaping */
745 /* remove empty elements */
746 while(is_array($filter) and isset($filter[0]) and $filter[0] === '') {
747 array_shift($filter);
750 $query = "";
751 if($this->is_assoc($filter)) {
752 $iter = 0;
753 foreach($filter as $key => $val) {
754 $iter++;
755 switch($key) {
756 case '-or': $query .= $this->parseQueryFilterArray($stats, $val, $op, $name, 'Or');
757 break;
758 case '-and': $query .= $this->parseQueryFilterArray($stats, $val, $op, $name, 'And');
759 break;
760 case '=':
761 case '~':
762 case '=~':
763 case '~~':
764 case '<':
765 case '>':
766 case '<=':
767 case '>=':
768 case '~':
769 case '!=':
770 case '!~':
771 case '!=~':
772 case '!~~': $query .= $this->parseQueryFilterArray($stats, $val, $key, $name, 'And');
773 break;
774 case '-sum':
775 case '-avg':
776 case '-min':
777 case '-max': $query .= $this->parseQueryFilterArray($stats, $val, substr($key, 1), '');
778 break;
779 default: $query .= $this->parseQueryFilterArray($stats, $val, '=', $key, 'And');
780 break;
783 if($iter > 1 && $listop === null) {
784 $listop = 'And';
786 if($iter > 1 && $listop !== null) {
787 $query .= ($stats ? 'Stats' : '').$listop.": ".$iter."\n";
789 return $query;
792 if($op === null and $listop !== null) {
793 $op = "=";
796 if($op !== null) {
797 if(!is_array($filter)) {
798 $query = ($stats ? 'Stats' : 'Filter').": $name $op $filter\n";
800 else {
801 foreach($filter as $val) {
802 if(is_array($val)) {
803 $query .= $this->parseQueryFilterArray($stats, $val, $op, $name);
804 } else {
805 $query .= ($stats ? 'Stats' : 'Filter').": $name $op $val\n";
808 if(count($filter) > 1) {
809 $query .= ($stats ? 'Stats' : '').$listop.": ".count($filter)."\n";
812 return $query;
815 if($filter === "") {
816 return "";
819 throw new op5LivestatusException("broken filter");
822 private function is_assoc($array) {
823 return (is_array($array) && (count($array)==0 || 0 !== count(array_diff_key($array, array_keys(array_keys($array))) )));
826 private function objects2Assoc($objects, $columns, $callbacks = null) {
827 $result = array();
828 foreach($objects as $o) {
829 $n = array();
830 if (!is_array($columns)) {
831 $n = $o[0];
832 } else {
833 $i = 0;
834 foreach($columns as $c) {
835 $n[$c] = $o[$i];
836 $i++;
838 if($callbacks != null) {
839 foreach($callbacks as $key => $cb) {
840 $n[$key] = call_user_func($cb, $n);
844 array_push($result, $n);
846 return $result;