Skip to content

Commit

Permalink
feat(history): Log & stats for API calls
Browse files Browse the repository at this point in the history
  • Loading branch information
zooley committed Jan 22, 2024
1 parent e187fee commit dfc3a8f
Show file tree
Hide file tree
Showing 9 changed files with 1,015 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ public function index(StatefulRequest $request)

$apps = Log::query()
->select(DB::raw('DISTINCT(app)'))
->where('app', '!=', 'api')
->get();

return view('history::admin.activity.index', [
Expand Down
227 changes: 227 additions & 0 deletions app/Modules/History/Http/Controllers/Admin/ApiController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
<?php

namespace App\Modules\History\Http\Controllers\Admin;

use Illuminate\Http\Request;
use Illuminate\Http\RedirectResponse;
use Illuminate\Contracts\View\View;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\DB;
use App\Halcyon\Http\StatefulRequest;
use App\Modules\History\Models\Log;
use Carbon\Carbon;

class ApiController extends Controller
{
/**
* Display a listing of the resource.
*
* @param StatefulRequest $request
* @return View
*/
public function index(StatefulRequest $request)
{
// Get filters
$filters = array(
'search' => null,
'app' => null,
'limit' => config('list_limit', 20),
'page' => 1,
'order' => Log::$orderBy,
'order_dir' => Log::$orderDir,
'action' => '',
'transport' => '',
'status' => '',
);

$reset = false;
$request = $request->mergeWithBase();
foreach ($filters as $key => $default)
{
if ($key != 'page'
&& $request->has($key) //&& session()->has('history.api.filter_' . $key)
&& $request->input($key) != session()->get('history.api.filter_' . $key))
{
$reset = true;
}
$filters[$key] = $request->state('history.api.filter_' . $key, $key, $default);
}
$filters['page'] = $reset ? 1 : $filters['page'];

if (!in_array($filters['order'], ['id', 'name']))
{
$filters['order'] = Log::$orderBy;
}

if (!in_array($filters['order_dir'], ['asc', 'desc']))
{
$filters['order_dir'] = Log::$orderDir;
}

$query = Log::query()
->where('app', '=', 'api');

if ($filters['search'])
{
$query->where(function($query) use ($filters)
{
$query->where('classname', 'like', '%' . $filters['search'] . '%')
->orWhere('classmethod', 'like', '%' . $filters['search'] . '%')
->orWhere('uri', 'like', '%' . $filters['search'] . '%');
});
}

if ($filters['transport'])
{
$query->where('transportmethod', '=', $filters['transport']);
}

if ($filters['status'])
{
$query->where('status', '=', $filters['status']);
}

$rows = $query
->orderBy($filters['order'], $filters['order_dir'])
->paginate($filters['limit'], ['*'], 'page', $filters['page']);

$types = Log::query()
->select('classname')
->where('app', '=', 'api')
->distinct()
->orderBy('classname', 'asc')
->get();

return view('history::admin.api.index', [
'filters' => $filters,
'rows' => $rows,
'types' => $types,
]);
}

/**
* Show the form for editing the specified entry
*
* @param int $id
* @return View
*/
public function show($id)
{
$row = Log::findOrFail($id);

return view('history::admin.api.show', [
'row' => $row
]);
}

/**
* Show the form for editing the specified resource.
*
* @return View
*/
public function stats(Request $request)
{
$start = Carbon::now()->modify('-1 month');
$today = Carbon::now()->modify('+1 day');

// Get filters
$filters = array(
'start' => $start->format('Y-m-d'),
'end' => $today->format('Y-m-d'),
);

foreach ($filters as $key => $default)
{
$filters[$key] = $request->input($key, $default);
}

if ($filters['end'] < $filters['start'])
{
$request->session()->flash('error', trans('history::history.errors.end cannot be before start'));
$filters['end'] = Carbon::parse($filters['start'])->modify('+1 week')->format('Y-m-d');
}

$methods = array(
'GET',
'POST',
'PUT',
'DELETE',
'HEAD',
);

$stats = array();

$stats['made'] = Log::query()
->where('app', '=', 'api')
->where('datetime', '>=', $filters['start'])
->where('datetime', '<', $filters['end'])
->count();

$stats['errors'] = Log::query()
->where('app', '=', 'api')
->where('datetime', '>=', $filters['start'])
->where('datetime', '<', $filters['end'])
->where('status', '>=', 400)
->count();

$stats['ips'] = Log::query()
->select('ip', DB::raw('COUNT(*) AS requests'))
->where('app', '=', 'api')
->where('datetime', '>=', $filters['start'])
->where('datetime', '<', $filters['end'])
->groupBy('ip')
->orderBy('requests', 'desc')
->limit(20)
->get();

$stats['uris'] = Log::query()
->select('uri', DB::raw('COUNT(*) AS requests'))
->where('app', '=', 'api')
->where('datetime', '>=', $filters['start'])
->where('datetime', '<', $filters['end'])
->groupBy('uri')
->orderBy('requests', 'desc')
->limit(20)
->get();

foreach ($methods as $method)
{
$stats['methods'][$method] = Log::query()
->where('app', '=', 'api')
->where('transportmethod', '=', $method)
->where('datetime', '>=', $filters['start'])
->where('datetime', '<', $filters['end'])
->count();
}

$stats['daily'] = array();

$start = Carbon::parse($filters['start']);
$stop = Carbon::parse($filters['end']);
$timeframe = round(($stop->timestamp - $start->timestamp) / (60 * 60 * 24));

$now = Carbon::now();
$placed = array();
for ($d = $timeframe; $d >= 0; $d--)
{
$yesterday = Carbon::now()->modify('- ' . $d . ' days');
$tomorrow = Carbon::now()->modify(($d ? '- ' . ($d - 1) : '+ 1') . ' days');

$query = Log::query()
->where('app', '=', 'api');

$placed[$yesterday->format('Y-m-d')] = $query
->where('datetime', '>', $yesterday->format('Y-m-d') . ' 00:00:00')
->where('datetime', '<', $tomorrow->format('Y-m-d') . ' 00:00:00')
->count();
}

$stats['daily'] = $placed;

return view('history::admin.api.stats', [
'methods' => $methods,
'filters' => $filters,
'stats' => $stats,
]);
}
}
10 changes: 10 additions & 0 deletions app/Modules/History/Resources/lang/en/history.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,14 @@
'recipient' => 'Recipient',
'data' => 'Data',
'message' => 'Message',
'api' => 'API',
'requests' => 'Requests',
'stats' => 'Stats',
'payload' => 'Payload',
'objectid' => 'Object ID',
'errors' => 'Errors',
'success' => 'Success',
'start date' => 'Start date',
'end date' => 'End date',
'back' => 'Back',
];
18 changes: 15 additions & 3 deletions app/Modules/History/Resources/views/admin/activity/show.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
@section('toolbar')
{!!
Toolbar::spacer();
Toolbar::cancel(route('admin.history.activity.cancel'));
Toolbar::link('back', trans('history::history.back'), route('admin.history.api'), false);
!!}

{!! Toolbar::render() !!}
Expand Down Expand Up @@ -85,7 +85,7 @@
</div>

<div class="form-group">
<label for="field-datetime">{{ trans('history::history.datetime') }}</label>
<label for="field-datetime">{{ trans('history::history.timestamp') }}</label>
<input type="text" name="fields[datetime]" id="field-datetime" class="form-control" disabled="disabled" readonly="readonly" value="{{ $row->datetime }}" />
</div>
</fieldset>
Expand All @@ -94,11 +94,23 @@

<fieldset class="adminform">
<legend>{{ trans('history::history.changes') }}</legend>
<?php
$payload = $row->payload;
if ($row->jsonPayload)
{
$payload = $row->jsonPayload;
if (isset($payload->api_token))
{
$payload->api_token = '<TOKEN>';
}
$payload = json_encode($payload, JSON_PRETTY_PRINT);
}
?>
<div class="row">
<div class="col-md-12">
<div class="form-group">
<label for="field-payload">{{ trans('history::history.payload') }}</label>
<textarea name="fields[payload]" id="field-payload" class="form-control" disabled="disabled" readonly="readonly" rows="20" cols="40">{{ $row->payload }}</textarea>
<textarea name="fields[payload]" id="field-payload" class="form-control" disabled="disabled" readonly="readonly" rows="20" cols="40">{{ $payload }}</textarea>
</div>
</div>
</div>
Expand Down
Loading

0 comments on commit dfc3a8f

Please sign in to comment.