### 2019 年 7 月 28 日 发布 `6.0`的日志类比之前版本完善了很多,主要新特性包括: * 日志信息格式化 * 多通道写入支持 * 延时/实时写入 * 日志信息处理事件 * 日志级别指定通道写入 * 支持关闭日志/通道 新版的日志类最大的变化就是支持多通道写入,也就是说你可以同时或者给部分日志类型增加另外的日志通道写入,例如对于一些异常日志可以选择发送错误到邮件通知。 其它的变化主要包括: * WEB日志和CLI日志合并并统一格式; * 默认不再记录访问信息,需要可以自己记录; * 独立日志也支持JSON格式记录; 日志的相关配置可以在`config/log.php`文件中设置,本篇主要描述下新版日志的变化。 ## 日志通道 日志通道的概念相当于给日志信息做了一个日志空间,每个日志通道的日志信息采用独立的写入机制或者配置参数,你可以给日志信息指定默认的日志通道,也可以动态切换通道写入,并且支持同一个日志信息同时写入多个日志通道。 你可以在日志配置文件的`channels`配置中定义通道,默认仅定义了一个`file`通道 ``` // 日志通道列表 'channels' => [ 'file' => [ // 日志记录方式 'type' => 'File', // 日志保存目录 'path' => '', // 单文件日志写入 'single' => false, // 独立日志级别 'apart_level' => [], // 最大日志文件数量 'max_files' => 0, // 使用JSON格式记录 'json' => false, // 日志输出格式化 'format' => '[%s][%s] %s', // 是否实时写入 'realtime_write' => false, ], // 其它日志通道配置 ], ``` 每个日志通道必须指定`type`参数,该参数决定了日志的写入方式是什么,`file`就表示文件日志方式写入,如果需要指定其它的写入方式需要安装额外的扩展。但你也可以给不同的日志通道指定相同的`type`,只是其它的配置参数不同,例如写入的路径不同之类。 无论使用什么日志写入类型,每个日志通道可以支持的通用配置如下: 参数|说明 ---|--- level|日志通道记录的日志级别 realtime_write|日志是否实时写入 `level`参数的用法和全局日志配置一致,除了在命令行模式下,默认的日志都是在请求结束后统一一次性写入,如果需要实时写入日志信息需要设置。 ``` 'realtime_write' => true, ``` >[danger] 如果在命令行下,无论是否设置都会自动实时写入日志。 ### 默认通道 通过设置`default`参数定义日志的默认通道,例如: ``` 'default' => 'file', ``` ### 级别通道 可以设置不同的日志级别使用不同的日志通道 ``` 'type_channel' => [ // 对于error日志级别 同时写入file和email两个日志通道 'error' => ['file','email'], ] ``` >[danger] 设置了级别通道后,该级别的日志不会记录到默认通道,请注意。 日志通道需要日志驱动的配合,你也可以自定义日志驱动。 ### 切换通道 你也可以手动切换当前的日志的默认写入通道,例如: ``` Log::channel('email')->info('这是日志信息'); ``` 支持切换使用多个通道记录,例如: ``` Log::channel(['email', 'file'])->info('这是日志信息'); ``` ## 日志处理 日志写入支持事件监听,例如。 ~~~ Event::listen('think\event\LogWrite', function($event) { if('file' == $event->channel) { $event->log['info'][] = 'test info'; } }); ~~~ 闭包的参数是`LogWrite`事件类对象实例,你可以获取两个属性: 属性名|描述 ----|---- channel |写入日志的通道名 log |写入的日志信息 日志信息是一个二维数组,包含了当前日志通道下(允许记录的)所有级别的日志信息。 ## 格式化日志信息 系统提供了两个参数用于日志信息的格式化,第一个是用于自定义时间显示格式的`time_format`,第二个是调整日志输出格式的`format`参数。 ``` 'channels' => [ 'file' => [ 'type' => 'file', 'json' => true 'file_size' => 1024*1024*10, 'time_format' => 'Y-m-d H:i:s', 'format' => '[%s][%s]:%s', ], ], ``` `format`参数的第一个`%s`是日志记录时间(日志时间的格式化由`time_format`参数定义) 第二个`%s`是日志级别 第三个`%s`是日志信息,顺序不能调整。 ## JSON格式日志 可以支持`JSON`格式记录文件日志,更加方便一些第三方日志分析工具进行日志分析。 在日志配置文件中,添加 ~~~ return [ 'default' => 'file', 'channels' => [ 'file' => [ 'type' => 'file', 'json' => true 'file_size' => 1024*1024*10, ], ], ]; ~~~ 即可开启`JSON`格式记录,CLI命令行的日志记录同样有效。 >[danger] 和之前版本的区别在于,新版的每个日志信息都是一条JSON数据(旧版本是每个请求一条JSON数据)。 ## 关闭日志 你可以通过调用`close`方法动态关闭日志写入。 ``` // 关闭全局日志写入 Log::close(); // 关闭某个通道日志写入 Log::close('file'); ``` 如果调用`close`方法动态关闭日志,会自动调用`clear`方法清空日志。 ## 清空日志 一旦执行`save`方法后,内存中的日志信息就会被自动清空,如果需要提前清空日志可以使用: ``` // 清空所有日志 Log::clear(); //清空通道日志可以使用 Log::clear('file'); ``` 在清空日志方法之前,你可以使用`getLog`方法获取内存中的日志。 ~~~ // 获取(默认通道)日志 $logs = Log::getLog(); // 获取指定通道日志 $logs = Log::getLog('file'); ~~~ >[danger] 日志清空仅仅是清空内存中的日志。 ## 自定义驱动 日志通道需要自定义日志驱动,该日志驱动需要实现`think\contract\LogHandlerInterface`接口。 ``` interface LogHandlerInterface { /** * 日志写入接口 * @access public * @param array $log 日志信息 * @return bool */ public function save(array $log): bool; } ```