From 35078669abfbe296b578b3f131a30dcb38ed99f5 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Thu, 7 Mar 2019 13:29:48 +0100 Subject: [locationinfo] Add error log for backends --- modules-available/locationinfo/api.inc.php | 2 +- .../locationinfo/inc/coursebackend.inc.php | 32 +++++++--- .../coursebackend/coursebackend_davinci.inc.php | 36 +++++------ .../inc/coursebackend/coursebackend_dummy.inc.php | 12 ++-- .../coursebackend/coursebackend_exchange.inc.php | 12 ++-- .../coursebackend/coursebackend_hisinone.inc.php | 70 +++++++++------------- .../locationinfo/inc/locationinfo.inc.php | 17 +++++- modules-available/locationinfo/install.inc.php | 17 ++++++ .../locationinfo/lang/de/messages.json | 1 - .../locationinfo/lang/en/messages.json | 1 - modules-available/locationinfo/page.inc.php | 43 +++++++++++-- .../locationinfo/templates/page-server-log.html | 17 ++++++ .../locationinfo/templates/page-servers.html | 6 ++ .../locationinfo/templates/page-tabs.html | 9 +++ 14 files changed, 183 insertions(+), 92 deletions(-) create mode 100644 modules-available/locationinfo/templates/page-server-log.html diff --git a/modules-available/locationinfo/api.inc.php b/modules-available/locationinfo/api.inc.php index 9ebbcea6..c44ec72d 100644 --- a/modules-available/locationinfo/api.inc.php +++ b/modules-available/locationinfo/api.inc.php @@ -204,7 +204,7 @@ function getCalendar($idList) $calendarFromBackend = array(); } - LocationInfo::setServerError($serverid, $serverInstance->getError()); + LocationInfo::setServerError($serverid, $serverInstance->getErrors()); if (is_array($calendarFromBackend)) { foreach ($calendarFromBackend as $key => $value) { diff --git a/modules-available/locationinfo/inc/coursebackend.inc.php b/modules-available/locationinfo/inc/coursebackend.inc.php index 68a0e09b..bc5b059e 100644 --- a/modules-available/locationinfo/inc/coursebackend.inc.php +++ b/modules-available/locationinfo/inc/coursebackend.inc.php @@ -15,9 +15,13 @@ abstract class CourseBackend */ private static $backendTypes = false; /** - * @var boolean|string false = no error, error message otherwise + * @var boolean|string legacy, do not use */ - protected $error; + protected $error = false; + /** + * @var array list of errors that occured, fill using addError() + */ + private $errors; /** * @var int as internal serverId */ @@ -32,7 +36,12 @@ abstract class CourseBackend */ public final function __construct() { - $this->error = false; + $this->errors = []; + } + + protected final function addError($message, $fatal) + { + $this->errors[] = ['time' => time(), 'message' => $message, 'fatal' => $fatal]; } /** @@ -156,13 +165,13 @@ abstract class CourseBackend /** * Method for fetching the schedule of the given rooms on a server. * - * @param array $roomId array of room ID to fetch + * @param array $requestedLocationIds array of room ID to fetch * @return array|bool array containing the timetables as value and roomid as key as result, or false on error */ public final function fetchSchedule($requestedLocationIds) { if (!is_array($requestedLocationIds)) { - $this->error = 'No array of roomids was given to fetchSchedule'; + $this->addError('No array of roomids was given to fetchSchedule', false); return false; } if (empty($requestedLocationIds)) @@ -286,9 +295,18 @@ abstract class CourseBackend */ public final function getError() { + trigger_error('getError() is legacy; use getErrors()'); return $this->error; } + /** + * @return array list of errors that occured during processing. + */ + public final function getErrors() + { + return $this->errors; + } + /** * Query path in array-representation of XML document. * e.g. 'path/syntax/foo/wanteditem' @@ -349,13 +367,13 @@ abstract class CourseBackend * @param string $response xml document to convert * @return bool|array array representation of the xml if possible, false otherwise */ - protected function xmlStringToArray($response) + protected function xmlStringToArray($response, &$error) { $cleanresponse = preg_replace('/(<\/?)(\w+):([^>]*>)/', '$1$2$3', $response); try { $xml = @new SimpleXMLElement($cleanresponse); // This spams before throwing exception } catch (Exception $e) { - $this->error = 'Could not parse reply as XML, got ' . get_class($e) . ': ' . $e->getMessage(); + $error = get_class($e) . ': ' . $e->getMessage(); if (CONFIG_DEBUG) { error_log($cleanresponse); } diff --git a/modules-available/locationinfo/inc/coursebackend/coursebackend_davinci.inc.php b/modules-available/locationinfo/inc/coursebackend/coursebackend_davinci.inc.php index ed3d7ec2..2b2b9d00 100644 --- a/modules-available/locationinfo/inc/coursebackend/coursebackend_davinci.inc.php +++ b/modules-available/locationinfo/inc/coursebackend/coursebackend_davinci.inc.php @@ -14,7 +14,7 @@ class CourseBackend_Davinci extends CourseBackend public function setCredentialsInternal($data) { if (empty($data['baseUrl'])) { - $this->error = "No url is given"; + $this->addError("No url is given", true); return false; } $location = preg_replace('#/+(davinciis\.dll)?\W*$#i', '', $data['baseUrl']); @@ -27,16 +27,17 @@ class CourseBackend_Davinci extends CourseBackend public function checkConnection() { if (empty($this->location)) { - $this->error = "Credentials are not set"; - } else { - $startDate = new DateTime('today 0:00'); - $endDate = new DateTime('+7 days 0:00'); - $data = $this->fetchRoomRaw('someroomid123', $startDate, $endDate); - if ($data !== false && strpos($data, 'DAVINCI SERVER') === false) { - $this->error = "Unknown reply; this doesn't seem to be a DAVINCI server."; - } + $this->addError("Credentials are not set", true); + return false; + } + $startDate = new DateTime('today 0:00'); + $endDate = new DateTime('+7 days 0:00'); + $data = $this->fetchRoomRaw('someroomid123', $startDate, $endDate); + if ($data !== false && strpos($data, 'DAVINCI SERVER') === false) { + $this->addError("Unknown reply; this doesn't seem to be a DAVINCI server.", true); + return false; } - return $this->error === false; + return true; } public function getCredentialDefinitions() @@ -87,11 +88,8 @@ class CourseBackend_Davinci extends CourseBackend curl_setopt_array($this->curlHandle, $options); $output = curl_exec($this->curlHandle); if ($output === false) { - $this->error = 'Curl error: ' . curl_error($this->curlHandle); + $this->addError('Curl error: ' . curl_error($this->curlHandle), true); return false; - } else { - $this->error = false; - ///Operation completed successfully } return $output; @@ -109,22 +107,20 @@ class CourseBackend_Davinci extends CourseBackend if ($return === false) { continue; } - $return = $this->xmlStringToArray($return); + $return = $this->xmlStringToArray($return, $err); if ($return === false) { - if (CONFIG_DEBUG) { - error_log('Room was ' . $roomId); - } + $this->addError("Parsing room $roomId XML: $err", false); continue; } $lessons = $this->getArrayPath($return, '/Lessons/Lesson'); if ($lessons === false) { - $this->error = "Cannot find /Lessons/Lesson in XML"; + $this->addError("Cannot find /Lessons/Lesson in XML", false); continue; } $timetable = []; foreach ($lessons as $lesson) { if (!isset($lesson['Date']) || !isset($lesson['Start']) || !isset($lesson['Finish'])) { - $this->error = 'Lesson is missing Date, Start or Finish'; + $this->addError('Lesson is missing Date, Start or Finish', false); continue; } $c = (int)$lesson['Date']; diff --git a/modules-available/locationinfo/inc/coursebackend/coursebackend_dummy.inc.php b/modules-available/locationinfo/inc/coursebackend/coursebackend_dummy.inc.php index 94c967de..5807a4ff 100644 --- a/modules-available/locationinfo/inc/coursebackend/coursebackend_dummy.inc.php +++ b/modules-available/locationinfo/inc/coursebackend/coursebackend_dummy.inc.php @@ -21,12 +21,10 @@ class CourseBackend_Dummy extends CourseBackend $this->pw = $x['password']; if ($this->pw === "mfg") { - $this->error = false; return true; - } else { - $this->error = "USE mfg as password!"; - return false; } + $this->addError("USE mfg as password!", true); + return false; } /** @@ -35,12 +33,10 @@ class CourseBackend_Dummy extends CourseBackend public function checkConnection() { if ($this->pw == "mfg") { - $this->error = false; return true; - } else { - $this->error = "USE mfg as password!"; - return false; } + $this->addError("USE mfg as password!", true); + return false; } /** diff --git a/modules-available/locationinfo/inc/coursebackend/coursebackend_exchange.inc.php b/modules-available/locationinfo/inc/coursebackend/coursebackend_exchange.inc.php index 1623755f..c61c3f2f 100755 --- a/modules-available/locationinfo/inc/coursebackend/coursebackend_exchange.inc.php +++ b/modules-available/locationinfo/inc/coursebackend/coursebackend_exchange.inc.php @@ -82,7 +82,7 @@ class CourseBackend_Exchange extends CourseBackend try { $response = $client->ResolveNames($request); } catch (Exception $e) { - $this->error = $e->getMessage(); + $this->addError($e->getMessage(), true); return false; } @@ -92,7 +92,7 @@ class CourseBackend_Exchange extends CourseBackend return !empty($mailadress); } } catch (Exception $e) { - $this->error = $e->getMessage(); + $this->addError($e->getMessage(), true); } return false; } @@ -108,13 +108,13 @@ class CourseBackend_Exchange extends CourseBackend { foreach (['username', 'password'] as $field) { if (empty($data[$field])) { - $this->error = 'setCredentials: Missing field ' . $field; + $this->addError('setCredentials: Missing field ' . $field, true); return false; } } if (empty($data['serverAddress'])) { - $this->error = "No url is given"; + $this->addError("No url is given", true); return false; } @@ -166,7 +166,7 @@ class CourseBackend_Exchange extends CourseBackend try { $items = $this->findEventsForRoom($client, $startDate, $endDate, $roomId); } catch (Exception $e) { - $this->error .= "Failed to search for events for room $roomId: '{$e->getMessage()}'\n"; + $this->addError("Failed to search for events for room $roomId: '{$e->getMessage()}'", true); continue; } @@ -216,7 +216,7 @@ class CourseBackend_Exchange extends CourseBackend if ($response_message->ResponseClass !== ResponseClassType::SUCCESS) { $code = $response_message->ResponseCode; $message = $response_message->MessageText; - $this->error .= "Failed to search for events for room $roomAddress: '$code: $message'\n"; + $this->addError("Failed to search for events for room $roomAddress: '$code: $message'", true); continue; } $items = array_merge($items, $response_message->RootFolder->Items->CalendarItem); diff --git a/modules-available/locationinfo/inc/coursebackend/coursebackend_hisinone.inc.php b/modules-available/locationinfo/inc/coursebackend/coursebackend_hisinone.inc.php index 2ffb9f41..809634ad 100644 --- a/modules-available/locationinfo/inc/coursebackend/coursebackend_hisinone.inc.php +++ b/modules-available/locationinfo/inc/coursebackend/coursebackend_hisinone.inc.php @@ -20,17 +20,16 @@ class CourseBackend_HisInOne extends CourseBackend // If not using OpenCourseService, require credentials foreach (['username', 'password'] as $field) { if (empty($data[$field])) { - $this->error = 'setCredentials: Missing field ' . $field; + $this->addError('setCredentials: Missing field ' . $field, true); return false; } } } if (empty($data['baseUrl'])) { - $this->error = "No url is given"; + $this->addError("No url is given", true); return false; } - $this->error = false; $this->username = $data['username']; if (!empty($data['role'])) { $this->username .= "\t" . $data['role']; @@ -65,11 +64,10 @@ class CourseBackend_HisInOne extends CourseBackend public function checkConnection() { if (empty($this->location)) { - $this->error = "Credentials are not set"; - } else { - $this->findUnit(123456789, date('Y-m-d'), true); + $this->addError("Credentials are not set", true); + return false; } - return $this->error === false; + return $this->findUnit(123456789, date('Y-m-d'), true) !== false; } /** @@ -100,22 +98,21 @@ class CourseBackend_HisInOne extends CourseBackend $soap_request = $doc->saveXML(); $response1 = $this->postToServer($soap_request, "findUnit"); - if ($this->error !== false) { + if ($response1 === false) { + $this->addError('Could not fetch room ' . $roomId, true); return false; } - $response2 = $this->xmlStringToArray($response1); + $response2 = $this->xmlStringToArray($response1, $err); if (!is_array($response2)) { - if ($this->error === false) { - $this->error = 'Cannot convert XML response to array'; - } + $this->addError("Parsing room $roomId: $err", false); return false; } if (!isset($response2['soapenvBody'])) { - $this->error = 'Backend reply is missing element soapenvBody'; + $this->addError('Backend reply is missing element soapenvBody', true); return false; } if (isset($response2['soapenvBody']['soapenvFault'])) { - $this->error = 'SOAP-Fault (' . $response2['soapenvBody']['soapenvFault']['faultcode'] . ") " . $response2['soapenvBody']['soapenvFault']['faultstring']; + $this->addError('SOAP-Fault (' . $response2['soapenvBody']['soapenvFault']['faultcode'] . ") " . $response2['soapenvBody']['soapenvFault']['faultstring'], true); return false; } // We only need to check if the connection is working (URL ok, credentials ok, ..) so bail out early @@ -131,7 +128,7 @@ class CourseBackend_HisInOne extends CourseBackend } $idSubDoc = $this->getArrayPath($response2, $path); if ($idSubDoc === false) { - $this->error = 'Cannot find ' . $path; + $this->addError('Cannot find ' . $path, false); //@file_put_contents('/tmp/findUnit-1.' . $roomId . '.' . microtime(true), print_r($response2, true)); return false; } @@ -139,7 +136,7 @@ class CourseBackend_HisInOne extends CourseBackend return $idSubDoc; $idList = $this->getArrayPath($idSubDoc, $subpath); if ($idList === false) { - $this->error = 'Cannot find ' . $subpath . ' after ' . $path; + $this->addError('Cannot find ' . $subpath . ' after ' . $path, false); @file_put_contents('/tmp/bwlp-findUnit-2.' . $roomId . '.' . microtime(true), print_r($idSubDoc, true)); } return $idList; @@ -201,10 +198,7 @@ class CourseBackend_HisInOne extends CourseBackend $output = curl_exec($this->curlHandle); if ($output === false) { - $this->error = 'Curl error: ' . curl_error($this->curlHandle); - } else { - $this->error = false; - ///Operation completed successfully + $this->addError('Curl error: ' . curl_error($this->curlHandle), false); } return $output; } @@ -239,14 +233,8 @@ class CourseBackend_HisInOne extends CourseBackend $ok = false; foreach ($currentWeek as $day) { $roomEventIds = $this->findUnit($roomId, $day, false); - if ($roomEventIds === false) { - if ($this->error !== false) { - error_log('Cannot findUnit(' . $roomId . '): ' . $this->error); - $this->error = false; - } - // TODO: Error gets swallowed + if ($roomEventIds === false) continue; - } $ok = true; $eventIds = array_merge($eventIds, $roomEventIds); } @@ -262,12 +250,8 @@ class CourseBackend_HisInOne extends CourseBackend //get all information on each event foreach ($eventIds as $eventId) { $event = $this->readUnit(intval($eventId)); - if ($event === false) { - error_log('Cannot readUnit(' . $eventId . '): ' . $this->error); - $this->error = false; - // TODO: Error gets swallowed + if ($event === false) continue; - } $eventDetails = array_merge($eventDetails, $event); } $name = false; @@ -286,9 +270,9 @@ class CourseBackend_HisInOne extends CourseBackend } $planElements = $this->getArrayPath($event, '/hisplanelements/hisplanelement'); if ($planElements === false) { - $this->error = 'Cannot find ./hisplanelements/hisplanelement'; - error_log('Cannot find ./hisplanelements/hisplanelement'); - error_log(print_r($event, true)); + $this->addError('Cannot find ./hisplanelements/hisplanelement', false); + //error_log('Cannot find ./hisplanelements/hisplanelement'); + //error_log(print_r($event, true)); continue; } foreach ($planElements as $planElement) { @@ -308,9 +292,9 @@ class CourseBackend_HisInOne extends CourseBackend $unitPlannedDates = $this->getArrayPath($planElement, '/hisplannedDates/hisplannedDate/hisindividualDates/hisindividualDate'); if ($unitPlannedDates === false) { - $this->error = 'Cannot find ./hisplannedDates/hisplannedDate/hisindividualDates/hisindividualDate'; - error_log('Cannot find ./hisplannedDates/hisplannedDate/hisindividualDates/hisindividualDate'); - error_log(print_r($planElement, true)); + $this->addError('Cannot find ./hisplannedDates/hisplannedDate/hisindividualDates/hisindividualDate', false); + //error_log('Cannot find ./hisplannedDates/hisplannedDate/hisindividualDates/hisindividualDate'); + //error_log(print_r($planElement, true)); continue; } $localName = $this->getArrayPath($planElement, '/hisdefaulttext'); @@ -366,15 +350,17 @@ class CourseBackend_HisInOne extends CourseBackend if ($response1 === false) { return false; } - $response2 = $this->xmlStringToArray($response1); - if ($response2 === false) + $response2 = $this->xmlStringToArray($response1, $err); + if ($response2 === false) { + $this->addError("Cannot parse unit $unit as XML: $err", false); return false; + } if (!isset($response2['soapenvBody'])) { - $this->error = 'Backend reply is missing element soapenvBody'; + $this->addError('Backend reply is missing element soapenvBody', true); return false; } if (isset($response2['soapenvBody']['soapenvFault'])) { - $this->error = 'SOAP-Fault (' . $response2['soapenvBody']['soapenvFault']['faultcode'] . ") " . $response2['soapenvBody']['soapenvFault']['faultstring']; + $this->addError('SOAP-Fault (' . $response2['soapenvBody']['soapenvFault']['faultcode'] . ") " . $response2['soapenvBody']['soapenvFault']['faultstring'], true); return false; } return $this->getArrayPath($response2, '/soapenvBody/hisreadUnitResponse/hisunit'); diff --git a/modules-available/locationinfo/inc/locationinfo.inc.php b/modules-available/locationinfo/inc/locationinfo.inc.php index 377e960b..6cc71b3e 100644 --- a/modules-available/locationinfo/inc/locationinfo.inc.php +++ b/modules-available/locationinfo/inc/locationinfo.inc.php @@ -46,10 +46,25 @@ class LocationInfo * Set current error message of given server. Pass null or false to clear. * * @param int $serverId id of server - * @param string $message error message to set, null or false clears error. + * @param string|array $message error message to set, array of error message struct, null or false clears error. */ public static function setServerError($serverId, $message) { + if (is_array($message)) { + $fatal = false; + foreach ($message as $m) { + if ($m['fatal']) { + $fatal = $m['message']; + } + Database::exec('INSERT INTO locationinfo_backendlog (serverid, dateline, message) + VALUES (:sid, :dateline, :message)', [ + 'sid' => $serverId, + 'dateline' => $m['time'], + 'message' => ($m['fatal'] ? '[F]' : '[W]') . $m['message'], + ]); + } + $message = $fatal; + } if ($message === false || $message === null) { Database::exec("UPDATE `locationinfo_coursebackend` SET error = NULL WHERE serverid = :id", array('id' => $serverId)); diff --git a/modules-available/locationinfo/install.inc.php b/modules-available/locationinfo/install.inc.php index fc02ed76..7e58315b 100644 --- a/modules-available/locationinfo/install.inc.php +++ b/modules-available/locationinfo/install.inc.php @@ -35,6 +35,16 @@ $t3 = $res[] = tableCreate('locationinfo_panel', " KEY `panelname` (`panelname`) "); +// 2019-03-06: Add logging table +$res[] = tableCreate('locationinfo_backendlog', " + `logid` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, + `serverid` int(10) UNSIGNED NOT NULL, + `dateline` int(10) UNSIGNED NOT NULL, + `message` varchar(500) NOT NULL, + PRIMARY KEY (`logid`), + KEY (`serverid`) +"); + // Update if ($t1 === UPDATE_NOOP) { @@ -89,6 +99,13 @@ if (!tableHasColumn('locationinfo_locationconfig', 'lastuse')) { $res[] = UPDATE_DONE; } +// 2019-03-06: Add logging table constraint +if (tableGetConstraints('locationinfo_backendlog', 'serverid', + 'locationinfo_coursebackend', 'serverid') === false) { + $res[] = tableAddConstraint('locationinfo_backendlog', 'serverid', + 'locationinfo_coursebackend', 'serverid', 'ON UPDATE CASCADE ON DELETE CASCADE'); +} + // Create response for browser if (in_array(UPDATE_RETRY, $res)) { diff --git a/modules-available/locationinfo/lang/de/messages.json b/modules-available/locationinfo/lang/de/messages.json index 622b94ac..bcaf687d 100644 --- a/modules-available/locationinfo/lang/de/messages.json +++ b/modules-available/locationinfo/lang/de/messages.json @@ -1,5 +1,4 @@ { - "auth-failed": "[{{0}}] {{1}} Error: {{2}}", "config-saved": "Einstellungen erfolgreich gespeichert.", "ignored-invalid-end": "Eintrag mit ung\u00fcltiger Endzeit ignoriert", "ignored-invalid-range": "Eintrag mit ung\u00fcltiger Range ignoriert", diff --git a/modules-available/locationinfo/lang/en/messages.json b/modules-available/locationinfo/lang/en/messages.json index 348390dd..5111a408 100644 --- a/modules-available/locationinfo/lang/en/messages.json +++ b/modules-available/locationinfo/lang/en/messages.json @@ -1,5 +1,4 @@ { - "auth-failed": "[{{0}}] {{1}} Error: {{2}}", "config-saved": "Config successfully saved.", "ignored-invalid-end": "Ignored entry with invalid end time", "ignored-invalid-range": "Ignored entry with invalid range", diff --git a/modules-available/locationinfo/page.inc.php b/modules-available/locationinfo/page.inc.php index 7be875d0..b082c0f4 100644 --- a/modules-available/locationinfo/page.inc.php +++ b/modules-available/locationinfo/page.inc.php @@ -59,11 +59,16 @@ class Page_LocationInfo extends Page */ protected function doRender() { + $data = array('class-' . $this->show => 'active', 'errors' => []); // Do this here so we always see backend errors if (User::hasPermission('backend.*')) { $backends = $this->loadBackends(); + foreach ($backends as $backend) { + if (!empty($backend['error'])) { + $data['errors'][] = $backend; + } + } } - $data = array('class-' . $this->show => 'active'); Permission::addGlobalTags($data['perms'], null, ['backend.*', 'location.*', 'panel.list']); Render::addTemplate('page-tabs', $data); switch ($this->show) { @@ -79,6 +84,9 @@ class Page_LocationInfo extends Page case 'panels': $this->showPanelsTable(); break; + case 'backendlog': + $this->showBackendLog(); + break; default: Util::redirect('?do=locationinfo'); } @@ -471,7 +479,7 @@ class Page_LocationInfo extends Page $serverInstance->checkConnection(); } - LocationInfo::setServerError($serverid, $serverInstance->getError()); + LocationInfo::setServerError($serverid, $serverInstance->getErrors()); } private function loadBackends() @@ -495,14 +503,14 @@ class Page_LocationInfo extends Page } if (!empty($row['error'])) { - $row['autherror'] = true; $error = json_decode($row['error'], true); if (isset($error['timestamp'])) { - $time = date('Y/m/d H:i:s', $error['timestamp']); + $time = date('Y-m-d H:i', $error['timestamp']); } else { $time = '???'; } - Message::addError('auth-failed', $row['servername'], $time, $error['error']); + $row['error'] = $error['error']; + $row['errtime'] = $time; } $serverlist[] = $row; } @@ -523,6 +531,31 @@ class Page_LocationInfo extends Page Render::addTemplate('page-servers', $data); } + private function showBackendLog() + { + $id = Request::get('serverid', false, 'int'); + if ($id === false) { + Message::addError('main.parameter-missing', 'serverid'); + Util::redirect('?do=locationinfo'); + } + $server = Database::queryFirst('SELECT servername FROM locationinfo_coursebackend + WHERE serverid = :id', ['id' => $id]); + if ($server === false) { + Message::addError('invalid-server-id', $id); + Util::redirect('?do=locationinfo'); + } + $server['list'] = []; + $res = Database::simpleQuery('SELECT dateline, message FROM locationinfo_backendlog + WHERE serverid = :id ORDER BY logid DESC LIMIT 100', ['id' => $id]); + while ($row = $res->fetch(PDO::FETCH_ASSOC)) { + $row['dateline_s'] = Util::prettyTime($row['dateline']); + $row['class'] = substr($row['message'], 0, 3) === '[F]' ? 'text-danger' : 'text-warning'; + $row['message'] = Substr($row['message'], 3); + $server['list'][] = $row; + } + Render::addTemplate('page-server-log', $server); + } + private function showLocationsTable() { $allowedLocations = User::getAllowedLocations('location.edit'); diff --git a/modules-available/locationinfo/templates/page-server-log.html b/modules-available/locationinfo/templates/page-server-log.html new file mode 100644 index 00000000..7fc3b997 --- /dev/null +++ b/modules-available/locationinfo/templates/page-server-log.html @@ -0,0 +1,17 @@ +

{{lang_serverLogHead}}

+

{{servername}}

+ + + + + + + + {{#list}} + + + + + {{/list}} + +
{{lang_when}}{{lang_event}}
{{dateline_s}}{{message}}
\ No newline at end of file diff --git a/modules-available/locationinfo/templates/page-servers.html b/modules-available/locationinfo/templates/page-servers.html index 7c1cf79d..e295c4fd 100644 --- a/modules-available/locationinfo/templates/page-servers.html +++ b/modules-available/locationinfo/templates/page-servers.html @@ -9,6 +9,7 @@ {{lang_locationName}} {{lang_edit}} {{lang_checkConnection}} + {{lang_showLog}} {{lang_delete}} @@ -33,6 +34,11 @@ + + + + +