01-monolog - PHP 日志神器

Monolog sends your logs to files, sockets, inboxes, databases and various web services.

Monolog 发送你的日志到文件、到sockets、到邮箱、到数据库或(和)者其他网路存储服务(云)。这里用了,因为Monolog的确可以做到同时保存到一个或多个存储介质。

安装

$ composer require monolog/monolog

基本用法 (初步印象)

<?php
use Monolog\Logger;
use Monolog\Handler\StreamHandler;

// create a log channel
$log = new Logger('name');
$log->pushHandler(new StreamHandler('path/to/your.log', Logger::WARNING));

// add records to the log
$log->warning('Foo');$log->error('Bar');

核心概念

Every Logger instance has a channel (name) and a stack of handlers. Whenever you add a record to the logger, it traverses the handler stack. Each handler decides whether it fully handled the record, and if so, the propagation of the record ends there.

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

这就允许我们灵活的设置日志了。比如我们有一个StreamHandler,它在的最底部,它会把记录都保存到硬盘上,在它上面有一个MailHandler,它会在错误消息被记录的时候发送邮件。Handlers 都有一个$bubble属性,用来定义当某个处理程序在处理记录的时候是否阻塞处理(阻塞的话,就是这个记录到我这里就算处理完毕了,不要冒泡处理了,听话)。在这个例子中,我们设置MailHandler$bubblefalse,意思就是说记录都会被MailHandler处理,不会冒泡到StreamHandler了。

我必须补充一下:这里提到了栈,也提到了冒泡,乍一看有点晕,因为我们理解冒泡是自下而上的过程,栈就是一个类似杯子的容器,然后上面又说底部是StreamHandler,上面是MailHandler,结果是MailHandler处理了,停止冒泡到StreamHandler了,给人的感觉是这个泡是从上往下冒的,666,这能叫冒泡么?英雄时刻:堆呀栈呀啥的,我也看过N次,但也总是忘(原谅我野生的),这里再次谨记,堆是先进先出(First-In/First-Out),想想[自来]水管;栈就是先进后出(First-In/Last-Out),想想一个有N层颜色的冰淇淋装在一个杯子里,下面是黄色的,...,最上面是粉红的,所以,你先吃得是粉红色的(MailHandler),后吃的是黄色的(StreamHandler),实际上,这个泡冒的没错,确切的说,这个泡冒在了一个倒立的杯子中,当然杯口没有被封住。

继续...

我们可以创建很多Logger,每个Logger定义一个通道(e.g.:db,request,router,...),每个通道可结合多个Handler,Handler可以被写成可通用的或者不可通用的。通道,同日志中日期时间一样,它是一个名称,在日志中就是一个字符串被记录下来,大概是这样 2016-04-25 12:33:00 通道名称 记录内容,具体格式看设置了,可以用来识别或者过滤。

每一个Handler都有一个Formatter,用来格式化日志了。不详细介绍了。

自定义日志等级在monolog中不可用,只有8种RFC 5424 等级,即 debug, info, notice, warning, error, critical, alert, emergency。但是如果我们真的有特殊需求的话,比如归类等,我们可以添加Processors到 Logger,当然是在日志消息被处理之前。<strike>我这估计这辈子都不会添加Processors。</strike>

日志等级

  • DEBUG (100): Detailed debug information.详细的Debug信息
  • INFO (200): Interesting events. Examples: User logs in, SQL logs.感兴趣的事件或信息,如用户登录信息,SQL日志信息
  • NOTICE (250): Normal but significant events.普通但重要的事件信息
  • WARNING (300): Exceptional occurrences that are not errors. Examples: Use of deprecated APIs, poor use of an API, undesirable things that are not necessarily wrong.
  • ERROR (400): Runtime errors that do not require immediate action but should typically be logged and monitored.
  • CRITICAL (500): Critical conditions. Example: Application component unavailable, unexpected exception.
  • ALERT (550): Action must be taken immediately. Example: Entire website down, database unavailable, etc. This should trigger the SMS alerts and wake you up.
  • EMERGENCY (600): Emergency: system is unusable.

配置一个Logger

Here is a basic setup to log to a file and to firephp on the DEBUG level:

<?php
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\FirePHPHandler;

// Create the logger
$logger = new Logger('my_logger');

// Now add some handlers
$logger->pushHandler(new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG));
$logger->pushHandler(new FirePHPHandler());

// You can now use your logger
$logger->addInfo('My logger is now ready');

我们来分析一下这个配置。
The first step is to create the logger instance which will be used in your code. The argument is a channel name, which is useful when you use several loggers (see below for more details about it).
第一步,创建Logger实例,参数即通道名字。

The logger itself does not know how to handle a record. It delegates it to some handlers. The code above registers two handlers in the stack to allow handling records in two different ways.
Logger本身不知道如何处理记录,它将处理委托给Handler[s],上面的代码注册了两个Handlers,这样就可以用两种方法来处理记录。

Note that the FirePHPHandler is called first as it is added on top of the stack. This allows you to temporarily add a logger with bubbling disabled if you want to override other configured loggers.
提示:FirePHPHandler最先被调用,因为它被添加在栈的顶部。这就允许你临时添加一个阻塞的Logger,如果你想覆盖其他Logger[s]的话。

添加额外的数据到记录

Monolog 提供两种方法来添加额外的信息到简单的文本信息(along the simple textual message)。

使用日志上下文

第一种,即当前日志上下文,允许传递一个数组作为第二个参数,这个数组的数据是额外的信息:

<?php

$logger->addInfo('Adding a new user', array('username' => 'Seldaek'));

简单的Handler(SteamHandler)会简单的将数组格式化为字符串,功能丰富点的Handler(FirePHP)可以搞得更好看。

使用 processors

Processors 可以是任何可调用的方法(回调)。它们接受$record作为参数,然后返回它($record),返回之前,即是我们添加额外信息的操作,在这里,这个操作是改变$recordextrakey的值。像这样:

<?php

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

Monolog 提供了一些内置的 processors。看dedicated chapter
收回我说的话,我可能很快就会用到 Processors的。

使用通道

通道是识别record记录的是程序哪部分的好方法(当然,关键词匹配啊),这在大型应用中很有用,如 MonologBundle in Symfony2。

想象一下,两个Logger共用一个Handler,通过这个Handler将记录写入一个文件。这时使用通道能够让我们识别出是哪一个Logger处理的。我们可简单的在这个文件中过滤这个或者那个通道。

<?php

use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\FirePHPHandler;

// Create some handlers
$stream = new StreamHandler(__DIR__ . '/my_app.log', Logger::DEBUG);
$firephp = new FirePHPHandler();

// Create the main logger of the app
$logger = new Logger('my_logger');
$logger->pushHandler($stream);
$logger->pushHandler($firephp);

// Create a logger for the security-related stuff with a different channel
$securityLogger = new Logger('security');
$securityLogger->pushHandler($stream);
$securityLogger->pushHandler($firephp);

// Or clone the first one to only change the channel
$securityLogger = $logger->withName('security');

自定义日志格式

在 Monolog 中个性化日志是很easy的。大部分 Handler 使用

$record['formatted']

的值。这个值依赖于 formatter 的设置。我们可以选择预定义的 formatter 类或者编写自己的。

配置一个预定义的 formatter 类,只需要将其设置成 Handler 的字段(属性)即可:

// the default format is "Y-m-d H:i:s"
$dateFormat = "Y n j, g:i a";
// the default output format is [%datetime%] %channel%.%level_name%: %message% %context% %extra%\n"
$output = "%datetime% > %level_name% > %message% %context% %extra%\n";
$formatter = new LineFormatter($output, $dateFormat);

// Create a handler
$stream = new StreamHandler(__DIR__ . 'my_app.log', Logger:DEBUG);
$stream->setFormatter($formatter);
// bind it to a logger object
$securityLogger = new Logger('security');
$securityLogger->pushHandler($stream);

formatter 是可以在N个 Handler 之间复用的,并且可在N个 Logger 之间共享 Handler。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容