Laravel 4.2: Logging all Requests and Responses to the database

A good chunk of our day to day business is maintenance of existing projects that are ‘bought and paid for’, so we find ourselves adding features to a Laravel 4.2 project we worked on a few years ago.

Logging all Requests and Responses

For API Debugging while we UAT our new release, we are recording all requests and responses made to our server. If anything goes wrong during UAT phase, we can find exactly what happened, correct the bug and write some new tests with no guess work whatsoever.

This is an invaluable tool when debugging, and is a great way to spend a few Mb in your database.

Creating the Request Logs table

 

<?php use Illuminate\Database\Migrations\Migration; 
use Illuminate\Database\Schema\Blueprint; 

class CreateRequestLogsTable extends Migration { 
/** * Run the migrations. * 
* @return void */ 
    public function up() { 
        Schema::create('request_logs', function(Blueprint $table) { $table->increments('id');
			$table->text('request');
			$table->text('response');
			$table->string('code', 10);
			$table->integer('took_ms');
			$table->text('uri');
			$table->string('ip', 24);
			$table->text('session');
			$table->timestamps();
		});
    }

	/**
	 * Reverse the migrations.
	 *
	 * @return void
	 */
	public function down()
	{
		Schema::drop('request_logs');
	}
}

Normal enough stuff.

We’re going to add an App::after filter to record the request, response, and a few other useful details. took_ms is super useful to keep an eye out for bad requests.

App::after(function($request, $response)
{
    $end = microtime(true) * 1000;
    $ip = $request->ip();

    if (array_key_exists("HTTP_CF_CONNECTING_IP", $_SERVER)) {
        $ip = $_SERVER["HTTP_CF_CONNECTING_IP"];
    }
    $record = [
        'uri' => $request->url(),
        'request' => json_encode($request->all()),
        'response' => $response->getContent(),
        'code' => $response->getStatusCode(),
        'ip' => $ip,
        'took_ms' => $end - (LARAVEL_START * 1000),
        'created_at' => date("Y-m-d H:i:s")
    ];
    \DB::table('request_logs')->insert($record);
});

You might notice above that we are translating the IP from the HTTP_CF_CONNECTING_IP header if possible. Most of our client apps sit behind CloudFlare, which obscures their IP, so we need to interrogate the headers.

 

Published