You are here

class SensorRunner in Monitoring 8

Same name and namespace in other branches
  1. 7 lib/Drupal/monitoring/SensorRunner.php \Drupal\monitoring\SensorRunner

Instantiate and run requested sensors.

@todo more

Hierarchy

Expanded class hierarchy of SensorRunner

6 files declare their use of SensorRunner
ForceRunController.php in src/Controller/ForceRunController.php
MonitoringSensorResultResource.php in src/Plugin/rest/resource/MonitoringSensorResultResource.php
Definition of Drupal\monitoring\Plugin\rest\resource\MonitoringSensorInfoResource.
RequirementsIgnore.php in src/Controller/RequirementsIgnore.php
Contains \Drupal\monitoring\Controller\RequirementsIgnore.
SensorDetailForm.php in src/Form/SensorDetailForm.php
Contains \Drupal\monitoring\Form\SensorDetailForm.
SensorList.php in src/Controller/SensorList.php

... See full list

1 string reference to 'SensorRunner'
monitoring.services.yml in ./monitoring.services.yml
monitoring.services.yml
1 service uses SensorRunner
monitoring.sensor_runner in ./monitoring.services.yml
Drupal\monitoring\SensorRunner

File

src/SensorRunner.php, line 24
Contains \Drupal\monitoring\SensorRunner.

Namespace

Drupal\monitoring
View source
class SensorRunner {

  /**
   * The sensor manager.
   *
   * @var \Drupal\monitoring\Sensor\SensorManager
   */
  protected $sensorManager;

  /**
   * Internal sensor result cache.
   *
   * @var array
   */
  protected $sensorResultCache = array();

  /**
   * List of sensors info keyed by sensor name that are meant to run.
   *
   * @var \Drupal\monitoring\Entity\SensorConfig[]
   */
  protected $sensorConfig = array();

  /**
   * Flag to force sensor run.
   *
   * @var bool
   */
  protected $forceRun = FALSE;

  /**
   * Flag to switch the collecting of verbose output.
   *
   * @var bool
   */
  protected $verbose = FALSE;

  /**
   * @var \Drupal\Core\Cache\CacheBackendInterface
   */
  protected $cache;

  /**
   * @var \Drupal\Core\Config\Config
   */
  protected $config;

  /**
   * Constructs a SensorRunner.
   *
   * @param \Drupal\monitoring\Sensor\SensorManager $sensor_manager
   * @param \Drupal\Core\Cache\CacheBackendInterface $cache
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   */
  public function __construct(SensorManager $sensor_manager, CacheBackendInterface $cache, ConfigFactoryInterface $config_factory) {
    $this->sensorManager = $sensor_manager;
    $this->config = $config_factory
      ->get('monitoring.settings');
    $this->cache = $cache;
  }

  /**
   * Loads available sensor results from cache.
   *
   * @param \Drupal\monitoring\Entity\SensorConfig[] $sensors_config
   *   List of sensor config object that we want to run.
   */
  protected function loadCache(array $sensors_config) {
    $cids = array();

    // Only load sensor caches if they define caching.
    foreach ($sensors_config as $sensor_config) {
      if ($sensor_config
        ->getCachingTime()) {
        $cids[] = $this
          ->getSensorCid($sensor_config
          ->id());
      }
    }
    if ($cids) {
      foreach ($this->cache
        ->getMultiple($cids) as $cache) {
        $this->sensorResultCache[$cache->data['name']] = $cache->data;
      }
    }
  }

  /**
   * Runs the defined sensors.
   *
   * @param \Drupal\monitoring\Entity\SensorConfig[] $sensors_config_all
   *   List of sensor config object that we want to run.
   * @param bool $force
   *   Force sensor execution.
   * @param bool $verbose
   *   Collect verbose info.
   *
   * @return \Drupal\monitoring\Result\SensorResultInterface[]
   *   Array of sensor results.
   *
   * @throws \Drupal\monitoring\Sensor\DisabledSensorException
   *   Thrown if any of the passed sensors is not enabled.
   *
   * @see \Drupal\monitoring\SensorRunner::runSensor()
   */
  public function runSensors(array $sensors_config_all = array(), $force = FALSE, $verbose = FALSE) {
    $this->verbose = $verbose;
    $this->forceRun = $force;
    if (empty($sensors_config_all)) {
      $sensors_config_all = $this->sensorManager
        ->getEnabledSensorConfig();
    }
    $this
      ->loadCache($sensors_config_all);
    $results = array();
    foreach ($sensors_config_all as $name => $sensor_config) {
      if ($result = $this
        ->runSensor($sensor_config)) {
        $result
          ->setPreviousResult(monitoring_sensor_result_last($result
          ->getSensorId()));
        $results[$name] = $result;
      }
    }
    $this
      ->logResults($results);
    $this
      ->cacheResults($results);

    // Trigger a hook to allow processing of sensors data.
    \Drupal::moduleHandler()
      ->invokeAll('monitoring_run_sensors', [
      $results,
    ]);
    return $results;
  }

  /**
   * Run a single given sensor.
   *
   * @param \Drupal\monitoring\Entity\SensorConfig $sensor_config
   *   Sensor config
   *
   * @return SensorResultInterface
   *   Sensor result.
   *
   * @throws \Drupal\monitoring\Sensor\DisabledSensorException
   *   Thrown if the passed sensor is not enabled.
   *
   * @see \Drupal\monitoring\Sensor\SensorInterface::runSensor()
   */
  protected function runSensor(SensorConfig $sensor_config) {
    $plugin = $sensor_config
      ->getPlugin();

    // Check if sensor is enabled.
    if (!$plugin
      ->isEnabled()) {
      throw new DisabledSensorException(new FormattableMarkup('Sensor @sensor_name is not enabled and must not be run.', array(
        '@sensor_name' => $sensor_config
          ->id(),
      )));
    }
    $result = $this
      ->getResultObject($sensor_config);

    // In case result is not yet cached run sensor.
    if (!$result
      ->isCached()) {
      Timer::start($sensor_config
        ->id());
      try {
        $plugin
          ->runSensor($result);
      } catch (\Exception $e) {

        // In case the sensor execution results in an exception, mark it as
        // critical and set the sensor status message.
        $result
          ->setStatus(SensorResultInterface::STATUS_CRITICAL);
        $result
          ->setMessage(get_class($e) . ': ' . $e
          ->getMessage());

        // Log the error to watchdog.
        watchdog_exception('monitoring_exception', $e);

        // @todo Improve logging by e.g. integrating with past or save the
        //   backtrace as part of the sensor verbose output.
      }
      $timer = Timer::stop($sensor_config
        ->id());
      $result
        ->setExecutionTime($timer['time']);

      // Capture verbose output if requested and if we are able to do so.
      try {
        if ($this->verbose && $sensor_config
          ->isExtendedInfo()) {

          /** @var \Drupal\monitoring\SensorPlugin\ExtendedInfoSensorPluginInterface $plugin */
          $result
            ->setVerboseOutput($plugin
            ->resultVerbose($result));
        }
      } catch (\Exception $e) {
        $result
          ->setVerboseOutput(array(
          '#markup' => $e
            ->getMessage(),
        ));
      }
      try {
        $result
          ->compile();
      } catch (\Exception $e) {
        $result
          ->setStatus(SensorResultInterface::STATUS_CRITICAL);
        $result
          ->setMessage(get_class($e) . ': ' . $e
          ->getMessage());
      }
    }
    return $result;
  }

  /**
   * Log results if needed.
   *
   * @param \Drupal\monitoring\Result\SensorResultInterface[] $results
   *   Results to be saved.
   */
  protected function logResults(array $results) {
    foreach ($results as $result) {

      // Skip if the result is cached.
      if ($result
        ->isCached()) {
        continue;
      }
      $old_status = NULL;

      // Try to load the previous log result for this sensor.
      if ($result
        ->getPreviousResult()) {
        $old_status = $result
          ->getPreviousResult()
          ->getStatus();
      }

      // Check if we need to log the result.
      if ($this
        ->needsLogging($result, $old_status, $result
        ->getStatus())) {
        monitoring_sensor_result_save($result);
      }
    }
  }

  /**
   * Checks if sensor results should be logged.
   *
   * @param \Drupal\monitoring\Result\SensorResultInterface $result
   *   The sensor result.
   * @param string $old_status
   *   The old sensor status.
   * @param string $new_status
   *   Thew new sensor status.
   *
   * @return bool
   *   TRUE if the result should be logged, FALSE if not.
   */
  protected function needsLogging($result, $old_status = NULL, $new_status = NULL) {
    $log_activity = $result
      ->getSensorConfig()
      ->getSetting('result_logging', FALSE);

    // We log if requested or on status change.
    if ($this->config
      ->get('sensor_call_logging') == 'on_request') {
      return $log_activity || $old_status != $new_status;
    }

    // We are logging all.
    if ($this->config
      ->get('sensor_call_logging') == 'all') {
      return TRUE;
    }
    return FALSE;
  }

  /**
   * Cache results if caching applies.
   *
   * @param \Drupal\monitoring\Result\SensorResultInterface[] $results
   *   Results to be cached.
   */
  protected function cacheResults(array $results) {

    // @todo: Cache in a single array, with per item expiration?
    foreach ($results as $result) {
      $definition = $result
        ->getSensorConfig();
      if ($definition
        ->getCachingTime() && !$result
        ->isCached()) {
        $data = array(
          'name' => $result
            ->getSensorId(),
          'sensor_status' => $result
            ->getStatus(),
          'sensor_message' => $result
            ->getMessage(),
          'sensor_expected_value' => $result
            ->getExpectedValue(),
          'sensor_value' => $result
            ->getValue(),
          'execution_time' => $result
            ->getExecutionTime(),
          'timestamp' => $result
            ->getTimestamp(),
        );
        $this->cache
          ->set($this
          ->getSensorCid($result
          ->getSensorId()), $data, \Drupal::time()
          ->getRequestTime() + $definition
          ->getCachingTime(), array(
          'monitoring_sensor_result',
        ));
      }
    }
  }

  /**
   * Instantiates sensor result object.
   *
   * @param \Drupal\monitoring\Entity\SensorConfig $sensor_config
   *   Sensor config.
   *
   * @return \Drupal\monitoring\Result\SensorResultInterface
   *   Instantiated sensor result object.
   */
  protected function getResultObject(SensorConfig $sensor_config) {
    $result_class = '\\Drupal\\monitoring\\Result\\SensorResult';
    if (!$this->forceRun && isset($this->sensorResultCache[$sensor_config
      ->id()])) {
      $result = new $result_class($sensor_config, $this->sensorResultCache[$sensor_config
        ->id()]);
    }
    else {
      $result = new $result_class($sensor_config);
    }
    return $result;
  }

  /**
   * Gets sensor cache id.
   *
   * @param string $sensor_name
   *
   * @return string
   *   Cache id.
   */
  protected function getSensorCid($sensor_name) {
    return 'monitoring_sensor_result:' . $sensor_name;
  }

  /**
   * Reset sensor result caches.
   *
   * @param array $sensor_names
   *   (optional) Array of sensors to reset the cache for. An empty array clears
   *   all results, which is the default.
   */
  public function resetCache(array $sensor_names = array()) {
    if (empty($sensor_names)) {

      // No sensor names provided, clear all caches.
      Cache::invalidateTags(array(
        'monitoring_sensor_result',
      ));
    }
    else {
      $cids = array();
      foreach ($sensor_names as $sensor_name) {
        $cids[] = $this
          ->getSensorCid($sensor_name);
      }
      $this->cache
        ->deleteMultiple($cids);
    }
  }

}

Members

Namesort descending Modifiers Type Description Overrides
SensorRunner::$cache protected property
SensorRunner::$config protected property
SensorRunner::$forceRun protected property Flag to force sensor run.
SensorRunner::$sensorConfig protected property List of sensors info keyed by sensor name that are meant to run.
SensorRunner::$sensorManager protected property The sensor manager.
SensorRunner::$sensorResultCache protected property Internal sensor result cache.
SensorRunner::$verbose protected property Flag to switch the collecting of verbose output.
SensorRunner::cacheResults protected function Cache results if caching applies.
SensorRunner::getResultObject protected function Instantiates sensor result object.
SensorRunner::getSensorCid protected function Gets sensor cache id.
SensorRunner::loadCache protected function Loads available sensor results from cache.
SensorRunner::logResults protected function Log results if needed.
SensorRunner::needsLogging protected function Checks if sensor results should be logged.
SensorRunner::resetCache public function Reset sensor result caches.
SensorRunner::runSensor protected function Run a single given sensor.
SensorRunner::runSensors public function Runs the defined sensors.
SensorRunner::__construct public function Constructs a SensorRunner.