Merge remote-tracking branch 'MyIgel/logentry-model'
This commit is contained in:
commit
0734807eef
|
@ -0,0 +1,47 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Engelsystem\Database\Migration\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
|
||||||
|
class CreateLogEntriesTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migration
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
$this->schema->create('log_entries', function (Blueprint $table) {
|
||||||
|
$table->increments('id');
|
||||||
|
$table->string('level', 20);
|
||||||
|
$table->text('message');
|
||||||
|
$table->timestamp('created_at')->nullable();
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->schema->getConnection()->unprepared('
|
||||||
|
INSERT INTO log_entries (`id`, `level`, `message`, `created_at`)
|
||||||
|
SELECT `id`, `level`, `message`, FROM_UNIXTIME(`timestamp`) FROM LogEntries
|
||||||
|
');
|
||||||
|
|
||||||
|
$this->schema->dropIfExists('LogEntries');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migration
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
$this->schema->create('LogEntries', function (Blueprint $table) {
|
||||||
|
$table->increments('id');
|
||||||
|
$table->string('level', 20);
|
||||||
|
$table->text('message');
|
||||||
|
$table->integer('timestamp');
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->schema->getConnection()->unprepared('
|
||||||
|
INSERT INTO LogEntries (`id`, `level`, `message`, `timestamp`)
|
||||||
|
SELECT `id`, `level`, `message`, UNIX_TIMESTAMP(`created_at`) FROM log_entries
|
||||||
|
');
|
||||||
|
|
||||||
|
$this->schema->dropIfExists('log_entries');
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,7 +13,6 @@ $includeFiles = [
|
||||||
|
|
||||||
__DIR__ . '/../includes/model/AngelType_model.php',
|
__DIR__ . '/../includes/model/AngelType_model.php',
|
||||||
__DIR__ . '/../includes/model/EventConfig_model.php',
|
__DIR__ . '/../includes/model/EventConfig_model.php',
|
||||||
__DIR__ . '/../includes/model/LogEntries_model.php',
|
|
||||||
__DIR__ . '/../includes/model/Message_model.php',
|
__DIR__ . '/../includes/model/Message_model.php',
|
||||||
__DIR__ . '/../includes/model/NeededAngelTypes_model.php',
|
__DIR__ . '/../includes/model/NeededAngelTypes_model.php',
|
||||||
__DIR__ . '/../includes/model/Room_model.php',
|
__DIR__ . '/../includes/model/Room_model.php',
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
use Engelsystem\Database\DB;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a log entry.
|
|
||||||
*
|
|
||||||
* @param string $logLevel Log level
|
|
||||||
* @param string $message Log Message
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
function LogEntry_create($logLevel, $message)
|
|
||||||
{
|
|
||||||
return DB::insert('
|
|
||||||
INSERT INTO `LogEntries` (`timestamp`, `level`, `message`)
|
|
||||||
VALUES(?, ?, ?)
|
|
||||||
', [time(), $logLevel, $message]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns log entries with maximum count of 10000.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
function LogEntries()
|
|
||||||
{
|
|
||||||
return DB::select('SELECT * FROM `LogEntries` ORDER BY `timestamp` DESC LIMIT 10000');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns log entries filtered by a keyword
|
|
||||||
*
|
|
||||||
* @param string $keyword
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
function LogEntries_filter($keyword)
|
|
||||||
{
|
|
||||||
if ($keyword == '') {
|
|
||||||
return LogEntries();
|
|
||||||
}
|
|
||||||
|
|
||||||
$keyword = '%' . $keyword . '%';
|
|
||||||
return DB::select('
|
|
||||||
SELECT *
|
|
||||||
FROM `LogEntries`
|
|
||||||
WHERE `level` LIKE ?
|
|
||||||
OR `message` LIKE ?
|
|
||||||
ORDER BY `timestamp` DESC
|
|
||||||
',
|
|
||||||
[$keyword, $keyword]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delete all log entries.
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
function LogEntries_clear_all()
|
|
||||||
{
|
|
||||||
return DB::connection()->statement('TRUNCATE `LogEntries`');
|
|
||||||
}
|
|
|
@ -1,5 +1,7 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use Engelsystem\Models\LogEntry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
|
@ -17,10 +19,14 @@ function admin_log()
|
||||||
if (request()->has('keyword')) {
|
if (request()->has('keyword')) {
|
||||||
$filter = strip_request_item('keyword');
|
$filter = strip_request_item('keyword');
|
||||||
}
|
}
|
||||||
$log_entries = LogEntries_filter($filter);
|
|
||||||
|
|
||||||
foreach ($log_entries as &$log_entry) {
|
$log_entries = LogEntry::filter($filter);
|
||||||
$log_entry['date'] = date('d.m.Y H:i', $log_entry['timestamp']);
|
|
||||||
|
$entries = [];
|
||||||
|
foreach ($log_entries as $entry) {
|
||||||
|
$data = $entry->toArray();
|
||||||
|
$data['created_at'] = date_format($entry->created_at, 'd.m.Y H:i');
|
||||||
|
$entries[] = $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
return page_with_title(admin_log_title(), [
|
return page_with_title(admin_log_title(), [
|
||||||
|
@ -30,9 +36,9 @@ function admin_log()
|
||||||
form_submit(__('Search'), 'Go')
|
form_submit(__('Search'), 'Go')
|
||||||
]),
|
]),
|
||||||
table([
|
table([
|
||||||
'date' => 'Time',
|
'created_at' => 'Time',
|
||||||
'level' => 'Type',
|
'level' => 'Type',
|
||||||
'message' => 'Log Entry'
|
'message' => 'Log Entry'
|
||||||
], $log_entries)
|
], $entries)
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace Engelsystem\Logger;
|
namespace Engelsystem\Logger;
|
||||||
|
|
||||||
|
use Engelsystem\Models\LogEntry;
|
||||||
use Psr\Log\AbstractLogger;
|
use Psr\Log\AbstractLogger;
|
||||||
use Psr\Log\InvalidArgumentException;
|
use Psr\Log\InvalidArgumentException;
|
||||||
use Psr\Log\LogLevel;
|
use Psr\Log\LogLevel;
|
||||||
|
@ -19,6 +20,14 @@ class EngelsystemLogger extends AbstractLogger
|
||||||
LogLevel::WARNING,
|
LogLevel::WARNING,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/** @var LogEntry */
|
||||||
|
protected $log;
|
||||||
|
|
||||||
|
public function __construct(LogEntry $log)
|
||||||
|
{
|
||||||
|
$this->log = $log;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logs with an arbitrary level.
|
* Logs with an arbitrary level.
|
||||||
*
|
*
|
||||||
|
@ -33,12 +42,12 @@ class EngelsystemLogger extends AbstractLogger
|
||||||
public function log($level, $message, array $context = [])
|
public function log($level, $message, array $context = [])
|
||||||
{
|
{
|
||||||
if (!$this->checkLevel($level)) {
|
if (!$this->checkLevel($level)) {
|
||||||
throw new InvalidArgumentException();
|
throw new InvalidArgumentException('Unknown log level: ' . $level);
|
||||||
}
|
}
|
||||||
|
|
||||||
$message = $this->interpolate($message, $context);
|
$message = $this->interpolate($message, $context);
|
||||||
|
|
||||||
LogEntry_create($level, $message);
|
$this->log->create(['level' => $level, 'message' => $message]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
abstract class BaseModel extends Model
|
||||||
|
{
|
||||||
|
/** @var bool Disable timestamps by default because of "Datensparsamkeit" */
|
||||||
|
public $timestamps = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $attributes
|
||||||
|
* @return BaseModel
|
||||||
|
*/
|
||||||
|
public function create(array $attributes = [])
|
||||||
|
{
|
||||||
|
$instance = new static($attributes);
|
||||||
|
$instance->save();
|
||||||
|
|
||||||
|
return $instance;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
|
|
||||||
|
class LogEntry extends BaseModel
|
||||||
|
{
|
||||||
|
/** @var bool enable timestamps for created_at */
|
||||||
|
public $timestamps = true;
|
||||||
|
|
||||||
|
/** @var null Disable updated_at */
|
||||||
|
const UPDATED_AT = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The attributes that are mass assignable.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $fillable = [
|
||||||
|
'level',
|
||||||
|
'message',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param $keyword
|
||||||
|
* @return Builder[]|Collection|LogEntry[]
|
||||||
|
*/
|
||||||
|
public static function filter($keyword = null)
|
||||||
|
{
|
||||||
|
$query = LogEntry::query()
|
||||||
|
->select()
|
||||||
|
->orderByDesc('created_at')
|
||||||
|
->orderByDesc('id')
|
||||||
|
->limit(10000);
|
||||||
|
|
||||||
|
if (!empty($keyword)) {
|
||||||
|
$query
|
||||||
|
->where('level', '=', $keyword)
|
||||||
|
->orWhere('message', 'LIKE', '%' . $keyword . '%');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query->get();
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,7 @@
|
||||||
namespace Engelsystem\Test\Feature\Logger;
|
namespace Engelsystem\Test\Feature\Logger;
|
||||||
|
|
||||||
use Engelsystem\Logger\EngelsystemLogger;
|
use Engelsystem\Logger\EngelsystemLogger;
|
||||||
|
use Engelsystem\Models\LogEntry;
|
||||||
use Engelsystem\Test\Feature\ApplicationFeatureTest;
|
use Engelsystem\Test\Feature\ApplicationFeatureTest;
|
||||||
use Psr\Log\InvalidArgumentException;
|
use Psr\Log\InvalidArgumentException;
|
||||||
use Psr\Log\LoggerInterface;
|
use Psr\Log\LoggerInterface;
|
||||||
|
@ -15,12 +16,13 @@ class EngelsystemLoggerTest extends ApplicationFeatureTest
|
||||||
*/
|
*/
|
||||||
public function getLogger()
|
public function getLogger()
|
||||||
{
|
{
|
||||||
return new EngelsystemLogger();
|
$logEntry = new LogEntry();
|
||||||
|
return new EngelsystemLogger($logEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testImplements()
|
public function testImplements()
|
||||||
{
|
{
|
||||||
$this->assertInstanceOf('Psr\Log\LoggerInterface', $this->getLogger());
|
$this->assertInstanceOf(LoggerInterface::class, $this->getLogger());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -46,21 +48,20 @@ class EngelsystemLoggerTest extends ApplicationFeatureTest
|
||||||
*/
|
*/
|
||||||
public function testAllLevels($level)
|
public function testAllLevels($level)
|
||||||
{
|
{
|
||||||
|
LogEntry::query()->truncate();
|
||||||
$logger = $this->getLogger();
|
$logger = $this->getLogger();
|
||||||
|
|
||||||
LogEntries_clear_all();
|
|
||||||
|
|
||||||
$logger->log($level, 'First log message');
|
$logger->log($level, 'First log message');
|
||||||
$logger->{$level}('Second log message');
|
$logger->{$level}('Second log message');
|
||||||
|
|
||||||
$entries = LogEntries();
|
$entries = LogEntry::all();
|
||||||
$this->assertCount(2, $entries);
|
$this->assertCount(2, $entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testContextReplacement()
|
public function testContextReplacement()
|
||||||
{
|
{
|
||||||
|
LogEntry::query()->truncate();
|
||||||
$logger = $this->getLogger();
|
$logger = $this->getLogger();
|
||||||
LogEntries_clear_all();
|
|
||||||
|
|
||||||
$logger->log(LogLevel::INFO, 'My username is {username}', ['username' => 'Foo']);
|
$logger->log(LogLevel::INFO, 'My username is {username}', ['username' => 'Foo']);
|
||||||
|
|
||||||
|
@ -100,8 +101,8 @@ class EngelsystemLoggerTest extends ApplicationFeatureTest
|
||||||
|
|
||||||
public function testContextToString()
|
public function testContextToString()
|
||||||
{
|
{
|
||||||
|
LogEntry::query()->truncate();
|
||||||
$logger = $this->getLogger();
|
$logger = $this->getLogger();
|
||||||
LogEntries_clear_all();
|
|
||||||
|
|
||||||
$mock = $this->getMockBuilder('someDataProvider')
|
$mock = $this->getMockBuilder('someDataProvider')
|
||||||
->setMethods(['__toString'])
|
->setMethods(['__toString'])
|
||||||
|
@ -132,14 +133,14 @@ class EngelsystemLoggerTest extends ApplicationFeatureTest
|
||||||
*/
|
*/
|
||||||
public function getLastEntry()
|
public function getLastEntry()
|
||||||
{
|
{
|
||||||
$entries = LogEntries();
|
$entries = LogEntry::all();
|
||||||
$entry = array_pop($entries);
|
$entry = $entries->last();
|
||||||
|
|
||||||
return $entry;
|
return $entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function tearDown()
|
public function tearDown()
|
||||||
{
|
{
|
||||||
LogEntries_clear_all();
|
LogEntry::query()->truncate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
namespace Engelsystem\Test\Feature\Model;
|
|
||||||
|
|
||||||
use Engelsystem\Test\Feature\ApplicationFeatureTest;
|
|
||||||
use Psr\Log\LogLevel;
|
|
||||||
|
|
||||||
class LogEntriesModelTest extends ApplicationFeatureTest
|
|
||||||
{
|
|
||||||
public function testCreateLogEntry()
|
|
||||||
{
|
|
||||||
LogEntries_clear_all();
|
|
||||||
$count = count(LogEntries());
|
|
||||||
$this->assertNotFalse(LogEntry_create(LogLevel::WARNING, 'test_LogEntry_create'));
|
|
||||||
|
|
||||||
// There should be one more log entry now
|
|
||||||
$this->assertEquals(count(LogEntries()), $count + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testClearAllLogEntries()
|
|
||||||
{
|
|
||||||
LogEntry_create(LogLevel::WARNING, 'test');
|
|
||||||
$this->assertTrue(count(LogEntries()) > 0);
|
|
||||||
|
|
||||||
$this->assertNotFalse(LogEntries_clear_all());
|
|
||||||
$this->assertCount(0, LogEntries());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function tearDown()
|
|
||||||
{
|
|
||||||
LogEntries_clear_all();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Test\Feature\Model;
|
||||||
|
|
||||||
|
use Engelsystem\Models\LogEntry;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Psr\Log\LogLevel;
|
||||||
|
|
||||||
|
class LogEntryTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Models\LogEntry::filter
|
||||||
|
*/
|
||||||
|
public function testFilter()
|
||||||
|
{
|
||||||
|
foreach ([
|
||||||
|
'Lorem Ipsum' => LogLevel::INFO,
|
||||||
|
'Some test content' => LogLevel::ERROR,
|
||||||
|
'Foo bar bartz!' => LogLevel::INFO,
|
||||||
|
'Someone did something?' => LogLevel::NOTICE,
|
||||||
|
'This is a Test!' => LogLevel::INFO,
|
||||||
|
'I\'m verbose notice!' => LogLevel::DEBUG,
|
||||||
|
'The newest stuff!!' => LogLevel::ERROR,
|
||||||
|
] as $message => $level) {
|
||||||
|
$entry = new LogEntry(['level' => $level, 'message' => $message]);
|
||||||
|
$entry->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
$model = new LogEntry();
|
||||||
|
|
||||||
|
$return = $model->filter();
|
||||||
|
$this->assertCount(7, $return);
|
||||||
|
|
||||||
|
/** @var LogEntry $first */
|
||||||
|
$first = $return->first();
|
||||||
|
|
||||||
|
$this->assertEquals('The newest stuff!!', $first->message);
|
||||||
|
|
||||||
|
$return = $model->filter(LogLevel::INFO);
|
||||||
|
$this->assertCount(3, $return);
|
||||||
|
|
||||||
|
$return = $model->filter('notice');
|
||||||
|
$this->assertCount(2, $return);
|
||||||
|
|
||||||
|
$return = $model->filter('bartz');
|
||||||
|
$this->assertCount(1, $return);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called before a test is executed.
|
||||||
|
*/
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
LogEntry::query()->truncate();
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,7 @@ class LoggerServiceProviderTest extends ServiceProviderTest
|
||||||
{
|
{
|
||||||
/** @var PHPUnit_Framework_MockObject_MockObject|EngelsystemLogger $logger */
|
/** @var PHPUnit_Framework_MockObject_MockObject|EngelsystemLogger $logger */
|
||||||
$logger = $this->getMockBuilder(EngelsystemLogger::class)
|
$logger = $this->getMockBuilder(EngelsystemLogger::class)
|
||||||
|
->disableOriginalConstructor()
|
||||||
->getMock();
|
->getMock();
|
||||||
|
|
||||||
$app = $this->getApp(['make', 'instance', 'bind']);
|
$app = $this->getApp(['make', 'instance', 'bind']);
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Test\Unit\Models;
|
||||||
|
|
||||||
|
use Engelsystem\Test\Unit\Models\Stub\BaseModelImplementation;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
class BaseModelTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Models\BaseModel::create
|
||||||
|
*/
|
||||||
|
public function testCreate()
|
||||||
|
{
|
||||||
|
$model = new BaseModelImplementation();
|
||||||
|
$newModel = $model->create(['foo' => 'bar']);
|
||||||
|
|
||||||
|
$this->assertNotEquals($model, $newModel);
|
||||||
|
$this->assertEquals('bar', $newModel->foo);
|
||||||
|
$this->assertEquals(1, $newModel->saveCount);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Engelsystem\Test\Unit\Models\Stub;
|
||||||
|
|
||||||
|
use Engelsystem\Models\BaseModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property string foo
|
||||||
|
*/
|
||||||
|
class BaseModelImplementation extends BaseModel
|
||||||
|
{
|
||||||
|
/** @var array */
|
||||||
|
protected $fillable = ['foo'];
|
||||||
|
|
||||||
|
/** @var int */
|
||||||
|
public $saveCount = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $options
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function save(array $options = [])
|
||||||
|
{
|
||||||
|
$this->saveCount++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue