You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

208 lines
5.7 KiB

<?php
/**
* @author Robin Appelman <icewind@owncloud.com>
*
* @copyright Copyright (c) 2015, ownCloud, Inc.
* @license AGPL-3.0
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/
namespace OCA\LogReader\Controller;
use OCA\LogReader\Log\LogIterator;
use OCA\LogReader\Log\LogIteratorFactory;
use OCA\LogReader\Log\SearchFilter;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\IConfig;
use OCP\IRequest;
use OCP\Log\IFileBased;
use OCP\Log\ILogFactory;
/**
* Class LogController
*
* @package OCA\LogReader\Controller
*/
class LogController extends Controller {
private $logIteratorFactory;
private $config;
public function __construct($appName,
IRequest $request,
IConfig $config,
LogIteratorFactory $logIteratorFactory
) {
parent::__construct($appName, $request);
$this->logIteratorFactory = $logIteratorFactory;
$this->config = $config;
}
/**
* @param int $count
* @param int $offset
* @param string $levels
* @return TemplateResponse
*/
public function get($count = 50, $offset = 0, $levels = '11111') {
$iterator = $this->logIteratorFactory->getLogIterator($levels);
return $this->responseFromIterator($iterator, $count, $offset);
}
/**
* @brief Gets the last item in the log, bypassing any cache.
* @return mixed
*/
private function getLastItem($levels) {
$iterator = $this->logIteratorFactory->getLogIterator($levels);
$iterator->next();
return $iterator->current();
}
/**
* @brief polls for a new log message since $lastReqId.
* This method will sleep for maximum 20 seconds before returning an empty
* result.
*
* Note that there is a race condition possible: when the user loads the
* logging page when a request isn't finished and this specific request
* is the last request in the log, then new messages of this request
* won't be polled. This is because there is no reliable way to identify
* a log message, so we have to use the reqid:
* - the key of the iterator will change when a new message is saved
* - a combination of reqid and counting the messages for that specific reqid
* will work in some cases but not when there are more than 50 messages of that
* request.
* @param $lastReqId
* @param string $levels
* @return JSONResponse
*/
public function poll($lastReqId, $levels = '11111') {
$cycles = 0;
$maxCycles = 20;
while ($this->getLastItem($levels)['reqId'] === $lastReqId) {
sleep(1);
$cycles++;
if ($cycles === $maxCycles) {
return new JSONResponse([]);
}
}
$iterator = $this->logIteratorFactory->getLogIterator($levels);
$iterator->next();
$data = [];
while ($iterator->valid()) {
$line = $iterator->current();
if ($line['reqId'] === $lastReqId) {
break;
}
if (!is_null($line)) {
$line['id'] = uniqid();
$data[] = $line;
}
$iterator->next();
}
return new JSONResponse($data);
}
/**
* @param string $query
* @param int $count
* @param int $offset
* @param string $levels
* @return TemplateResponse
*
* @NoCSRFRequired
*/
public function search($query = '', $count = 50, $offset = 0, $levels = '11111') {
$iterator = $this->logIteratorFactory->getLogIterator($levels);
$iterator = new \LimitIterator($iterator, 0, 100000); // limit the number of message we search to avoid huge search times
$iterator->rewind();
$iterator = new SearchFilter($iterator, $query);
$iterator->rewind();
return $this->responseFromIterator($iterator, $count, $offset);
}
public function getLevels() {
return new JSONResponse($this->config->getAppValue('logreader', 'levels', '11111'));
}
public function getSettings() {
return new JSONResponse([
'levels' => $this->config->getAppValue('logreader', 'levels', '11111'),
'dateformat' => $this->config->getSystemValue('logdateformat', \DateTime::ISO8601),
'timezone' => $this->config->getSystemValue('logtimezone', 'UTC'),
'relativedates' => (bool)$this->config->getAppValue('logreader', 'relativedates', false),
'live' => (bool)$this->config->getAppValue('logreader', 'live', true),
]);
}
/**
* @param bool $relative
*/
public function setRelative($relative) {
$this->config->setAppValue('logreader', 'relativedates', $relative);
}
/**
* @param bool $live
*/
public function setLive($live) {
$this->config->setAppValue('logreader', 'live', $live);
}
public function setLevels($levels) {
$intLevels = array_map('intval', str_split($levels));
$minLevel = 4;
foreach ($intLevels as $level => $log) {
if ($log) {
$minLevel = $level;
break;
}
}
$this->config->setAppValue('logreader', 'levels', $levels);
return $minLevel;
}
protected function responseFromIterator(\Iterator $iterator, $count, $offset) {
$iterator->rewind();
for ($i = 0; $i < $offset; $i++) {
$iterator->next();
}
$data = [];
for ($i = 0; $i < $count && $iterator->valid(); $i++) {
$line = $iterator->current();
if (!is_null($line)) {
$line["id"] = uniqid();
$data[] = $line;
}
$iterator->next();
}
return new JSONResponse([
'data' => $data,
'remain' => $iterator->valid()
]);
}
}