本日来学习的扩展是和日记相关的一个扩展,对于 PHP 的日记应用来说,除了本身自带的 error_log() 、 syslog() 之外,在大多数的框架中还会经常见到 monolog 的踪影。当然,我们本日讲的并不是 monolog ,而是需要自己安装的一个扩展日记组件。
关于 SeasLog
首先要说明的是,SeasLog 这个扩展是我们国人开发的哦,Neeke 大佬。并且这个扩展也是收录在官方文档中的,下面是他的知乎主页的链接,大家可以去多多向大佬学习。
架构师 Neeke:https://www.zhihu.com/people/ciogao
对于 PHP 内置的那两个日记函数,也就是 error_log() 、 syslog() 来说,固然功能强大并且性能极好,但是并没有错误级别的设置,也没有固定的格式,更分不了模块记录。而 monolog 、 log4php 这类的日记步伐在性能上又多少略有缺憾。正因为这些各种各样的原因,Neeke 大佬就开发了这个 SeasLog 扩展,为的就是办理上面这些日记相关系统的问题。
因为是我们国人开发的,所以它的中文文档很友好,在 Gibhub 和官方文档中都有详细的中文文档说明,非常方便我们利用。安装过程也和普通的 PHP 扩展没有区别,并不需要什么别的特别的软件支持。
日记记录格式
我们先来相识一下 SeasLog 的日记记录格式。它的日记格式模板是在 php.ini 文件中配置的,无法动态修改,需要配置 seaslog.default_template 这个选项,默认值是 "%T | %L | %P | %Q | %t | %M" 。其中,%T 代表时间、%L 代表日记级别、%P 代表历程ID 、%Q 代表哀求ID 、%t 代表时间戳、%M 代表日记信息。
当然,除了默认的这些参数之外 ,它还有一些别的参数,文档中说明得很详细,我们在下面的文章中也会再提到两个。具体的内容大家可以自行在官方文档中查阅,这里就不多说了。
相关属性参数设置
除了一些需要在 php.ini 中配置的选项参数之外,SeasLog 还可以在步伐运行时配置及获取一些配置信息。
日记根目录
// 获取设置日记根目录var_dump(SeasLog::getBasePath()); // string(12) "/var/log/www"SeasLog::setBasePath("./");var_dump(SeasLog::getBasePath()); // string(2) "./"这是日记所要记录到的文件目录信息,我们可以通过 getBasePath() 来获得当前配置的文件目录信息。默认情况下是 "/var/log/www" 这个目录,当然,我们也可以在 php.ini 中配置 seaslog.default_basepath 这个选项来修改这个默认的目录。而在代码中,我们可以通过 setBasePath() 函数来修改这个目录,比如我们在上面的测试代码中将日记的目录修改到当前目录下了。
Logger 信息
// 获取设置日记 Logger 名称var_dump(SeasLog::getLastLogger()); // string(7) "default"SeasLog::info("Test Logger Default");// ./default/20200106.log// 2021-01-06 01:01:53 | INFO | 5038 | 5ff50c019ebe9 | 1609894913.650 | Test Logger DefaultSeasLog::setLogger("mylog");var_dump(SeasLog::getLastLogger()); // string(5) "mylog"SeasLog::info("Test Logger MyLog");// ./mylog/20200106.log// 2021-01-06 01:01:53 | INFO | 5038 | 5ff50c019ebe9 | 1609894913.650 | Test Logger MyLogLogger 信息可以看做是一个日记分类,它会把这个分类下的日记放到同一个文件夹中。比如我们在默认情况这个 Logger 是 default ,如果在默认情况下直接利用 info() 记录日记的话,就会在当前日记根目录天生一个 default 目录,并且创建一个以当前日期命名的日记文件。
如果我们利用 setLogger() 设置了一个新的 Logger ,那么两次记录日记的时候,就会天生创建一个新的 Logger 目录并将日记记录到这个目录中。
日期格式
// 获取设置日记日期格式var_dump(SeasLog::getDatetimeFormat()); // string(11) "Y-m-d H:i:s"SeasLog::info("Test Datetime Default");// 2021-01-06 01:04:44 …………SeasLog::setDatetimeFormat("Y/m/d His");var_dump(SeasLog::getDatetimeFormat()); // string(9) "Y/m/d His"SeasLog::info("Test Datetime New");// 2021/01/06 010444 …………日期格式的修改实在就是针对的我们的日记格式中的 %T 这个参数。这个就不多解释了,代码中已经演示得很清楚了,利用 getDatetimeFormat() 可以获得当前设置的日期信息,而 setDatetimeFormat() 方法则是设置日期的格式。
哀求 ID
var_dump(SeasLog::getRequestID()); // string(13) "5ff50e4721a06"SeasLog::setRequestID("new_request_id" . uniqid());var_dump(SeasLog::getRequestID()); // string(27) "new_request_id5ff50e6519202"SeasLog::info("Test New Request ID");// 2021/01/06 011216 | INFO | 5250 | new_request_id5ff50e70337b8 | 1609895536.210 | Test New Request ID哀求ID 针对的是 %Q 这个参数的内容。默认情况下它就是调用 uniqid() 天生的一个唯一ID数据,我们可以通过 setRequestID() 来指定当前这条日记要天生的哀求ID是什么内容。
其它日记变量
除了上面的这些固定功能的函数外,我们还可以设置一些别的哀求参数信息。
ar_dump(SeasLog::getRequestVariable(SEASLOG_REQUEST_VARIABLE_DOMAIN_PORT));var_dump(SeasLog::getRequestVariable(SEASLOG_REQUEST_VARIABLE_REQUEST_URI));var_dump(SeasLog::getRequestVariable(SEASLOG_REQUEST_VARIABLE_REQUEST_METHOD));var_dump(SeasLog::getRequestVariable(SEASLOG_REQUEST_VARIABLE_CLIENT_IP));// string(3) "cli"// string(5) "1.php"// string(9) "/bin/bash"// string(5) "local"// seaslog.default_template="%T | %L | %P | %Q | %t | %M | %H | %m"SeasLog::info("Test Other Request Variable");// 2021/01/06 012512 | INFO | 5496 | new_request_id5ff5117888f86 | 1609896312.561 | Test Other Request Variable | localhost.localdomain | /bin/bashSeasLog::setRequestVariable(SEASLOG_REQUEST_VARIABLE_REQUEST_METHOD, "Get");var_dump(SeasLog::getRequestVariable(SEASLOG_REQUEST_VARIABLE_REQUEST_METHOD)); // string(3) "Get"SeasLog::info("Test New Other Request Variable");// 2021/01/06 012625 | INFO | 5520 | new_request_id5ff511c1367c2 | 1609896385.223 | Test New Other Request Variable | localhost.localdomain | GetgetRequestVariable() 和 setRequestVariable() 方法就是用于获取和设置其它哀求变量信息的方法。它们都只支持四个常量,也就是代码中演示的这些,分别代表哀求的端口号、URI、方法和客户端IP。不过这些内容并没有配置在默认日记模板中,所以我们需要默认的日记模板来检察这些内容。
在这段代码中,我们测试的是给默认模板添加了 %H 和 %m 两个参数,%H 代表的是主机名,%m 代表的是哀求的 method ,也就是哀求方法。其中 %H 是无法设置修改的,这里只是测试一下格式的配置,而重点在于 %m 的内容。默认情况下,在日记中记录的这个哀求方法是 /bin/bash ,实在就是因为我们利用的是命令行来运行的测试代码,它的哀求方法就是命令情况 bash 了。这时,我们通过 setRequestVariable() 将哀求方法的值修改为 "Get" ,在之后的日记记录中所有的 %m 参数中输出的就都是 Get 了。
日记记录
通过上面的学习,我们已经看到了一个 info() 方法的利用。它就是记录普通的日记信息的一个函数,通过它记录的日记信息中的 %L 信息都会表现为 "info" 。后面还有其它的日记类型方法,我们先来看看这个 info() 方法还有什么可以深挖的东西。
SeasLog::info("Test Info Log");// 2021/01/06 013018 | INFO | 5583 | new_request_id5ff512aaafcde | 1609896618.720 | Test Info Log | localhost.localdomain | GetSeasLog::info("Test {name} Log", ['name'=>'Info1']);// 2021/01/06 013018 | INFO | 5583 | new_request_id5ff512aaafcde | 1609896618.720 | Test Info1 Log | localhost.localdomain | GetSeasLog::info("Test {name} Log", ['name'=>'Info1'], 'default');// ./default/20210106.log// 2021/01/06 013140 | INFO | 5609 | new_request_id5ff512fc264f3 | 1609896700.156 | Test Info1 Log | localhost.localdomain | GetSeasLog::info("Test {name} Log", ['name'=>'Info1'], 'defaultNew');// defaultNew/20210106.log// 2021/01/06 013230 | INFO | 5631 | new_request_id5ff5132e3e143 | 1609896750.254 | Test Info1 Log | localhost.localdomain | Get没错,这个 info() 方法除了第一个参数是日记的内容信息之外,它还有两个参数。
第二个参数的作用是可以界说一个数组用来替换第一个参数中的一些占位符。是不是感觉和数据库中的预编译占位符很像。第三个参数则是可以直接指定一个 Logger ,也就是要记录的日记分类目录。这个参数可就方便了,我们当前测试情况是前面设置过的 "mysql" ,所以前两条日记都记录在 mysql 目录下的日记文件中了。而后面两条则是一条记录在 default 目录下,而另一条则是一个新的 defaultNew 目录下。这个新的 Logger 目录我们并没有通过 setLogger() 来创建,但这里也会直接和 setLogger() 一样去创建新的目录和日记文件,非常方便。
除了 info() 外,常见的日记类型还有 notice 、warning、error、alter、debug、critical、emergency 这些。相信只要是用过框架开发大概利用过 monolog 的同砚都不会生疏。在 SeasLog 中,这些对应的方法函数也都是存在的,并且所有的参数和 info() 都是一样的。
SeasLog::alert("Test {name} Log", ['name'=>'Alert'], 'defaultNew');SeasLog::error("Test {name} Log", ['name'=>'Error'], 'defaultNew');SeasLog::debug("Test {name} Log", ['name'=>'Debug'], 'defaultNew');SeasLog::critical("Test {name} Log", ['name'=>'Critical'], 'defaultNew');SeasLog::emergency("Test {name} Log", ['name'=>'Emergency'], 'defaultNew');SeasLog::notice("Test {name} Log", ['name'=>'Notice'], 'defaultNew');SeasLog::warning("Test {name} Log", ['name'=>'Warning'], 'defaultNew');// 2021/01/06 014106 | ALERT | 5762 | new_request_id5ff5153200b30 | 1609897266.2 | Test Alert Log | localhost.localdomain | Get// 2021/01/06 014106 | ERROR | 5762 | new_request_id5ff5153200b30 | 1609897266.2 | Test Error Log | localhost.localdomain | Get// 2021/01/06 014106 | DEBUG | 5762 | new_request_id5ff5153200b30 | 1609897266.2 | Test Debug Log | localhost.localdomain | Get// 2021/01/06 014106 | CRITICAL | 5762 | new_request_id5ff5153200b30 | 1609897266.2 | Test Critical Log | localhost.localdomain | Get// 2021/01/06 014106 | EMERGENCY | 5762 | new_request_id5ff5153200b30 | 1609897266.2 | Test Emergency Log | localhost.localdomain | Get// 2021/01/06 014106 | NOTICE | 5762 | new_request_id5ff5153200b30 | 1609897266.2 | Test Notice Log | localhost.localdomain | Get// 2021/01/06 014106 | WARNING | 5762 | new_request_id5ff5153200b30 | 1609897266.2 | Test Warning Log | localhost.localdomain | Get可以看到,它们记录的日记信息中的 %L 内容都是和自身相对应的。当然,除了这些固定的方法函数之外,我们还有一个通用的记录日记的方法。
SeasLog::log(SEASLOG_INFO, "Test log() {name} Log", ['name'=>"Info"], 'defaultNew');// 2021/01/06 014330 | INFO | 5809 | new_request_id5ff515c2ddd5d | 1609897410.908 | Test log() Info Log | localhost.localdomain | Get就是这个 log() 方法,它和上面的 info() 那些方法相比,就是多了一个需要指定当前日记类型的参数,而且这个参数也提供了常量。
日记信息检察
接下来就是对日记信息的一些数据的检察了。就像上面的测试中我们来回测试实在已经记了不少日记数据了,有没有什么方法函数可以方便地检察这些日记信息内容呢?
SeasLog::setLogger('defaultNew');var_dump(SeasLog::analyzerCount());// array(8) {// ["DEBUG"]=>// int(40)// ["INFO"]=>// int(80)// ["NOTICE"]=>// int(40)// ["WARNING"]=>// int(40)// ["ERROR"]=>// int(40)// ["CRITICAL"]=>// int(40)// ["ALERT"]=>// int(40)// ["EMERGENCY"]=>// int(40)// }首先就是这个 analyzerCount() ,它用来统计日记的数量。可以看到在默认情况下它是返回一个数组并且表现的是所有日记类型记录的日记数量的。当然,它可以增加参数,但如果增加参数指定日记类型之后,它返回的就是一个普通的数字值了,也就是这个指定的日记类型的数量信息。
var_dump(SeasLog::analyzerCount(SEASLOG_WARNING)); // int(10)var_dump(SeasLog::analyzerCount(SEASLOG_ERROR, null)); // int(10)var_dump(SeasLog::analyzerCount(SEASLOG_ERROR, null, "1609897995.939")); // int(1)此外,它还有别的两个参数,第二个参数是指定日记的路径信息,也就是在当前 Logger 目录下如果还有别的目录的话,可以通过这个参数指定,如果是设置为 null 则忽略这个函数。第三个参数则是过滤信息,就有点像含糊查找的概念,比如我们这里只查找指定的这个时间戳的日记,返回的结果就是只有一条。
var_dump(SeasLog::analyzerDetail(SEASLOG_ALL, 'secpath/', null, 1, 2, SEASLOG_DETAIL_ORDER_DESC));// array(2) {// [0]=>// string(125) "2021/01/06 020212 | INFO | 6840 | new_request_id5ff51a248e1e2 | 1609898532.582 | Test Info1 Log | localhost.localdomain | Get"// [1]=>// string(124) "2021/01/06 020212 | INFO | 6840 | new_request_id5ff51a248e1e2 | 1609898532.582 | Test Info Log | localhost.localdomain | Get"// }analyzerDetail() 是可以根据条件展示具体的日记信息。它也是可以指定日记类型、路径目录、关键词信息的,别的它还能够指定返回的条数、排序等,也就是自带范围查找及翻页功能。是不是非常地强悍。同 analyzerCount() 一样,它的参数也都可以设置为 null 表示当前这个参数不启用走默认的值。比如我们这个测试代码中的 null 就是关键字那个参数位置,表示的就是不消去含糊匹配关键字。
内存缓冲区日记
除了可以直接记录文件日记外,SeasLog 还可以在 php.ini 中通过配置来将文件发送到指定的 tcp 或 ftp 服务器,这个大家可以自行相识下。而接下来要学习的是在内存中缓存日记的操作。通过这个配置,我们可以更进一步地提升 SeasLog 的性能表现。
如果每条日记都是及时地写入磁盘大概发送的外部,无疑都会带来额外的磁盘IO大概网络IO开销,为了进一步提升性能,SeasLog 中提供的内存缓冲能力就可以帮我们办理问题,它的意思实在就是先将日记保存在内存中,然后到达肯定命量之后再一次性地写入到磁盘大概发送给外部。
var_dump(SeasLog::getBufferEnabled()); // bool(false)// seaslog.use_buffer=1// seaslog.buffer_disabled_in_cli=0// seaslog.buffer_size=100var_dump(SeasLog::getBufferEnabled()); // bool(true)我们需要在 php.ini 中配置 seaslog.use_buffer 为 1 ,也就是开启内存缓冲的功能。如果是命令行脚本运行的话,还需要将 seaslog.buffer_disabled_in_cli 设置为 0 ,关闭“内存缓冲在cli情况下不启用”的功能。最后,设置一下 seaslog.buffer_size ,也就是缓冲区保存多少条数据。当这些设置完成之后,利用 getBufferEnabled() 就可以看到返回的内容是 true 了,也就是我们已经开启了内存缓冲的能力。
接下来,利用 getBuffer() 方法就可以看到目前在内存缓冲区中的所有日记信息了。
var_dump(SeasLog::getBuffer());// array(3) {// [".//default/20210106.log"]=>// array(2) {// [0]=>// string(125) "2021-01-06 02:21:43 | INFO | 8006 | 5ff51eb7e1a54 | 1609899703.924 | Test Logger Default | localhost.localdomain | /bin/bash// "// ……………………// }// [".//mylog/20210106.log"]=>// array(8) {// [0]=>// string(123) "2021-01-06 02:21:43 | INFO | 8006 | 5ff51eb7e1a54 | 1609899703.924 | Test Logger MyLog | localhost.localdomain | /bin/bash// "// ……………………// }// [".//defaultNew/20210106.log"]=>// array(9) {// [0]=>// string(126) "2021/01/06 022143 | INFO | 8006 | new_request_id5ff51eb7e1b30 | 1609899703.924 | Test Info1 Log | localhost.localdomain | Get// "// ……………………// }// }当开启了内存缓冲的功能之后,我们前面的测试代码中的所有记录日记的操作都会将日记记录在内存中了,所以 getBuffer() 方法返回的数组中会有非常多的数据。当脚本结束运行大概哀求终止的时候,这些内存中的数据就会写入磁盘大概发送走。当然,我们也可以手动地将这些数据刷新到磁盘上。
// 刷新内存缓冲区SeasLog::flushBuffer();var_dump(SeasLog::getBuffer());// array(0) {// }调用 flushBuffer() 方法就可以手动地将内存数据刷新掉,这时再调用 getBuffer() 就没有任何数据了。同时我们的测试文件中也一次性地写入了所有的日记数据。
总结
不得不说,通过这个扩展的学习貌似又发现了一个大宝藏。这种日记系统在底层扩展上举行操作,效率肯定是没有问题,但是麻烦的也是需要安装底层的扩展,而不像 monolog 之类的可以直接利用 Composer 就完成安装利用。事物总有利弊,具体符合哪种还是要根据我们的业务场景来深入分析判断。
测试代码:
https://github.com/zhangyue0503/dev-blog/blob/master/php/2021/01/source/2.学习相识PHP中的SeasLog日记扩展.php
参考文档:
https://www.php.net/manual/zh/book.seaslog.php
Github文档 [https://github.com/SeasX/SeasLog/blob/master/README_zh.md] |