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/EventConfig_model.php',
|
||||
__DIR__ . '/../includes/model/LogEntries_model.php',
|
||||
__DIR__ . '/../includes/model/Message_model.php',
|
||||
__DIR__ . '/../includes/model/NeededAngelTypes_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
|
||||
|
||||
use Engelsystem\Models\LogEntry;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
|
@ -17,10 +19,14 @@ function admin_log()
|
|||
if (request()->has('keyword')) {
|
||||
$filter = strip_request_item('keyword');
|
||||
}
|
||||
$log_entries = LogEntries_filter($filter);
|
||||
|
||||
foreach ($log_entries as &$log_entry) {
|
||||
$log_entry['date'] = date('d.m.Y H:i', $log_entry['timestamp']);
|
||||
$log_entries = LogEntry::filter($filter);
|
||||
|
||||
$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(), [
|
||||
|
@ -30,9 +36,9 @@ function admin_log()
|
|||
form_submit(__('Search'), 'Go')
|
||||
]),
|
||||
table([
|
||||
'date' => 'Time',
|
||||
'level' => 'Type',
|
||||
'message' => 'Log Entry'
|
||||
], $log_entries)
|
||||
'created_at' => 'Time',
|
||||
'level' => 'Type',
|
||||
'message' => 'Log Entry'
|
||||
], $entries)
|
||||
]);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Engelsystem\Logger;
|
||||
|
||||
use Engelsystem\Models\LogEntry;
|
||||
use Psr\Log\AbstractLogger;
|
||||
use Psr\Log\InvalidArgumentException;
|
||||
use Psr\Log\LogLevel;
|
||||
|
@ -19,6 +20,14 @@ class EngelsystemLogger extends AbstractLogger
|
|||
LogLevel::WARNING,
|
||||
];
|
||||
|
||||
/** @var LogEntry */
|
||||
protected $log;
|
||||
|
||||
public function __construct(LogEntry $log)
|
||||
{
|
||||
$this->log = $log;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs with an arbitrary level.
|
||||
*
|
||||
|
@ -33,12 +42,12 @@ class EngelsystemLogger extends AbstractLogger
|
|||
public function log($level, $message, array $context = [])
|
||||
{
|
||||
if (!$this->checkLevel($level)) {
|
||||
throw new InvalidArgumentException();
|
||||
throw new InvalidArgumentException('Unknown log level: ' . $level);
|
||||
}
|
||||
|
||||
$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;
|
||||
|
||||
use Engelsystem\Logger\EngelsystemLogger;
|
||||
use Engelsystem\Models\LogEntry;
|
||||
use Engelsystem\Test\Feature\ApplicationFeatureTest;
|
||||
use Psr\Log\InvalidArgumentException;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
@ -15,12 +16,13 @@ class EngelsystemLoggerTest extends ApplicationFeatureTest
|
|||
*/
|
||||
public function getLogger()
|
||||
{
|
||||
return new EngelsystemLogger();
|
||||
$logEntry = new LogEntry();
|
||||
return new EngelsystemLogger($logEntry);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
LogEntry::query()->truncate();
|
||||
$logger = $this->getLogger();
|
||||
|
||||
LogEntries_clear_all();
|
||||
|
||||
$logger->log($level, 'First log message');
|
||||
$logger->{$level}('Second log message');
|
||||
|
||||
$entries = LogEntries();
|
||||
$entries = LogEntry::all();
|
||||
$this->assertCount(2, $entries);
|
||||
}
|
||||
|
||||
public function testContextReplacement()
|
||||
{
|
||||
LogEntry::query()->truncate();
|
||||
$logger = $this->getLogger();
|
||||
LogEntries_clear_all();
|
||||
|
||||
$logger->log(LogLevel::INFO, 'My username is {username}', ['username' => 'Foo']);
|
||||
|
||||
|
@ -100,8 +101,8 @@ class EngelsystemLoggerTest extends ApplicationFeatureTest
|
|||
|
||||
public function testContextToString()
|
||||
{
|
||||
LogEntry::query()->truncate();
|
||||
$logger = $this->getLogger();
|
||||
LogEntries_clear_all();
|
||||
|
||||
$mock = $this->getMockBuilder('someDataProvider')
|
||||
->setMethods(['__toString'])
|
||||
|
@ -132,14 +133,14 @@ class EngelsystemLoggerTest extends ApplicationFeatureTest
|
|||
*/
|
||||
public function getLastEntry()
|
||||
{
|
||||
$entries = LogEntries();
|
||||
$entry = array_pop($entries);
|
||||
$entries = LogEntry::all();
|
||||
$entry = $entries->last();
|
||||
|
||||
return $entry;
|
||||
}
|
||||
|
||||
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 */
|
||||
$logger = $this->getMockBuilder(EngelsystemLogger::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$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