seaslog的文檔非常詳細: [中文文檔](https://github.com/SeasX/SeasLog/blob/master/README_zh.md)
這里只提幾個注意點:
## 千分比采樣性能追蹤
~~~
;是否開啟性能追蹤 1開啟 0關閉(默認)
seaslog.trace_performance = 0
;性能追蹤時的千分比采樣率
;默認10,即百分之一 **測試的時候可以設置為1000**
seaslog.trace_performance_sample_rate = 10
;性能追蹤時的開始層級 默認從第1層開始
seaslog.trace_performance_start_depth = 1
;性能追蹤時深度層級 默認5層, **如果使用框架類可以調高一點,我設的是20**
seaslog.trace_performance_max_depth = 5
;性能追蹤時每層的函數最大數 按wall_time降序排列top 默認top5
seaslog.trace_performance_max_functions_per_depth = 5
;性能追蹤時當前請求執行時間的記錄閾值 只有當請求執行時間大于該值時,才記錄性能日志 默認1000ms
seaslog.trace_performance_min_wall_time = 1000
;性能追蹤時每個方法執行時間的記錄閾值 只有當方法執行時間大于該值時,才參與計算 默認10ms
seaslog.trace_performance_min_function_wall_time = 10
~~~
1. 在某一個**請求超過了1秒**,就在每100次里面就會記錄1次這1秒的性能追蹤。在測試時可以把 **seaslog.trace_performance_sample_rate**設為1000,讓觸發率達百分之百;
2. 如果使用框架開發的話,由于加載的層級過多,所以建議設置 **seaslog.trace_performance_max_depth = 20**
**追蹤內容如下:**
```
{
...
"16":[
{
"cm":"GuzzleHttp\Ring\Client\CurlHandler::_invokeAsArray",
"ct":1,
"wt":1767,
"mu":87912
},
{
// 類名::方法名
"cm":"Symfony\Component\VarDumper\Cloner\Data::dumpChildren",
// call_times 方法調用計數
"ct":105,
// wall_time, 見下文
"wt":149,
// 使用內存:memory_usage byte
"mu":45064
}
],
"main()":{
//
總的wall_time和memory_usage
"wt":1844,
"mu":4519032
}
}
```
**理解wall_time**
wall time也可以稱為real-world time或wall-block time,指的是用計時器(如手表或掛鐘)度量的實際時間。實際時間和用計算微處理器的脈沖時鐘或時鐘周期不同,實際時間的一秒鐘包含的微處理器時鐘周期數決定于微處理器的時鐘速度。微處理器時鐘不是計時器,而只是一個以高的、精確的并且不變的頻率輸出脈沖的發生器。一個2 GHz計算機的微處理器時鐘要比1 GHz的快一倍。所謂根據日期、小時、分鐘和秒來按序顯示時間的計算機顯示的是實際時間,而不是微處理器周期時間。??在處理問題時,一個程序運行或執行任務所花的時間通常是以秒度量的實際時間。當計算機支持多任務時,每個程序的實際執行時間決定于處理器是如何在各個程序之間分配資源的。例如,如果在一個連續的60秒時間段內,計算機要運行三個程序,這時就可能一個程序占用10秒,第二個占用20秒,而第三個占用30秒,但各個程序占用的時間并不是連續的時間塊,而是以循環機制分配的,就像是在通信中的時分復用一樣。對于一個計算機用戶來說,計算機處理一個具體的任務花的總時間是以實際時間來度量來度量的,這個時間不一定是連續的,因為計算機在一個時間段內可能要完成多個任務。
> 由于在一個生命周期里面,PHP是單線程的。輪流讓各個任務交替執行,任務1執行0.01秒,切換到任務2,任務2執行0.01秒,再切換到任務3,執行0.01秒……這樣反復執行下去。表面上看,每個任務都是交替執行的,但是,由于CPU的執行速度實在是太快了,我們感覺就像所有任務都在同時執行一樣。我的理解就是在循環調用中,執行時間加上等待時間就是wall_time
## 回溯層級的配置
一般我們都要封裝一下再使用,比如下面的二次封裝
```
Log::err($arg1,$arg2,$arg3,....);
```
但這樣就會讓日志模板中的某些變量失去意義
<br />


<br />
這種情況下,seasLog給我們提供了一個回溯層級的配置
`seaslog.recall_depth` 日志函數所在的層級。這將影響預置變量中的行號取值 `%F`。 默認值為 0。
比如我把日志封裝到`libs/Log`的類里面,然后在業務代碼中調用`Log::$level()`。如果不設置回溯層級的話,`%F`和`%C`只能記錄到`libs/Log`的文件。但設置以后
<br />

## 日志報警(TP5舉例)
我們一般都是基于框架開發,而框架都有類似“行為,標簽,鉤子,事件”這類AOP切面編程機制。在TP中的處理方案就是:
1. 增加鉤子
2. 監聽鉤子
3. 特定type的日志扔進隊列
4. 異步發郵件(短信,釘釘)報警
**二次封裝**
~~~
<?php
namespace libs;
use think\facade\Log as TPlog;
/**
* 自定義日志適配器,多參數記錄
* Class Log
* @method void emergency(mixed $message, array $context = []) static 記錄emergency信息
* @method void alert(mixed $message, array $context = []) static 記錄alert信息
* @method void critical(mixed $message, array $context = []) static 記錄critical信息
* @method void error(mixed $message, array $context = []) static 記錄error信息,會造成程序運行,業務邏輯錯誤,臟數據等,需要及時處理和解決;
* @method void warning(mixed $message, array $context = []) static 記錄warning信息,程序能正常運行,業務邏輯沒錯誤,但需要及時解決;
* @method void notice(mixed $message, array $context = []) static 記錄notice信息,程序能正常運行,業務邏輯沒錯誤但不美;
* @method void info(mixed $message, array $context = []) static 需要關注的。像用戶登錄,交易等入參;
* @method void debug(mixed $message, array $context = []) static 記錄debug信息
* @method void sql(mixed $message, array $context = []) static 記錄sql信息
* @package libs
* Log::info('日志title',__METHOD__,__LINE__,'haha','''');
*/
class Log {
/**
* 靜態調用
* @param $method
* @param $args
* @return mixed
*/
public static function __callStatic($method, $args = [])
{
// 以高性能日志收集組件seaslog為最優先;
if(extension_loaded('SeasLog')){
return self::seasLog($method, $args);
}
return TPlog::$method($args);
}
private static function seasLog($method, $args){
$config = config('log.');
if (empty($config['path'])) {
$config['path'] = app()->getRuntimePath() . 'log' . DIRECTORY_SEPARATOR;
}
\SeasLog::setBasePath($config['path']);
\SeasLog::setLogger('seasLog');
if($config['append_info'] || $method == 'error'){
$args = [
'_sys' => self::getSysLog(),
'_msg' => $args
];
}
$args = json_encode($args, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
if($method == 'error'){
// todo: 寫入隊列,異步發郵件報警
}
\SeasLog::log($method,$args);
// 如果為true的話,馬上寫入;
config('app.app_debug') && \SeasLog::flushBuffer();
}
/**
* 追加調試日志
* @return array
*/
private static function getSysLog()
{
$request = app('request');
$runtime = round(microtime(true) - app()->getBeginTime(), 10);
$reqs = $runtime > 0 ? number_format(1 / $runtime, 2) : '∞';
$memory_use = number_format((memory_get_usage() - app()->getBeginMem()) / 1024, 2);
$info = [
'method' => $request->method(),
'uri' => $request->url(),
'ip' => $request->ip(),
'c/a' => $request->controller() . '/' . $request->action(),
'runtime' => number_format($runtime, 6) . 's',
'reqs' => $reqs . 'req/s',
'memory' => $memory_use . 'kb',
'file' => count(get_included_files()),
];
return $info;
}
}
~~~
**鉤子文件**
~~~php
<?php
namespace app\common\behavior;
class LogAlarm
{
#todo: 后續要寫進rabbitMq
public function run($params)
{
// 發送郵件通知
list($type , $message) = $params;
if ('error' == $type) {
#todo: 這個地方要異步發送
// mail('admin@mail.com' , '日志報警' , implode(' ' , $message));
}
}
}
~~~