Login   Register  
PHP Classes
elePHPant
Icontem

File: logging.php

Recommend this page to a friend!
Stumble It! Stumble It! Bookmark in del.icio.us Bookmark in del.icio.us
  Classes of Junai Hassan  >  PHP Log File Database  >  logging.php  >  Download  
File: logging.php
Role: Application script
Content type: text/plain
Description: Class for logging
Class: PHP Log File Database
Log messages to files or to a MySQL database
Author: By
Last change:
Date: 1 year ago
Size: 12,048 bytes
 

Contents

Class file image Download
<?php

/*
 * Name : Logging 
 * Description : Implement file and database logging
 * Created by : Junaid Hassan, email : junaidhassanalvi@gmail.com, blog : junaidhassanalvi.wordpress.com
 * Created at : 28April2013
 * 
 * Change history : 
 */

class Logging {

    //jha-- define private variables
    private $unique_id;
    private $location;
    private $file_name;
    private $qualified_path;
    private $type;
    private $db_host;
    private $db_user;
    private $db_password;
    private $db_name;
    private $logs;
    private $concatenator;
    private $end_of_entry;
    private $level;
    private $retry_interval;
    private $retry_count;
    private $table_name;

    //jha-- constant define to used them as Enumeration
    //jha-- logs levels, given values according to there criticality
    //jha-- you can define as many logs levels you want 
    const Error = 4;
    const Warning = 3;
    const Debug = 2;
    const Info = 1;

    //jha-- logging types
    const DB = "Database";
    const File = "File";
    const FileAndDB = "File and database";

    //jha-- file types
    const Fixed = "Fixed";
    const Daily = "Daily";

    //jha-- some variables need to be initialized at any cost
    //jha-- here, you can change the default values of the variables
    function __construct() {
        $logs = array();
        
        //jha-- create unique id, it will be used to identify all logs from single instance
        $this->create_unique_id();

        //jha-- default logging level. it will all errors
        $this->level = 0;

        //jha-- if files is lock and used by another process
        //jha-- retry interval defines, how many times code will try to get file handle
        //jha-- retry count define, after what interval code will try to get file handle
        $this->retry_interval = 10;
        $this->retry_count = 10;


        $this->concatenator = PHP_EOL;
        $this->end_of_entry = PHP_EOL . '---------------------------------------------------------------------------' . PHP_EOL;
        $this->table_name = 'site_logs';
    }

    //jha-- there are setter methods for important variables
    //jha-- but this is the singal funtion used to initialized any varaibale
    public function set($location = '', $logging_type = '', $level = '', $db_host = '', $db_user = '', $db_password = '', $db_name = '', $file_name_type = '', $prefix = '', $postfix = '') {

        if ('' != $location) {
            $this->set_location($location);
        }

        if ('' != $logging_type) {
            $this->set_type($logging_type);
        }

        if ('' != $level) {
            $this->set_level($level);
        }

        if ('' != $db_host && '' != $db_user && '' != $db_password && '' != $db_name) {
            $this->set_db_credentails($db_host, $db_user, $db_password, $db_name);
        }

        if ('' != $file_name_type && '' != $prefix) {
            $this->set_file_name($file_name_type, $prefix, $postfix);
        }
    }

    //jha-- set file location
    public function set_location($location) {
        $location = str_replace("/", "\\", $location);

        if (!$this->endsWith($location, '\\')) {
            $location = $location . '\\';
        }

        if (!is_dir($location))
            mkdir($location);

        $this->location = $location;
    }

    //jha-- set type of logging required, coulde be database, logging or both
    public function set_type($type) {
        $this->type = $type;
    }

    //jha-- set logging level
    public function set_level($level) {
        $this->level = $level;
    }

    //jha-- set credentails to log messages into database
    public function set_db_credentails($db_host, $db_user, $db_password, $db_name) {
        $this->db_host = $db_host;
        $this->db_user = $db_user;
        $this->db_password = $db_password;
        $this->db_name = $db_name;
    }

    //jha-- set file name
    //jha-- filename can be fixed, in this case $prefix and $postfix just appended to form file name
    //jha-- filename can be Daily, for this current data stamp will be added betwen $postfix and $prefix to create file name 
    public function set_file_name($type, $prefix, $postfix = '') {
        if (self::Fixed)
            $this->file_name = $prefix + $postfix;
        if (self::Daily)
            $this->create_file_name($prefix, $postfix);

        //jha-- create full path
        $this->qualified_path = $this->location . $this->file_name;

        //jha-- create file if not exists
        if (!file_exists($this->qualified_path)) {
            $fh = fopen($this->qualified_path, 'w');
            if (!is_resource($fh)) {
                trigger_error("Unable to create file for logging");
            }
            fclose($fh);
        }
    }

    //jha-- set concatenator, used to concatenate message together
    public function set_concatenator($concatenator) {
        $this->concatenator = $concatenator;
    }

    //jha-- set end of entry, this is kind or marker that logs are finished here for singal transaction
    public function set_end_of_entry($end_of_entry) {
        $this->end_of_entry = $end_of_entry;
    }

    //jha-- public method to add messages in logs Array
    //jha-- some time user want to log only critical errors and not lower level like info and debugs logs
    //jha-- here user will pass the logs level and logs having that or higher level will be logged
    public function write($message, $level) {
        $this_level = intval($level);
        $global_level = intval($this->level);
        if ($this_level >= $global_level) {
            $current_date = array(
                'Y' => date('Y'),
                'm' => date('m'),
                'd' => date('d'),
                'H' => date('H'),
                'i' => date('i'),
                's' => date('s')
            );

            $this->logs[] = array('date' => $current_date, "message" => $message);
        }
    }

    //jha-- write data
    public function flush($clear, $end_of_entry) {

        //jha-- if any logs are written
        if (count($this->logs) > 0) {

            //jha-- if user wants file based logging
            if (self::File == $this->type || self::FileAndDB == $this->type) {
                $values = array();
                //jha-- create singal enrty
                foreach ($this->logs as $key => $val) {
                    $dt = $val['date'];
                    $dt_string = date($dt['Y'] . '-' . $dt['m'] . '-' . $dt['d'] . ' ' . $dt['H'] . ':' . $dt['i'] . ':' . $dt['s']);
                    $values[] .= $this->unique_id . ' :: ' . $dt_string . ' :: ' . $val['message'];
                }

                if (count($values) > 0) {
                    //jha-- create complete log for all entries
                    $message = implode($this->concatenator, $values);

                    //jha-- if true, append end of entry as marker
                    if ($end_of_entry) {
                        $message .= $this->end_of_entry;
                    }

                    //jha-- write to file
                    $this->write_file($message);
                }
            }

            //jha-- if user wants database logging
            if (self::DB == $this->type || self::FileAndDB == $this->type) {
                $que = 'INSERT INTO ' . $this->table_name . '(log_identifer,log_date,log_details) VALUES ';
                $values = array();

                //jha-- create insert values string for all entries
                foreach ($this->logs as $key => $val) {
                    $dt = $val['date'];
                    $dt_string = date($dt['Y'] . '-' . $dt['m'] . '-' . $dt['d'] . ' ' . $dt['H'] . ':' . $dt['i'] . ':' . $dt['s']);
                    $values[] = "('" . $this->unique_id . "','" . $dt_string . "','" . $val['message'] . "')";
                }


                if (count($values) > 0) {
                    //jha-- create complete query 
                    $que .= implode(',', $values);
                    //jha-- write to db
                    $this->write_db($que);
                }
            }
        }

        //jha-- if true, removes logs and clear logs array
        if ($clear) {
            $this->logs = array();
        }
    }

    //jha-- create file name if file type is Daily
    private function create_file_name($prefix, $postfix) {
        $stamp = date('Y') . date('m') . date('d');
        $this->file_name = $prefix . '-' . $stamp . $postfix;
    }

    //jha-- finds if $haystack is ends with $needle
    private function endsWith($haystack, $needle) {
        $length = strlen($needle);
        if ($length == 0) {
            return true;
        }
        return (substr($haystack, -$length) === $needle);
    }

    //jha-- write to file
    private function write_file($message) {

        //jha-- if logginf file exists, else raise notice
        
        if (file_exists($this->qualified_path)) {
            $has_written = false;
            $retry = intval($this->retry_count);
            $interval = intval($this->retry_interval);
            $i = 0;

            //jha-- while logs have been written or all retry counts spent
            while ($has_written === false && $i < $interval) {

                try {
                    //jha-- try to get file handle
                    $fh = fopen($this->qualified_path, 'a');

                    //jha-- do not get handle, throw excpetion
                    if (!is_resource($fh)) {
                        throw new Exception('Unable to get file handler');
                    }

                    //jha-- write to file
                    $result = fwrite($fh, $message);

                    //jha-- unable to write, throw exception
                    if (FALSE === $result) {
                        throw new Exception('Unable to append file');
                    }
                    fclose($fh);
                    $has_written = true;
                } catch (Exception $exc) {
                    trigger_error("Exception case");
                    //jha-- something went wrong, means logs were not written
                    $has_written = false;
                }
                
                //jha-- logs were not written yet, still have some retries, sleep for specified inteval
                if (!$has_written && $i < $interval - 1)
                    sleep($interval);

                $i++;
            }

            //jha-- if all retries spent and still messages has not written, raise notice
            if (!$has_written)
                trigger_error("Unable to do file logging");
        }else {
            //jha-- raise notice
            trigger_error("Unable to find logging file");
        }
    }

    //jha-- execute query, write to the database
    private function write_db($query) {
        $con = mysql_connect($this->db_host, $this->db_user, $this->db_password);
        if (!is_resource($con)) {
            trigger_error("Unable to connect to the database");
        }
        if (!mysql_select_db($this->db_name, $con))
            trigger_error("Unable to select the database");

        if (!mysql_query($query))
         trigger_error("Unable to insert logs into database");
        
    }

    //jha-- create unique id to identify all logs from singal instance
    private function create_unique_id() {
        $rand = 0;
        for ($i = 0; $i < 3; $i++) {
            $rand .= rand(10, 99);
        }
        $this->unique_id = uniqid($rand . '-');
    }

    //jha-- no matter what happens, flush function must be called when object is disposed to write any data in streams
    function __destruct() {
        $this->flush(true, true);
    }

}
?>