【PHP調試篇】PHP高性能日志組件SeasLog


簡述

什么是SeasLog

SeasLog是一個C語言編寫的PHP擴展,提供一組規范標准的功能函數,在PHP項目中方便、規范、高效地寫日志,以及快速地讀取和查詢日志。

為什么使用SeasLog

無論在什么應用中,log日志都是架構中不可缺少的一個重要組成部分,它通常是系統或軟件、應用的運行記錄。通過log的分析,可以方便用戶了解系統或軟件、應用的運行情況;如果你的應用log足夠豐富,也可以分析以往用戶的操作行為、類型喜好、地域分布或其他更多信息;如果一個應用的log同時也分了多個級別,那么可以很輕易地分析得到該應用的健康狀況,及時發現問題並快速定位、解決問題,補救損失。

我們知道,php內置了很多log函數,如error_logsyslogfile_put_content,這些函數功能強大且性能極好,但由於各種缺陷(error_logfile_put_content無錯誤級別、無固定格式像是信馬由韁隨處亂畫;syslog不區分模塊、而且與系統日志混合,讀syslog記錄會讓人抓狂的。),靈活度降低了很多,很不能滿足應用需求。基本上所有的開發者,都會自行設計封裝log庫,當然也會有很多開發者選擇已有的開源日志庫。

也有很多開源log類庫彌補了上述缺陷,如log4phpplogAnalog等(當然也有很多應用在項目中自己開發的log類)。其中以log4php最為著名,它的設計精良、格式完美、文檔完善、功能強大。但是經過測試,log4php的性能非常差。

sealog在性能上有着強大的優勢,假設一個請求中需要寫出1000處log,那么勢必會有1000次IO,這對性能將是一個很大的拖延點。一般對於處理這種多次相同的請求場景,我們要解決的其實也很簡單,使用cache或buffer,把多次請求作歸並,從而降低對磁盤或網絡的IO,這是一個基本的思想。

SeasLog也是這么做的。設定一個buffer_size(默認100log),使用PHP請求內存,每寫一次log,塞入內存,同時buffer_size加;當buffer_size等於設置值時,則進行一次IO,同時清除buffer; 當然,如果請求結束了、或執行了dieexit或其他異常退出時,不管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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM