- Any-LLM Gateway setup with Docker Compose - Laravel 11 admin interface with Livewire - Dashboard with usage statistics and charts - Gateway Users management with budget tracking - API Keys management with revocation - Budget templates with assignment - Usage Logs with filtering and CSV export - Model Pricing management with calculator - PostgreSQL database integration - Complete authentication system for admins
188 lines
5.4 KiB
PHP
188 lines
5.4 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Models\UsageLog;
|
|
use App\Models\GatewayUser;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class UsageLogController extends Controller
|
|
{
|
|
/**
|
|
* Display a listing of usage logs with filters
|
|
*/
|
|
public function index(Request $request)
|
|
{
|
|
$query = UsageLog::with(['gatewayUser', 'apiKey']);
|
|
|
|
// Date Range Filter
|
|
if ($request->filled('date_from')) {
|
|
$query->where('timestamp', '>=', $request->date_from . ' 00:00:00');
|
|
}
|
|
|
|
if ($request->filled('date_to')) {
|
|
$query->where('timestamp', '<=', $request->date_to . ' 23:59:59');
|
|
}
|
|
|
|
// User Filter
|
|
if ($request->filled('user_id')) {
|
|
$query->where('user_id', $request->user_id);
|
|
}
|
|
|
|
// Provider Filter
|
|
if ($request->filled('provider')) {
|
|
$query->where('provider', $request->provider);
|
|
}
|
|
|
|
// Model Filter
|
|
if ($request->filled('model')) {
|
|
$query->where('model', $request->model);
|
|
}
|
|
|
|
// Status Filter
|
|
if ($request->filled('status')) {
|
|
if ($request->status === 'success') {
|
|
$query->success();
|
|
} elseif ($request->status === 'failed') {
|
|
$query->failed();
|
|
}
|
|
}
|
|
|
|
// Get filter options for dropdowns
|
|
$users = GatewayUser::select('user_id', 'alias')
|
|
->orderBy('alias')
|
|
->get();
|
|
|
|
$providers = UsageLog::select('provider')
|
|
->distinct()
|
|
->whereNotNull('provider')
|
|
->orderBy('provider')
|
|
->pluck('provider');
|
|
|
|
$models = UsageLog::select('model')
|
|
->distinct()
|
|
->whereNotNull('model')
|
|
->orderBy('model')
|
|
->pluck('model');
|
|
|
|
// Get summary statistics for current filter
|
|
$summary = $query->clone()
|
|
->selectRaw('
|
|
COUNT(*) as total_requests,
|
|
SUM(CASE WHEN status = \'success\' THEN 1 ELSE 0 END) as successful_requests,
|
|
SUM(prompt_tokens) as total_prompt_tokens,
|
|
SUM(completion_tokens) as total_completion_tokens,
|
|
SUM(total_tokens) as total_tokens,
|
|
SUM(cost) as total_cost
|
|
')
|
|
->first();
|
|
|
|
// Paginate results
|
|
$logs = $query->orderByDesc('timestamp')
|
|
->paginate(50)
|
|
->withQueryString(); // Preserve query parameters
|
|
|
|
return view('usage-logs.index', compact(
|
|
'logs',
|
|
'users',
|
|
'providers',
|
|
'models',
|
|
'summary'
|
|
));
|
|
}
|
|
|
|
/**
|
|
* Export usage logs to CSV
|
|
*/
|
|
public function export(Request $request)
|
|
{
|
|
$query = UsageLog::with(['gatewayUser', 'apiKey']);
|
|
|
|
// Apply same filters as index
|
|
if ($request->filled('date_from')) {
|
|
$query->where('timestamp', '>=', $request->date_from . ' 00:00:00');
|
|
}
|
|
|
|
if ($request->filled('date_to')) {
|
|
$query->where('timestamp', '<=', $request->date_to . ' 23:59:59');
|
|
}
|
|
|
|
if ($request->filled('user_id')) {
|
|
$query->where('user_id', $request->user_id);
|
|
}
|
|
|
|
if ($request->filled('provider')) {
|
|
$query->where('provider', $request->provider);
|
|
}
|
|
|
|
if ($request->filled('model')) {
|
|
$query->where('model', $request->model);
|
|
}
|
|
|
|
if ($request->filled('status')) {
|
|
if ($request->status === 'success') {
|
|
$query->success();
|
|
} elseif ($request->status === 'failed') {
|
|
$query->failed();
|
|
}
|
|
}
|
|
|
|
// Limit export to 10,000 records for performance
|
|
$logs = $query->orderByDesc('timestamp')
|
|
->limit(10000)
|
|
->get();
|
|
|
|
$filename = 'usage-logs-' . now()->format('Y-m-d-His') . '.csv';
|
|
|
|
$headers = [
|
|
'Content-Type' => 'text/csv',
|
|
'Content-Disposition' => "attachment; filename=\"{$filename}\"",
|
|
];
|
|
|
|
$callback = function() use ($logs) {
|
|
$file = fopen('php://output', 'w');
|
|
|
|
// CSV Header
|
|
fputcsv($file, [
|
|
'Timestamp',
|
|
'User ID',
|
|
'User Alias',
|
|
'API Key',
|
|
'Provider',
|
|
'Model',
|
|
'Endpoint',
|
|
'Prompt Tokens',
|
|
'Completion Tokens',
|
|
'Total Tokens',
|
|
'Cost',
|
|
'Status',
|
|
'Error Message'
|
|
]);
|
|
|
|
// CSV Rows
|
|
foreach ($logs as $log) {
|
|
fputcsv($file, [
|
|
$log->timestamp->format('Y-m-d H:i:s'),
|
|
$log->user_id,
|
|
$log->gatewayUser?->alias ?? 'N/A',
|
|
$log->api_key_id,
|
|
$log->provider,
|
|
$log->model,
|
|
$log->endpoint,
|
|
$log->prompt_tokens,
|
|
$log->completion_tokens,
|
|
$log->total_tokens,
|
|
$log->cost,
|
|
$log->status,
|
|
$log->error_message ?? ''
|
|
]);
|
|
}
|
|
|
|
fclose($file);
|
|
};
|
|
|
|
return response()->stream($callback, 200, $headers);
|
|
}
|
|
}
|