aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--app/class/Logger.php94
-rw-r--r--index.php4
-rw-r--r--tests/LoggerTest.php228
4 files changed, 327 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index e8830c1..98ddd57 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
.vscode/*
.env
+*.log
*.bundle.js
*.bundle.js.map
assets/render/*
diff --git a/app/class/Logger.php b/app/class/Logger.php
new file mode 100644
index 0000000..939dbf8
--- /dev/null
+++ b/app/class/Logger.php
@@ -0,0 +1,94 @@
+<?php
+
+namespace Wcms;
+
+use Throwable;
+
+/**
+ * Class used to log messages.
+ * It must be init once at the very beginning of the application.
+ */
+class Logger
+{
+ private static $file = null;
+ private static $verbosity = 4;
+
+ /**
+ * Initialize the logger by openning the file and setting the log level.
+ *
+ * @param string $path the logfile's path
+ * @param int $verbosity 0: no log, 1: errors only, 2: add warn, 3: add info, 4: add debug.
+ */
+ public static function init(string $path, int $verbosity = 4)
+ {
+ self::$file = fopen($path, "a") or die("Unable to open log file!");
+ self::$verbosity = $verbosity;
+ }
+
+ protected static function write(string $level, string $msg, array $args = [])
+ {
+ $caller = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1];
+ $pwd = getcwd() . DIRECTORY_SEPARATOR;
+ $args = array_merge([
+ "[ $level ]",
+ str_replace($pwd, '', $caller['file']),
+ $caller['line']
+ ], $args);
+ vfprintf(self::$file, date('c') . " %-9s %s(%d) $msg\n", $args);
+ }
+
+ /**
+ * Log an error message using printf format.
+ */
+ public static function error(string $msg, ...$args)
+ {
+ if (self::$verbosity > 0) {
+ self::write('ERROR', $msg, $args);
+ }
+ }
+
+ /**
+ * Log a xarning message using printf format.
+ */
+ public static function warning(string $msg, ...$args)
+ {
+ if (self::$verbosity > 1) {
+ self::write('WARN', $msg, $args);
+ }
+ }
+
+ /**
+ * Log an info message using printf format.
+ */
+ public static function info(string $msg, ...$args)
+ {
+ if (self::$verbosity > 2) {
+ self::write('INFO', $msg, $args);
+ }
+ }
+
+ /**
+ * Log a debug message using printf format.
+ */
+ public static function debug(string $msg, ...$args)
+ {
+ if (self::$verbosity > 3) {
+ self::write('DEBUG', $msg, $args);
+ }
+ }
+
+ /**
+ * Log an exception.
+ */
+ public static function exception(Throwable $e, bool $withtrace = false)
+ {
+ if (self::$verbosity > 0) {
+ $msg = $e->getMessage();
+ if ($withtrace) {
+ // TODO: Maybe print a more beautiful stack trace.
+ $msg .= PHP_EOL . $e->getTraceAsString();
+ }
+ self::write('ERROR', $msg);
+ }
+ }
+}
diff --git a/index.php b/index.php
index f7f6843..fb05952 100644
--- a/index.php
+++ b/index.php
@@ -1,10 +1,13 @@
<?php
+use Wcms\Logger;
+
session_start();
require('./vendor/autoload.php');
+Logger::init('w_error.log', 2);
$app = new Wcms\Application();
$app->wakeup();
@@ -30,5 +33,6 @@ try {
if (isreportingerrors()) {
Sentry\captureException($e);
}
+ Logger::exception($e, true);
echo '<h1>⚠ Woops ! There is a little problem : </h1>', $e->getMessage(), "\n";
}
diff --git a/tests/LoggerTest.php b/tests/LoggerTest.php
new file mode 100644
index 0000000..18dcb02
--- /dev/null
+++ b/tests/LoggerTest.php
@@ -0,0 +1,228 @@
+<?php
+
+namespace Wcms\Tests;
+
+use Exception;
+use PHPUnit\Framework\TestCase;
+use Throwable;
+use Wcms\Logger;
+
+class LoggerTest extends TestCase
+{
+ protected $logfile = 'build/w_error.log';
+
+ protected function setUp(): void
+ {
+ parent::setUp();
+ if (file_exists($this->logfile)) {
+ unlink($this->logfile);
+ }
+ }
+
+ /**
+ * @test
+ */
+ public function initTest(): void
+ {
+ Logger::init($this->logfile);
+ $this->assertFileExists($this->logfile, 'Log file has not been created.');
+ $this->assertEmpty(file_get_contents($this->logfile));
+ }
+
+ /**
+ * @test
+ * @dataProvider errorNotLoggedProvider
+ */
+ public function errorNotLoggedTest(int $verbosity): void
+ {
+ Logger::init($this->logfile, $verbosity);
+ Logger::error('Error.');
+ $this->assertEmpty(file_get_contents($this->logfile));
+ }
+
+ public function errorNotLoggedProvider(): array
+ {
+ return [[0]];
+ }
+
+ /**
+ * @test
+ * @dataProvider errorLoggedProvider
+ */
+ public function errorLoggedTest(int $verbosity, string $msg, array $args, string $expected): void
+ {
+ Logger::init($this->logfile, $verbosity);
+ Logger::error($msg, ...$args);
+ $expected = " [ ERROR ] tests/LoggerTest.php(55) $expected\n";
+ $this->assertEquals($expected, substr(file_get_contents($this->logfile), 25));
+ }
+
+ public function errorLoggedProvider(): array
+ {
+ return [
+ [1, 'Error %s.', ['test'], 'Error test.'],
+ [2, 'Error %s %d.', ['test', 2], 'Error test 2.'],
+ [3, 'Error.', [], 'Error.'],
+ [4, 'Error.', [], 'Error.'],
+ ];
+ }
+
+ /**
+ * @test
+ * @dataProvider warningNotLoggedProvider
+ */
+ public function warningNotLoggedTest(int $verbosity): void
+ {
+ Logger::init($this->logfile, $verbosity);
+ Logger::warning('Error.');
+ $this->assertEmpty(file_get_contents($this->logfile));
+ }
+
+ public function warningNotLoggedProvider(): array
+ {
+ return [[0], [1]];
+ }
+
+ /**
+ * @test
+ * @dataProvider warningLoggedProvider
+ */
+ public function warningLoggedTest(int $verbosity, string $msg, array $args, string $expected): void
+ {
+ Logger::init($this->logfile, $verbosity);
+ Logger::warning($msg, ...$args);
+ $expected = " [ WARN ] tests/LoggerTest.php(93) $expected\n";
+ $this->assertEquals($expected, substr(file_get_contents($this->logfile), 25));
+ }
+
+ public function warningLoggedProvider(): array
+ {
+ return [
+ [2, 'Error %s.', ['test'], 'Error test.'],
+ [3, 'Error.', [], 'Error.'],
+ [4, 'Error.', [], 'Error.'],
+ ];
+ }
+
+ /**
+ * @test
+ * @dataProvider infoNotLoggedProvider
+ */
+ public function infoNotLoggedTest(int $verbosity): void
+ {
+ Logger::init($this->logfile, $verbosity);
+ Logger::info('Error.');
+ $this->assertEmpty(file_get_contents($this->logfile));
+ }
+
+ public function infoNotLoggedProvider(): array
+ {
+ return [[0], [1], [2]];
+ }
+
+ /**
+ * @test
+ * @dataProvider infoLoggedProvider
+ */
+ public function infoLoggedTest(int $verbosity, string $msg, array $args, string $expected): void
+ {
+ Logger::init($this->logfile, $verbosity);
+ Logger::info($msg, ...$args);
+ $expected = " [ INFO ] tests/LoggerTest.php(130) $expected\n";
+ $this->assertEquals($expected, substr(file_get_contents($this->logfile), 25));
+ }
+
+ public function infoLoggedProvider(): array
+ {
+ return [
+ [3, 'Error %s.', ['test'], 'Error test.'],
+ [4, 'Error.', [], 'Error.'],
+ ];
+ }
+
+ /**
+ * @test
+ * @dataProvider debugNotLoggedProvider
+ */
+ public function debugNotLoggedTest(int $verbosity): void
+ {
+ Logger::init($this->logfile, $verbosity);
+ Logger::debug('Error.');
+ $this->assertEmpty(file_get_contents($this->logfile));
+ }
+
+ public function debugNotLoggedProvider(): array
+ {
+ return [[0], [1], [2], [3]];
+ }
+
+ /**
+ * @test
+ * @dataProvider debugLoggedProvider
+ */
+ public function debugLoggedTest(int $verbosity, string $msg, array $args, string $expected): void
+ {
+ Logger::init($this->logfile, $verbosity);
+ Logger::debug($msg, ...$args);
+ $expected = " [ DEBUG ] tests/LoggerTest.php(166) $expected\n";
+ $this->assertEquals($expected, substr(file_get_contents($this->logfile), 25));
+ }
+
+ public function debugLoggedProvider(): array
+ {
+ return [
+ [4, 'Error %s.', ['test'], 'Error test.'],
+ ];
+ }
+
+ /**
+ * @test
+ * @dataProvider exceptionNotLoggedProvider
+ */
+ public function exceptionNotLoggedTest(int $verbosity): void
+ {
+ Logger::init($this->logfile, $verbosity);
+ Logger::exception(new Exception('Error'));
+ $this->assertEmpty(file_get_contents($this->logfile));
+ }
+
+ public function exceptionNotLoggedProvider(): array
+ {
+ return [[0]];
+ }
+
+ /**
+ * @test
+ * @dataProvider exceptionLoggedProvider
+ */
+ public function exceptionLoggedTest(int $verbosity, Throwable $e, string $expected)
+ {
+ Logger::init($this->logfile, $verbosity);
+ Logger::exception($e);
+ $expected = " [ ERROR ] tests/LoggerTest.php(201) $expected\n";
+ $this->assertEquals($expected, substr(file_get_contents($this->logfile), 25));
+ }
+
+ public function exceptionLoggedProvider(): array
+ {
+ return [
+ [1, new Exception('Test 1'), 'Test 1'],
+ [2, new Exception('Test 2'), 'Test 2'],
+ [3, new Exception('Test 3'), 'Test 3'],
+ [4, new Exception('Test 4'), 'Test 4'],
+ ];
+ }
+
+ /**
+ * @test
+ */
+ public function exceptionBacktraceTest(): void
+ {
+ Logger::init($this->logfile, 1);
+ Logger::exception(new Exception('Error'), true);
+ $content = file_get_contents($this->logfile);
+ $expected = " [ ERROR ] tests/LoggerTest.php(222) Error\n";
+ $this->assertEquals($expected, substr($content, 25, 43));
+ $this->assertRegExp('/(#\d+ [\w\/\.]*\(\d+\): .*\)\n)+#\d+ \{main\}\n/U', substr($content, 68));
+ }
+}