Skip to content

Commit d28e3ec

Browse files
committed
feat: log status code
1 parent 267855d commit d28e3ec

5 files changed

Lines changed: 43 additions & 36 deletions

File tree

app/Providers/EventServiceProvider.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
use Echo\Framework\Event\Model\ModelCreated;
1515
use Echo\Framework\Event\Model\ModelUpdated;
1616
use Echo\Framework\Event\Model\ModelDeleted;
17-
use Echo\Framework\Event\Http\RequestReceived;
17+
use Echo\Framework\Event\Http\ResponseSending;
1818
use Echo\Framework\Http\Listeners\ActivityListener;
1919

2020
/**
@@ -38,8 +38,8 @@ class EventServiceProvider extends BaseEventServiceProvider
3838
AuditListener::class,
3939
],
4040

41-
// HTTP activity logging
42-
RequestReceived::class => [
41+
// HTTP activity logging (on ResponseSending to capture status code)
42+
ResponseSending::class => [
4343
ActivityListener::class,
4444
],
4545

src/Framework/Http/Kernel.php

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,12 @@ public function handle(RequestInterface $request): ResponseInterface
2828

2929
// If there is no route, then 404
3030
if (is_null($route)) {
31-
return $this->renderer->renderNotFound($request);
31+
$response = $this->renderer->renderNotFound($request);
32+
try {
33+
event(new ResponseSending($request, $response));
34+
} catch (\Throwable) {
35+
}
36+
return $response;
3237
}
3338

3439
// Set the current route in the request
@@ -50,7 +55,12 @@ public function handle(RequestInterface $request): ResponseInterface
5055

5156
return $response;
5257
} catch (\Throwable $e) {
53-
return $this->renderer->renderException($e, $request);
58+
$response = $this->renderer->renderException($e, $request);
59+
try {
60+
event(new ResponseSending($request, $response));
61+
} catch (\Throwable) {
62+
}
63+
return $response;
5464
}
5565
}
5666

src/Framework/Http/Listeners/ActivityListener.php

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,33 @@
55
use App\Models\Activity;
66
use App\Services\GeoIpService;
77
use Echo\Framework\Event\EventInterface;
8-
use Echo\Framework\Event\Http\RequestReceived;
8+
use Echo\Framework\Event\Http\ResponseSending;
99
use Echo\Framework\Event\ListenerInterface;
1010

1111
/**
1212
* Activity Listener
1313
*
14-
* Logs HTTP request activity to the database.
15-
* Previously this logic was coupled directly in the LogActivity middleware.
14+
* Logs HTTP request activity to the database after the response is built.
15+
* Listens on ResponseSending so the HTTP status code is available.
1616
*/
1717
class ActivityListener implements ListenerInterface
1818
{
1919
public function handle(EventInterface $event): void
2020
{
21-
if (!$event instanceof RequestReceived) {
21+
if (!$event instanceof ResponseSending) {
2222
return;
2323
}
2424

2525
try {
2626
$request = $event->request;
27+
28+
// Skip logging for benchmark and debug routes
29+
$route = $request->getAttribute('route');
30+
$middleware = $route['middleware'] ?? [];
31+
if (is_array($middleware) && (in_array('benchmark', $middleware, true) || in_array('debug', $middleware, true))) {
32+
return;
33+
}
34+
2735
$user = user();
2836
$clientIp = $request->getClientIp();
2937

@@ -41,6 +49,7 @@ public function handle(EventInterface $event): void
4149
"uri" => $request->getUri(),
4250
"ip" => ip2long($clientIp),
4351
"country_code" => $countryCode,
52+
"status_code" => $event->response->getStatusCode(),
4453
]]);
4554
} catch (\Exception|\Error|\PDOException $e) {
4655
error_log("-- Skipping activity insert --");

src/Framework/Http/Middleware/LogActivity.php

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,36 +3,21 @@
33
namespace Echo\Framework\Http\Middleware;
44

55
use Closure;
6-
use Echo\Framework\Event\Http\RequestReceived;
76
use Echo\Framework\Http\RequestInterface;
87
use Echo\Framework\Http\ResponseInterface;
98
use Echo\Framework\Http\MiddlewareInterface;
109

1110
/**
1211
* LogActivity Middleware
1312
*
14-
* Dispatches a RequestReceived event for activity logging.
15-
* The actual logging is handled by the ActivityListener.
13+
* Activity logging is now handled by the ActivityListener on the
14+
* ResponseSending event, which has access to the HTTP status code.
15+
* This middleware remains as a passthrough for backward compatibility.
1616
*/
1717
class LogActivity implements MiddlewareInterface
1818
{
1919
public function handle(RequestInterface $request, Closure $next): ResponseInterface
2020
{
21-
$route = $request->getAttribute("route");
22-
$middleware = $route["middleware"] ?? [];
23-
24-
// Skip logging for benchmark and debug routes
25-
if (is_array($middleware) && (in_array('benchmark', $middleware, true) || in_array('debug', $middleware, true))) {
26-
return $next($request);
27-
}
28-
29-
// Dispatch RequestReceived event — listeners handle the logging
30-
try {
31-
event(new RequestReceived($request));
32-
} catch (\Throwable) {
33-
// Event dispatching should never break the request pipeline
34-
}
35-
3621
return $next($request);
3722
}
3823
}

tests/Http/Middleware/LogActivityIntegrationTest.php

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414
/**
1515
* Integration tests for LogActivity middleware
1616
*
17+
* Activity logging has moved to the ActivityListener on the ResponseSending
18+
* event. This middleware is now a passthrough — these tests verify it still
19+
* passes the request through the pipeline without interference.
20+
*
1721
* @runTestsInSeparateProcesses
1822
* @preserveGlobalState disabled
1923
*/
@@ -40,10 +44,10 @@ private function createRequest(array $route = []): Request
4044
return $request;
4145
}
4246

43-
private function createNextHandler(): Closure
47+
private function createNextHandler(int $statusCode = 200): Closure
4448
{
45-
return function ($request): ResponseInterface {
46-
return new Response('OK', 200);
49+
return function ($request) use ($statusCode): ResponseInterface {
50+
return new Response('OK', $statusCode);
4751
};
4852
}
4953

@@ -61,7 +65,7 @@ public function testNextHandlerIsCalledForWebRoutes(): void
6165
$this->assertTrue($called);
6266
}
6367

64-
public function testSkipsBenchmarkRoutes(): void
68+
public function testPassesThroughBenchmarkRoutes(): void
6569
{
6670
$called = false;
6771
$next = function ($request) use (&$called): ResponseInterface {
@@ -76,7 +80,7 @@ public function testSkipsBenchmarkRoutes(): void
7680
$this->assertEquals(200, $response->getStatusCode());
7781
}
7882

79-
public function testSkipsDebugRoutes(): void
83+
public function testPassesThroughDebugRoutes(): void
8084
{
8185
$called = false;
8286
$next = function ($request) use (&$called): ResponseInterface {
@@ -99,12 +103,11 @@ public function testResponsePassesThrough(): void
99103
$this->assertEquals(200, $response->getStatusCode());
100104
}
101105

102-
public function testHandlesEventDispatcherFailureGracefully(): void
106+
public function testPreservesResponseStatusCode(): void
103107
{
104-
// Even if event() throws, middleware should not break
105108
$request = $this->createRequest();
106-
$response = $this->middleware->handle($request, $this->createNextHandler());
109+
$response = $this->middleware->handle($request, $this->createNextHandler(404));
107110

108-
$this->assertEquals(200, $response->getStatusCode());
111+
$this->assertEquals(404, $response->getStatusCode());
109112
}
110113
}

0 commit comments

Comments
 (0)