您的位置:首页 > 编程语言 > PHP开发

CodeIgniter框架源码笔记(9)——日志记录类Log.php

2016-07-27 20:23 766 查看
日志记录类Log结构:
$_log_path:日志存放路径
$_file_permissions:写入的日志文件权限,默认为0644,即rw-r--r--
$_threshold:允许写日志的阀值,默认为1

    0 = Disables logging, Error logging TURNED OFF

    1 = Error Messages (including PHP errors)

    2 = Debug Messages

    3 = Informational Messages

    4 = All Messages
$_threshold_array :也是允许写日志的阀值,但与$_threshold有些不同。

比如设置配置文件$config['log_threshold'] = 3,这个值会读到$_threshold属性中。那么写日志允许的level可以是1,2,3

可是如果设置$config['log_threshold'] = array(3),那么系统会把这个3读到$_threshold_array数组中,写日志level只允许3,其它的1和2不允许
$_date_fmt :日志的时间格式,由$config['log_date_format']决定。默认'Y-m-d H:i:s'。主要作于$date->format的参数
$_file_ext:日志文件扩展名
$_enabled:标记字段。标记是否有权限写日志。
$_levels:预定义的level级别数组

一、构造函数

1、在构造函数中,获取配置文件中关于日志的配置选项,主要有:

$config['log_path']:赋值给$this->_log_path,如果没有设置,系统默认用APPPATH.'logs/'。

$config['log_file_extension']:赋值给$this->_file_ext,如果没有设置,则默认日志文件扩展名为'php'。

$config['log_threshold']:config['log_threshold']为整型数字时,赋值给$this->_threshold; config['log_threshold']为数组时,赋值给$this->_threshold_array

$config['log_date_format']:日志的日志格式,赋值给$this->_date_fmt

$config['log_file_permissions']:赋给$this->_file_permissions

2、判断日志文件目录是否存在,如果不存在则创建。这里再次用了OR的短路技巧。

section1 OR section2 相当于if(! section1 ){ section2 }

file_exists($this->_log_path) OR mkdir($this->_log_path, 0755, TRUE);

3、调用公共库common.php中的is_really_writable()函数判断目录是否有写权限,如果没有就设置$this->_enabled=FALSE
源码注释:

public function __construct()
{
//获取配置文件中关于日志的配置选项
$config =& get_config();
//确定日志文件存放路径
$this->_log_path = ($config['log_path'] !== '') ? $config['log_path'] : APPPATH.'logs/';
//确定日志文件扩展名
$this->_file_ext = (isset($config['log_file_extension']) && $config['log_file_extension'] !== '')
? ltrim($config['log_file_extension'], '.') : 'php';
//判断日志文件目录是否存在,如果不存在则创建。
file_exists($this->_log_path) OR mkdir($this->_log_path, 0755, TRUE);
//目录是否有写权限,如果没有就设置$this->_enabled=FALSE
if ( ! is_dir($this->_log_path) OR ! is_really_writable($this->_log_path))
{
$this->_enabled = FALSE;
}
//config['log_threshold']为整型数字时,赋值给$this->_threshold; config['log_threshold']
if (is_numeric($config['log_threshold']))
{
$this->_threshold = (int) $config['log_threshold'];
}
//为数组时,赋值给$this->_threshold_array
elseif (is_array($config['log_threshold']))
{
//将$this->_threshold置为0,也就是让$this->_threshold失效
$this->_threshold = 0;
$this->_threshold_array = array_flip($config['log_threshold']);
}
//确定日志日期格式
if ( ! empty($config['log_date_format']))
{
$this->_date_fmt = $config['log_date_format'];
}
//确定创建的日志文件权限
if ( ! empty($config['log_file_permissions']) && is_int($config['log_file_permissions']))
{
$this->_file_permissions = $config['log_file_permissions'];
}
}

二、写日志方法write_log()

该方法以下几种情况下不写:
1、目录没有写权限时。$this->_enabled===FALSE时。

2、阀值与Log记录等级不匹配时。


$_threshold和$_threshold_array 都是允许写日志的阀值,但两者之间有些不同。

比如设置配置文件$config['log_threshold'] = 3,这个值会读到$_threshold属性中。那么写日志允许的level可以是1,2,3

可是如果设置$config['log_threshold'] = array(3),那么系统会把这个3读到$_threshold_array数组中,写日志level只允许3,其它的1和2不允许。

来看这句强大的if语句
if (( ! isset($this->_levels[$level]) OR ($this->_levels[$level] > $this->_threshold))
&& ! isset($this->_threshold_array[$this->_levels[$level]]))
{
return FALSE;
}
3、文件打开失败时。

if ( ! $fp = @fopen($filepath, 'ab'))

{

    return FALSE;

}

如果以上条件都不满足,那么该方法就计算得到日志文件名,计算文件内容,最后写入,并更改文件权限为$this->_file_permissions

对于新创建并且后缀为php的文件,系统首先在前面加上"<?php defined('BASEPATH') OR exit('No direct script access allowed'); ?>\n\n"
源码注释:
public function write_log($level, $msg)
{
//目录没有写权限时,返回FALSE退出
if ($this->_enabled === FALSE)
{
return FALSE;
}

$level = strtoupper($level);
//写日志的level级别大于阀值设置值,同时level级别也不能匹配阀值数组中设置的值,返回FALSE退出
if (( ! isset($this->_levels[$level]) OR ($this->_levels[$level] > $this->_threshold)) && ! isset($this->_threshold_array[$this->_levels[$level]])) { return FALSE; }
//设置文件全路径及名称
$filepath = $this->_log_path.'log-'.date('Y-m-d').'.'.$this->_file_ext;
$message = '';
//新创建并且后缀为php的文件,系统首先在前面加上"<?php defined('BASEPATH') OR exit('No direct script access allowed'); ?>\n\n"
if ( ! file_exists($filepath))
{
$newfile = TRUE;
// Only add protection to php files
if ($this->_file_ext === 'php')
{
$message .= "<?php defined('BASEPATH') OR exit('No direct script access allowed'); ?>\n\n";
}
}
//无法打开文件,返回FALSE退出
if ( ! $fp = @fopen($filepath, 'ab'))
{
return FALSE;
}

// Instantiating DateTime with microseconds appended to initial date is needed for proper support of this format
//实例化时间
if (strpos($this->_date_fmt, 'u') !== FALSE)
{
$microtime_full = microtime(TRUE);
$microtime_short = sprintf("%06d", ($microtime_full - floor($microtime_full)) * 1000000);
$date = new DateTime(date('Y-m-d H:i:s.'.$microtime_short, $microtime_full));
$date = $date->format($this->_date_fmt);
}
else
{
$date = date($this->_date_fmt);
}
//合成日志内容
$message .= $level.' - '.$date.' --> '.$msg."\n";

flock($fp, LOCK_EX);
//写文件
for ($written = 0, $length = strlen($message); $written < $length; $written += $result)
{
if (($result = fwrite($fp, substr($message, $written))) === FALSE)
{
break;
}
}

flock($fp, LOCK_UN);
fclose($fp);
//更改文件权限
if (isset($newfile) && $newfile === TRUE)
{
chmod($filepath, $this->_file_permissions);
}

return is_int($result);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: