FEATURE #2389 @2h: add request detail into profiler

This commit is contained in:
Michal Kváček
2017-03-24 01:28:21 +01:00
parent 52e02d67c6
commit 05c9e56973
11 changed files with 273 additions and 90 deletions
+2 -1
View File
@@ -14,6 +14,7 @@
"tether": "~1.1.1", "tether": "~1.1.1",
"tinycolor": "~1.2.1", "tinycolor": "~1.2.1",
"dropzone": "~4.2.0", "dropzone": "~4.2.0",
"jquery.are-you-sure": "~1.9" "jquery.are-you-sure": "~1.9",
"chart.js": "^2.5.0"
} }
} }
+1
View File
@@ -11,6 +11,7 @@ elixir (function (mix) {
'responsive-bootstrap-toolkit/dist/bootstrap-toolkit.js', 'responsive-bootstrap-toolkit/dist/bootstrap-toolkit.js',
'metisMenu/dist/metisMenu.min.js', 'metisMenu/dist/metisMenu.min.js',
'tinycolor/dist/tinycolor-min.js', 'tinycolor/dist/tinycolor-min.js',
'chart.js/dist/Chart.bundle.min.js',
'jquery.are-you-sure/jquery.are-you-sure.js', 'jquery.are-you-sure/jquery.are-you-sure.js',
'../resources/assets/admin/js/app.js', '../resources/assets/admin/js/app.js',
], 'public/js/vendor.js', 'bower_components'); ], 'public/js/vendor.js', 'bower_components');
@@ -1,15 +1,28 @@
<?php namespace Modules\Profiler\Http\Controllers; <?php namespace Modules\Profiler\Http\Controllers;
use App\Http\Controllers\Admin\Controller; use App\Http\Controllers\Admin\Controller;
use Illuminate\Support\Facades\Input;
use Modules\Profiler\Entities\HttpLog; use Modules\Profiler\Entities\HttpLog;
class ProfilerController extends Controller class ProfilerController extends Controller
{ {
public function index() public function index()
{ {
$filters = [];
$httpLog = HttpLog::orderBy('created_at', 'DESC') $httpLog = HttpLog::orderBy('created_at', 'DESC')
->with('queries') ->with('queries');
->paginate(25);
if (Input::get('method')) {
$filters[] = 'method';
$httpLog = $httpLog->where('method', Input::get('method'));
}
if (Input::get('url')) {
$filters[] = 'url';
$httpLog = $httpLog->where('url', Input::get('url'));
}
$httpLog = $httpLog->paginate(25);
return view('profiler::index', compact('httpLog')); return view('profiler::index', compact('httpLog'));
} }
@@ -0,0 +1,23 @@
<?php
namespace Modules\Profiler\Http\Controllers;
use App\Http\Controllers\Admin\Controller;
use Modules\Profiler\Entities\HttpLog;
class RequestController extends Controller
{
public function detail(HttpLog $httpLog)
{
$sameRequests = HttpLog::where('url', $httpLog->url)
->where('method', $httpLog->method)
->get();
$times = [
'avg' => $sameRequests->avg('time'),
'min' => $sameRequests->min('time'),
'max' => $sameRequests->max('time')
];
return view('profiler::request.detail', compact('httpLog', 'sameRequests', 'times'));
}
}
+11 -5
View File
@@ -1,14 +1,20 @@
<?php <?php
Route::group([ Route::group([
'prefix' => LaravelLocalization::setLocale(), 'prefix' => LaravelLocalization::setLocale(),
'namespace' => 'Modules\Profiler\Http\Controllers' 'namespace' => 'Modules\Profiler\Http\Controllers'
], function () { ], function () {
Route::group([ Route::group([
'middleware' => ['admin'], 'middleware' => ['admin'],
'prefix' => 'profiler' 'prefix' => 'admin/profiler'
], function () { ], function () {
Route::get('/', 'ProfilerController@index')->name('profiler.index'); Route::get('/', 'ProfilerController@index')
Route::get('{httpLog}/queries', 'QueryController@index')->name('queries.index'); ->name('profiler.index');
Route::get('{httpLog}', 'RequestController@detail')
->name('request.detail');
Route::get('{httpLog}/queries', 'QueryController@index')
->name('queries.index');
}); });
}); });
@@ -11,5 +11,15 @@ return [
'settings' => [ 'settings' => [
'useProfilerInVisitorArea' => 'Zapnout měření ve veřejné části?', 'useProfilerInVisitorArea' => 'Zapnout měření ve veřejné části?',
'useProfilerInAdmin' => 'Zapnout měření v administraci?' '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'
] ]
]; ];
@@ -0,0 +1,55 @@
<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>
@@ -4,34 +4,12 @@
@section('content') @section('content')
<table class="table stripped"> <div class="card">
<thead> <div class="card-block">
<tr> @include('profiler::_partials.requestList', ['requests' => $httpLog])
<td>@lang('profiler::module.index.createdAt')</td> </div>
<td>@lang('profiler::module.index.httpMethod')</td> <div class="card-footer">
<td>@lang('profiler::module.index.url')</td> {!! $httpLog->render() !!}
<td>@lang('profiler::module.index.time')</td> </div>
<td>@lang('profiler::module.index.systemLoad')</td> </div>
<td></td>
</tr>
</thead>
<tbody>
@foreach($httpLog as $request)
<tr>
<td>{{$request->created_at->format('d.m.Y G:i')}}</td>
<td>{{$request->method}}</td>
<td>{{$request->url}}</td>
<td>{{number_format($request->time, 3)}} ms</td>
<td>{{$request->load_1}}, {{$request->load_5}}, {{$request->load_15}}</td>
<td>
<a href="{{route('queries.index', ['httpLog' => $request])}}">SQL</a>
</td>
</tr>
@endforeach
</tbody>
</table>
{!! $httpLog->render() !!}
@stop @stop
@@ -4,30 +4,34 @@
@section('content') @section('content')
<table class="table stripped"> <div class="card">
<thead> <div class="card-block">
<tr> <table class="table stripped">
<td>@lang('profiler::module.queries.createdAt')</td> <thead>
<td>@lang('profiler::module.queries.sql')</td> <tr>
<td>@lang('profiler::module.queries.binding')</td> <td>@lang('profiler::module.queries.sql')</td>
<td>@lang('profiler::module.queries.time')</td> <td>@lang('profiler::module.queries.time')</td>
<td></td> <td></td>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@foreach($queries as $query) @foreach($queries as $query)
<tr> <tr>
<td>{{$query->created_at->format('d.m.Y G:i')}}</td> <td>
<td>{{$query->query}}</td> @php $sql = $query->query; @endphp
<td> @foreach($query->bindings as $value)
@php $sql = preg_replace('/\?/', $value, $sql, 1); @endphp
@endforeach
{{var_export($query->bindings)}} {{$sql}}
</td> </td>
<td>{{number_format($query->time, 3)}} ms</td> <td>{{number_format($query->time, 3)}} ms</td>
</tr> </tr>
@endforeach @endforeach
</tbody> </tbody>
</table> </table>
</div>
</div>
@endsection @endsection
@@ -0,0 +1,92 @@
@extends('admin.layoutWithNavigation')
@section('pageHeading', trans('profiler::module.name'))
@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)}}</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"><h3>{{count($sameRequests)}} &times;</h3> volano</div>
<div class="col-sm-3"><h3>{{number_format($times['min'], 2)}} ms</h3> min</div>
<div class="col-sm-3"><h3>{{number_format($times['max'], 2)}} ms</h3> max</div>
<div class="col-sm-3"><h3>{{number_format($times['avg'], 2)}} ms</h3> prumer</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
+29 -29
View File
@@ -340,77 +340,77 @@ img {
} }
/*.tag {*/ /*.tag {*/
/*display: inline-block;*/ /*display: inline-block;*/
/*padding: 0.25em 0.4em;*/ /*padding: 0.25em 0.4em;*/
/*font-size: 75%;*/ /*font-size: 75%;*/
/*font-weight: bold;*/ /*font-weight: bold;*/
/*line-height: 1;*/ /*line-height: 1;*/
/*color: #FFF;*/ /*color: #FFF;*/
/*text-align: center;*/ /*text-align: center;*/
/*white-space: nowrap;*/ /*white-space: nowrap;*/
/*vertical-align: baseline;*/ /*vertical-align: baseline;*/
/*border-radius: 0.25rem;*/ /*border-radius: 0.25rem;*/
/*}*/ /*}*/
/*.tag:empty {*/ /*.tag:empty {*/
/*display: none;*/ /*display: none;*/
/*}*/ /*}*/
/*.btn .tag {*/ /*.btn .tag {*/
/*position: relative;*/ /*position: relative;*/
/*top: -1px;*/ /*top: -1px;*/
/*}*/ /*}*/
/*a.tag:focus, a.tag:hover {*/ /*a.tag:focus, a.tag:hover {*/
/*color: #FFF;*/ /*color: #FFF;*/
/*text-decoration: none;*/ /*text-decoration: none;*/
/*cursor: pointer;*/ /*cursor: pointer;*/
/*}*/ /*}*/
/*.tag-pill {*/ /*.tag-pill {*/
/*padding-right: 0.6em;*/ /*padding-right: 0.6em;*/
/*padding-left: 0.6em;*/ /*padding-left: 0.6em;*/
/*border-radius: 10rem;*/ /*border-radius: 10rem;*/
/*}*/ /*}*/
/*.tag-default {*/ /*.tag-default {*/
/*background-color: #818A91;*/ /*background-color: #818A91;*/
/*}*/ /*}*/
/*.tag-default[href]:focus, .tag-default[href]:hover {*/ /*.tag-default[href]:focus, .tag-default[href]:hover {*/
/*background-color: #687077;*/ /*background-color: #687077;*/
/*}*/ /*}*/
/*.tag-success {*/ /*.tag-success {*/
/*background-color: #5CB85C;*/ /*background-color: #5CB85C;*/
/*}*/ /*}*/
/*.tag-success[href]:focus, .tag-success[href]:hover {*/ /*.tag-success[href]:focus, .tag-success[href]:hover {*/
/*background-color: #449D44;*/ /*background-color: #449D44;*/
/*}*/ /*}*/
/*.tag-info {*/ /*.tag-info {*/
/*background-color: #5BC0DE;*/ /*background-color: #5BC0DE;*/
/*}*/ /*}*/
/*.tag-info[href]:focus, .tag-info[href]:hover {*/ /*.tag-info[href]:focus, .tag-info[href]:hover {*/
/*background-color: #31B0D5;*/ /*background-color: #31B0D5;*/
/*}*/ /*}*/
/*.tag-warning {*/ /*.tag-warning {*/
/*background-color: #F0AD4E;*/ /*background-color: #F0AD4E;*/
/*}*/ /*}*/
/*.tag-warning[href]:focus, .tag-warning[href]:hover {*/ /*.tag-warning[href]:focus, .tag-warning[href]:hover {*/
/*background-color: #EC971F;*/ /*background-color: #EC971F;*/
/*}*/ /*}*/
/*.tag-danger {*/ /*.tag-danger {*/
/*background-color: #D9534F;*/ /*background-color: #D9534F;*/
/*}*/ /*}*/
/*.tag-danger[href]:focus, .tag-danger[href]:hover {*/ /*.tag-danger[href]:focus, .tag-danger[href]:hover {*/
/*background-color: #C9302C;*/ /*background-color: #C9302C;*/
/*}*/ /*}*/