乐趣区

关于php:学习了解PHP中的SeasLog日志扩展

明天来学习的扩大是和日志相干的一个扩大,对于 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 Default

SeasLog::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 MyLog

Logger 信息能够看做是一个日志分类,它会把这个分类下的日志放到同一个文件夹中。比方咱们在默认状况这个 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/bash

SeasLog::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 | Get

getRequestVariable() 和 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 | Get

SeasLog::info("Test {name} Log", ['name'=>'Info1']);
// 2021/01/06 013018 | INFO | 5583 | new_request_id5ff512aaafcde | 1609896618.720 | Test Info1 Log | localhost.localdomain | Get

SeasLog::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 | Get

SeasLog::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=100
var_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/Seas…]

退出移动版