Last active
January 9, 2019 18:52
-
-
Save rcubitto/10e2c772922b448f1e174c0e3d430000 to your computer and use it in GitHub Desktop.
Class for "logging" data into a buffer in memory and then save all the logs into a file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Traits; | |
use App\Facades\FileLogger; | |
use Carbon\Carbon; | |
/** | |
* Makes easier the action of beginning/ending a file log. | |
* | |
* Class FileLoggable | |
* @package App\Traits | |
*/ | |
trait FileLoggable | |
{ | |
/** @var Carbon */ | |
protected $start; | |
/** @var Carbon */ | |
protected $end; | |
/** | |
* Clear existent entries and set the beginning time. | |
*/ | |
public function beginFileLog() | |
{ | |
$this->clearFileLog(); | |
$this->start = Carbon::now(); | |
FileLogger::logCentered($this->start->toFormattedDateString().' @ '.$this->start->format('h:i A'), '-'); | |
} | |
/** | |
* Log elapsed time and store the buffer into the storage path defined. | |
* | |
* @param string $storagePath | |
* @param string $filename | |
* @return string | |
*/ | |
public function endFileLog($storagePath, $filename) | |
{ | |
$end = Carbon::now(); | |
$timeElapsed = $this->start->diff($end); | |
$endLine = $end->toFormattedDateString() . ' @ ' . $end->format('h:i A'); | |
$endLine .= " | Time elapsed: $timeElapsed->h hours, $timeElapsed->i minutes, $timeElapsed->s seconds."; | |
FileLogger::logCentered($endLine, '-'); | |
return FileLogger::storeAs($storagePath, $filename); | |
} | |
//////////////////////////////////////////////////////////// | |
private function clearFileLog() | |
{ | |
FileLogger::clear(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Libraries; | |
use Carbon\Carbon; | |
use Illuminate\Support\Facades\Storage; | |
class FileLogger | |
{ | |
protected static $columns = 80; | |
/** | |
* A collection containing an element per line. | |
* | |
* @var \Illuminate\Support\Collection | |
*/ | |
protected $buffer; | |
/** | |
* Indicate if we are faking the usage of the logger. | |
* | |
* @var bool | |
*/ | |
protected $fake = false; | |
public function __construct() | |
{ | |
$this->buffer = collect(); | |
} | |
/** | |
* Mark the instance as a fake. | |
* | |
* @return FileLogger | |
*/ | |
public function fake() | |
{ | |
$this->fake = true; | |
return $this; | |
} | |
/** | |
* Store the buffer's content into a file. | |
* | |
* @param $path | |
* @return string | |
*/ | |
public function store($path) | |
{ | |
$filename = $this->generateFilename(); | |
return $this->storeAs($path, $filename); | |
} | |
/** | |
* Store the buffer's content into a file setting the file's name. | |
* | |
* @param $path | |
* @param $filename | |
* @return string | |
*/ | |
public function storeAs($path, $filename) | |
{ | |
$filepath = $this->sanitizePath($path) . $filename; | |
return $this->write($filepath); | |
} | |
/** | |
* Store a line into the logger's buffer. | |
* | |
* @param $col | |
* @param null $content | |
* @return $this | |
*/ | |
public function log($col, $content = null) | |
{ | |
if (!$content) { | |
$content = $col; | |
$col = 0; | |
} | |
$spaces = str_repeat(' ', $col); | |
$this->buffer->push($spaces . $content); | |
return $this; | |
} | |
/** | |
* Store an empty line into the logger's buffer. | |
* | |
* @param int $amount | |
* @return FileLogger | |
*/ | |
public function logBreak($amount = 1) | |
{ | |
for ($i = 1; $i <= $amount; $i++) { | |
$this->log(''); | |
} | |
return $this; | |
} | |
/** | |
* Store a horizontal line that works as a separator. | |
* | |
* @param string $separator | |
* @return FileLogger | |
*/ | |
public function logSeparator($separator = '-') | |
{ | |
return $this->log(str_repeat($separator, self::$columns)); | |
} | |
/** | |
* Store a centered text, with the possibility to set the wings on each side. | |
* | |
* @param $text | |
* @param string $leftSeparator | |
* @param null $rightSeparator | |
* @return FileLogger | |
*/ | |
public function logCentered($text, $leftSeparator = ' ', $rightSeparator = null) | |
{ | |
$rightSeparator = $rightSeparator ?: $leftSeparator; | |
$amountOfCharsEachSide = (self::$columns - strlen($text) - 2) / 2; | |
$amountOnTheLeft = floor($amountOfCharsEachSide); // 5.5 => 5.0 | |
$amountOnTheRight = round($amountOfCharsEachSide); // 5.5 => 6.0 we add the extra char on the right side. | |
$left = str_repeat($leftSeparator, $amountOnTheLeft); | |
$right = str_repeat($rightSeparator, $amountOnTheRight); | |
return $this->log("$left $text $right"); | |
} | |
/** | |
* @return \Illuminate\Support\Collection | |
*/ | |
public function buffer() | |
{ | |
return $this->buffer; | |
} | |
/** | |
* Clear all the logged entries from the buffer. | |
* | |
* @return $this | |
*/ | |
public function clear() | |
{ | |
$this->buffer = collect(); | |
return $this; | |
} | |
// Private Methods //////////////////////////////////////////////////////////// | |
/** | |
* Adds a trailing slash to the end of the path, if missing. | |
* | |
* @param $path | |
* @return string | |
*/ | |
private function sanitizePath($path) | |
{ | |
return ends_with($path, '/') ? $path : ($path . '/'); | |
} | |
/** | |
* Write the content of the logger to the corresponding filepath. | |
* | |
* @param $filepath | |
* @return string | |
*/ | |
private function write($filepath) | |
{ | |
// If we have the fake flag on, that means we want to fake the usage of the logger. | |
// That's why we prevent storing real files and clearing the buffer. | |
// The idea is to make assertions directly to the buffer. | |
if ($this->fake) { | |
return $filepath; | |
} | |
Storage::put($filepath, $this->buffer()->implode(PHP_EOL)); | |
$this->clear(); | |
return $filepath; | |
} | |
/** | |
* Generate a random file name using current timestamp. | |
* | |
* @return string | |
*/ | |
private function generateFilename() | |
{ | |
return Carbon::now()->format('YmdHis') . '.txt'; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Facades; | |
use Illuminate\Support\Facades\Facade; | |
class FileLogger extends Facade | |
{ | |
/** | |
* Get the registered name of the component. | |
* | |
* @return string | |
*/ | |
protected static function getFacadeAccessor() { return 'filelogger'; } | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Tests\Feature; | |
use App\Facades\FileLogger; | |
use Illuminate\Support\Facades\Storage; | |
class FileLoggerTest extends TestCase | |
{ | |
/** | |
* Storage relative path where we store invoice files -> storage/app/invoices | |
* | |
* @var string | |
*/ | |
protected $storagePath = 'invoices'; | |
/** | |
* Remove storage path with all its files. | |
*/ | |
public function tearDown() | |
{ | |
\Storage::deleteDirectory($this->storagePath); | |
parent::tearDown(); | |
} | |
// Tests /////////////////////////////////////////////////////////////// | |
/** @test */ | |
public function set_the_storage_path_when_storing_a_file() | |
{ | |
$filepath = FileLogger::store($this->storagePath); | |
$this->assertFileInStorage($filepath); | |
} | |
/** @test */ | |
public function set_the_name_of_the_file_to_store() | |
{ | |
$filepath = FileLogger::storeAs($this->storagePath, 'foo.txt'); | |
$this->assertFileInStorage($filepath); | |
$this->assertTrue(ends_with($filepath, 'foo.txt')); | |
} | |
/** @test */ | |
public function set_a_line_into_the_buffer_setting_the_colum_space() | |
{ | |
FileLogger::log(1, 'Hello World'); // ' Hello World' (4 spaces = 1 unit) | |
$buffer = FileLogger::buffer(); | |
$this->assertTrue($buffer instanceof \Illuminate\Support\Collection); | |
$this->assertEquals(1, $buffer->count()); | |
$this->assertEquals(' Hello World', $buffer->first()); | |
} | |
/** @test */ | |
public function set_various_lines_into_the_buffer() | |
{ | |
FileLogger::log(1, 'Hello World'); | |
FileLogger::log(2, 'Foo'); | |
FileLogger::log('First line without any indent'); | |
$buffer = FileLogger::buffer(); | |
$this->assertEquals(3, $buffer->count()); | |
$this->assertEquals(' Hello World', $buffer->first()); | |
$this->assertEquals(' Foo', $buffer->get(1)); | |
$this->assertEquals('First line without any indent', $buffer->get(2)); | |
} | |
/** @test */ | |
public function log_a_couple_of_lines_and_store_them_in_a_file() | |
{ | |
FileLogger::log(1, 'Hello World'); | |
FileLogger::log(2, 'Foo'); | |
FileLogger::log('First line without any indent'); | |
$filename = FileLogger::store($this->storagePath); | |
$content = Storage::get($filename); | |
$this->assertEquals(" Hello World\n Foo\nFirst line without any indent", $content); | |
} | |
/** @test */ | |
public function log_a_couple_of_lines_and_choose_the_name_of_the_file() | |
{ | |
FileLogger::log(1, 'Hello World'); | |
FileLogger::log(2, 'Foo'); | |
FileLogger::log('First line without any indent'); | |
FileLogger::storeAs($this->storagePath, 'test.txt'); | |
$content = Storage::get('invoices/test.txt'); | |
$this->assertEquals(" Hello World\n Foo\nFirst line without any indent", $content); | |
} | |
/** @test */ | |
public function log_empty_lines() | |
{ | |
FileLogger::log('Foo'); | |
FileLogger::logBreak(); | |
FileLogger::log(1, 'Bar'); | |
FileLogger::logBreak(); | |
FileLogger::log('Baz'); | |
$buffer = FileLogger::buffer(); | |
$this->assertEquals('Foo', $buffer->first()); | |
$this->assertEquals('', $buffer->get(1)); | |
$this->assertEquals(' Bar', $buffer->get(2)); | |
$this->assertEquals('', $buffer->get(3)); | |
$this->assertEquals('Baz', $buffer->get(4)); | |
} | |
/** @test */ | |
public function log_a_centered_text() | |
{ | |
FileLogger::logCentered('SomeRandomString'); | |
$buffer = FileLogger::buffer(); | |
$this->assertEquals(' SomeRandomString ', $buffer->first()); | |
} | |
/** @test */ | |
public function log_a_centered_text_and_set_the_wings() | |
{ | |
FileLogger::logCentered('FooBarBaz', '-'); | |
$buffer = FileLogger::buffer(); | |
$this->assertEquals('---------------------------------- FooBarBaz -----------------------------------', $buffer->first()); | |
} | |
/** @test */ | |
public function log_a_centered_text_and_set_different_wings_on_each_side() | |
{ | |
FileLogger::logCentered('FooBarBaz', '>', '<'); | |
$buffer = FileLogger::buffer(); | |
$this->assertEquals('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> FooBarBaz <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<', $buffer->first()); | |
} | |
/** @test */ | |
public function clear_the_buffer_after_storing_to_a_file() | |
{ | |
FileLogger::log('Foo'); | |
FileLogger::store($this->storagePath); | |
$this->assertTrue(FileLogger::buffer()->isEmpty()); | |
} | |
// Private Methods //////////////////////////////////////////////// | |
/** | |
* @param $filepath | |
*/ | |
public function assertFileInStorage($filepath) | |
{ | |
$this->assertTrue( | |
file_exists(storage_path('app/' . $filepath)), | |
"Failed asserting that the file {$filepath} exists." | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment