Язык: PHP
Framework: Laravel
Демо: http://laravel.jobtools.ru
Исходники: https://bitbucket.org/gerz/laravel.jobtools.ru/src/master/
Поставим задачу: нам нужен простой логгер сохраняющий все обращения к нашему серверу. Для удобства просмотра через WEB интерфейс всех, кто нас посетил, пусть данные будут сохранятся в таблицу MySQL. И пусть будет возможность отключения логгирования в конфиг файле.
Для начала опишем миграцию для создания нашей таблицы логов, для этого в консоли набираем artisan команду:
php artisan make:migration create_logs_table
Редактируем создавшийся файл миграции, который, кстати, по умолчанию создается по следующему пути: \database\migrations\2019_06_04_133003_create_logs_table.php
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateLogTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('logs', function (Blueprint $table) {
$table->bigIncrements('id');
$table->dateTime('time');
$table->integer('duration');
$table->string('ip',100)->nullabe();
$table->string('url')->nullabe();
$table->string('method',10)->nullabe();
$table->string('input')->nullabe();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('logs');
}
}
Мы определили поля, необходимые для нашего логера:
- time — время события;
- duration — длительность;
- ip — ip адрес зашедшего пользователя;
- url — адрес, который запросил пользователь;
- method — HTTP метод (GET, POST);
- input — передаваемые параметры.
Создадим таблицу по нашей миграции:
php artisan migrate
Таблица создана, приступаем к созданию middleware — фильтр обработки HTTP-запросов. Советую ознакомится с документацией Что такое Middleware. На помощь нам опять придет artisan:
php artisan make:middleware DataLogger
Допишем в созданный по пути \app\Http\Middleware\DataLogger.php файл следующий код:
<?php
namespace App\Http\Middleware;
use Closure;
use App\Models\Log; //Прописываем нашу модель, для возможности доступа к ней
class DataLogger
{
private $startTime; //Сохраним в дальнейшем в этой переменной время начала запроса, для просчета общей длительности запроса
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next) //Функция в которую приходи наш запрос
{
$this->startTime = microtime(true);
return $next($request);
}
public function terminate($request, $response) //Функция, которая вызывается после посылки ответа пользователю
{
if ( env('API_DATALOGGER', true) ) { //Если в env файле прописана опция API_DATALOGGER = true используем логирование
if ( env('API_DATALOGGER_USE_DB', true) ) { // Если в env файле прописана опция API_DATA_LOGGER_USE_DB=true, то для сохранения используем БД иначе пишем просто в файл
$endTime = microtime(true);
$log = new Log();
$log->time = gmdate('Y-m-d H:i:s');
$log->duration = number_format($endTime - LARAVEL_START, 3);
$log->ip = $request->ip();
$log->url = $request->fullUrl();
$log->method = $request->method();
$log->input = $request->getContent();
$log->save(); //Сохранили в базу нашу запись
}
else //Если опция записи в БД недоступна пишем в файл
{
$endTime = microtime(true);
$filename = 'api_datalogger_' . date('d-m-y') . '.log';
$dataToLog = 'Time: ' . gmdate("F j, Y, g:i a") . "\n";
$dataToLog .= 'Duration: ' . number_format($endTime - LARAVEL_START, 3) . "\n";
$dataToLog .= 'IP Address: ' . $request->ip() . "\n";
$dataToLog .= 'URL: ' . $request->fullUrl() . "\n";
$dataToLog .= 'Method: ' . $request->method() . "\n";
$dataToLog .= 'Input: ' . $request->getContent() . "\n";
\File::append( storage_path('logs' . DIRECTORY_SEPARATOR . $filename), $dataToLog . "\n" . str_repeat("=", 20) . "\n\n"); //Записали в файл
}
}
}
}
В приведенном выше примере, все достаточно просто и прозрачно. При поступлении запроса в наш фильтр (функция Handle) сохраняем время начала запроса. После ответа пользователю в браузер, вызывается ‘завершающая процедура’ terminate, которая в зависимости от параметров в лог файле записывает данный в БД или файл.
Если сейчас запустить сервер и открыть любую страницу нашего приложения, то ничего не произойдет, не будет ни ошибки, ни записи логов. Нужно завершить создание middleware, зарегистрировав его в app\Http\Kernel.php
Допишите в переменной $middleware наш класс (он последний в списке):
protected $middleware = [
\App\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\App\Http\Middleware\TrustProxies::class,
\App\Http\Middleware\DataLogger::class,
];
Наш фильтр будет вызываться при каждом запросе к серверу.
В следующей части создадим контроллер и шаблон для просмотра наших логов, хранящихся в базе данных.
В поле duration может возникнуть ошибка, т.к. число вероятнее будет дробным.
$table->integer(‘duration’);
Как добавить новое поле?
А где продожение?