_processObservation(); } /** * Adds additional editor fields to the Contentserv interface * * @param CSGuiEditor $editor Editor object that can add fields * @param CSMonitorObserver $observer */ public function prepareEditor(CSGuiEditor $editor, CSMonitorObserver $observer) { $this->_observer = $observer; $editor->addField("RecordType", CS::translate('CSALIVE_MONITOR_RECORD_TYPE', 'sawsalive'), $this->getRecordTypes(), 'Pdmarticle', FALSE, array( 'PaneTitle' => CS::translate('REST_GUI_EDIT_SETTINGS'), 'noEmptyOption' => true, 'onlyFolder' => true )); $editor->addField("InspectRequests", CS::translate('CSALIVE_MONITOR_REQUEST_VALUES', 'sawsalive'), $this->getInspectProcesses(), '', FALSE, array( 'PaneTitle' => CS::translate('REST_GUI_EDIT_SETTINGS'), 'noEmptyOption' => true, 'multiple' => true )); $editor->addField('ObjectToSearch', CS::translate('CSALIVE_MONITOR_OBJECT_TO_SEARCH', 'sawsalive'), '', '', FALSE, array( 'PaneTitle' => CS::translate('REST_GUI_EDIT_SETTINGS') )); } /////// PROTECTED FUNCTIONS ////////////////////////////////////////////////////////////////////////////////////////////// /** * Function is automatically called when the observation runs. */ protected function _processObservation() { $intObserverID = $this->_observer->getID(); $this->strObjectType = $this->_observer->getValue('RecordType'); $this->arrChosenRequests = explode(',', $this->_observer->getValue('InspectRequests')); $this->strToSearch = $this->_observer->getValue('ObjectToSearch'); if (!empty($this->arrChosenRequests)) { try { foreach ((array) $this->arrChosenRequests as $strFunctionName) { if (!method_exists($this, $strFunctionName)) { continue; } $arrReturnValues = $this->$strFunctionName(); if (!empty($arrReturnValues)) { if (!empty($arrReturnValues['Service'])) { $this->storeResultsInDatabase($intObserverID, $arrReturnValues['Value'], $arrReturnValues['Unit'], $arrReturnValues['Service']); } else { $this->storeResultsInDatabase($intObserverID, $arrReturnValues['Value'], $arrReturnValues['Unit'], 'ElasticSearch.' . substr($strFunctionName, 7)); } } } $this->storeResultsInDatabase($intObserverID, 1000, '', 'ElasticSearch.Error'); } catch (Exception $ex) { $this->storeResultsInDatabase($intObserverID, 99999, $ex->getMessage(), 'ElasticSearch.Error'); } } } ///// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////////////////////////////////////////// /** * Returns an array of Strings of all available filetypes * * @return array Possible datatypes that can be chosen to be monitored */ private function getRecordTypes() { return (array) array( 'Pdmarticle' => CS::translate('Pdmarticle'), 'Mamfile' => CS::translate('Mamfile'), 'Pdmarticlestructure' => CS::translate('Pdmarticlestructure'), 'User' => CS::translate('User') ); } /** * Stores a value with the given parameter in the monitor observation database * * @param integer $intObserverID ID which the observation ID shall have * @param mixed $mixedMeasuredValue Result that shall be stored in the value column * @param string $strUnit Unit of the value (ca. 150 character text field) * @param string $strServiceName Name of the result */ private function storeResultsInDatabase(int $intObserverID, $mixedMeasuredValue, string $strUnit, string $strServiceName) { $observation = CSMonitor::createObservation($intObserverID, $strServiceName); $observation->setMeasuredValue($mixedMeasuredValue); $observation->setTimestamp(CS::getDate()); $observation->setUnit($strUnit); $state = CSMonitor::MONITOR_GUI_NOTIFICATION_NONE_ID; $observation->setState($state); $observation->setWarningValue(0); $observation->setCriticalValue(1); $observation->store(); } /** * Returns a the current time as float. * * Helper function to measure script durations * * @return float Returns current microtime */ private function microtimeFloat() { list($usec, $sec) = explode(" ", microtime()); return ((float) $usec + (float) $sec); } /** * Returns an array of Strings of all processes the plugin can monitor. * * @return array Returns all processes possible to be inspect */ private function getInspectProcesses() { $arrClassMethods = get_class_methods($this); $strSearchWord = 'request'; $arrMatches = array_filter((array) $arrClassMethods, function ($var) use ($strSearchWord) { return preg_match("/$strSearchWord/i", $var); }); foreach ((array) $arrMatches as $value) { $arrTranslatedMatches[$value] = CS::translate($value, 'sawsalive'); } return (array) $arrTranslatedMatches; } /** * Returns the time difference between current time and given time in seconds. * * Helper function to measure script durations * * @return float returns current microtime */ private function getDuration($intStartTime) { return number_format((self::microtimeFloat() - $intStartTime), 4); } /** * Compares the number of stored objects between the Elasticsearch and MySQL databases. * * @return array Returns the quantity difference with the unit. */ private function requestObjectDiff() { //ElasticSearch $aResult = ServiceProviderUtils::getExportStatistics($this->strObjectType); return ['Value' => (int) $aResult['elasticsearch']['ItemCount'] - $aResult['contentserv']['ItemCount'], 'Unit' => 'Items']; } /** * Compares the date of the last change between the Elasticsearch and MySQL databases. * * @return array Returns the difference of dates. */ private function requestChangeDate() { //ElasticSearch try { $intSQLLastChange = strtotime(Database::queryValue("SELECT `LastChange` FROM " . CS::getTablePrefix() . $this->strObjectType . " ORDER BY `" . CS::getTablePrefix() . $this->strObjectType . "`.`LastChange` DESC LIMIT 0 , 1;")); $strESAIndexNameResult = CSExportStagingConfigurations::getDefaultExportDbName(Database::getCurrentDatabase(), CS::getProjectName()); $strQuery = '{"index":"' . $strESAIndexNameResult . '_' . strtolower($this->strObjectType) . '","type":"_doc","size":1,"body":{"query":{"nested":{"path":"dateFields","query":{"bool":{"must":[{"bool":{"should":[{"match":{"dateFields.languageId":"2"}},{"match":{"dateFields.languageId":"0"}}]}},{"bool":{"must_not":{"exists":{"field":"dateFields.tableId"}}}},{"bool":{"must_not":{"exists":{"field":"dateFields.referenceId"}}}},{"match":{"dateFields.attrId":"LastChange"}},{"range":{"dateFields.value":{"gt":"' . date("Y-m-d H:i:s", $intSQLLastChange - 7200) . '"}}}]}}}},"_source":true},"from":0,"client":{"headers":{"Content-Type":["application\/json"]}}}'; $objClient = CSElasticClientFactory::getCSElasticClient()->createClient(); $intESLastChange = 0; $docs = $objClient->search(json_decode($strQuery, true)); foreach ($docs['hits']['hits'] as $aDoc) { foreach ((array) $aDoc['_source']['dateFields'] as $aField) { if ($aField['attrId'] == 'LastChange' && $intESLastChange < strtotime($aField['value'])) { $intESLastChange = strtotime($aField['value']); } } } return ['Value' => $intESLastChange - $intSQLLastChange, 'Unit' => 's']; } catch (Exception $e) { return ['Value' => 99999, 'Unit' => $e->getMessage(), 'Service' => substr(__CLASS__, 0, -8) . '.Error']; } } /** * Compares the storage used between the Elasticsearch and MySQL databases. * * @return array Returns the storage difference with the unit. */ private function requestUsedStorage() { //ElasticSearch $objSTD = json_decode(Curl::GET('http://' . CS::getOption('elasticsearchAddress', 'exportstaging') . '/_stats', '', '', '30', FALSE, FALSE, TRUE, NULL, NULL, 9200, TRUE)); if (json_last_error() === JSON_ERROR_NONE) { $arrObjectAttributes = $this->convertSTDObjectToArray($objSTD, true); $intESSize = $arrObjectAttributes['memory_in_bytes']; return ['Value' => $intESSize, 'Unit' => 'Bytes']; } else { return ['Value' => 99999, 'Unit' => 'JSON Error->Wrong URL', 'Service' => substr(__CLASS__, 0, -8) . '.Error']; } } /** * Compares the search time for an object between the Elasticsearch and MySQL databases. * * @return array Returns the time needed for a search in the database with the unit. */ private function requestSearchTime() { if (empty($this->strToSearch)) { return ['Value' => 99999, 'Unit' => 'No search word entered.', 'Service' => substr(__CLASS__, 0, -8) . '.Error']; } else { //ElasticSearch $intESStartTime = $this->microtimeFloat(); $oSearch = new CSItemSearchFilter(); $oSearch->addFilter( array($this->strToSearch), CSElasticSearch::CS_OPERATOR_IS_CONTAINING, ['Label'] ); $oElasticSearch = new CSElasticSearch(); $sComparatorField = 'LastChange'; //ElasticSearchAPI::_getComparatorField($this->strObjectType); $oElasticSearch->setFieldName(array('Label', CSExportStagingUtils::ES_FIELD_ID, $sComparatorField)); $aSearchResult = []; $aSearchResult = $oElasticSearch->searchContent( $oSearch, [0], CSUser::getUser()->getCurrentLanguageID(), $this->strObjectType, 10, [], false, false ); $intElasticSearchDuration = $this->getDuration($intESStartTime); if (json_last_error() === JSON_ERROR_NONE) { return ['Value' => $intElasticSearchDuration, 'Unit' => 's']; } else { return ['Value' => 99999, 'Unit' => 'JSON Error->Wrong URL', 'Service' => substr(__CLASS__, 0, -8) . '.Error']; } } } /** * Converts an stdClass object recursively into an array. So that values may be extracted easier. * * @param object $objSTD stdClass object which shall be converted * @param boolean $bolSearchForSubArrays Wether the subarrays in one layer beneath shall searched for objects, too * @return array Returns an array containing the flat keys of all object attributes. */ private function convertSTDObjectToArray($objSTD, $bolSearchForSubArrays = false) { $arrAllObjectValues = array(); $arrObjectAttributes = get_object_vars($objSTD); foreach ($arrObjectAttributes as $strKey => $mixValue) { if (is_object($mixValue)) { $arrAllObjectValues = array_merge($arrAllObjectValues, $this->convertSTDObjectToArray($mixValue, $bolSearchForSubArrays)); } else { if (empty($arrAllObjectValues[$strKey])) { if ($mixValue > 0) { $arrAllObjectValues[$strKey] = $mixValue; } } else { $arrAllObjectValues[] = $mixValue; } } if ($bolSearchForSubArrays) { if (is_array($mixValue)) { foreach ($mixValue as $strSubKey => $mixSubValue) { if (is_object($mixSubValue)) { $arrAllObjectValues = array_merge($arrAllObjectValues, $this->convertSTDObjectToArray($mixSubValue, $bolSearchForSubArrays)); } else { if (empty($arrAllObjectValues[$strSubKey])) { $arrAllObjectValues[$strSubKey] = $mixSubValue; } else { $arrAllObjectValues[] = $mixSubValue; } } } } } } return $arrAllObjectValues; } /** * Quality of life method for faster debugging. * * @param mixed $mixMessage */ private function quickAlert($mixMessage) { alert($mixMessage, 1); die(); } }