每一个Logger实例都有一个通道(也就是一个唯一的名称)和一个有由一个或多个处理程序组成的栈。当我们添加一个记录到Logger的时候,它会遍历这个处理程序栈。每一个处理程序决定是否去充分处理这个记录,如果是,则处理到此为止(停止冒泡)。这里的充分指的是我们想不想了,想的话就继续,不想就停止。
这就允许我们灵活的设置日志了。比如我们有一个StreamHandler,它在栈的最底部,它会把记录都保存到硬盘上,在它上面有一个MailHandler,它会在错误消息被记录的时候发送邮件。Handlers 都有一个 b u b b l e 属 性 , 用 来 定 义 当 某 个 处 理 程 序 在 处 理 记 录 的 时 候 是 否 阻 塞 处 理 ( 阻 塞 的 话 , 就 是 这 个 记 录 到 我 这 里 就 算 处 理 完 毕 了 , 不 要 冒 泡 处 理 了 , 听 话 ) 。 在 这 个 例 子 中 , 我 们 设 置 M a i l H a n d l e r 的 bubble属性,用来定义当某个处理程序在处理记录的时候是否阻塞处理(阻塞的话,就是这个记录到我这里就算处理完毕了,不要冒泡处理了,听话)。在这个例子中,我们设置MailHandler的 bubble属性,用来定义当某个处理程序在处理记录的时候是否阻塞处理(阻塞的话,就是这个记录到我这里就算处理完毕了,不要冒泡处理了,听话)。在这个例子中,我们设置MailHandler的bubble为false,意思就是说记录都会被MailHandler处理,不会冒泡到StreamHandler了。
我必须补充一下:这里提到了栈,也提到了冒泡,乍一看有点晕,因为我们理解冒泡是自下而上的过程,栈就是一个类似杯子的容器,然后上面又说底部是StreamHandler,上面是MailHandler,结果是MailHandler处理了,停止冒泡到StreamHandler了,给人的感觉是这个泡是从上往下冒的,666,这能叫冒泡么?英雄时刻:堆呀栈呀啥的,我也看过N次,但也总是忘(原谅我野生的),这里再次谨记,堆是先进先出(First-In/First-Out),想想[自来]水管;栈就是先进后出(First-In/Last-Out),想想一个有N层颜色的冰淇淋装在一个杯子里,下面是黄色的,…,最上面是粉红的,所以,你先吃得是粉红色的(MailHandler),后吃的是黄色的(StreamHandler),实际上,这个泡冒的没错,确切的说,这个泡冒在了一个倒立的杯子中,当然杯口没有被封住。
总结:简而言之,pushHandler(xxx)执行一次,相当于入栈。所以各handle处理日志的顺序根据pushHandle调用顺序有关
use Monolog\Formatter\HtmlFormatter;
use Monolog\Formatter\NormalizerFormatter;
use Monolog\Formatter\ScalarFormatter;
use Monolog\Formatter\WildfireFormatter;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\FirePHPHandler;
use Monolog\Processor\IntrospectionProcessor;
use Monolog\Processor\UidProcessor;
use Monolog\Processor\ProcessIdProcessor;
use Monolog\Processor\WebProcessor;
use Monolog\Formatter\JsonFormatter;
use Monolog\Processor\MemoryUsageProcessor;
use Monolog\Processor\MemoryPeakUsageProcessor;
use Monolog\Processor\GitProcessor;
use Monolog\Processor\MercurialProcessor;
use Monolog\Processor\TagProcessor;
class Test
{
$date = date('Y-m-d');
$filePath = storage_path() . "/logs/test-{$date}.log";
$stream = new StreamHandler($filePath, Logger::DEBUG);
//创建一个通道
$logger = new Logger('my_logger');
//设置日志格式
$firephp = new FirePHPHandler();
$formatter = new JsonFormatter();
$formatter = new HtmlFormatter();//日志变为html
$formatter = new NormalizerFormatter();
$formatter = new ScalarFormatter();
$formatter = new WildfireFormatter();
$stream->setFormatter($formatter);
//设置处理者
$logger->pushHandler($stream);
//额外增加日志内容
$logger->pushProcessor(new WebProcessor());
$logger->pushProcessor(new IntrospectionProcessor());
$logger->pushProcessor(new MemoryUsageProcessor());
$logger->pushProcessor(new MemoryPeakUsageProcessor());
$logger->pushProcessor(new ProcessIdProcessor());
$logger->pushProcessor(new GitProcessor());
$logger->pushProcessor(new MercurialProcessor());
$logger->pushProcessor(new TagProcessor());
$logger->pushProcessor(function ($record) {
$record['extra']['dummy'] = 'Hello world!';
return $record;
});
//写日志
$logger->info('ok', ['name' => 'jack', 'age' => 20]);
}
<h1 style="background: #468847;color: #ffffff;padding: 5px;" class="monolog-output">INFO</h1><table cellspacing="1" width="100%" class="monolog-output"><tr style="padding: 4px;text-align: left;">
<th style="vertical-align: top;background: #ccc;color: #000" width="100">Message:</th>
<td style="padding: 4px;text-align: left;vertical-align: top;background: #eee;color: #000"><pre>ok</pre></td>
</tr><tr style="padding: 4px;text-align: left;">
<th style="vertical-align: top;background: #ccc;color: #000" width="100">Time:</th>
<td style="padding: 4px;text-align: left;vertical-align: top;background: #eee;color: #000"><pre>2020-11-05 18:08:16</pre></td>
</tr><tr style="padding: 4px;text-align: left;">
<th style="vertical-align: top;background: #ccc;color: #000" width="100">Channel:</th>
<td style="padding: 4px;text-align: left;vertical-align: top;background: #eee;color: #000"><pre>my_logger</pre></td>
</tr><tr style="padding: 4px;text-align: left;">
<th style="vertical-align: top;background: #ccc;color: #000" width="100">Extra:</th>
<td style="padding: 4px;text-align: left;vertical-align: top;background: #eee;color: #000"><table cellspacing="1" width="100%"><tr style="padding: 4px;text-align: left;">
<th style="vertical-align: top;background: #ccc;color: #000" width="100">dummy:</th>
<td style="padding: 4px;text-align: left;vertical-align: top;background: #eee;color: #000"><pre>Hello world!</pre></td>
</tr><tr style="padding: 4px;text-align: left;">
<th style="vertical-align: top;background: #ccc;color: #000" width="100">url:</th>
<td style="padding: 4px;text-align: left;vertical-align: top;background: #eee;color: #000"><pre>/admin/admin/list</pre></td>
</tr><tr style="padding: 4px;text-align: left;">
<th style="vertical-align: top;background: #ccc;color: #000" width="100">ip:</th>
<td style="padding: 4px;text-align: left;vertical-align: top;background: #eee;color: #000"><pre>127.0.0.1</pre></td>
</tr><tr style="padding: 4px;text-align: left;">
<th style="vertical-align: top;background: #ccc;color: #000" width="100">http_method:</th>
<td style="padding: 4px;text-align: left;vertical-align: top;background: #eee;color: #000"><pre>GET</pre></td>
</tr><tr style="padding: 4px;text-align: left;">
<th style="vertical-align: top;background: #ccc;color: #000" width="100">server:</th>
<td style="padding: 4px;text-align: left;vertical-align: top;background: #eee;color: #000"><pre>localhost.ab.com</pre></td>
</tr><tr style="padding: 4px;text-align: left;">
<th style="vertical-align: top;background: #ccc;color: #000" width="100">referrer:</th>
<td style="padding: 4px;text-align: left;vertical-align: top;background: #eee;color: #000"><pre>http://localhost.ab.com/admin/index/index</pre></td>
</tr></table></td>
</tr></table>
{"message":"ok","context":[],"level":200,"level_name":"INFO","channel":"my_logger","datetime":{"date":"2020-11-05 18:12:02.370318","timezone_type":3,"timezone":"Asia/Shanghai"},"extra":{"dummy":"Hello world!","url":"/admin/admin/list","ip":"127.0.0.1","http_method":"GET","server":"localhost.ab.com","referrer":"http://localhost.ab.com/admin/index/index"}}
253|[{"Type":"INFO","File":"","Line":"","Label":"my_logger"},{"message":"ok","extra":{"dummy":"Hello world!","url":"/admin/admin/list","ip":"127.0.0.1","http_method":"GET","server":"localhost.ab.com","referrer":"http://localhost.ab.com/admin/index/index"}}]|
{
"dummy":"Hello world!",
"url":"/admin/admin/list",
"ip":"127.0.0.1",
"http_method":"GET",
"server":"localhost.ab.com",
"referrer":"http://localhost.ab.com/admin/index/index"
}
{
"file":"E:\CodeSoftware\workspace\php\git\accountBook\app\Http\Controllers\Admin\AdminController.php",
"line":91,
"class":"App\Http\Controllers\Admin\AdminController",
"function":"listAdmin"
}
{
"memory_usage":"2 MB"
}
{
"memory_peak_usage":"2 MB"
}
{
"process_id":8624
}
{
"git":{
"branch":"master",
"commit":"63940b3472086a150ff77209a6a641340d0f835a"
}
{
"hg":[
]
}
{
"tags":[
]
}
$logger->pushProcessor(function ($record) {
$record['extra']['dummy'] = 'Hello world!';
return $record;
});
{
"dummy":"Hello world!"
}
{
"uid":"1a01a96"
}
monolog的设置项当然还有很多,以上是最常用的选项。
monolog github 仓库:https://github.com/Seldaek/monolog
优秀的帖子:
laravel接合monolog实现日志记录到Elasticsearch实践https://blog.csdn.net/qq_39941141/article/details/103960234
monolog使用参考
https://blog.csdn.net/wuqing2012mxd/article/details/99645095