文档章节

Thinkphp3的monolog实现

goodman_fz
 goodman_fz
发布于 2017/07/21 15:20
字数 2306
阅读 398
收藏 14

一【背景】

  公司有个基于tp3的项目,此项目经历多次改版重构,有种千疮百孔的感觉,让人看着隐隐心疼,特别是在日志模块上,基于tp提供的日志功能,各种混乱不协调,且与业务的耦合非常高;

  但是这个项目又是很重要的,是最直接面向用户的入口,不出现问题则好,一出现就是一团乱,问题定位均需依赖后端接口或者第三方,也因此背过不少的锅,眼泪总是默默的流在心里;

  是时候做出改变了!

二【选定方案】

  项目基于Thinkphp3.2版本,此版本在日志方面使用的是php内置的error_log函数实现,在不改动tp内核源码情况,很难定制自己的日志驱动,我们使用过程存在几个埋怨点:

1)日志格式难统一,没有一个标准什么时候写日志,写什么日志等

2)日志扩展困难,特别对于项目中特定的需要log的情况

3)log代码与业务耦合厉害,维护起来很让人烦躁

那么基于tp3本身的日志做些修补,意义不是太大,治标不治本,所以我们努力寻找第三方完整的开源日志库:

1)这里我们应该首先就会想到php4log,一个很强大,很完整的日志库,但使用过程总是感觉结构太复杂(或者没有深刻体会到作者的精髓吧);

2)性能方面国产的seaslog无疑是最佳的,不论从官方测试数据还是本地的验证,也都证实seaslog是个硬货,但有几个痛点让我们放弃了它:1-需要安装扩展+添加配置;2-日志格式被限定太不自由3-扩展困难;

3)Monolog,功能强大,可支持把日志发送到文件、socket、邮箱、数据库、各种webservices等(虽然我们就只用到文件);遵循PSR3日志接口规范,可容易与其他日志类库替换;使用composer维护相关依赖,遵循PSR4规范,自动加载;扩展性良好,可轻松定制各种格式;使用便利,这个很重要;包括symfony、laravel、cakephp框架均内置monolog;另外,我们有个基于lume框架的系统(此框架内置了monolog)已稳定使用1年多,且每天日志量再千万级,轻松支撑;

基于对monolog的了解,我们就选择了monolog

三【方案实现】

这是一个不断挖坑,并埋坑的过程,痛并快乐

Tp3日志模块是直接耦合在核心源码里,特别是错误或异常处理,框架本身没有提供入口给你去重新实现或扩展日志功能(tp5添加了日志的扩展口,通过钩子的方式,可怜的是tp3到tp5的升级是不可能平滑的,看到这里真是有一万只草泥马飘过)

这里有个很重要的前提:不修改tp本身的源码,不用问为什么

下面我们开始说明实现流程:

1、Composer安装monolog

#composer requrie snowair/think-monolog:dev-master

这里我找了个对monolog针对tp3的一层封装,github如下:(其实只是做了一层monolog的启动操作)

https://github.com/snowair/think-monolog

注意:composer安装是一项苦力活,特别是在国内神奇的网络下,那么有解决么,伟大的开源斗士为你准备了下面代码:

找到根目录composer.json,添加国内源,其实还是慢的,这时候需要耐心、耐性、耐操

另外,记得添加下面的autoload,这是一个神奇的东西,它会自动生成一个autoload.php文件,完全支持PSR4规范,后面我们就要用到它

{
    "name": "test",
    "require": {
        "snowair/think-monolog": "dev-master"
    },
    "autoload": {
      "autoload": {
        "psr-4": {"App\\": "app/"}
      }
    },
    "repositories": {
      "packagist": {
        "type": "composer",
        "url": "https://packagist.phpcomposer.com"
      }
    }
}

装好后,根目录下就有vendor,完美拥有monolog。革命成功走出第一步

2、将monolog添加到框架自动加载

根目录index.php,添加上面自动加载文件autoload.php

 

此操作,可实现后面调用monolog过程可直接引入,如

 

3、首先我们要接管tp本身的错误处理器

研究了下tp核心代码,他的错误处理是直接在代码里写死的,在Think.class.php下:

 

这也是我们很难去扩展他的原因,所以我们第一想法就是直接改源码,这太不和谐了。经过一夜的冥思,想到了一个绝妙的方案:

1)入口文件index.php添加了一个异常处理类,所以异常可方便的可一个类中处理掉

感兴趣的我这可以提供此类

 

2)异常类中接管register_shutdown_function

注意,此处不能接管set_error_handler、set_exception_handler,原因跟他们3个的机制有关,这个我后面另外详细说明:

 

3)添加tp的action_begin行为来接管set_error_handler、set_exception_handler

 

到此tp的错误及异常情况均已接管到异常类下,我们可以自由实现异常逻辑,包括写log

4)通用的错误页面

支持了pc和h5端通用的错误页,在出现致命错误时记录log的同时也会重定向到错误页的展示,以便在用户出错情况下,可以提供给我们查下bug的依据

 

错误页效果:其中error code为每次请求的位置requestid,可通过日志系统唯一定位到

 

4、统一访问log的实现

1)同样用到tp的行为,添加2个行为,分别对应action_beigin和app_end

即在php进程的开始和结束我们做行为操作,行为其实就类似钩子,执行到某个点时会自动触发

 

 

2)明确定义了日志的格式,字段等,保证所有访问均可记录详细log,且不需要修改业务代码

3)为了更好的使用日志,我们定义了几个可变化的字段,可在业务过程中使用:

elk_mor_info:需要额外记录的log均放置在此字段下,使用例子如下

record($msg, $key = '', $type = 'elk')

$msg-内容,json格式

$key-二级json格式字段名,几个通用定义

curl_request curl请求第三方参数

curl_response curl请求返回结果

curl_time curl请求处理时间

curl_getinfo curl请求info信息

error_sys 系统错误

Info_xxxx 其他信息类型

$type-需定义为’elk_more_info’

大家需严格按照定义的规则进行记录,否则容易导致日志格式混乱

 

 

response:tp3没找到捕捉最终返回的content值,这里使用的方法是,在controller的基类basecontroller里设置统一的返回格式:

 

在此处做response的收集,这里收集是针对ajax,对于面向用户访问的项目,很多是直接访问html页面,这时候其实是没有response这个东西。

另外,如果没有调用到通用返回方法,但又想添加response值,也可以类似elk_more_info方式进行设置收集

5、需要注意的点

1)业务开发过程,尽量不要使用exit()、die()来结束,因为这2个方法都是直接终止脚本执行,表示结束一个php进程,之后的代码将都不会被执行,包括行为里面的函数或者各种钩子函数都不会被触发到。

此情况,一般情况均可使用return来代替,不过在业务逻辑上就需要做相应处理

2)如果非要用exit或die时,又要记录log,这里也提供了在exit之前强制写log的函数供调用:

Logger::foreWrite() -- 无需带参数,它的作用是将内存中的log及当前需要记录的信息强制写入的文件中

3)为了更好控制log,添加了几个log相关的配置,配置文件在每个模块下,即只对相应模块有效,如Event模块/Apps/Event/Conf/config.php

 

在实际环境中,可根据业务需要自行调整

6、日志的后续

日志存放位置:/home/www/log/xxxx/  

并根据模块划分如Event/2017-07-21.log,每天每个模块一份日志

公司已有完善的log监控系统,基于ELK做的二次开发,添加log采集程序即可完成log系统接入,这时候查log就各种方便:

从此妈妈再也不担心查不到bug了

四【最后的话】

以上是基于thinkphp3上monolog实现的详细思路,大家如果有更好的方案欢迎探讨。

另外,注意下,最终我们log是有落地到log监控系统的,大家在实际项目中需要评估好是否有这样条件,以免不能满足实际要求

我们项目中也有用到thinkphp5,它就是一个完全跟随laravel思想的国货,已经能很好的扩展自己的日志系统,包括扩展monolog支持也就不需要上面那么复杂了。但此文实现思路还是值得探讨的,希望对有需要的人有帮助

© 著作权归作者所有

共有 人打赏支持
goodman_fz
粉丝 12
博文 16
码字总数 15181
作品 0
福州
项目经理
新手问题,dwz_thinkphp3 有个__PUBLIC__ 怎么来的?

在看dwz_thinkphp3 (http://dwz4php.googlecode.com/files/jUI-ThinkPHP3.0.zip ) 代码的时候 dwz_thinkphp3AdminTplIndexindex.html 里面有两句:...

kjpioo
2012/09/30
1K
4
Composer 常用命令总结(三)

init(初始化) 该命令用于创建 composer.json 文件,并进行基础信息配置: 可以配置Package name、Description、Author、Minimum、Package Type、License、dependencies 及 dev dependenci...

天秤vs永恒
2016/08/22
16
0
PHP 的一个依赖管理工具Composer

1:下载 php 或者 php 2:移动到bin目录下,以后每次使用直接使用composer命令 查看版本 3.composer.json 在项目中安装monolog composer.json文件内容如下 使用composer install 安装,在当前...

不肥的小肥羊
2016/04/28
23
0
作为PHP开发者请务必了解Composer

原文出处:虞大胆 Composer是一个非常流行的PHP包依赖管理工具,已经取代PEAR包管理器,对于PHP开发者来说掌握Composer是必须的. 对于使用者来说Composer非常的简单,通过简单的一条命令将需要的...

虞大胆
2016/12/15
0
0
composer linux全局安装

我把它放在系统的PATH目录中,这样就能在全局访问它。 curl -sS https://getcomposer.org/installer | phpmv composer.phar /usr/local/bin/composer 注意:如果上诉命令因为权限执行失败, ...

刘晓强
2016/03/15
297
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

[MicroPython]STM32F407开发板驱动OLED液晶屏

1.实验目的 1.学习在PC机系统中扩展简单I/O 接口的方法。 2.进一步学习编制数据输出程序的设计方法。 3.学习 F407 Micropython开发板控制OLED显示字符。 2.所需元器件 F407 Micropython开发板...

bodasisiter
32分钟前
0
0
php require和include 相对路径一个有趣的坑

以前总是被教育,不要使用相对路径,这样性能比较差,但是相对路径的问题不仅仅是性能哦,看下面这里例子 这是项目结构 .├── main.php├── t│ ├── t1.php│ └── t2.php└─...

anoty
33分钟前
17
0
x64技术之SSDT_Hook

测试环境: 虚拟机: Windows 7 64bit 过PG工具 驱动加载工具 PCHunter64 系统自带的计算器和任务管理器等 实现思路: 实际思路与win32的思路一样.都是替换SSDT表里边的函数地址.不过微软被搞怕...

simpower
34分钟前
0
0
TreeMap源码分析,看了都说好

一、简介 TreeMap最早出现在JDK 1.2中,是 Java 集合框架中比较重要一个的实现。TreeMap 底层基于红黑树实现,可保证在log(n)时间复杂度内完成 containsKey、get、put 和 remove 操作,效率很...

Java小铺
44分钟前
0
0
协变、逆变

概念 假设 A、B表示类型 ≤ 表示继承关系 f<⋅>表示类型转换 若A ≤ B,则 A是B的子类,B是A的超类 协变、逆变 什么是型变?型变(type variance)允许对类型进行子类型转换。 为了下面讲解先...

obaniu
50分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部