簡述
什么是SeasLog
SeasLog是一個C語言編寫的PHP擴展,提供一組規范標准的功能函數,在PHP項目中方便、規范、高效地寫日志,以及快速地讀取和查詢日志。
為什么使用SeasLog
無論在什么應用中,log
日志都是架構中不可缺少的一個重要組成部分,它通常是系統或軟件、應用的運行記錄。通過log
的分析,可以方便用戶了解系統或軟件、應用的運行情況;如果你的應用log
足夠豐富,也可以分析以往用戶的操作行為、類型喜好、地域分布或其他更多信息;如果一個應用的log
同時也分了多個級別,那么可以很輕易地分析得到該應用的健康狀況,及時發現問題並快速定位、解決問題,補救損失。
我們知道,php
內置了很多log
函數,如error_log
、syslog
、file_put_content
,這些函數功能強大且性能極好,但由於各種缺陷(error_log
、file_put_content
無錯誤級別、無固定格式像是信馬由韁隨處亂畫;syslog
不區分模塊、而且與系統日志混合,讀syslog
記錄會讓人抓狂的。),靈活度降低了很多,很不能滿足應用需求。基本上所有的開發者,都會自行設計封裝log
庫,當然也會有很多開發者選擇已有的開源日志庫。
也有很多開源log
類庫彌補了上述缺陷,如log4php
、plog
、Analog
等(當然也有很多應用在項目中自己開發的log
類)。其中以log4php
最為著名,它的設計精良、格式完美、文檔完善、功能強大。但是經過測試,log4php
的性能非常差。
而sealog
在性能上有着強大的優勢,假設一個請求中需要寫出1000處log,那么勢必會有1000次IO,這對性能將是一個很大的拖延點。一般對於處理這種多次相同的請求場景,我們要解決的其實也很簡單,使用cache或buffer,把多次請求作歸並,從而降低對磁盤或網絡的IO,這是一個基本的思想。
SeasLog
也是這么做的。設定一個buffer_size
(默認100
條log
),使用PHP
請求內存,每寫一次log
,塞入內存,同時buffer_size
加;當buffer_size
等於設置值時,則進行一次IO
,同時清除buffer
; 當然,如果請求結束了、或執行了die
、exit
或其他異常退出時,不管buffer_size
有沒有攢夠設置值,立刻進行一次IO
,同時清除buffer
。
安裝
編譯安裝
$ /path/to/phpize
$ ./configure --with-php-config=/path/to/php-config
$ make && make install
PECL安裝SeasLog
$ pecl install seaslog
配置php.ini
[SeasLog]
extension = "/usr/local/php/lib/php/extensions/no-debug-non-zts-20131226/seaslog.so"
; configuration for php SeasLog module
extension = seaslog.so
seaslog.default_basepath = /log/seaslog-test ;默認log根目錄
seaslog.default_logger = default ;默認logger目錄
seaslog.disting_type = 1 ;是否以type分文件 1是 0否(默認)
seaslog.disting_by_hour = 1 ;是否每小時划分一個文件 1是 0否(默認)
seaslog.use_buffer = 1 ;是否啟用buffer 1是 0否(默認)
seaslog.buffer_size = 100 ;buffer中緩沖數量 默認0(不使用buffer_size)
seaslog.level = 0 ;記錄日志級別 默認0(所有日志)
seaslog.trace_error = 1 ;自動記錄錯誤 默認1(開啟)
seaslog.trace_exception = 0 ;自動記錄異常信息 默認0(關閉)
seaslog.default_datetime_format = "%Y:%m:%d %H:%M:%S" ;日期格式配置 默認"%Y:%m:%d %H:%M:%S"
seaslog.disting_type = 1
開啟以type分文件,即log文件區分info\warn\error
seaslog.disting_by_hour = 1
開啟每小時划分一個文件
seaslog.use_buffer = 1
開啟buffer。默認關閉。當開啟此項時,日志預存於內存,當請求結束時(或異常退出時)一次寫入文件。
seaslog.buffer_size = 100
設置緩沖數量為100. 默認為0,即無緩沖數量限制.當buffer_size大於0時,緩沖量達到該值則寫一次文件..
seaslog.level = 3
記錄的日志級別.默認為0,即所有日志均記錄。當level為1時,關注debug以上級別(包括debug),以此類推。level大於8時,所有日志均不記錄。
記錄
常量列表
SeasLog 共將日志分成8個級別
- SEASLOG_DEBUG "debug" debug,僅僅是在debug模式下才可以記錄的debug日志。
- SEASLOG_INFO "info" 重要事件,例如:用戶登錄和SQL記錄。
- SEASLOG_NOTICE "notice" 一般性重要的事件。
- SEASLOG_WARNING "warning" 出現非錯誤性的異常。例如:使用了被棄用的API、錯誤地使用了API或者非預想的不必要錯誤。
- SEASLOG_ERROR "error" 錯誤,運行時出現的錯誤,不需要立刻采取行動,但必須記錄下來以備檢測。
- SEASLOG_CRITICAL "critical" 緊急情況, 例如:程序組件不可用或者出現非預期的異常。
- SEASLOG_ALERT "alert" 必須立刻采取行動的錯誤級別,比如在整個網站都垮掉了、數據庫不可用了或者其他的情況下,應該發送一條警報短信把你叫醒。
- SEASLOG_EMERGENCY "emergency" 緊急情況,最高級別,系統已不可用。
函數列表
SeasLog 提供了這樣一組函數,可以方便地獲取與設置根目錄、模塊目錄、快速寫入與統計log。
<?php
/**
* @author neeke@php.net
* Date: 14-1-27 下午4:47
*/
class SeasLog
{
public function __construct()
{
#SeasLog init
}
public function __destruct()
{
#SeasLog distroy
}
/**
* 設置basePath
*
* @param $basePath
*
* @return bool
*/
static public function setBasePath($basePath)
{
return TRUE;
}
/**
* 獲取basePath
*
* @return string
*/
static public function getBasePath()
{
return 'the base_path';
}
/**
* 設置模塊目錄
* @param $module
*
* @return bool
*/
static public function setLogger($module)
{
return TRUE;
}
/**
* 獲取最后一次設置的模塊目錄
* @return string
*/
static public function getLastLogger()
{
return 'the lastLogger';
}
/**
* 設置DatetimeFormat配置
* @param $format
*
* @return bool
*/
static public function setDatetimeFormat($format)
{
return TRUE;
}
/**
* 返回當前DatetimeFormat配置格式
* @return string
*/
static public function getDatetimeFormat()
{
return 'the datetimeFormat';
}
/**
* 統計所有類型(或單個類型)行數
* @param string $level
* @param string $log_path
* @param null $key_word
*
* @return array | long
*/
static public function analyzerCount($level = 'all', $log_path = '*', $key_word = NULL)
{
return array();
}
/**
* 以數組形式,快速取出某類型log的各行詳情
*
* @param $level
* @param string $log_path
* @param null $key_word
* @param int $start
* @param int $limit
* @param $order
*
* @return array
*/
static public function analyzerDetail($level = SEASLOG_INFO, $log_path = '*', $key_word = NULL, $start = 1, $limit = 20, $order = SEASLOG_DETIAL_ORDER_ASC)
{
return array();
}
/**
* 獲得當前日志buffer中的內容
*
* @return array
*/
static public function getBuffer()
{
return array();
}
/**
* 將buffer中的日志立刻刷到硬盤
*
* @return bool
*/
static public function flushBuffer()
{
return TRUE;
}
/**
* 記錄debug日志
*
* @param $message
* @param array $content
* @param string $module
*/
static public function debug($message, array $content = array(), $module = '')
{
#$level = SEASLOG_DEBUG
}
/**
* 記錄info日志
*
* @param $message
* @param array $content
* @param string $module
*/
static public function info($message, array $content = array(), $module = '')
{
#$level = SEASLOG_INFO
}
/**
* 記錄notice日志
*
* @param $message
* @param array $content
* @param string $module
*/
static public function notice($message, array $content = array(), $module = '')
{
#$level = SEASLOG_NOTICE
}
/**
* 記錄warning日志
*
* @param $message
* @param array $content
* @param string $module
*/
static public function warning($message, array $content = array(), $module = '')
{
#$level = SEASLOG_WARNING
}
/**
* 記錄error日志
*
* @param $message
* @param array $content
* @param string $module
*/
static public function error($message, array $content = array(), $module = '')
{
#$level = SEASLOG_ERROR
}
/**
* 記錄critical日志
*
* @param $message
* @param array $content
* @param string $module
*/
static public function critical($message, array $content = array(), $module = '')
{
#$level = SEASLOG_CRITICAL
}
/**
* 記錄alert日志
*
* @param $message
* @param array $content
* @param string $module
*/
static public function alert($message, array $content = array(), $module = '')
{
#$level = SEASLOG_ALERT
}
/**
* 記錄emergency日志
*
* @param $message
* @param array $content
* @param string $module
*/
static public function emergency($message, array $content = array(), $module = '')
{
#$level = SEASLOG_EMERGENCY
}
/**
* 通用日志方法
* @param $level
* @param $message
* @param array $content
* @param string $module
*/
static public function log($level, $message, array $content = array(), $module = '')
{
}
}
Example
獲取與設置basePath
$basePath_1 = SeasLog::getBasePath(); //直接使用 SeasLog::getBasePath(),將獲取php.ini(seaslog.ini)中設置的 seaslog.default_basepath 的值。
SeasLog::setBasePath('/log/base_test');
$basePath_2 = SeasLog::getBasePath();
設置logger與獲取lastLogger
$lastLogger_1 = SeasLog::getLastLogger(); // 直接使用 SeasLog::getLastLogger(),將獲取php.ini(seaslog.ini)中設置的 seaslog.default_logger 的值。
SeasLog::setLogger('testModule/app1');
$lastLogger_2 = SeasLog::getLastLogger();
快速寫入log
SeasLog::log(SEASLOG_ERROR,'this is a error test by ::log');
SeasLog::debug('this is a {userName} debug',array('{userName}' => 'neeke'));
SeasLog::info('this is a info log');
SeasLog::notice('this is a notice log');
SeasLog::warning('your {website} was down,please {action} it ASAP!',array('{website}' => 'github.com','{action}' => 'rboot'));
SeasLog::error('a error log');
SeasLog::critical('some thing was critical');
SeasLog::alert('yes this is a {messageName}',array('{messageName}' => 'alertMSG'));
SeasLog::emergency('Just now, the house next door was completely burnt out! {note}',array('{note}' => 'it`s a joke'));
/*
這些函數同時也接受第3個參數為logger的設置項
注意,當last_logger == 'default'時等同於:
SeasLog::setLogger('test/new/path');
SeasLog::error('test error 3');
如果已經在前文使用過SeasLog::setLogger()函數,第3個參數的log只在此處臨時使用,不影響下文。
*/
log格式統一為: {type} | {pid} | {timeStamp} |{dateTime} | {logInfo}
相關鏈接:
https://github.com/Neeke/SeasLog
SeasLog Analyzer的使用
快速統計某類型log的count值
$countResult_1 = SeasLog::analyzerCount();
$countResult_2 = SeasLog::analyzerCount(SEASLOG_WARNING);
$countResult_3 = SeasLog::analyzerCount(SEASLOG_ERROR,date('Ymd',time()));
var_dump($countResult_1,$countResult_2,$countResult_3);
獲取某類型log列表
$detailErrorArray_inAll = SeasLog::analyzerDetail(SEASLOG_ERROR);
$detailErrorArray_today = SeasLog::analyzerDetail(SEASLOG_ERROR,date('Ymd',time()));
var_dump($detailErrorArray_inAll,$detailErrorArray_today);
/*
SeasLog::analyzerDetail(SEASLOG_ERROR) == SeasLog::analyzerDetail(SEASLOG_ERROR,'*');
取當前模塊下所有level為 SEASLOG_ERROR 的信息列表:
array(6) {
[0] =>
string(66) "error | 8568 | 1393172042.717 | 2014:02:24 00:14:02 | test error 3 "
[1] =>
string(66) "error | 8594 | 1393172044.104 | 2014:02:24 00:14:04 | test error 3 "
[2] =>
string(66) "error | 8620 | 1393172044.862 | 2014:02:24 00:14:04 | test error 3 "
[3] =>
string(66) "error | 8646 | 1393172045.989 | 2014:02:24 00:14:05 | test error 3 "
[4] =>
string(66) "error | 8672 | 1393172047.882 | 2014:02:24 00:14:07 | test error 3 "
[5] =>
string(66) "error | 8698 | 1393172048.736 | 2014:02:24 00:14:08 | test error 3 "
}
SeasLog::analyzerDetail(SEASLOG_ERROR,date('Ymd',time()));
只取得當前模塊下,當前一天內,level為SEASLOG_ERROR 的信息列表:
array(2) {
[0] =>
string(66) "error | 8568 | 1393172042.717 | 2014:02:24 00:14:02 | test error 3 "
[1] =>
string(66) "error | 8594 | 1393172044.104 | 2014:02:24 00:14:04 | test error 3 "
}
同理,取當月
$detailErrorArray_mouth = SeasLog::analyzerDetail(SEASLOG_ERROR,date('Ym',time()));
*/
使用SeasLog進行健康預警
預警的配置
[base]
wait_analyz_log_path = /log/base_test
[fork]
;是否開啟多線程 1開啟 0關閉
fork_open = 1
;線程個數
fork_count = 3
[warning]
email[smtp_host] = smtp.163.com
email[smtp_port] = 25
email[subject_pre] = 預警郵件 -
email[smtp_user] = seaslogdemo@163.com
email[smtp_pwd] = seaslog#demo
email[mail_from] = seaslogdemo@163.com
email[mail_to] = gaochitao@weiboyi.com
email[mail_cc] = ciogao@gmail.com
email[mail_bcc] =
[analyz]
; enum
; SEASLOG_DEBUG "debug"
; SEASLOG_INFO "info"
; SEASLOG_NOTICE "notice"
; SEASLOG_WARNING "warning"
; SEASLOG_ERROR "error"
; SEASLOG_CRITICAL "critical"
; SEASLOG_ALERT "alert"
; SEASLOG_EMERGENCY "emergency"
test1[module] = test/bb
test1[level] = SEASLOG_ERROR
test1[bar] = 1
test1[mail_to] = gaochitao@weiboyi.com
test2[module] = 222
test2[level] = SEASLOG_WARNING
test3[module] = 333
test3[level] = SEASLOG_CRITICAL
test4[module] = 444
test4[level] = SEASLOG_EMERGENCY
test5[module] = 555
test5[level] = SEASLOG_DEBUG
crontab配置
;每天凌晨3點執行
0 3 * * * /path/to/php /path/to/SeasLog/Analyzer/SeasLogAnalyzer.php