日志处理

优质
小牛编辑
140浏览
2023-12-01

日志记录和写入由\think\Log类完成,通常我们使用think\facade\Log类进行静态调用。

由于日志记录了所有的运行错误,因此养成经常查看日志文件的习惯,可以避免和及早发现很多的错误隐患。

5.1的日志遵循PSR-3规范

[TOC=2,3]

日志配置

日志的配置文件是配置文件目录下的log.php文件,如果需要针对不同的模块设置不同的日志类型,则需要在模块配置目录下的log.php中配置,系统在进行日志写入之前会读取该配置文件进行初始化。

日志配置参数根据不同的日志类型有所区别,内置的日志类型包括:filesockettest(仅用于测试,不会实际记录任何日志),日志类型使用type参数配置即可。

日志的全局配置参数包含(无论使用什么日志类型都支持):

参数描述
type日志类型(或者驱动类名称)
level允许记录的日志级别
allow_key允许日志写入的授权key
close是否关闭日志写入(V5.1.8+

默认的日志类型是File方式,可以通过驱动的方式来扩展支持更多的记录方式。

文件类型日志的话,还支持下列配置参数:

参数描述
path日志存储路径
file_size日志文件大小限制(超出会生成多个文件)
apart_level独立记录的日志级别
time_format时间记录格式
single是否单一文件日志
max_files最大日志文件数(超过自动清理 V5.1.6+

为了避免同一个目录下面的日志文件过多的性能问题,日志文件会自动生成日期子目录。

下面是一个log.php配置示例:

return [
    // 日志记录方式,支持 file socket 或者自定义驱动类
    'type' => 'File',
    //日志保存目录
    'path' => '../logs/',
    //单个日志文件的大小限制,超过后会自动记录到第二个文件
    'file_size'     =>2097152,
    //日志的时间格式,默认是` c `
    'time_format'   =>'c'
],

系统并未提供关闭日志的方法,但有两种方式可以关闭日志的写入,第一种方式是设置日志类型为test,即不写入任何日志。第二种方式是设置日志记录级别,只记录需要的日志。V5.1.8+版本开始,支持配置close参数关闭全局日志写入(但不影响write方法写入日志)。

日志写入

手动记录

一般情况下,系统的日志记录是自动的,无需手动记录,但是某些时候也需要手动记录日志信息,Log类提供了3个方法用于记录日志。

方法描述
record()记录日志信息到内存
save()把保存在内存中的日志信息(用指定的记录方式)写入,并清空内存中的日志
write()实时写入一条日志信息,会触发save操作

V5.1.15+版本开始,write方法不会触发save操作

由于系统在请求结束后会自动调用Log::save方法,所以通常,你只需要调用Log::record记录日志信息即可。

record方法用法如下:

Log::record('测试日志信息');

默认记录的日志级别是info,也可以指定日志级别:

Log::record('测试日志信息,这是警告级别','notice');

采用record方法记录的日志信息不是实时保存的,如果需要实时记录的话,可以采用write方法,例如:

Log::write('测试日志信息,这是警告级别,并且实时写入','notice');

为避免内存溢出,在命令行下面执行的话日志信息会实时写入。

V5.1.6+版本开始,可以使用close方法临时关闭当前请求的日志写入。

日志级别

ThinkPHP对系统的日志按照级别来分类记录,按照PSR-3日志规范,日志的级别从低到高依次为: debug, info, notice, warning, error, critical, alert, emergency,ThinkPHP额外增加了一个sql日志级别仅用于记录SQL日志(并且仅当开启数据库调试模式有效)。

系统发生异常后记录的日志级别是error

系统提供了不同日志级别的快速记录方法,例如:

Log::error('错误信息');
Log::info('日志信息');
// 和下面的用法等效
Log::record('错误信息','error');
Log::record('日志信息','info');

还封装了一个助手函数用于日志记录,例如:

trace('错误信息','error');
trace('日志信息','info');

事实上,你可以增加自定义的日志类型,例如:

Log::record('自定义错误信息','diy');
trace('自定义错误信息','diy');

也支持指定级别日志的输入,需要配置信息:

return [
    'type'  => 'File',
    // 日志记录级别,使用数组表示
    'level' => ['error','alert'],
],

上面的配置表示只记录erroralert级别的日志信息。

默认情况下是不会记录HTTP异常日志(避免受一些攻击的影响写入大量日志),除非你接管了系统的异常处理,重写了report方法。

上下文信息

日志可以传入上下文信息(数组),并且被替换到日志内容中,例如:

Log::info('日志信息{user}', ['user'=>'流年']);

实际写入日志的时候,{user}会被替换为流年。

独立日志

为了便于分析,File类型的日志还支持设置某些级别的日志信息单独文件记录,例如:

return [
    'type'          => 'file', 
    // error和sql日志单独记录
    'apart_level'   =>  ['error','sql'],
],

设置后,就会单独生成errorsql两个类型的日志文件,主日志文件中将不再包含这两个级别的日志信息。

V5.1.17+版本开始,如果apart_level设置为true,则表示所有的日志类型都会独立记录。

单文件日志

默认情况下,日志是按照日期为目录,按天为文件生成的,但如果希望仅生成单个文件(方便其它的工具或者服务读取以及分析日志)。

return [
    'single'        =>  true,
    'file_size'     =>  1024*1024*10,    
];

开启生成单个文件后,file_sizeapart_level参数依然有效,超过文件大小限制后,系统会自动生成备份日志文件。

默认的单文件日志名是single.log,如果需要更改日志文件名,可以设置

return [
    'single'        =>  'single_file',
    'file_size'     =>  1024*1024*10,    
];

那么实际生成的日志文件名是 single_file.log,如果设置了apart_level的话,可能还会生成 single_file.error.log之类的日志。

写入授权

日志支持写入授权,我们可以设置某个请求的日志授权Key,然后设置允许授权写入的配置Key,实现个别用户日志记录的功能,从而提高高负载下的日志记录性能。

首先需要在应用配置文件或者应用公共文件中添加当前访问的授权Key定义,例如:

// 设置IP为授权Key
Log::key(Request::ip());

然后在日志配置参数中增加allow_key参数,如下:

return  [
    // 日志类型为File
    'type'      =>  'File',
    // 授权只有202.12.36.89 才能记录日志
    'allow_key' =>  ['202.12.36.89'],
]

清空日志

一旦执行save方法后,内存中的日志信息就会被自动清空,如果需要手动清空可以使用:

Log::clear();

在清空日志方法之前,你可以使用getLog方法获取内存中的日志。

// 获取错误类型日志
$error = Log::getLog('error');
// 获取全部日志
$logs = Log::getLog();

日志清空仅仅是清空内存中的日志。

日志自动清理(V5.1.6+

V5.1.6+版本开始,文件类型的日志支持自动清理。可以设置max_files参数,超过数量的最早日志将会自动删除。

例如,下面设置日志最多保存数量为30个

return [
    'type'      =>  'File',
    'max_files' =>  30,
];

设置max_files参数后,日志文件将不会分日期子目录存放。

JSON格式日志(V5.1.15+

V5.1.15+版本开始,可以支持JSON格式记录文件日志,更加方便一些第三方日志分析工具进行日志分析。

在日志配置文件中,添加

'json'  =>  true

即可开启JSON格式记录,CLI命令行的日志记录同样有效。

使用JSON格式记录后,每次请求是一行JSON数据,但如果使用Log::write记录的日志是例外的单独一行JSON数据。

JSON格式记录日志的时候,独立记录日志级别参数apart_level无效。