Thinkphp3的monolog实现


声明:本文转载自https://my.oschina.net/u/125977/blog/1477131,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

一【背景】

  公司有个基于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

三【方案实现】

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

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支持也就不需要上面那么复杂了。但此文实现思路还是值得探讨的,希望对有需要的人有帮助

本文发表于2017年07月22日 06:36
(c)注:本文转载自https://my.oschina.net/u/125977/blog/1477131,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 2427 讨论 0 喜欢 0

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1