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);
}