views:

40

answers:

1

So I want to find the best method of allowing my Logger class to access any part of the script either another class/function/etc... How would I do this? How do I make it global.

Could I do something like this:

Logger::info('Add message like this?');

Calling script: calling.php

require_once('Logger.class.php'); // Just adding the class initializes the Logger Object
require_once('Another.class.php');
require_once('Functions.php');

$logEntry->info("Log info");
$logEntry->error("Log error");
$logEntry->warning("Log warning");
$logEntry->notice("Log notice");

$logEntry->enableDebug(); // prints debug to log
$logEntry->debug("Log debug enabled");
$logEntry->disableDebug();
$logEntry->debug("Log debug disabled"); // will not print to log

$another_obj = new Another(); // want the Logger to have access inside this class
More(); // want the Logger to have access inside this function

Another.class.php

class Another {
   private $var;

   // I want to add the Logger here
   $logEntry->info("Another Log");

   // More code here it's just an example ...
}

Functions.php

function More() {
   // I want to add the Logger here
   $logEntry->info("More Log");
}

Here is the Logger.class.php script

<?php 
//Define Constants
define("LOG_FILE_DIRECTORY", "/var/www/logs");
ini_set("memory_limit","128M"); // Logger class is taking up memory

class Logger {
    private $log_file_directory = LOG_FILE_DIRECTORY;
    private $first_run;         // Flag to add line break at the beginning of script execution
    private $calling_script;    // Base name of the calling script
    private $log_file;          // log file path and name
    private $log_entry;         // information to be logged
    private $log_level;         // Log severity levels: error, warning, notice, debug, info
    private $fh;                // File handle
    private $file_name;         // File path and name
    private $file_parts;        // Array of $file_name
    private $script_name;       // Script Name
    private $script_parts;      // Array of $script_name
    private $line_number_arr;   // Line number of where the logging event occurred 
    private $debug_flag;        // Set to true if you want to log your debug logger

    function __construct() {
        $this->first_run        = true;
        $this->debug_flag       = false;
        $this->calling_script   = '';       
        $this->log_file         = '';
        $this->log_entry        = '';
        $this->log_level        = '';
        $this->fh               = '';
        $this->file_name        = '';
        $this->file_parts       = '';
        $this->script_name      = '';
        $this->script_parts     = '';   
        $this->line_number_arr  = '';   
    }

    /**
     * @enableDebug
     */
    public function enableDebug() {
        $this->debug_flag = true;
    }

    /**
     * @disbaleDebug
     */
    public function disableDebug() {
        $this->debug_flag = false;
    }

    /**
     * @info
     */
    public function info($message) {
        $this->log_level = 'info';
        $this->line_number_arr = debug_backtrace();
        $this->addEntry($message);
    }

    /**
     * @error
     */
    public function error($message) {
        $this->log_level = 'error';
        $this->line_number_arr = debug_backtrace();
        $this->addEntry($message);
    }

    /**
     * @warning
     */
    public function warning($message) {
        $this->log_level = 'warning';
        $this->line_number_arr = debug_backtrace();
        $this->addEntry($message);
    }

    /**
     * @notice
     */
    public function notice($message) {
        $this->log_level = 'notice';
        $this->line_number_arr = debug_backtrace();
        $this->addEntry($message);
    }

    /**
     * @debug
     * must add the below to the script you wish to debug
     * define("DEBUG", true); // true enables, false disables
     */
    public function debug($message) {
        if($this->debug_flag) {
            $this->log_level = 'debug';
            $this->line_number_arr = debug_backtrace();
            $this->addEntry($message);
        }       
    }

    private function addEntry($message) {
        $this->calling_script = $this->getScriptBaseName();
        $this->log_file = $this->log_file_directory."/".$this->calling_script.".log";
        $this->fh = fopen($this->log_file, 'a') or die("Can't open log file: ".$this->log_file);

        if($this->first_run) {
            $this->log_entry = "\n[" . date("Y-m-d H:i:s", mktime()) . "][line:".$this->line_number_arr[0]['line']."|".$this->log_level."]:\t".$message."\n";
        } else {
            $this->log_entry = "[" . date("Y-m-d H:i:s", mktime()) . "][line:".$this->line_number_arr[0]['line']."|".$this->log_level."]:\t".$message."\n";
        }   
        fwrite($this->fh, $this->log_entry);
        fclose($this->fh);

        $this->first_run = false;
    }

    /**
     * return the base name of the calling script
     */
    private function getScriptBaseName() {
        $this->file_name    = $_SERVER["SCRIPT_NAME"];
        $this->file_parts   = explode('/', $this->file_name);
        $this->script_name  = $this->file_parts[count($this->file_parts) - 1];
        $this->script_parts = explode('.', $this->script_name);

        // If file doesn't exists don't add line break
        if(!file_exists($this->script_parts[0].".log")) {
            $this->first_run = false;
        }
        return $this->script_parts[0];
    }
}

// Start log instance 
$logEntry = new Logger();

?>
+3  A: 

You could implement it as a class full of static functions, e.g.:

class Logger {
  protected $logfile = null;

  public static load() {
    self::$logfile = fopen('error.log', 'a');
  }

  public static info($msg) {
    if(self::$logfile == null)
      self::load();

    fwrite(self::$logfile, $msg);
  }
}

and then use it with Logger::info("My message..");. Another common method of doing this is using a singleton class, so that you can only create a single object of "Logger" and retrieve it using e.g. Logger::getInstance()->logInfo("My message");.

In your case (as you already implemented Logger as a normal class) I would make the __construct private and implement the class as a singleton. It's not possible to make $logEntry globally available. Your code would become:

<?php 
//Define Constants
define("LOG_FILE_DIRECTORY", "/var/www/logs");
ini_set("memory_limit","128M"); // Logger class is taking up memory

class Logger {
    private $log_file_directory = LOG_FILE_DIRECTORY;
    private $first_run;         // Flag to add line break at the beginning of script execution
    private $calling_script;    // Base name of the calling script
    private $log_file;          // log file path and name
    private $log_entry;         // information to be logged
    private $log_level;         // Log severity levels: error, warning, notice, debug, info
    private $fh;                // File handle
    private $file_name;         // File path and name
    private $file_parts;        // Array of $file_name
    private $script_name;       // Script Name
    private $script_parts;      // Array of $script_name
    private $line_number_arr;   // Line number of where the logging event occurred 
    private $debug_flag;        // Set to true if you want to log your debug logger
    private static $instance = null;

    private function __construct() {
        $this->first_run        = true;
        $this->debug_flag       = false;
        $this->calling_script   = '';       
        $this->log_file         = '';
        $this->log_entry        = '';
        $this->log_level        = '';
        $this->fh               = '';
        $this->file_name        = '';
        $this->file_parts       = '';
        $this->script_name      = '';
        $this->script_parts     = '';   
        $this->line_number_arr  = '';   
    }

    public static function getInstance() {
        if (!isset(self::$instance)) {
            $c = __CLASS__;
            self::$instance = new $c;
        }

        return self::$instance;
    }

    /**
     * @enableDebug
     */
    public function enableDebug() {
        $this->debug_flag = true;
    }

    /**
     * @disbaleDebug
     */
    public function disableDebug() {
        $this->debug_flag = false;
    }

    /**
     * @info
     */
    public function info($message) {
        $this->log_level = 'info';
        $this->line_number_arr = debug_backtrace();
        $this->addEntry($message);
    }

    /**
     * @error
     */
    public function error($message) {
        $this->log_level = 'error';
        $this->line_number_arr = debug_backtrace();
        $this->addEntry($message);
    }

    /**
     * @warning
     */
    public function warning($message) {
        $this->log_level = 'warning';
        $this->line_number_arr = debug_backtrace();
        $this->addEntry($message);
    }

    /**
     * @notice
     */
    public function notice($message) {
        $this->log_level = 'notice';
        $this->line_number_arr = debug_backtrace();
        $this->addEntry($message);
    }

    /**
     * @debug
     * must add the below to the script you wish to debug
     * define("DEBUG", true); // true enables, false disables
     */
    public function debug($message) {
        if($this->debug_flag) {
            $this->log_level = 'debug';
            $this->line_number_arr = debug_backtrace();
            $this->addEntry($message);
        }       
    }

    private function addEntry($message) {
        $this->calling_script = $this->getScriptBaseName();
        $this->log_file = $this->log_file_directory."/".$this->calling_script.".log";
        $this->fh = fopen($this->log_file, 'a') or die("Can't open log file: ".$this->log_file);

        if($this->first_run) {
            $this->log_entry = "\n[" . date("Y-m-d H:i:s", mktime()) . "][line:".$this->line_number_arr[0]['line']."|".$this->log_level."]:\t".$message."\n";
        } else {
            $this->log_entry = "[" . date("Y-m-d H:i:s", mktime()) . "][line:".$this->line_number_arr[0]['line']."|".$this->log_level."]:\t".$message."\n";
        }   
        fwrite($this->fh, $this->log_entry);
        fclose($this->fh);

        $this->first_run = false;
    }

    /**
     * return the base name of the calling script
     */
    private function getScriptBaseName() {
        $this->file_name    = $_SERVER["SCRIPT_NAME"];
        $this->file_parts   = explode('/', $this->file_name);
        $this->script_name  = $this->file_parts[count($this->file_parts) - 1];
        $this->script_parts = explode('.', $this->script_name);

        // If file doesn't exists don't add line break
        if(!file_exists($this->script_parts[0].".log")) {
            $this->first_run = false;
        }
        return $this->script_parts[0];
    }
}

?>

You would then use your class globally using Logger::getInstance()->info($msg);

halfdan
Wow that works great, Thanks!
Phill Pafford