Source of file Logger.php

Size: 7,032 Bytes - Last Modified: 2021-01-12T22:04:13+00:00

C:/Users/MAKS/Code/_PROJECTS/amqp-agent/src/Helper/Logger.php

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
Covered by 5 test(s):
  • MAKS\AmqpAgent\Tests\ClientTest::testGetLoggerInstance
  • MAKS\AmqpAgent\Tests\ClientTest::testGetInstanceByName
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGeneratingALogFileIfItDoesNotExistAndWritingToIt
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGettersAndSetters
56
Covered by 5 test(s):
  • MAKS\AmqpAgent\Tests\ClientTest::testGetLoggerInstance
  • MAKS\AmqpAgent\Tests\ClientTest::testGetInstanceByName
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGeneratingALogFileIfItDoesNotExistAndWritingToIt
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGettersAndSetters
57
Covered by 5 test(s):
  • MAKS\AmqpAgent\Tests\ClientTest::testGetLoggerInstance
  • MAKS\AmqpAgent\Tests\ClientTest::testGetInstanceByName
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGeneratingALogFileIfItDoesNotExistAndWritingToIt
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGettersAndSetters
58596061626364656667
Covered by 2 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGeneratingALogFileIfItDoesNotExistAndWritingToIt
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGettersAndSetters
686970717273747576
Covered by 1 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGettersAndSetters
77787980818283848586
Covered by 1 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGettersAndSetters
87
Covered by 1 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGettersAndSetters
888990919293949596
Covered by 1 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGettersAndSetters
979899100101102103104105106
Covered by 1 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGettersAndSetters
107
Covered by 1 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGettersAndSetters
108109110111112113114115116117118119120
Covered by 3 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGeneratingALogFileIfItDoesNotExistAndWritingToIt
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGettersAndSetters
121122
Covered by 3 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGeneratingALogFileIfItDoesNotExistAndWritingToIt
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGettersAndSetters
123
Covered by 1 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
124
Covered by 1 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
125126
Covered by 1 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
127
Covered by 1 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
128129
Covered by 1 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
130
Covered by 1 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
131132133134
Covered by 3 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGeneratingALogFileIfItDoesNotExistAndWritingToIt
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGettersAndSetters
135
Covered by 1 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
136
Covered by 1 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
137138
Covered by 1 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
139
Covered by 1 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
140141
Covered by 1 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
142
Covered by 1 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
143144145146
Covered by 3 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGeneratingALogFileIfItDoesNotExistAndWritingToIt
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGettersAndSetters
147148149
Covered by 3 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGeneratingALogFileIfItDoesNotExistAndWritingToIt
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGettersAndSetters
150
Covered by 3 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGeneratingALogFileIfItDoesNotExistAndWritingToIt
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGettersAndSetters
151
Covered by 3 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGeneratingALogFileIfItDoesNotExistAndWritingToIt
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGettersAndSetters
152
Covered by 3 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGeneratingALogFileIfItDoesNotExistAndWritingToIt
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGettersAndSetters
153154155156
Covered by 3 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGeneratingALogFileIfItDoesNotExistAndWritingToIt
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGettersAndSetters
157158159160161162163164165166167168169170171
Covered by 3 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGeneratingALogFileIfItDoesNotExistAndWritingToIt
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGettersAndSetters
172
Covered by 3 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGeneratingALogFileIfItDoesNotExistAndWritingToIt
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGettersAndSetters
173174
Covered by 3 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGeneratingALogFileIfItDoesNotExistAndWritingToIt
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGettersAndSetters
175
Covered by 3 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGeneratingALogFileIfItDoesNotExistAndWritingToIt
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGettersAndSetters
176
Covered by 3 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGeneratingALogFileIfItDoesNotExistAndWritingToIt
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGettersAndSetters
177
Covered by 3 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGeneratingALogFileIfItDoesNotExistAndWritingToIt
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGettersAndSetters
178
Covered by 3 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGeneratingALogFileIfItDoesNotExistAndWritingToIt
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGettersAndSetters
179180181182
Covered by 3 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGeneratingALogFileIfItDoesNotExistAndWritingToIt
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGettersAndSetters
183184185186187188189190191192
Covered by 1 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
193194195196197198199200201202
Covered by 1 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
203
Covered by 1 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
204
Covered by 1 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
205206
Covered by 1 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
207208209210211212213214215216217218
Covered by 3 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGeneratingALogFileIfItDoesNotExistAndWritingToIt
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGettersAndSetters
219
Covered by 3 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGeneratingALogFileIfItDoesNotExistAndWritingToIt
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGettersAndSetters
220
Covered by 3 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGeneratingALogFileIfItDoesNotExistAndWritingToIt
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGettersAndSetters
221
Covered by 3 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGeneratingALogFileIfItDoesNotExistAndWritingToIt
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGettersAndSetters
222223
Covered by 3 test(s):
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGeneratingALogFileIfItDoesNotExistAndWritingToIt
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testStaticCallingAndInsufficientCalling
  • MAKS\AmqpAgent\Tests\Helper\LoggerTest::testGettersAndSetters
224225226
<?php

/**
 * @author Marwan Al-Soltany <MarwanAlsoltany@gmail.com>
 * @copyright Marwan Al-Soltany 2020
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

declare(strict_types=1);

namespace MAKS\AmqpAgent\Helper;

use MAKS\AmqpAgent\Helper\Utility;

/**
 * A class to write logs, exposing methods that work statically and on instantiation.
 * This class DOES NOT implement `Psr\Log\LoggerInterface`.
 *
 * Example:
 * ```
 * // static
 * Logger::log('Some message to log.', 'filename', 'path/to/some/directory');
 * // instantiated
 * $logger = new Logger();
 * $logger->setFilename('filename');
 * $logger->setDirectory('path/to/some/directory');
 * $logger->write('Some message to log.');
 * ```
 *
 * @since 1.0.0
 */
class Logger
{
    /**
     * The filename of the log file.
     * @var string
     */
    public $filename;

    /**
     * The directory where the log file gets written.
     * @var string
     */
    public $directory;


    /**
     * Passing null for $directory will raise a warning and force the logger to find a reasonable directory to write the file in.
     * @param string|null $filename The name wished to be given to the file. Pass null for auto-generate.
     * @param string|null $directory The directory where the log file should be written.
     */
    public function __construct(?string $filename, ?string $directory)
    {
        $this->filename = $filename;
        $this->directory = $directory;
    }


    /**
     * Logs a message to a file, generates it if it does not exist and raises a user-level warning and/or notice on misuse.
     * @param string $message The message wished to be logged.
     * @return bool True on success.
     */
    public function write(string $message): bool
    {
        return self::log($message, $this->filename, $this->directory);
    }

    /**
     * Gets filename property.
     * @return string
     */
    public function getFilename()
    {
        return $this->filename;
    }

    /**
     * Sets filename property.
     * @param string $filename The filename.
     * @return self
     */
    public function setFilename(string $filename)
    {
        $this->filename = $filename;
        return $this;
    }

    /**
     * Gets directory property.
     * @return string
     */
    public function getDirectory()
    {
        return $this->directory;
    }

    /**
     * Sets directory property.
     * @param string $directory The directory.
     * @return self
     */
    public function setDirectory(string $directory)
    {
        $this->directory = $directory;
        return $this;
    }


    /**
     * Logs a message to a file, generates it if it does not exist and raises a user-level warning and/or notice on misuse.
     * @param string $message The message wished to be logged.
     * @param string|null $filename [optional] The name wished to be given to the file. If not provided a Notice will be raised with the auto-generated filename.
     * @param string|null $directory [optional] The directory where the log file should be written. If not provided a Warning will be raised with the used path.
     * @return bool True if message was written.
     */
    public static function log(string $message, ?string $filename = null, ?string $directory = null): bool
    {
        $passed = false;

        if (null === $filename) {
            $filename = self::getFallbackFilename();
            Utility::emit(
                [
                    'yellow' => sprintf('%s() was called without specifying a filename.', __METHOD__),
                    'green'  => sprintf('Log file will be named: "%s".', $filename)
                ],
                null,
                E_USER_NOTICE
            );
        }

        if (null === $directory) {
            $directory = self::getFallbackDirectory();
            Utility::emit(
                [
                    'yellow' => sprintf('%s() was called without specifying a directory.', __METHOD__),
                    'red'    => sprintf('Log file will be written in: "%s".', $directory)
                ],
                null,
                E_USER_WARNING
            );
        }

        $file = self::getNormalizedPath($directory, $filename);

        // create log file if it does not exist
        if (!is_file($file) && is_writable($directory)) {
            $signature = 'Created by ' . __METHOD__ . date('() \o\\n l jS \of F Y h:i:s A (Ymdhis)') . PHP_EOL;
            file_put_contents($file, $signature, 0, stream_context_create());
            chmod($file, 0775);
        }

        // write in the log file
        if (is_writable($file)) {
            // empty the the file if it exceeds 64MB
            // @codeCoverageIgnoreStart
            clearstatcache(true, $file);
            if (filesize($file) > 6.4e+7) {
                $stream = fopen($file, 'r');
                if (is_resource($stream)) {
                    $signature = fgets($stream) . 'For exceeding 64MB, it was overwritten on ' . date('l jS \of F Y h:i:s A (Ymdhis)') . PHP_EOL;
                    fclose($stream);
                    file_put_contents($file, $signature, 0, stream_context_create());
                    chmod($file, 0775);
                }
            }
            // @codeCoverageIgnoreEnd

            $timestamp = Utility::time()->format(DATE_ISO8601);
            $log = $timestamp . ' ' . $message . PHP_EOL;

            $stream = fopen($file, 'a+');
            if (is_resource($stream)) {
                fwrite($stream, $log);
                fclose($stream);
                $passed = true;
            }
        }

        return $passed;
    }

    /**
     * Returns a fallback filename based on date.
     * @since 1.2.1
     * @return string
     */
    protected static function getFallbackFilename(): string
    {
        return 'maks-amqp-agent-log-' . date("Ymd");
    }

    /**
     * Returns a fallback writing directory based on caller.
     * @since 1.2.1
     * @return string
     */
    protected static function getFallbackDirectory(): string
    {
        $backtrace = Utility::backtrace(['file'], 0);
        $fallback1 = strlen($_SERVER["DOCUMENT_ROOT"]) ? $_SERVER["DOCUMENT_ROOT"] : null;
        $fallback2 = isset($backtrace['file']) ? dirname($backtrace['file']) : __DIR__;

        return $fallback1 ?? $fallback2;
    }

    /**
     * Returns a normalized path based on OS.
     * @since 1.2.1
     * @param string $directory The directory.
     * @param string $filename The Filename.
     * @return string The full normalized path.
     */
    protected static function getNormalizedPath(string $directory, string $filename): string
    {
        $ext = '.log';
        $filename = substr($filename, -strlen($ext)) === $ext ? $filename : $filename . $ext;
        $directory = $directory . DIRECTORY_SEPARATOR;
        $path = $directory . $filename;

        return preg_replace("/\/+|\\+/", DIRECTORY_SEPARATOR, $path);
    }
}