You are here

function nagios_check_watchdog in Nagios Monitoring 8

Same name and namespace in other branches
  1. 6 nagios.module \nagios_check_watchdog()
  2. 7 nagios.module \nagios_check_watchdog()

Check Drupal {watchdog} table recent entries.

Corrensponds to opening the admin/reports/dblog page in the browser.

Return value

array

File

./nagios.module, line 431
Main file for Nagios service monitoring.

Code

function nagios_check_watchdog() {

  // @TODO Allow multi-value 'type' and/or 'severity' inputs for filtering
  // @TODO Allow datetime ranges
  // Constuct base select query.
  $conn = Database::getConnection();
  $query = $conn
    ->select('watchdog', 'w');
  $query
    ->fields('w', [
    'wid',
    'uid',
    'type',
    'severity',
    'message',
    'variables',
    'link',
    'location',
    'hostname',
    'timestamp',
  ]);
  $query
    ->orderBy('timestamp', 'DESC');
  $query
    ->orderBy('severity');
  $state = Drupal::state();
  $config = Drupal::config('nagios.settings');
  $query
    ->range(0, 10);

  // Check if we are limiting to only new logs since last check.
  $limit_watchdog = $config
    ->get('nagios.limit_watchdog.display');
  if (!empty($limit_watchdog)) {

    // Get timestamp of the last watchdog entry retrieved.
    $limit_watchdog_timestamp = $state
      ->get('nagios.limit_watchdog_timestamp') ?: FALSE;
    if ($limit_watchdog_timestamp !== FALSE) {

      // Ensure we only get entries that are greater than the timestamp.
      $query
        ->condition('timestamp', $limit_watchdog_timestamp, '>');
    }
  }
  $min_severity = $config
    ->get('nagios.min_report_severity') ?: NAGIOS_STATUS_WARNING;

  // RFC3164/Watchdog has 8 levels. Nagios module has 3 (plus UNKNOWN).
  // This maps Watchdog => Nagios.
  $severity_translation = [
    RfcLogLevel::EMERGENCY => NAGIOS_STATUS_CRITICAL,
    RfcLogLevel::ALERT => NAGIOS_STATUS_CRITICAL,
    RfcLogLevel::CRITICAL => NAGIOS_STATUS_CRITICAL,
    RfcLogLevel::ERROR => NAGIOS_STATUS_CRITICAL,
    RfcLogLevel::WARNING => NAGIOS_STATUS_WARNING,
    RfcLogLevel::NOTICE => NAGIOS_STATUS_OK,
    RfcLogLevel::INFO => NAGIOS_STATUS_OK,
    RfcLogLevel::DEBUG => NAGIOS_STATUS_OK,
  ];
  $query
    ->condition('severity', array_flip($severity_translation)[$min_severity], '<=');
  $channel_filter = $config
    ->get('nagios.limit_watchdog.channel_filter');
  if ($channel_filter) {
    $negate = $config
      ->get('nagios.limit_watchdog.negate');
    $query
      ->condition('type', $channel_filter, $negate ? 'IN' : 'NOT IN');
  }

  // Execute query.
  try {
    $result = $query
      ->execute();
  } catch (Exception $e) {
    $result = FALSE;
  }
  if (!$result) {
    return [
      'key' => 'WATCHDOG',
      'data' => [
        'status' => NAGIOS_STATUS_UNKNOWN,
        'type' => 'state',
        'text' => t('Unable to SELECT FROM {watchdog}'),
      ],
    ];
  }

  // Maximize this across the result set:
  $severity = NAGIOS_STATUS_OK;
  $messages = [];
  $descriptions = [];
  $count = 0;
  while ($row = $result
    ->fetchAssoc()) {

    // Set timestamp of the first watchdog error for use when restricting logs to only new entries.
    if ($count == 0) {
      $state
        ->set('nagios.limit_watchdog_timestamp', $row['timestamp']);
      $count++;
    }

    // Get severity of log entry.
    $nagios_severity = $severity_translation[$row['severity']];

    // If the severity is greater then our current severity level, set it it to new level.
    if ($nagios_severity > $severity) {
      $severity = $nagios_severity;
    }

    // Create error message.
    $message = "{$row['type']} {$row['message']}";

    // @TODO Untangle l(truncate_utf8(_dblog_format_message($dblog), 56, TRUE, TRUE), 'admin/reports/event/'. $dblog->wid, array('html' => TRUE)) and use it here
    try {

      /** @noinspection SuspiciousBinaryOperationInspection */
      if (PHP_VERSION_ID >= 70000) {

        /* graceful approach which supports older versions of PHP */
        $variables = unserialize($row['variables'], [
          'allowed_classes' => [
            TranslatableMarkup::class,
          ],
        ]);
      }
      else {

        /** @noinspection UnserializeExploitsInspection */
        $variables = unserialize($row['variables']);
      }
    } catch (Throwable $exception) {

      // ignore "Object of class __PHP_Incomplete_Class could not be converted to string"
      $variables = FALSE;
    }
    if (is_array($variables)) {
      foreach ($variables as $key => $value) {
        if ($value instanceof __PHP_Incomplete_Class) {
          continue;
        }
        $message = str_replace((string) $key, $value, $message);
      }
    }

    // Add message to messages array only if there isn't already an identical entry.
    if (!in_array($message, $messages, TRUE)) {
      $messages[] = $message;
    }
    else {

      // We only want to show each message once so continue.
      continue;
    }

    // Prepend the timestamp onto the front of the message.
    $message = date('Y-m-d H:i:s', $row['timestamp']) . " " . $message;

    // Add message to descriptions array.
    $descriptions[] = $message;
  }

  // Join all descriptions together into a string.
  $desc = implode(', ', $descriptions);
  return [
    'key' => 'WATCHDOG',
    'data' => [
      'status' => $severity,
      'type' => 'state',
      'text' => t('@desc', [
        '@desc' => $desc,
      ]),
    ],
  ];
}