自定义PHP日志类保持双重写入错误消息


Custom PHP logging class keeps double writing error messages

我正在用PHP为我的网站编写一个自定义日志类,主要是为了有更多的编程经验,我有一个奇怪的问题,我无法解决。我用下面的方式调用这个类;

$objLogger = new logger(DIRECTORY_LOG, logger::DEBUG);
$objLogger->logDebug("Debug message 1", "Extra Notes Here");
$objLogger->logDebug("Debug message 2", "Extra Notes Here");

在加载页面后,日志文件显示(注意,它先是1-2,然后重复1-2);

2013-03-07 16:03:41 - DEBUG --> Debug message 1 ('Extra Notes Here')
2013-03-07 16:03:41 - DEBUG --> Debug message 2 ('Extra Notes Here')
2013-03-07 16:03:41 - DEBUG --> Debug message 1 ('Extra Notes Here')
2013-03-07 16:03:41 - DEBUG --> Debug message 2 ('Extra Notes Here')

我只调用了一次代码,它写了2行。我包括下面类的代码;

// Logging class to record data from the website into the daily log files
class logger {
    // Define and set the class constants
    const EMAIL = 0;        // Errors with sending/dealing with emails
    const DATABASE = 1;     // Errors with any sort of database work
    const SERVER = 2;       // 404 type server errors
    const INFO = 3;         // Basic information messages
    const SCRIPT = 4;       // Errors encountered by running scripts
    const DEBUG = 5;        // Debug messages
    const ARGUMENTS = 'none';
    // Define the static variables that may be used
    private static $permissions = 0777;             // File writing permissions
    private static $timestamp = 'Y-m-d G:i:s';      // Format for the log timestamp
    private static $date = 'Y-m-d';                 // Format for the file name
    // Define the variables that may be used
    private $pathway = null;
    private $status = false;
    private $file = null;
    // Construct the class object when it is called initially
    public function __construct($_directory, $_severity = self::SCRIPT) {
        // Create the full pathway to the log file to record to
        $this->pathway = $_directory . 'log_' . date(self::$date) . '.log';
        // Set the threshold for logging (match the severity level to record)
        $this->threshold = $_severity;
        // Check for and create the directory for the logs if not created already
        if (!file_exists($_directory)) {
            mkdir($_directory, self::$permissions, true);
        }
        // Check if the log file exists and can be written to
        if (file_exists($this->pathway) && !is_writable($this->pathway)) {
            // Set the flag so we don't attempt to write later
            $this->status = false;
        }
        // Open the log file for writting
        if (($this->file = fopen($this->pathway, 'a'))) {
            // Set the flag so we can write later
            $this->status = true;
        } else {
            // Set the flag so we don't attempt to write later
            $this->status = false;
        }
    }
    // Log: Debugging
    public function logDebug($_line, $_args = self::ARGUMENTS) {
        $this->writeLog($_line, self::DEBUG, $_args);
    }
    // Write the constructed string into the log file
    public function writeLog($_line, $_severity, $_args = self::ARGUMENTS) {
        // Check if we can write to the log file first
        if (!$this->status) {
            // There is some reason we cannot write to the log file
            return false;
        }
        // Check to make sure the severity is not higher then the threshold set earlier
        if ($_severity > $this->threshold) {
            // A message above the threshold is trying to log so ignore it
            return false;
        }
        // Build the string for the log
        $line = $this->buildString($_severity, $_line);
        // Check for and add any additional arguments if passed
        if ($_args !== self::ARGUMENTS) {
            $line .= ' (' . var_export($_args, true) . ')';
        }
        // Add the proper 'new line' character to the end of the line
        $line .= "'r'n";
        // Write to the log file
        if (fwrite($this->file, $line) === false) {
            // Writting to the log failed for some reason
            return false;
        }
    }
    // Return the string with in its constructed format
    private function buildString($_level, $_line) {
        // Build the timestamp
        $time = date(self::$timestamp);
        // Build the string based on the passed level
        switch ($_level) {
            case self::EMAIL:
                return "$time - EMAIL --> $_line";
            case self::DATABASE:
                return "$time - DATABASE --> $_line";
            case self::SERVER:
                return "$time - SERVER --> $_line";
            case self::INFO:
                return "$time - INFO --> $_line";
            case self::SCRIPT:
                return "$time - SCRIPT --> $_line";
            case self::DEBUG:
                return "$time - DEBUG --> $_line";
            default:
                return "$time - LOG --> $_line";
        }
    }
}

我真的可以使用一些帮助,我没有调用它两次,所以我不知道问题在哪里。我在网上看了一些例子,并使用了一些例子来构建这个,它似乎是正确运行。我在所有5个浏览器上都试过了,它做同样的事情。

代码看起来不错。如果您使用mod_rewrite通过一个PHP脚本重写所有请求,我猜浏览器正在向/favicon.ico发出第二个请求,这就是导致第二个日志条目的原因。验证这一点的最简单方法是将REQUEST_URI临时添加到日志数据中:

$objLogger->logDebug("Debug message 1", "Request: {$_SERVER['REQUEST_URI']}");