当前位置: 首页 > 工具软件 > Monolog > 使用案例 >

monolog深度使用

丁勇
2023-12-01

核心概念

每一个Logger实例都有一个通道(也就是一个唯一的名称)和一个有由一个或多个处理程序组成的栈。当我们添加一个记录到Logger的时候,它会遍历这个处理程序栈。每一个处理程序决定是否去充分处理这个记录,如果是,则处理到此为止(停止冒泡)。这里的充分指的是我们想不想了,想的话就继续,不想就停止。

这就允许我们灵活的设置日志了。比如我们有一个StreamHandler,它在栈的最底部,它会把记录都保存到硬盘上,在它上面有一个MailHandler,它会在错误消息被记录的时候发送邮件。Handlers 都有一个 b u b b l e 属 性 , 用 来 定 义 当 某 个 处 理 程 序 在 处 理 记 录 的 时 候 是 否 阻 塞 处 理 ( 阻 塞 的 话 , 就 是 这 个 记 录 到 我 这 里 就 算 处 理 完 毕 了 , 不 要 冒 泡 处 理 了 , 听 话 ) 。 在 这 个 例 子 中 , 我 们 设 置 M a i l H a n d l e r 的 bubble属性,用来定义当某个处理程序在处理记录的时候是否阻塞处理(阻塞的话,就是这个记录到我这里就算处理完毕了,不要冒泡处理了,听话)。在这个例子中,我们设置MailHandler的 bubbleMailHandlerbubble为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]);
}

HtmlFormatter:日志为一个html(多个日志,则会叠加)

<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>

JsonFormatter:日志为一个json格式的字符串

{"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"}}

WildfireFormatter:用于将日志记录格式化为Wildfire/FirePHP协议,仅对FirePHPHandler有用

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"}}]|

额外增加日志内容

WebProcessor:将当前请求URI、请求方法和客户端IP添加到日志记录中

{
    "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"
}

IntrospectionProcessor:添加产生日志调用的行/文件/类/方法

{
    "file":"E:\CodeSoftware\workspace\php\git\accountBook\app\Http\Controllers\Admin\AdminController.php",
    "line":91,
    "class":"App\Http\Controllers\Admin\AdminController",
    "function":"listAdmin"
}

MemoryUsageProcessor:将当前内存使用情况添加到日志记录中

{
    "memory_usage":"2 MB"
}

MemoryPeakUsageProcessor:将当前峰值内存使用量添加到日志记录中内存使用量添加到日志记录

{
    "memory_peak_usage":"2 MB"
}

ProcessIdProcessor:将进程id添加到日志记录中

{
    "process_id":8624
}

GitProcessor:添加当前git分支并提交到日志记录

{
    "git":{
        "branch":"master",
        "commit":"63940b3472086a150ff77209a6a641340d0f835a"
    }

MercurialProcessor:添加当前hg分支并提交到日志记录

{
    "hg":[

    ]
}

TagProcessor:向日志记录添加预定义标记数组

{
    "tags":[

    ]
}

pushProcessor添加额外数据

$logger->pushProcessor(function ($record) {
	$record['extra']['dummy'] = 'Hello world!';
	return $record;
});
{
    "dummy":"Hello world!"
}

UidProcessor:向日志记录添加唯一标识符

{
    "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

 类似资料: