INIT: initial commit
This commit is contained in:
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
'name' => 'Profiler',
|
||||||
|
'translatedName' => 'profiler::module.name',
|
||||||
|
'translatedDescription' => 'profiler::module.description',
|
||||||
|
'alias' => 'profiler',
|
||||||
|
'handler' => \Modules\Profiler\Handlers\ProfileHandler::class,
|
||||||
|
'providers' => [\Modules\Profiler\Providers\ProfilerServiceProvider::class],
|
||||||
|
'files' => ['start.php'],
|
||||||
|
'order' => -100,
|
||||||
|
];
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
|
||||||
|
class CreateQueriesLogTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('queries_log', function (Blueprint $table) {
|
||||||
|
$table->increments('id');
|
||||||
|
$table->timestamps();
|
||||||
|
$table->text('query');
|
||||||
|
$table->text('bindings');
|
||||||
|
$table->double('time');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::drop('queries_log');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class CreateHttpLogTable extends Migration {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('http_log', function(Blueprint $table)
|
||||||
|
{
|
||||||
|
$table->increments('id');
|
||||||
|
$table->timestamps();
|
||||||
|
$table->string('method');
|
||||||
|
$table->text('url');
|
||||||
|
$table->double('time');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::drop('http_log');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
|
||||||
|
class UpdateHttpLogAddLoadAvg extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('http_log', function (Blueprint $table) {
|
||||||
|
$table->double('load_1')->nullable();
|
||||||
|
$table->double('load_5')->nullable();
|
||||||
|
$table->double('load_15')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('http_log', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('load_1');
|
||||||
|
$table->dropColumn('load_5');
|
||||||
|
$table->dropColumn('load_15');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
|
||||||
|
class UpdateQueryLogAddRequestId extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('queries_log', function (Blueprint $table) {
|
||||||
|
$table->integer('http_log_id')
|
||||||
|
->nullable()
|
||||||
|
->unsigned()
|
||||||
|
->after('id')
|
||||||
|
->comment('FK to http_log');
|
||||||
|
|
||||||
|
$table->foreign('http_log_id')
|
||||||
|
->references('id')
|
||||||
|
->on('http_log')
|
||||||
|
->onDelete('cascade')
|
||||||
|
->onUpdate('cascade');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('queries_log', function (Blueprint $table) {
|
||||||
|
|
||||||
|
// $table->dropForeign('');
|
||||||
|
$table->dropColumn('http_log_id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<?php namespace Modules\Profiler\Database\Seeders;
|
||||||
|
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class ProfilerDatabaseSeeder extends Seeder {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the database seeds.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function run()
|
||||||
|
{
|
||||||
|
Model::unguard();
|
||||||
|
|
||||||
|
// $this->call("OthersTableSeeder");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
namespace Modules\Profiler\Entities;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class HttpLog extends Model
|
||||||
|
{
|
||||||
|
public $table = 'http_log';
|
||||||
|
protected $fillable = [
|
||||||
|
'method',
|
||||||
|
'url',
|
||||||
|
'time',
|
||||||
|
'load_1',
|
||||||
|
'load_5',
|
||||||
|
'load_15'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function queries()
|
||||||
|
{
|
||||||
|
return $this->hasMany(QueryLog::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
namespace Modules\Profiler\Entities;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class QueryLog extends Model
|
||||||
|
{
|
||||||
|
public $table = 'queries_log';
|
||||||
|
protected $fillable = [
|
||||||
|
'query',
|
||||||
|
'bindings',
|
||||||
|
'time',
|
||||||
|
'http_log_id'
|
||||||
|
];
|
||||||
|
protected $casts = [
|
||||||
|
'bindings' => 'array'
|
||||||
|
];
|
||||||
|
|
||||||
|
public function httpLog()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(HttpLog::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
namespace Modules\Profiler\Handlers;
|
||||||
|
|
||||||
|
use App\CMS\Contracts\Modules\BaseModuleHandler;
|
||||||
|
use App\Models\User;
|
||||||
|
|
||||||
|
class ProfileHandler implements BaseModuleHandler
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Register admin menu (or multiple ones)
|
||||||
|
*
|
||||||
|
* This cannot be in ServiceProvider because Session is started at middleware. And ServiceProvider is called before
|
||||||
|
* starting any middleware..
|
||||||
|
*
|
||||||
|
* @param User $user model of logged user
|
||||||
|
*/
|
||||||
|
public static function registerAdminMenu(User $user)
|
||||||
|
{
|
||||||
|
// register links in admin menu
|
||||||
|
$menu = \Menu::instance('mainMenu');
|
||||||
|
|
||||||
|
$submenu = $menu->whereTitle(trans('admin/mainMenu.system'));
|
||||||
|
$submenu->route('profiler.index', trans('profiler::module.name'), [], 10, ['icon' => 'fa fa-dashboard']);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
<?php namespace Modules\Profiler\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Admin\Controller;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Support\Facades\Input;
|
||||||
|
use Modules\Profiler\Entities\HttpLog;
|
||||||
|
use Modules\Profiler\Entities\QueryLog;
|
||||||
|
|
||||||
|
class ProfilerController extends Controller
|
||||||
|
{
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$filters = [];
|
||||||
|
$pastDays = Input::get('pastDays', session('profilerPastDays', 0));
|
||||||
|
$httpLog = HttpLog::query();
|
||||||
|
|
||||||
|
if (is_numeric($pastDays) && $pastDays >= 0) {
|
||||||
|
$httpLog = $httpLog->where('created_at', '>=', Carbon::today()
|
||||||
|
->subDays($pastDays));
|
||||||
|
}
|
||||||
|
|
||||||
|
session(['profilerPastDays' => $pastDays]);
|
||||||
|
|
||||||
|
if (Input::get('method')) {
|
||||||
|
$filters[] = 'method';
|
||||||
|
$httpLog = $httpLog->where('method', Input::get('method'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$displayGrouped = false;
|
||||||
|
|
||||||
|
if (Input::get('url')) {
|
||||||
|
$httpLog = $httpLog->where('url', Input::get('url'))
|
||||||
|
->orderBy('created_at', 'DESC')
|
||||||
|
->with('queries');
|
||||||
|
} else {
|
||||||
|
$displayGrouped = true;
|
||||||
|
$httpLog = $httpLog->groupBy('url', 'method')
|
||||||
|
->select(\DB::raw('*'), \DB::raw('COUNT(url) as total'), \DB::raw('AVG(time) as time_avg'))
|
||||||
|
->orderBy('total', 'DESC');
|
||||||
|
}
|
||||||
|
|
||||||
|
$httpLog = $httpLog->paginate(25);
|
||||||
|
|
||||||
|
$filter = Input::all();
|
||||||
|
return view('profiler::index', compact('httpLog', 'displayGrouped', 'filter', 'pastDays'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy()
|
||||||
|
{
|
||||||
|
$older = Input::get('olderThan');
|
||||||
|
|
||||||
|
if (is_null($older)) {
|
||||||
|
\DB::statement("SET foreign_key_checks=0");
|
||||||
|
QueryLog::truncate();
|
||||||
|
HttpLog::truncate();
|
||||||
|
\DB::statement("SET foreign_key_checks=1");
|
||||||
|
} else {
|
||||||
|
HttpLog::where('created_at', '<=', Carbon::now()
|
||||||
|
->subDays($older))
|
||||||
|
->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
return redirect()
|
||||||
|
->back()
|
||||||
|
->with('success', trans('profiler::module.succesfullyDeleted'));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
namespace Modules\Profiler\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Admin\Controller;
|
||||||
|
use Modules\Profiler\Entities\HttpLog;
|
||||||
|
|
||||||
|
class QueryController extends Controller {
|
||||||
|
public function index(HttpLog $httpLog) {
|
||||||
|
$queries = $httpLog->queries;
|
||||||
|
|
||||||
|
return view('profiler::queries.index', compact('queries'));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Modules\Profiler\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Admin\Controller;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Support\Facades\Input;
|
||||||
|
use Modules\Profiler\Entities\HttpLog;
|
||||||
|
|
||||||
|
class RequestController extends Controller
|
||||||
|
{
|
||||||
|
public function detail(HttpLog $httpLog)
|
||||||
|
{
|
||||||
|
$sameRequests = HttpLog::where('url', $httpLog->url)
|
||||||
|
->where('method', $httpLog->method);
|
||||||
|
|
||||||
|
$pastDays = Input::get('pastDays', session('profilerPastDays', 0));
|
||||||
|
if (is_numeric($pastDays) && $pastDays >= 0) {
|
||||||
|
$sameRequests = $sameRequests->where('created_at', '>=', Carbon::today()
|
||||||
|
->subDays($pastDays));
|
||||||
|
}
|
||||||
|
|
||||||
|
session(['profilerPastDays' => $pastDays]);
|
||||||
|
|
||||||
|
$sameRequests = $sameRequests->get();
|
||||||
|
|
||||||
|
$times = [
|
||||||
|
'avg' => $sameRequests->avg('time'),
|
||||||
|
'min' => $sameRequests->min('time'),
|
||||||
|
'max' => $sameRequests->max('time')
|
||||||
|
];
|
||||||
|
|
||||||
|
$filter = Input::all();
|
||||||
|
|
||||||
|
return view('profiler::request.detail', compact('httpLog', 'sameRequests', 'times', 'pastDays', 'filter'));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
Route::group([
|
||||||
|
'prefix' => LaravelLocalization::setLocale(),
|
||||||
|
'namespace' => 'Modules\Profiler\Http\Controllers'
|
||||||
|
], function () {
|
||||||
|
Route::group([
|
||||||
|
'middleware' => ['admin'],
|
||||||
|
'prefix' => 'admin/profiler'
|
||||||
|
], function () {
|
||||||
|
|
||||||
|
Route::get('/', 'ProfilerController@index')
|
||||||
|
->name('profiler.index');
|
||||||
|
|
||||||
|
Route::get('{httpLog}', 'RequestController@detail')
|
||||||
|
->name('request.detail');
|
||||||
|
|
||||||
|
Route::get('{httpLog}/queries', 'QueryController@index')
|
||||||
|
->name('queries.index');
|
||||||
|
|
||||||
|
Route::get('delete/all', 'ProfilerController@destroy')
|
||||||
|
->name('profiler.deleteAll');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
namespace Modules\Profiler\Middleware;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Modules\Profiler\Entities\HttpLog;
|
||||||
|
use Modules\Profiler\Entities\QueryLog;
|
||||||
|
|
||||||
|
class Profiler
|
||||||
|
{
|
||||||
|
private $queries = [];
|
||||||
|
|
||||||
|
public function handle(Request $request, $next)
|
||||||
|
{
|
||||||
|
\DB::enableQueryLog();
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function terminate(Request $request, $response)
|
||||||
|
{
|
||||||
|
$this->queries = \DB::getQueryLog();
|
||||||
|
|
||||||
|
$requestId = $this->logRequest($request);
|
||||||
|
$this->logQueries($requestId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
*
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
protected function logRequest(Request $request)
|
||||||
|
{
|
||||||
|
$url = $request->fullUrl();
|
||||||
|
$method = $request->getMethod();
|
||||||
|
$time = (microtime(true) - LARAVEL_START) * 1000;
|
||||||
|
|
||||||
|
$data = ['url' => $url, 'method' => $method, 'time' => $time];
|
||||||
|
|
||||||
|
if (function_exists('sys_getloadavg')) {
|
||||||
|
$load = sys_getloadavg();
|
||||||
|
$data['load_1'] = $load[0];
|
||||||
|
$data['load_5'] = $load[1];
|
||||||
|
$data['load_15'] = $load[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
$http = HttpLog::create($data);
|
||||||
|
|
||||||
|
return $http->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function logQueries($httpLogId = null)
|
||||||
|
{
|
||||||
|
foreach ($this->queries as $query) {
|
||||||
|
QueryLog::create([
|
||||||
|
'query' => $query['query'],
|
||||||
|
'bindings' => $query['bindings'],
|
||||||
|
'time' => $query['time'],
|
||||||
|
'http_log_id' => $httpLogId
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
namespace Modules\Profiler\Providers;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
|
||||||
|
|
||||||
|
class ProfilerEventServiceProvider extends ServiceProvider
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
namespace Modules\Profiler\Providers;
|
||||||
|
|
||||||
|
use App\Providers\ModuleServiceProvider;
|
||||||
|
use Modules\Profiler\Middleware\Profiler;
|
||||||
|
|
||||||
|
class ProfilerServiceProvider extends ModuleServiceProvider
|
||||||
|
{
|
||||||
|
protected function setModuleAlias()
|
||||||
|
{
|
||||||
|
$this->alias = 'profiler';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Boot the application events.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function boot()
|
||||||
|
{
|
||||||
|
parent::boot();
|
||||||
|
|
||||||
|
$this->app->register(ProfilerEventServiceProvider::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function register()
|
||||||
|
{
|
||||||
|
parent::register();
|
||||||
|
|
||||||
|
// register settings form
|
||||||
|
$registrator = $this->app->make('registerSettingsExtension');
|
||||||
|
$registrator->register('profiler', 'profiler::module.name', 'profiler::settings.profiler');
|
||||||
|
|
||||||
|
// turn on profiler for visitor area (middleware group "web")
|
||||||
|
if (setting('useProfilerInVisitorArea', true)) {
|
||||||
|
$this->app['router']->prependMiddlewareToGroup('web', Profiler::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// use profiler also in admin?
|
||||||
|
if (setting('useProfilerInAdmin', true)) {
|
||||||
|
$this->app['router']->prependMiddlewareToGroup('admin', Profiler::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function setModulePath()
|
||||||
|
{
|
||||||
|
$this->path = __DIR__;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
return [
|
||||||
|
'name' => 'Profiler',
|
||||||
|
'index' => [
|
||||||
|
'createdAt' => 'Datum',
|
||||||
|
'httpMethod' => 'HTTP metoda',
|
||||||
|
'url' => 'URL',
|
||||||
|
'time' => 'Čas',
|
||||||
|
'timeAvg' => 'Průměrný čas',
|
||||||
|
'timeMin' => 'Minimální čas',
|
||||||
|
'timeMax' => 'Maximální čas',
|
||||||
|
'systemLoad' => 'Load serveru',
|
||||||
|
'calledTotal' => 'Volání',
|
||||||
|
'pastDays' => [
|
||||||
|
'today' => 'Dnes',
|
||||||
|
'overall' => 'Vše',
|
||||||
|
'days' => '1 den|:count dny|:count dní'
|
||||||
|
]
|
||||||
|
],
|
||||||
|
'settings' => [
|
||||||
|
'useProfilerInVisitorArea' => 'Zapnout měření ve veřejné části?',
|
||||||
|
'useProfilerInAdmin' => 'Zapnout měření v administraci?'
|
||||||
|
],
|
||||||
|
'request' => [
|
||||||
|
'info' => 'Detaily requestu',
|
||||||
|
'sql' => 'SQL dotazy',
|
||||||
|
'detail' => 'Detail požadavku',
|
||||||
|
'sameRequests' => 'Ostatní volání'
|
||||||
|
],
|
||||||
|
'graphs' => [
|
||||||
|
'responseTime' => 'Doba odezvy'
|
||||||
|
],
|
||||||
|
'queries' => [
|
||||||
|
'sql' => 'SQL dotaz',
|
||||||
|
'time' => 'Čas dotazu'
|
||||||
|
],
|
||||||
|
'listDescription' => 'Seznam HTTP požadavků na tuto aplikaci.',
|
||||||
|
'groupedListDescription' => 'Seznam HTTP požadavků na tuto aplikaci.',
|
||||||
|
'requestDetail' => 'Detail HTTP požadavku',
|
||||||
|
'deleteAllData' => 'Smazat všechna data',
|
||||||
|
'deleteOld' => 'Smazat data starší než 30 dní',
|
||||||
|
'succesfullyDeleted' => 'Úspěšně vymazána data z profileru.',
|
||||||
|
|
||||||
|
];
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
@if(count($requests) > 0)
|
||||||
|
<table class="item-list content-overview full-width table striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<td>@lang('profiler::module.index.calledTotal')</td>
|
||||||
|
<td>@lang('profiler::module.index.httpMethod')</td>
|
||||||
|
<td>@lang('profiler::module.index.url')</td>
|
||||||
|
<td>@lang('profiler::module.index.timeAvg')</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach($requests as $request)
|
||||||
|
<tr>
|
||||||
|
<td>{{$request->total}}</td>
|
||||||
|
<td><a href="{{route('profiler.index', ['method' => $request->method])}}">{{$request->method}}</a></td>
|
||||||
|
<td><a href="{{route('profiler.index', ['url' => $request->url])}}">{{$request->url}}</a></td>
|
||||||
|
<td>{{number_format($request->time_avg, 2)}} ms</td>
|
||||||
|
<td>
|
||||||
|
<a href="{{route('request.detail', ['httpLog' => $request])}}" data-toggle="tooltip"
|
||||||
|
title="@lang('profiler::module.request.info')">
|
||||||
|
<i class="fa fa-info"></i>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
@else
|
||||||
|
@lang('admin/common.empty')
|
||||||
|
@endif
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
@if(count($requests) > 0)
|
||||||
|
<table class="item-list content-overview full-width table striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<td>@lang('profiler::module.index.createdAt')</td>
|
||||||
|
<td>@lang('profiler::module.index.httpMethod')</td>
|
||||||
|
<td>@lang('profiler::module.index.url')</td>
|
||||||
|
<td>@lang('profiler::module.index.time')</td>
|
||||||
|
<td>@lang('profiler::module.index.systemLoad')</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
|
||||||
|
@foreach($requests as $request)
|
||||||
|
<tr>
|
||||||
|
<td>{{$request->created_at->format('d.m.Y G:i')}}</td>
|
||||||
|
<td><a href="{{route('profiler.index', ['method' => $request->method])}}">{{$request->method}}</a></td>
|
||||||
|
<td><a href="{{route('profiler.index', ['url' => $request->url])}}">{{$request->url}}</a></td>
|
||||||
|
<td>{{number_format($request->time, 3)}} ms</td>
|
||||||
|
<td>{{$request->load_1}}, {{$request->load_5}}, {{$request->load_15}}</td>
|
||||||
|
<td>
|
||||||
|
|
||||||
|
<div class="item-actions-dropdown">
|
||||||
|
<a class="item-actions-toggle-btn">
|
||||||
|
<span class="inactive">
|
||||||
|
<i class="fa fa-cog"></i>
|
||||||
|
</span>
|
||||||
|
<span class="active">
|
||||||
|
<i class="fa fa-chevron-circle-right"></i>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<div class="item-actions-block">
|
||||||
|
<ul class="item-actions-list">
|
||||||
|
<li>
|
||||||
|
<a href="{{route('request.detail', ['httpLog' => $request])}}" data-toggle="tooltip"
|
||||||
|
title="@lang('profiler::module.request.info')">
|
||||||
|
<i class="fa fa-info"></i>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{route('queries.index', ['httpLog' => $request])}}" data-toggle="tooltip"
|
||||||
|
title="@lang('profiler::module.request.sql')">
|
||||||
|
<i class="fa fa-database"></i></a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
@else
|
||||||
|
@lang('admin/common.empty')
|
||||||
|
@endif
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
@extends('admin.layoutWithNavigation')
|
||||||
|
|
||||||
|
@section('pageHeading', trans('profiler::module.name'))
|
||||||
|
|
||||||
|
@section('headerButtons')
|
||||||
|
@if($displayGrouped == false)
|
||||||
|
|
||||||
|
<a class="btn btn-sm rounded btn-primary" href="{{route('profiler.index')}}"><i class="fa fa-list"></i></a>
|
||||||
|
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<div class="pull-right">
|
||||||
|
@foreach(['0' => 'today', '7' => 'days', '30' => 'days', 'inf' => 'overall'] as $pastDay => $name)
|
||||||
|
@php $filter['pastDays'] = $pastDay; @endphp
|
||||||
|
|
||||||
|
<a class="btn btn-sm rounded @if($pastDays === (string)$pastDay) btn-primary @else btn-secondary @endif"
|
||||||
|
href="{{route('profiler.index', $filter)}}">{{trans_choice('profiler::module.index.pastDays.'.$name, $pastDay)}}</a>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@if($displayGrouped == false)
|
||||||
|
@section('pageDescription', trans('profiler::module.listDescription'))
|
||||||
|
@else
|
||||||
|
@section('pageDescription', trans('profiler::module.groupedListDescription'))
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-block">
|
||||||
|
|
||||||
|
@if ($displayGrouped == true)
|
||||||
|
@include('profiler::_partials.groupedRequestList', ['requests' => $httpLog])
|
||||||
|
@else
|
||||||
|
@include('profiler::_partials.requestList', ['requests' => $httpLog])
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
<div class="card-footer">
|
||||||
|
{!! $httpLog->render() !!}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
@extends('admin.layoutWithNavigation')
|
||||||
|
|
||||||
|
@section('pageHeading', trans('profiler::module.name'))
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-block">
|
||||||
|
<table class="table stripped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<td>@lang('profiler::module.queries.sql')</td>
|
||||||
|
<td>@lang('profiler::module.queries.time')</td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
|
||||||
|
@foreach($queries as $query)
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
@php $sql = $query->query; @endphp
|
||||||
|
@foreach($query->bindings as $value)
|
||||||
|
@php
|
||||||
|
if (is_array($value) && isset($value['date']))
|
||||||
|
{$value = \Carbon\Carbon::parse($value['date'])->toDateTimeString();}
|
||||||
|
$sql = preg_replace('/\?/', $value, $sql, 1);
|
||||||
|
@endphp
|
||||||
|
@endforeach
|
||||||
|
|
||||||
|
{{$sql}}
|
||||||
|
</td>
|
||||||
|
<td>{{number_format($query->time, 3)}} ms</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
@extends('admin.layoutWithNavigation')
|
||||||
|
|
||||||
|
@section('pageHeading', trans('profiler::module.requestDetail'))
|
||||||
|
|
||||||
|
@section('headerButtons')
|
||||||
|
<a class="btn btn-sm rounded btn-primary" href="{{route('profiler.index')}}"><i class="fa fa-list"></i></a>
|
||||||
|
<div class="pull-right">
|
||||||
|
@foreach(['0' => 'today', '7' => 'days', '30' => 'days', 'inf' => 'overall'] as $pastDay => $name)
|
||||||
|
@php $filter['httpLog'] = $httpLog ;$filter['pastDays'] = $pastDay; @endphp
|
||||||
|
|
||||||
|
<a class="btn btn-sm rounded @if($pastDays === (string)$pastDay) btn-primary @else btn-secondary @endif"
|
||||||
|
href="{{route('request.detail', $filter)}}">{{trans_choice('profiler::module.index.pastDays.'.$name, $pastDay)}}</a>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-5">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="header-block">
|
||||||
|
<p class="title">@lang('profiler::module.request.detail')</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-block">
|
||||||
|
<div class="row">
|
||||||
|
<ul>
|
||||||
|
<li>@lang('profiler::module.index.httpMethod'): {{$httpLog->method}}</li>
|
||||||
|
<li>@lang('profiler::module.index.url'): <a
|
||||||
|
href="{{route('profiler.index', ['url' => $httpLog->url])}}">{{$httpLog->url}}</a>
|
||||||
|
</li>
|
||||||
|
<li>@lang('profiler::module.index.time'): {{number_format($httpLog->time, 2)}} ms</li>
|
||||||
|
<li>@lang('profiler::module.index.systemLoad'): {{$httpLog->load_1}}, {{$httpLog->load_5}}
|
||||||
|
, {{$httpLog->load_15}}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row text-center">
|
||||||
|
<div class="col-sm-3"><h5>
|
||||||
|
{{count($sameRequests)}} ×</h5> @lang('profiler::module.index.calledTotal')</div>
|
||||||
|
<div class="col-sm-3"><h5>{{number_format($times['min'], 2)}}
|
||||||
|
ms</h5> @lang('profiler::module.index.timeMin')</div>
|
||||||
|
<div class="col-sm-3"><h5>{{number_format($times['max'], 2)}}
|
||||||
|
ms</h5> @lang('profiler::module.index.timeMax')</div>
|
||||||
|
<div class="col-sm-3"><h5>{{number_format($times['avg'], 2)}}
|
||||||
|
ms</h5> @lang('profiler::module.index.timeAvg')</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-7">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="header-block">
|
||||||
|
<p class="title">@lang('profiler::module.graphs.responseTime')</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-block">
|
||||||
|
<canvas id="responseTimeHistory" height="100"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<div class="header-block">
|
||||||
|
<p class="title">@lang('profiler::module.request.sameRequests')</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-block">
|
||||||
|
@include('profiler::_partials.requestList', ['requests' => $sameRequests])
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@section('javascripts')
|
||||||
|
<script>
|
||||||
|
var ctx = $ ("#responseTimeHistory");
|
||||||
|
var myChart = new Chart (ctx, {
|
||||||
|
type: 'bubble',
|
||||||
|
data: {
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: '@lang('profiler::module.graphs.responseTime')',
|
||||||
|
data: [
|
||||||
|
@foreach($sameRequests as $i => $request)
|
||||||
|
{
|
||||||
|
x: '{{$i}}',
|
||||||
|
y: '{{number_format($request->time, 2)}}',
|
||||||
|
r: 5
|
||||||
|
},
|
||||||
|
@endforeach
|
||||||
|
|
||||||
|
],
|
||||||
|
backgroundColor: "#413e39",
|
||||||
|
hoverBackgroundColor: "#515151",
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@endsection
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-9">
|
||||||
|
|
||||||
|
@php $profileVisitorArea = old('useProfilerInVisitorArea', isset($settings->useProfilerInVisitorArea) ? $settings->useProfilerInVisitorArea['val'] : null); @endphp
|
||||||
|
|
||||||
|
<span class="control-label">@lang('profiler::module.settings.useProfilerInVisitorArea')</span>
|
||||||
|
<label>
|
||||||
|
<input class="radio" type="radio" name="useProfilerInVisitorArea"
|
||||||
|
value="1"
|
||||||
|
@if($profileVisitorArea === "1") checked @endif />
|
||||||
|
<span>@lang('common.yes')</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input class="radio" type="radio" name="useProfilerInVisitorArea"
|
||||||
|
value="0"
|
||||||
|
@if($profileVisitorArea === "0") checked @endif />
|
||||||
|
<span>@lang('common.no')</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-3">
|
||||||
|
@include('admin.settings.snippets.commonSettings', ['field' => 'useProfilerInVisitorArea'])
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-9">
|
||||||
|
@php $profileAdmin = old('useProfilerInAdmin', isset($settings->useProfilerInAdmin) ? $settings->useProfilerInAdmin['val'] : false); @endphp
|
||||||
|
<span class="control-label">@lang('profiler::module.settings.useProfilerInAdmin')</span>
|
||||||
|
<label>
|
||||||
|
<input class="radio" type="radio" name="useProfilerInAdmin"
|
||||||
|
value="1"
|
||||||
|
@if($profileAdmin) checked @endif />
|
||||||
|
<span>@lang('common.yes')</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label>
|
||||||
|
<input class="radio" type="radio" name="useProfilerInAdmin"
|
||||||
|
value="0"
|
||||||
|
@if(!$profileAdmin) checked @endif />
|
||||||
|
<span>@lang('common.no')</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-3">
|
||||||
|
@include('admin.settings.snippets.commonSettings', ['field' => 'useProfilerInAdmin'])
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row text-center">
|
||||||
|
<a href="{{route('profiler.deleteAll')}}" class="btn btn-danger remove confirm">
|
||||||
|
<i class="fa fa-trash-o"></i> @lang('profiler::module.deleteAllData')
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{route('profiler.deleteAll', ['olderThan' => 30])}}" class="btn btn-danger remove confirm">
|
||||||
|
<i class="fa fa-trash-o"></i> @lang('profiler::module.deleteOld')
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"name": "pingpong-modules/profiler",
|
||||||
|
"description": "",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Pingpong Labs",
|
||||||
|
"email": "pingpong.labs@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Modules\\Profiler\\": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Register Namespaces And Routes
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When a module starting, this file will executed automatically. This helps
|
||||||
|
| to register some namespaces like translator or view. Also this file
|
||||||
|
| will load the routes file for each module. You may also modify
|
||||||
|
| this file as you want.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
require __DIR__ . '/Http/routes.php';
|
||||||
Reference in New Issue
Block a user