上一节说完了Common.php,然而跟代码打交道总是免不了日志记录,所以这一节我们说说Log.php文件。

先看看类里面的几个属性,

protected $_log_path;  日志路径

protected $_file_permissions = 0644; 文件权限

protected $_threshold = 1;  日志的等级,用来判断出现的错误异常什么的是否需要记录

protected $_threshold_array = array();

protected $_date_fmt = 'Y-m-d H:i:s';  日期格式

protected $_file_ext; 日志文件扩展名

protected $_enabled = TRUE; 是否可用

protected $_levels = array('ERROR' => 1, 'DEBUG' => 2, 'INFO' => 3, 'ALL' => 4);  log等级

protected static $func_override;  判断mbstring扩展函数重载配置是否开启

再来看构造函数,主要是对上面的属性赋值。

public function __construct()
{
$config =& get_config();//获取config.php配置 //判断变量function_override是否设置,如果没有设置,根据是否载入mbstring扩展,以及扩展的重载配置是否开启来赋值true或false
isset(self::$func_override) OR self::$func_override = (extension_loaded('mbstring') && ini_get('mbstring.func_override')); //设置日志记载的目录,若config没有配置,默认在application的logs文件夹下
$this->_log_path = ($config['log_path'] !== '') ? $config['log_path'] : APPPATH.'logs/';
//根据配置设置扩展名,默认为php
$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); //判断日志目录是否可写,若不可写,设置可用性判断的变量_enabled为false
if ( ! is_dir($this->_log_path) OR ! is_really_writable($this->_log_path))
{
$this->_enabled = FALSE;
} //如果配置log_threshold是数字那么直接设置为变量;否则如果配置为数组,那么设置变量_threshold为0,同时设置_threshold_array为配置log_threshold调换key与value后的数组
if (is_numeric($config['log_threshold']))
{
$this->_threshold = (int) $config['log_threshold'];
}
elseif (is_array($config['log_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'];
}
}

我们在看看几个辅助用到的方法

  protected function _format_line($level, $date, $message)
{
return $level.' - '.$date.' --> '.$message."\n";
}

方法内容很简单,就是构造成指定格式的。

    protected static function strlen($str)
{
return (self::$func_override)
? mb_strlen($str, '8bit')
: strlen($str);
}

用来测量字符串长度,当mb_string扩展开启时使用mb_strlen,否则使用php函数strlen。

  protected static function substr($str, $start, $length = NULL)
{
if (self::$func_override)
{
// mb_substr($str, $start, null, '8bit') returns an empty
// string on PHP 5.3
isset($length) OR $length = ($start >= 0 ? self::strlen($str) - $start : -$start);
return mb_substr($str, $start, $length, '8bit');
} return isset($length)
? substr($str, $start, $length)
: substr($str, $start);
}

截取字符串的方法。

其实整个类里面真正对外使用的方法就一个write_log,而且通常只会被函数log_message调用(这个函数我们在Common.php中有讲过)。

public function write_log($level, $msg)
{
//先判断变量$this->_enabled,若为false则不执行写入日志操作了(此时日志目录的属性不可写)
if ($this->_enabled === FALSE)
{
return FALSE;
} $level = strtoupper($level);//转换字符串为大写 //这里主要是判断我们要写入日志的错误信息的等级是否比我们在配置中配置的可写入日志的错误等级高
//配置中默认的为0,所以此时我们实际上是不会有写日志的操作的,所以我们需要把配置改成1后才能记录error日志
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代码,判断常量BASEPARH是否定义
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";
}
} //打开文件,若失败则退出
if ( ! $fp = @fopen($filepath, 'ab'))
{
return FALSE;
} //文件写锁
flock($fp, LOCK_EX); // 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 .= $this->_format_line($level, $date, $msg); //将日志信息写入到文件中
for ($written = 0, $length = self::strlen($message); $written < $length; $written += $result)
{
if (($result = fwrite($fp, self::substr($message, $written))) === FALSE)
{
break;
}
} //释放锁
flock($fp, LOCK_UN);
//释放文件资源
fclose($fp); //设置日志文件权限
if (isset($newfile) && $newfile === TRUE)
{
chmod($filepath, $this->_file_permissions);
} //通过返回的result是否为int来判断写入是否成功,因为fwrite成功时返回写入的字符数,失败时返回false
return is_int($result);
}

Log.php文件的内容不是很多,分析完毕,最后贴上完整代码。

class CI_Log {

    /**
* Path to save log files
*
* @var string
*/
protected $_log_path; /**
* File permissions
*
* @var int
*/
protected $_file_permissions = 0644; /**
* Level of logging
*
* @var int
*/
protected $_threshold = 1; /**
* Array of threshold levels to log
*
* @var array
*/
protected $_threshold_array = array(); /**
* Format of timestamp for log files
*
* @var string
*/
protected $_date_fmt = 'Y-m-d H:i:s'; /**
* Filename extension
*
* @var string
*/
protected $_file_ext; /**
* Whether or not the logger can write to the log files
*
* @var bool
*/
protected $_enabled = TRUE; /**
* Predefined logging levels
*
* @var array
*/
protected $_levels = array('ERROR' => 1, 'DEBUG' => 2, 'INFO' => 3, 'ALL' => 4); /**
* mbstring.func_override flag
*
* @var bool
*/
protected static $func_override; // -------------------------------------------------------------------- /**
* Class constructor
*
* @return void
*/
public function __construct()
{
$config =& get_config(); isset(self::$func_override) OR self::$func_override = (extension_loaded('mbstring') && ini_get('mbstring.func_override')); $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); if ( ! is_dir($this->_log_path) OR ! is_really_writable($this->_log_path))
{
$this->_enabled = FALSE;
} if (is_numeric($config['log_threshold']))
{
$this->_threshold = (int) $config['log_threshold'];
}
elseif (is_array($config['log_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 File
*
* Generally this function will be called using the global log_message() function
*
* @param string $level The error level: 'error', 'debug' or 'info'
* @param string $msg The error message
* @return bool
*/
public function write_log($level, $msg)
{
if ($this->_enabled === FALSE)
{
return FALSE;
} $level = strtoupper($level); 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 = ''; 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";
}
} if ( ! $fp = @fopen($filepath, 'ab'))
{
return FALSE;
} flock($fp, LOCK_EX); // 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 .= $this->_format_line($level, $date, $msg); for ($written = 0, $length = self::strlen($message); $written < $length; $written += $result)
{
if (($result = fwrite($fp, self::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);
} // -------------------------------------------------------------------- /**
* Format the log line.
*
* This is for extensibility of log formatting
* If you want to change the log format, extend the CI_Log class and override this method
*
* @param string $level The error level
* @param string $date Formatted date string
* @param string $message The log message
* @return string Formatted log line with a new line character '\n' at the end
*/
protected function _format_line($level, $date, $message)
{
return $level.' - '.$date.' --> '.$message."\n";
} // -------------------------------------------------------------------- /**
* Byte-safe strlen()
*
* @param string $str
* @return int
*/
protected static function strlen($str)
{
return (self::$func_override)
? mb_strlen($str, '8bit')
: strlen($str);
} // -------------------------------------------------------------------- /**
* Byte-safe substr()
*
* @param string $str
* @param int $start
* @param int $length
* @return string
*/
protected static function substr($str, $start, $length = NULL)
{
if (self::$func_override)
{
// mb_substr($str, $start, null, '8bit') returns an empty
// string on PHP 5.3
isset($length) OR $length = ($start >= 0 ? self::strlen($str) - $start : -$start);
return mb_substr($str, $start, $length, '8bit');
} return isset($length)
? substr($str, $start, $length)
: substr($str, $start);
}
}

CI框架源码学习笔记3——Log.php的更多相关文章

  1. CI框架源码学习笔记1——index.php

    做php开发一年多了,陆陆续续用过tp/ci/yii框架,一直停留在只会使用的层面上,关于框架内部的结构实际上是不甚了解的.为了深入的学习,决定把CI框架的源码从头到尾的学习一下, 主要因为CI框架工 ...

  2. CI框架源码学习笔记7——Utf8.php

    愉快的清明节假期结束了,继续回到CI框架学习.这一节我们来看看Utf8.php文件,它主要是用来做utf8编码,废话不多说,上代码. class CI_Utf8 { /** * Class const ...

  3. CI框架源码学习笔记2——Common.php

    上一节我们最后说到了CodeIgniter.php,可是这一节的标题是Common.php,有的朋友可能会觉得很奇怪.事实上,CodeIgniter.php其实包含了ci框架启动的整个流程. 里面引入 ...

  4. CI框架源码学习笔记5——Hooks.php

    接着Benchmark.php往下看,下一个引入的文件是Hooks.php,我们称之为钩子.它的目的是在不改变核心文件的基础上,来修改框架的内部运作流程.具体使用方法参见手册http://codeig ...

  5. CI框架源码学习笔记4——Benchmark.php

    我们回到Codeigniter.php上继续往下看,第一个引入的类文件是Benchmark.php,这个文件主要是提供基准测试,具体使用方法参考手册http://codeigniter.org.cn/ ...

  6. CI框架源码学习笔记6——Config.php

    接着上一节往下,我们这一节来看看配置类Config.php,对应手册内容http://codeigniter.org.cn/user_guide/libraries/config.html. clas ...

  7. CI框架源码阅读笔记4 引导文件CodeIgniter.php

    到了这里,终于进入CI框架的核心了.既然是“引导”文件,那么就是对用户的请求.参数等做相应的导向,让用户请求和数据流按照正确的线路各就各位.例如,用户的请求url: http://you.host.c ...

  8. CI框架源码阅读笔记3 全局函数Common.php

    从本篇开始,将深入CI框架的内部,一步步去探索这个框架的实现.结构和设计. Common.php文件定义了一系列的全局函数(一般来说,全局函数具有最高的加载优先权,因此大多数的框架中BootStrap ...

  9. CI框架源码阅读笔记5 基准测试 BenchMark.php

    上一篇博客(CI框架源码阅读笔记4 引导文件CodeIgniter.php)中,我们已经看到:CI中核心流程的核心功能都是由不同的组件来完成的.这些组件类似于一个一个单独的模块,不同的模块完成不同的功 ...

随机推荐

  1. python web框架 Django进阶

    django 进阶 基础中,一些操作都是手动创建连接的非主流操作,这样显得太low,当然也是为了熟悉这个框架! 实际中,django自带连接数据库和创建app的机制,同时还有更完善的路由系统机制.既然 ...

  2. composer update的错误使用以及如何更新composer.lock文件

    用composer update装包是错误的. 安装包标准的方法应该是 require ,或者手动写 compose.json 文件,然后 composer install .如果只是需要更新 com ...

  3. jdbcTemplate学习(二)

    前面讲了增加.删除.更新操作,这节讲一下查询. 查询操作: (一)查询一个值(不需要注入参数) queryForObject(String sql, Class<T> requiredTy ...

  4. DAY10-python并发之IO模型

    一 IO模型介绍 同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(non-blocking)IO分别是什么,到底有什么区别?这个问 ...

  5. sql server导入excel等数据

    1.首先打开并登陆sql server数据库 2.选择要将表导入的数据库,右击选择任务-->导入数据 3.在弹出的窗口中选择下一步 4.在弹出的窗口中选择数据源,也就是从哪种文件导入,sql s ...

  6. oracle DDL(create、alter、drop)

    一.创建表1.创建表CREATE TABLE <table_name>( column1 DATATYPE [NOT NULL] [PRIMARY KEY], column2 DATATY ...

  7. jQuery选择器大全整理

    一.选择网页元素 $(document) //选择整个文档对象 $('#myId') //选择ID为myId的网页元素 $('div.myClass') // 选择class为myClass的div元 ...

  8. vue安装vuex框架

    1.安装vuex npm install vuex --save-dev 2.创建storesrc下创建stores文件夹,创建noteStore.js import Vue from 'vue'; ...

  9. css 层叠式样式表(1)

    实用css有三种格式:内嵌:内联:外部: 分类:内联:写在标记的属性位置,优先级最高,重用性最差内嵌:写在页面的head中,优先级第二,重用性一般外部:写在一个以css结尾的文件中,通过引用来建立文件 ...

  10. AbstractFactoryPattern(23种设计模式之一)

    设计模式六大原则(1):单一职责原则 设计模式六大原则(2):里氏替换原则 设计模式六大原则(3):依赖倒置原则 设计模式六大原则(4):接口隔离原则 设计模式六大原则(5):迪米特法则 设计模式六大 ...