使用Monolog做日志
Symfony自帶了一個(gè)外部庫(kù) - 叫做 Monolog - 它允許你創(chuàng)建“可以存放在各種不同地方”的日志。
記錄一條信息 ?
要記錄一條信息,從控制器中的容器取出 logger
服務(wù):
public function indexAction(){ $logger = $this->get('logger'); $logger->info('I just got the logger'); $logger->error('An error occurred'); $logger->critical('I left the oven on!', array( // include extra "context" info in your logs / 在日志中附帶額外的“上下文”信息 'cause' => 'in_hurry', )); // ...}
logger 服務(wù)針對(duì)不同的日志等級(jí)/優(yōu)先級(jí)擁有不同的方法。你可以基于信息的 等級(jí) 來(lái)配置logger去做不同的事(如 有錯(cuò)誤發(fā)生時(shí)發(fā)送郵件)。
參考 LoggerInterface 以了解logger的全部方法列表。
日志被存在哪里 ?
對(duì)于把日志存放于 何處 的配置信息,位于特定的 environment 配置文件: config_dev.yml
和 config_prod.yml
之中。
當(dāng)你處于 dev
環(huán)境時(shí),日志文件入口被默認(rèn)寫(xiě)進(jìn)了 var/logs/dev.log
文件。在 prod
環(huán)境下,日志被寫(xiě)入 var/logs/prod.log
,但卻 僅 在請(qǐng)求過(guò)程中遇到錯(cuò)誤或是遇到高優(yōu)先級(jí)日志時(shí)才會(huì)發(fā)生(如 error()
, critical()
, alert()
或 emergency()
)。
要控制存放位置,你要配置不同的 handlers(控制器)來(lái)控制日志入口點(diǎn)(entries),必要時(shí)修改它們,最終存儲(chǔ)它們。
Handlers: 把日志寫(xiě)入不同的位置 ?
logger自帶了一組 handlers,每一種都用于把日志入口寫(xiě)入到不同的位置(如,文件,數(shù)據(jù)庫(kù),Slack等)。
你 還 能配置日志的 "channels"(頻道),這就像分類(lèi)。每個(gè)頻道可以有其 自己的 handlers,這意味著你可以把不同的信息記錄到不同的地方。參考 如何把日志信息寫(xiě)入不同的文件中。
Symfony在 config_dev.yml
和 config_prod.yml
文件中預(yù)置了一些handlers。要了解真實(shí)用例不妨查看它們。
下例使用了 兩個(gè) handlers: stream
(用于寫(xiě)入文件) 和 syslog
,后者使用 syslog
函數(shù)來(lái)完成日志:
YAML:# app/config/config.ymlmonolog: handlers: # this "file_log" key could be anything # 這個(gè) "file_log" 鍵可以是任何(合法)字符 file_log: type: stream # log to var/logs/(environment).log # 寫(xiě)入到 var/logs/(environment).log path: "%kernel.logs_dir%/%kernel.environment%.log" # log *all* messages (debug is lowest level) # 把 *全部* 信息寫(xiě)入(debug是最低級(jí)別) level: debug syslog_handler: type: syslog # log error-level messages and higher # 記錄 error-level(ERROR級(jí)別)或更高級(jí)別(的信息) level: error
XML:<!-- app/config/config.xml --><?xml version="1.0" encoding="UTF-8" ?><container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:monolog="http://symfony.com/schema/dic/monolog" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd http://symfony.com/schema/dic/monolog http://symfony.com/schema/dic/monolog/monolog-1.0.xsd"> <monolog:config> <monolog:handler name="file_log" type="stream" path="%kernel.logs_dir%/%kernel.environment%.log" level="debug" /> <monolog:handler name="syslog_handler" type="syslog" level="error" /> </monolog:config></container>
PHP:// app/config/config.php$container->loadFromExtension('monolog', array( 'handlers' => array( 'file_log' => array( 'type' => 'stream', 'path' => '%kernel.logs_dir%/%kernel.environment%.log', 'level' => 'debug', ), 'syslog_handler' => array( 'type' => 'syslog', 'level' => 'error', ), ),));
本例定義了一 組 handler,它們會(huì)按照各自被定義的順序被調(diào)用。
可修改日志入口的handlers ?
并非將日志寫(xiě)入某處的文件, 一些 handlers可用于“在將日志發(fā)送到 其他 handlers之前”過(guò)濾和修改它們。一個(gè)內(nèi)置的名為 fingers_crossed
的強(qiáng)大handleris默認(rèn)用于 prod
環(huán)境下。它在請(qǐng)求過(guò)程中存儲(chǔ) 全部 日志信息,卻 只是 將它們傳入第二個(gè)handler,如果某條信息達(dá)到 action_level
級(jí)別的話??匆韵吕?
YAML:# app/config/config.ymlmonolog: handlers: filter_for_errors: type: fingers_crossed # if *one* log is error or higher, pass *all* to file_log # 如果 *一條* 日志是error或更高(的級(jí)別),把它們 *全部* 傳入file_log action_level: error handler: file_log # now passed *all* logs, but only if one log is error or higher # 現(xiàn)在傳入了 *全部* 日志,但只是那些error或更高級(jí)別的 file_log: type: stream path: "%kernel.logs_dir%/%kernel.environment%.log" # still passed *all* logs, and still only logs error or higher # 仍然傳入了 *全部* 日志,并且仍然都是error或更高級(jí)別的 syslog_handler: type: syslog level: error
XML:<!-- app/config/config.xml --><?xml version="1.0" encoding="UTF-8" ?><container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:monolog="http://symfony.com/schema/dic/monolog" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd http://symfony.com/schema/dic/monolog http://symfony.com/schema/dic/monolog/monolog-1.0.xsd"> <monolog:config> <monolog:handler name="filter_for_errors" type="fingers_crossed" action-level="error" handler="file_log" /> <monolog:handler name="file_log" type="stream" path="%kernel.logs_dir%/%kernel.environment%.log" level="debug" /> <monolog:handler name="syslog_handler" type="syslog" level="error" /> </monolog:config></container>
PHP:// app/config/config.php$container->loadFromExtension('monolog', array( 'handlers' => array( 'filter_for_errors' => array( 'type' => 'fingers_crossed', 'action_level' => 'error', 'handler' => 'file_log', ), 'file_log' => array( 'type' => 'stream', 'path' => '%kernel.logs_dir%/%kernel.environment%.log', 'level' => 'debug', ), 'syslog_handler' => array( 'type' => 'syslog', 'level' => 'error', ), ),));
現(xiàn)在,如果某一日志入口(log entry,譯注:即“位于某處的日志文件”)遇到了 error
或更高級(jí)別的(信息),則該請(qǐng)求的 所有 日志入口將通過(guò) file_log
handler被存成一個(gè)文件。這意味著你的日志文件將包含問(wèn)題請(qǐng)求的 全部 相關(guān)細(xì)節(jié) - 這令調(diào)試變得更容易!
名為 "file_log" 的handler將不包括在控制器堆棧中,因?yàn)樗亲鳛?fingers_crossed
handler的嵌套控制器來(lái)使用。
如果你希望通過(guò)另一個(gè)配置文件來(lái)覆寫(xiě) monolog
配置信息,你需要重新定義整個(gè) handlers
stack(控制器堆棧)。這兩個(gè)文件中的配置信息不能被合并,因?yàn)椋╤andler的)順序很關(guān)鍵,一旦合并就無(wú)法控制順序。
所有的內(nèi)置handler ?
Monolog內(nèi)置了 許多 用于發(fā)送日志郵件的handlers,把它們發(fā)送到Loggly,或者在Slack中通知你。這些功能在MonologBundle中都有文檔。完整的列表請(qǐng)參考 Monolog Configuration。
如何翻轉(zhuǎn)你的日志文件 ?
時(shí)間一長(zhǎng),不管是開(kāi)發(fā)環(huán)境還是生產(chǎn)環(huán)境,日志文件會(huì)變得 極為巨大。解決方案中的一個(gè)最佳實(shí)踐是使用諸如 logrotate 這種Linux command來(lái)在日志文件巨型化之前反轉(zhuǎn)之。
另一個(gè)選項(xiàng)是使用rotating_file
handler來(lái)令Monolog去反轉(zhuǎn)日志文件。這個(gè)控制器每天會(huì)創(chuàng)建新的日志文件,并自動(dòng)刪除舊的。要使用它,把控制器中的 type
選項(xiàng)設(shè)為 rotating_file
即可:
PHP:// app/config/config_dev.php$container->loadFromExtension('monolog', array( 'handlers' => array( 'main' => array( 'type' => 'rotating_file', 'path' => "%kernel.logs_dir%/%kernel.environment%.log", 'level' => 'debug', // max number of log files to keep // defaults to zero, which means infinite files 'max_files' => 10, ), ),));
XAML:<!-- app/config/config_dev.xml --><?xml version="1.0" encoding="UTF-8" ?><container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:monolog="http://symfony.com/schema/dic/monolog" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd http://symfony.com/schema/dic/monolog http://symfony.com/schema/dic/monolog/monolog-1.0.xsd"> <monolog:config> <!-- "max_files": max number of log files to keep defaults to zero, which means infinite files --> <monolog:handler name="main" type="rotating_file" path="%kernel.logs_dir%/%kernel.environment%.log" level="debug" max_files="10" /> </monolog:config></container>
YAML:# app/config/config_dev.ymlmonolog: handlers: main: type: rotating_file path: '%kernel.logs_dir%/%kernel.environment%.log' level: debug # max number of log files to keep # defaults to zero, which means infinite files # 要保留的日志文件的最大數(shù)量,默認(rèn)是零,即,無(wú)限個(gè)文件 max_files: 10