diff --git a/app/Http/Controllers/ApiLogController.php b/app/Http/Controllers/ApiLogController.php index 753af441..4b8a2520 100644 --- a/app/Http/Controllers/ApiLogController.php +++ b/app/Http/Controllers/ApiLogController.php @@ -60,7 +60,18 @@ public function index(Request $request): View $logs = $query->paginate(50)->withQueryString(); - return view('api-logs.index', compact('logs', 'stats')); + // 현재 페이지 로그들의 그룹별 개수 조회 + $groupIds = $logs->pluck('group_id')->filter()->unique()->values()->toArray(); + $groupCounts = []; + if (!empty($groupIds)) { + $groupCounts = ApiRequestLog::whereIn('group_id', $groupIds) + ->selectRaw('group_id, COUNT(*) as count') + ->groupBy('group_id') + ->pluck('count', 'group_id') + ->toArray(); + } + + return view('api-logs.index', compact('logs', 'stats', 'groupCounts')); } /** @@ -75,7 +86,7 @@ public function show(int $id): View if ($log->group_id) { $groupLogs = ApiRequestLog::where('group_id', $log->group_id) ->where('id', '!=', $log->id) - ->orderBy('created_at') + ->orderByDesc('created_at') ->get(); } @@ -92,4 +103,15 @@ public function prune() return redirect()->route('dev-tools.api-logs.index') ->with('success', "{$deleted}개의 로그가 삭제되었습니다."); } + + /** + * 모든 로그 삭제 + */ + public function truncate() + { + $deleted = ApiRequestLog::truncate(); + + return redirect()->route('dev-tools.api-logs.index') + ->with('success', '모든 로그가 삭제되었습니다.'); + } } \ No newline at end of file diff --git a/resources/views/api-logs/index.blade.php b/resources/views/api-logs/index.blade.php index f2547054..2d3f7554 100644 --- a/resources/views/api-logs/index.blade.php +++ b/resources/views/api-logs/index.blade.php @@ -7,10 +7,16 @@

API 요청 로그

-
+ + @csrf + +
+
@csrf
@@ -97,72 +103,145 @@ class="w-full border rounded-lg px-3 py-2 text-sm">
- +
- - + + - - - - - - + + + + + + @forelse($logs as $log) - - + - - - - - - - - + + + + @empty @@ -182,4 +261,32 @@ class="text-purple-600 hover:text-purple-800" title="{{ $log->group_id }}"> @endif + + + + +@foreach($logs as $log) + @if($log->response_status >= 400) + + @endif +@endforeach @endsection \ No newline at end of file diff --git a/resources/views/api-logs/show.blade.php b/resources/views/api-logs/show.blade.php index a5506225..f6cffdf5 100644 --- a/resources/views/api-logs/show.blade.php +++ b/resources/views/api-logs/show.blade.php @@ -206,11 +206,18 @@ class="text-sm font-normal text-purple-600 hover:text-purple-800 ml-2">
@php $responseData = json_decode($log->response_body, true); + // json_decode 실패 시 유니코드 이스케이프를 한글로 변환하고 슬래시 이스케이프도 제거 + if ($responseData === null) { + $displayBody = preg_replace_callback('/\\\\u([0-9a-fA-F]{4})/', function($m) { + return mb_convert_encoding(pack('H*', $m[1]), 'UTF-8', 'UTF-16BE'); + }, $log->response_body); + $displayBody = str_replace('\\/', '/', $displayBody); + } @endphp @if($responseData)
{!! stripslashes(json_encode($responseData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)) !!}
@else -
{{ $log->response_body }}
+
{!! e($displayBody) !!}
@endif
diff --git a/routes/web.php b/routes/web.php index 1b01b9e1..a47a8bf4 100644 --- a/routes/web.php +++ b/routes/web.php @@ -267,6 +267,7 @@ Route::prefix('api-logs')->name('api-logs.')->group(function () { Route::get('/', [ApiLogController::class, 'index'])->name('index'); Route::post('/prune', [ApiLogController::class, 'prune'])->name('prune'); + Route::post('/truncate', [ApiLogController::class, 'truncate'])->name('truncate'); Route::get('/{id}', [ApiLogController::class, 'show'])->name('show'); });
시간메서드시간메서드 URL상태응답테넌트사용자그룹상태응답테넌트사용자그룹
+
{{ $log->created_at->format('H:i:s') }} + {{ $log->method }} - {{ $log->path }} + +
{{ $log->path }}
+ @php + $params = $log->request_body ?: $log->request_query ?: []; + if (is_array($params) && !empty($params)) { + $paramPairs = []; + foreach ($params as $key => $value) { + if (is_array($value)) { + $value = json_encode($value, JSON_UNESCAPED_UNICODE); + } + $paramPairs[] = $key . '=' . Str::limit((string)$value, 20); + } + $paramSummary = implode(', ', $paramPairs); + } else { + $paramSummary = ''; + } + @endphp + @if(!empty($paramSummary)) +
+ {{ $paramSummary }} +
+ @endif
+ {{ $log->response_status }} + {{ number_format($log->duration_ms) }}ms + @if($log->tenant) {{ Str::limit($log->tenant->company_name, 10) }} @else - @endif + @if($log->user) {{ $log->user->name ?? $log->user->email }} @else guest @endif - @if($log->group_id) + + @if($log->group_id && ($groupCounts[$log->group_id] ?? 0) >= 2) + class="text-purple-600 hover:text-purple-800" title="{{ $log->group_id }} ({{ $groupCounts[$log->group_id] }}개)"> + {{ $groupCounts[$log->group_id] }} @else - @endif - - 상세 - + +
+ @if($log->response_status >= 400) + + @endif + + + + + + +
+