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

日志记录类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);
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值