php 日志模块源码解析
php日志模块设计
Monolog 是PHP的一个日志类库解析
整体介绍:monolog日志模块遵循 PSR3 的接口规范。主要有日志格式类接口(格式化日志信息),处理类接口(写日志的驱动,通过扩展写入不同地方),过程类接口(在有机组合,利于扩展和兼容。
handler的level值决定其处理大于的等级日志,代码参考AbstractHandler里面的isHandling是否需要处理
public function isHandling(array $record)
{
return $record['level'] >= $this->level;
}
1. Logger.php文件里面的Logger类 logger可以通过构建的时候或者调用 pushHandler 添加处理里处理日志的输出驱动 pushProcessor添加处理过程其作用是给日志格式添加数据(源码可以看看ProcessIdProcessor类)。
addRecord方法比较关键 里面能看到handler的调用 process的调用
2. process都实现ProcessorInterface 接口,其只有__invoke 用于类的函数调用,就是把类当做方法调用是默认嗲用的方法。如: call_user_func($processor, $record); $processor 类 $record传入的参数。扩展添加process时
3. handle 处理日志的写入地方 ,实现HandlerInterface接口 AbstractHandler是HandlerInterface接口的抽象类 实现了部分方法 AbstractProcessingHandler是基于AbstractHandler的抽象了 他主要是实现了handle默认的方法, 一般扩展基于AbstractProcessingHandler 实现write方法。 handle处理类里面也可以添加process,这里看似和logger也添加process有点重复 handle类可以通过setFormatter方法添加FormatterInterface格式接口 对日志信息格式化
4. 格式化NormalizerFormatter实现FormatterInterface接口 主要实现 format方法。class LineFormatter extends NormalizerFormatter 重写了format方法。 所以一般扩展格式化类继承NormalizerFormatter类,重写NormalizerFormatter就可以。
关键的代码
// 抽象类的handle方法
abstract class AbstractProcessingHandler extends AbstractHandler
{
/**
* {@inheritdoc}
*/
public function handle(array $record)
{
if (!$this->isHandling($record)) {
return false;
} $record = $this->processRecord($record); $record['formatted'] = $this->getFormatter()->format($record); $this->write($record); return false === $this->bubble;
} /**
* Logger 类的 记录日志方法 里面调用了 process handle
* Adds a log record.
*
* @param int $level The logging level
* @param string $message The log message
* @param array $context The log context
* @return bool Whether the record has been processed
*/
public function addRecord($level, $message, array $context = array())
{
if (!$this->handlers) {
$this->pushHandler(new StreamHandler('php://stderr', static::DEBUG));
} $levelName = static::getLevelName($level); // check if any handler will handle this message so we can return early and save cycles
$handlerKey = null;
reset($this->handlers);
while ($handler = current($this->handlers)) {
if ($handler->isHandling(array('level' => $level))) {
$handlerKey = key($this->handlers);
break;
} next($this->handlers);
} if (null === $handlerKey) {
return false;
} if (!static::$timezone) {
static::$timezone = new \DateTimeZone(date_default_timezone_get() ?: 'UTC');
} // php7.1+ always has microseconds enabled, so we do not need this hack
if ($this->microsecondTimestamps && PHP_VERSION_ID < 70100) {
$ts = \DateTime::createFromFormat('U.u', sprintf('%.6F', microtime(true)), static::$timezone);
} else {
$ts = new \DateTime(null, static::$timezone);
}
$ts->setTimezone(static::$timezone); $record = array(
'message' => (string) $message,
'context' => $context,
'level' => $level,
'level_name' => $levelName,
'channel' => $this->name,
'datetime' => $ts,
'extra' => array(),
); try {
foreach ($this->processors as $processor) {
$record = call_user_func($processor, $record);
} while ($handler = current($this->handlers)) {
if (true === $handler->handle($record)) {
break;
} next($this->handlers);
}
} catch (Exception $e) {
$this->handleException($e, $record);
} return true;
}
测试:
monolog 采用composer安装:
composer require monolog/monolog
composer install
php 测试代码
<?php
use Monolog\Logger; use Monolog\Handler\StreamHandler; use Monolog\Handler\ErrorLogHandler; require 'vendor/autoload.php';
$logger = new Logger('my_logger'); $logger->pushHandler(new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG)); $logger->pushHandler(new ErrorLogHandler(ErrorLogHandler::OPERATING_SYSTEM, Logger::ERROR)); $logger->debug('行胜于言');
$logger->info('行胜于言');
$logger->notice('行胜于言');
$logger->error('行胜于言');
$logger->critical('行胜于言');
$logger->alert('行胜于言');
$logger->emergency('行胜于言'); ?>
使用
参考测试例子能看, 日志可以添加多个handle 注意handle后添加的先处理堆的方式。 记录的level大于设定的都会被相应的handle处理,
如new ErrorLogHandler(ErrorLogHandler::OPERATING_SYSTEM, Logger::ERROR) 处理错误等级以上的日志信息。$bubble决定是否冒泡给下一个handle处理 为false的时候 这个设定等级以上的日志被处理后其他handle将处理不到。
疑问
1. handler为什么是堆的方式,后加入的handler先处理日志。handler的bubble设置为false就会直接跳过后续handler的处理。
参考
文章详细介绍了monolog的各个模块的功能
https://blog.csdn.net/sanbingyutuoniao123/article/details/71079534
psr 规范的日志接口详细说面
https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
文章介绍了 日志系统的整体结构
https://www.cnblogs.com/mawang/p/6740862.html
php 日志模块源码解析的更多相关文章
- gorm的日志模块源码解析
gorm的日志模块源码解析 如何让gorm的日志按照我的格式进行输出 这个问题是<如何为gorm日志加traceId>之后,一个群里的朋友问我的.如何让gorm的sql日志不打印到控制台, ...
- 「从零单排canal 06」 instance模块源码解析
基于1.1.5-alpha版本,具体源码笔记可以参考我的github:https://github.com/saigu/JavaKnowledgeGraph/tree/master/code_read ...
- 「从零单排canal 05」 server模块源码解析
基于1.1.5-alpha版本,具体源码笔记可以参考我的github:https://github.com/saigu/JavaKnowledgeGraph/tree/master/code_read ...
- 「从零单排canal 07」 parser模块源码解析
基于1.1.5-alpha版本,具体源码笔记可以参考我的github:https://github.com/saigu/JavaKnowledgeGraph/tree/master/code_read ...
- C#软件授权、注册、加密、解密模块源码解析并制作注册机生成license
最近做了一个绿色免安装软件,领导临时要求加个注册机制,不能让现场工程师随意复制.事出突然,只能在现场开发(离开现场软件就不受我们控了).花了不到两个小时实现了简单的注册机制,稍作整理. ...
- step by step 之餐饮管理系统五(Util模块)------附上篇日志模块源码
这段时间一直在修改日志模块,现在基本上写好了,也把注释什么的都加上了,昨天邮件发送给mark的园友一直报失败,老是退回来,真是报歉,如下图所示:
- python Threading模块源码解析
查看源码: 这是一个线程控制的类,这个类可以被子类化(继承)在一定的条件限制下,这里有两种方式去明确活动:第一通过传入一个callable 对象也就是调用对象,一种是通过重写这个Thread类的run ...
- 30.Serializers模块源码解析
rest_framework序列化类的继承关系 field类: 序列化基类的基类 BaseSerializer: 继承field 派生ListSerializer序列化类 Serializer: 继承 ...
- 【nodejs原理&源码赏析(4)】深度剖析cluster模块源码与node.js多进程(上)
[摘要] 集群管理模块cluster浅析 示例代码托管在:http://www.github.com/dashnowords/blogs 一. 概述 cluster模块是node.js中用于实现和管理 ...
随机推荐
- Springboot+JdbcTemplate +thymeleaf 页面 做迷你版的bug系统
https://www.cnblogs.com/qianjinyan/p/10065160.html 在我上一篇随笔中介绍了关于要做的系统的数据结构,连接如上 今天实现连接mssql server, ...
- $(document).ready和window.onload,细微小区别,ready是jQuery的方法,onload是window的方法
$(document).ready和window.onload的区别 $(document).ready和window.onload都是在都是在页面加载完执行的函数,大多数情况下差别不大,但也是有区别 ...
- JFinal3.0 sql管理与动态生成
原文: 本节学习目标主要是使用JFinal中自带的Template Engin来实现对sql的管理.JFinal中为sql管理提供了3个指令#sql.#para.#namespace,来增强sql功能 ...
- English trip V1 - B 24. I'm Interested in... 我对...感兴趣 Teacher:Julia Key: (I/We/They) do/don't (He/She/it)does/doesn't
In this lesson you will learn to talk about people's interests. 课上内容(Lesson) interest v. 使…感兴趣(inter ...
- 如何启动iis(Internet 信息服务(IIS)管理器)
Internet 信息服务(IIS)管理器 启动 IIS 管理器1.从“开始”菜单,指向“管理工具”,然后单击“Internet 信息服务 (IIS) 管理器”. 从“运行”对话框启动 IIS 管理器 ...
- Hadoop-2.3.0的Eclipse插件编译
Hadoop-2.3.0的Eclipse插件编译 #cd /usr/local/src/hadoop2x-eclipse-plugin-master/src/contrib/eclipse-plugi ...
- 宽度优先搜索BFS(Breadth-First-Search)
Breadth-First-Search 1. 与DFS的异同 相同点:搜索所有可能的状态. 不同点:搜索顺序. 2. BFS总是先搜索距离初始状态近的状态,它是按照:开始状态->只需一次转移就 ...
- fiddler filter过滤+断点
转自 http://blog.csdn.net/u012808234/article/details/52767470
- python基础之生成器,生成器函数,列表推导式
内容梗概: 1. 生成器和生成器函数. 2. 列表推导式. 1.生成器函数1.1 生成器函数. 就是把return换成yield def gen(): print("爽歪歪") y ...
- python基础之小数据池,is和==区别 编码问题
主要内容 小数据池,is和==区别 编码问题 小数据池 一种缓存机制,也称为驻留机制,是为了能更快提高一些字符串和整数的处理速度is 和 == 的区别 == 主要指对变量值是否相等的判断,只要数值相同 ...