CI框架源码学习笔记3——Log.php
上一节说完了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的更多相关文章
- CI框架源码学习笔记1——index.php
做php开发一年多了,陆陆续续用过tp/ci/yii框架,一直停留在只会使用的层面上,关于框架内部的结构实际上是不甚了解的.为了深入的学习,决定把CI框架的源码从头到尾的学习一下, 主要因为CI框架工 ...
- CI框架源码学习笔记7——Utf8.php
愉快的清明节假期结束了,继续回到CI框架学习.这一节我们来看看Utf8.php文件,它主要是用来做utf8编码,废话不多说,上代码. class CI_Utf8 { /** * Class const ...
- CI框架源码学习笔记2——Common.php
上一节我们最后说到了CodeIgniter.php,可是这一节的标题是Common.php,有的朋友可能会觉得很奇怪.事实上,CodeIgniter.php其实包含了ci框架启动的整个流程. 里面引入 ...
- CI框架源码学习笔记5——Hooks.php
接着Benchmark.php往下看,下一个引入的文件是Hooks.php,我们称之为钩子.它的目的是在不改变核心文件的基础上,来修改框架的内部运作流程.具体使用方法参见手册http://codeig ...
- CI框架源码学习笔记4——Benchmark.php
我们回到Codeigniter.php上继续往下看,第一个引入的类文件是Benchmark.php,这个文件主要是提供基准测试,具体使用方法参考手册http://codeigniter.org.cn/ ...
- CI框架源码学习笔记6——Config.php
接着上一节往下,我们这一节来看看配置类Config.php,对应手册内容http://codeigniter.org.cn/user_guide/libraries/config.html. clas ...
- CI框架源码阅读笔记4 引导文件CodeIgniter.php
到了这里,终于进入CI框架的核心了.既然是“引导”文件,那么就是对用户的请求.参数等做相应的导向,让用户请求和数据流按照正确的线路各就各位.例如,用户的请求url: http://you.host.c ...
- CI框架源码阅读笔记3 全局函数Common.php
从本篇开始,将深入CI框架的内部,一步步去探索这个框架的实现.结构和设计. Common.php文件定义了一系列的全局函数(一般来说,全局函数具有最高的加载优先权,因此大多数的框架中BootStrap ...
- CI框架源码阅读笔记5 基准测试 BenchMark.php
上一篇博客(CI框架源码阅读笔记4 引导文件CodeIgniter.php)中,我们已经看到:CI中核心流程的核心功能都是由不同的组件来完成的.这些组件类似于一个一个单独的模块,不同的模块完成不同的功 ...
随机推荐
- AWS + Stunnel + Squid ***
[需求] 第一,能***. 第二,在企业网络要能突破端口限制. [原理] 利用AWS提供的一年免费EC2服务,搭建一台自己的VPS,在VPS中利用Stunnel与本机建立加密连接,将本地http请求通 ...
- java集合类(2)
java集合的主要分为三种类型:JAVA集合位于 java.util包 Set(集) List(列表) Map(映射) arrays函数, equals():比较两个array是否相等. fill() ...
- Celery-4.1 用户指南: Optimizing (优化)
简介 默认的配置做了很多折中考虑.它不是针对某个情况优化的,但是大多数情况下都工作的非常好. 基于一个特殊的使用场景,有很多优化可以做. 优化可以应用到运行环境的不同属性,可以是任务执行的时间,使用的 ...
- redis使用测试
import redis conn=redis.Redis(host='127.0.0.1',port=6379) conn.set('nn','morgana',10) #过期时间10s v=con ...
- java 多线程系列基础篇(十一)之生产消费者问题
1. 生产/消费者模型 生产/消费者问题是个非常典型的多线程问题,涉及到的对象包括“生产者”.“消费者”.“仓库”和“产品”.他们之间的关系如下:(01) 生产者仅仅在仓储未满时候生产,仓满则停止生产 ...
- 问题:oracle if;结果:Oracle IF语句的使用
oracle 之if..else用法 oracle条件分支用法 a.if...then b.if...then... else c.if...then... elsif.... else 实例 1 问 ...
- 监控和安全运维 1.6 nagios监控客户端-2
6. 继续添加服务服务端 vim /etc/nagios/objects/commands.cfg 增加: define command{ command_name check_nrpe comman ...
- JS中substring()方法(用于提取字符串中介于两个指定下标之间的字符)
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- 第一天:tomcat相关知识和浏览器的访问机制
1.tomcat的目录结构 1)bin目录:启动和关闭tomcat以及其他的脚本命令 2)conf目录:存放各种配置文件 a.server.xml配置文件的配置: *<host/>标签: ...
- Class类动态加载类的用法
编译时刻加载类出现的问题:一个功能有错,所有功能都用不了 动态加载类: