文档章节

Thinkphp3的monolog实现

goodman_fz
 goodman_fz
发布于 2017/07/21 15:20
字数 2306
阅读 404
收藏 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
粉丝 13
博文 17
码字总数 15283
作品 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
composer linux全局安装

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

刘晓强
2016/03/15
297
0
作为PHP开发者请务必了解Composer

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

虞大胆
2016/12/15
0
0

没有更多内容

加载失败,请刷新页面

加载更多

linux使用ntfs-3g操作ntfs格式硬盘

Linux内核目前只支持对微软NTFS文件系统的读取。 NTFS-3G 是微软 NTFS 文件系统的一个开源实现,同时支持读和写。NTFS-3G 开发者使用 FUSE 文件系统来辅助开发,同时对可移植性有益。 安装 ...

linuxprobe16
41分钟前
1
0
kubeadm部署kubernetes集群

一、环境要求 这里使用RHEL7.5 master、etcd:192.168.10.101,主机名:master node1:192.168.10.103,主机名:node1 node2:192.168.10.104,主机名:node2 所有机子能基于主机名通信,编辑...

人在艹木中
今天
7
0
Shell特殊符号总结以及cut,sort,wc,uniq,tee,tr,split命令

特殊符号总结一 * 任意个任意字符 ? 任意一个字符 # 注释字符 \ 脱义字符 | 管道符 # #号后的备注被忽略[root@centos01 ~]# ls a.txt # 备注 a.txt[root@centos01 ~]# a=1[root@centos01...

野雪球
今天
2
0
OSChina 周二乱弹 —— 程序员圣衣

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @达尔文:分享Skeeter Davis的单曲《The End of the World》 《The End of the World》- Skeeter Davis 手机党少年们想听歌,请使劲儿戳(这里...

小小编辑
今天
16
0
[ python import module ] 导入模块

import moudle_name ----> import module_name.py ---> import module_name.py文件路径 -----> sys.path (这里进行查找文件) # from app.web import Personimport app.web.Person as Pe......

_______-
昨天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部