日志工具类

原创
2013/11/01 19:29
阅读数 370
今天自己写了一个日志工具类,参考了 CI 的 Log.php、官方文档和 http://hqlong.com/2009/01/530.html,希望大家提出宝贵意见。

下载

源码
<?php
date_default_timezone_set("Asia/ShangHai");
/**
  * 日志通用类
  * 
  * 使用示例:
  * require 'LogUtil.php';
  * LogUtil::get_instance()->debug('debug msg');
  * output:
  * [2013-11-01 18:31:03][DEBUG][127.0.0.1][LogUtil.php:151][/LogUtil.php][debug msg]
  * wei.chungwei@gmail.com
  * 2013-11-01
  */
class LogUtil {

	private static $_instance;
	private $_log_dir = "./"; // 日志路径,默认是当前路径
	private $_log_max_size = 1 << 30; // 单个日志文件大小,默认1G
    private $_log_max_num = 1; // 日志数量,必须大于等于1,调试状态建议设为1

	private function __construct() {}

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

		return self::$_instance;
	}

	public function __clone(){
        trigger_error('Clone is not allowed.', E_USER_ERROR);
    }

    public function free() {
    	self::$_instance = null;
    }

    public function debug($msg) {
    	$time = time();
        $log_name = $this->get_log_name($time);
        $this->check_file_size($time, $log_file);
    	$log_msg = $this->format_log_msg($msg, $time, "DEBUG");
    	$this->write_log($time, $log_name, $log_msg);
    }

    public function fatal($msg) {
    	$time = time();
        $log_name = $this->get_log_name($time);
        $this->check_file_size($time, $log_file);
    	$log_msg = $this->format_log_msg($msg, $time, "FATAL");
    	$this->write_log($time, $log_name, $log_msg);
    	$this->free();
    }

    public function warn($msg) {
    	$time = time();
        $log_name = $this->get_log_name($time);
        $this->check_file_size($time, $log_file);
    	$log_msg = $this->format_log_msg($msg, $time, "WARN");
    	$this->write_log($time, $log_name, $log_msg);
    }

    public function info($msg) {
    	$time = time();
        $log_name = $this->get_log_name($time);
        $this->check_file_size($time, $log_name);
    	$log_msg = $this->format_log_msg($msg, $time, "INFO");
    	$this->write_log($time, $log_name, $log_msg);
    }

	/**
	  * 获取日志文件名称
	  * 文件名称格式=当前日期+随机数.log
	  * 以避免单个日志文件过大
	  */
    private function get_log_name($time) {
        $seq_num = rand(1, $this->_log_max_num);
        return $this->_log_dir . date("Y-m-d", $time) . "-{$seq_num}.log";
    }
	
	/**
	  * 格式化日志信息
	  */
    private function format_log_msg($msg, $time, $priority) {
    	$datetime = date("Y-m-d H:i:s", $time);
    	$priority = strtoupper(trim($priority));
    	$ip = get_user_ip();
    	$arr_trace = debug_backtrace();
    	$trace = end($arr_trace);
    	$file = basename($trace['file']);
    	$line = $trace['line'];
    	$uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
    	return "[{$datetime}] [{$priority}] [{$ip}] [{$file}:{$line}] [{$uri}] [{$msg}]" . PHP_EOL;
    }
	
	/**
	  * 检测单个日志文件大小,大于1G则重命名该日志文件
	  * 这样可以避免对大文件的读写过慢
	  */
    private function check_file_size($time, $log_name) {
    	try {
    		if (file_exists($log_name) && filesize($log_name) >= $this->_log_max_size) {
		    	// if log size >= 1GB(default), 
		    	// then rename this file and make it readonly
		    	$rename_log_file = $this->_log_dir . date("Y-m-d H:i:s", $time) . '.log';
		    	rename($log_name, $rename_log_file);
		    	chmod($rename_log_file, 0444); // 只有可读权限
		    }
    	} catch (Exception $e) {
    		die('error accoured at ' . basename(__FILE__) . ':' . __LINE__ . " with msg : " . $e->getMessage());
    	}
    	
    }
	
	/**
	  * 将日志信息写入文件
	  */
    private function write_log($time, $log_name, $log_msg = "") {
    	try {	    	
            if ($fp = fopen($log_name, 'a')) {
				// 以下代码对文件加锁,1ms内加锁失败,继续枷锁;
				// 超过1ms则让出锁给其他进程
                $start_time = microtime();
                do {
                    $lock = flock($fp, LOCK_EX);
                    if(!$lock) {
                        usleep(rand(10, 30000));
                    }
                } while ((!$lock) && ((microtime() - $start_time) < 1000));
                if ($lock) {
                  fwrite($fp, $log_msg);
                  flock($fp, LOCK_UN);
                }
                fclose($fp);
                chmod($log_name, 0666);
            } else {
                die("open {$log_name} failed at " . basename(__FILE__) . " line " . __LINE__);
            }
	    	clearstatcache();
    	} catch (Exception $e) {
    		die('error accoured at ' . basename(__FILE__) . ':' . __LINE__ . " with msg : " . $e->getMessage());
    	}
    }
}

/**
  * 获取用户ip
  */
function get_user_ip() {
    if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
    } elseif (isset($_SERVER['HTTP_CLIENTIP'])) {
        $ip = $_SERVER['HTTP_CLIENTIP'];
    } elseif (isset($_SERVER['REMOTE_ADDR'])) {
        $ip = $_SERVER['REMOTE_ADDR'];
    } elseif (getenv('HTTP_X_FORWARDED_FOR')) {
        $ip = getenv('HTTP_X_FORWARDED_FOR');
    } elseif (getenv('HTTP_CLIENTIP')) {
        $ip = getenv('HTTP_CLIENTIP');
    } elseif (getenv('REMOTE_ADDR')) {
        $ip = getenv('REMOTE_ADDR');
    } else {
        $ip = '127.0.0.1';
    }

    $pos = strpos($ip, ',');
    if( $pos > 0 ) {
        $ip = substr($ip, 0, $pos);
    }

    return trim($ip);
}
展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
1 收藏
0
分享
返回顶部
顶部