##PHP日志接口規范
關于日志系統,PHP規范給出了相當好的說明和定義,請見: [Logger Interface](http://www.php-fig.org/psr/psr-3/)

##1.17.1 簡化版
但在用過這么多開源框架進行各種項目開發,以及內部框架的開發后,發現實際上日志的分類并沒有使用得這么豐富,而通常只是頻繁地幾類。因此,為了減少不必要的復雜性,這里特地精簡為三種,只有:
+ error 系統異常類
+ info 業務紀錄類
+ debug 開發調試類
現分說如下。
###(1)error 系統異常類
此類是后臺開發同學認為 **不應該發生卻發生的事情 ** ,即我們通常所說的系統異常。
如:調用app store支付的接口失敗了,我們需要紀錄一下當時的場景,以便復查和給用戶補嘗其損失。
又如:寫入一條紀錄到數據紀錄,但失敗了,我們需要紀錄一下,以便排查。
用法很簡單,如:
```javascript
//只有描述
DI()->logger->error('fail to insert DB');
//描述 + 簡單的信息
DI()->logger->error('fail to insert DB', 'try to register user dogstar');
//描述 + 當時的上下文數據
$data = array('name' => 'dogstar', 'password' => '123456');
DI()->logger->error('fail to insert DB', $data);
```
上面三條紀錄,效果類如:
```javascript
dogstar@ubuntu:dev.phalapi.com$ tailf ./Runtime/log/201502/20150207.log
2015-02-07 20:37:55|ERROR|fail to insert DB
2015-02-07 20:37:55|ERROR|fail to insert DB|try to register user dogstar
2015-02-07 20:37:55|ERROR|fail to insert DB|{"name":"dogstar","password":"123456"}
```
截圖效果:

###(2)info 業務紀錄類
此類通常為業務需要進行必要的操作紀錄,以便發生系統問題后的回滾處理、問題排查以及數據統計。
如在有緩存的情況下,可能數據沒及時寫入數據庫而導致數據丟失或者回檔,這里可以通過日志簡單查看是否可以恢復。以及說明一下操作發生的背景或原由,如通常游戲中用戶的經驗值添加:
```javascript
//假設:10 + 2 = 12
DI()->logger->info('add user exp', array('name' => 'dogstar', 'before' => 10, 'addExp' => 2, 'after' => 12, 'reason' => 'help one more phper'));
//對應的LOG
2015-02-07 20:48:51|INFO|add user exp|{"name":"dogstar","before":10,"addExp":2,"after":12,"reason":"help one more phper"}
```
但當哪天我們看到以下的LOG是就會發現系統存在隱藏的BUG:
```javascript
//WTF? 10 + 2 = 11 ???
2015-02-07 20:48:51|INFO|add user exp|{"name":"dogstar","before":10,"addExp":2,"after":11,"reason":"help one more phper"}
```
而當用戶玩家來投訴客服時,客服妹子來找到我們后臺開發時,我們可以證明得了是系統原因造成了用戶丟失1點經驗值。
特別地,若我們看到以下的LOG時,不難看出有人在用非法的渠道刷經驗:
```javascript
2015-02-07 20:52:35|INFO|add user exp|{"name":"dogstar","before":10,"addExp":2,"after":12,"reason":"help one more phper"}
2015-02-07 20:52:35|INFO|add user exp|{"name":"dogstar","before":12,"addExp":2,"after":14,"reason":"help one more phper"}
....
2015-02-07 20:52:35|INFO|add user exp|{"name":"dogstar","before":998,"addExp":2,"after":1000,"reason":"help one more phper"}
```
所幸我們有日志并及時發現了,隨后如何處理就視具體的項目而定了。但當產品來追問時,我們可以及時給出反饋和做出處理。
還有更為重要的是 **數據統計** 。這塊就App數據分析和統計這塊已經有了很好的第三方服務支持,一如:友盟。但我們仍然可以輕松實現自己的數據統計,以便二次確認和定制化。畢竟,總是依賴第三方不是那么輕便,而且存在敏感數據安全問題。
這里簡單提供一個上報接口,如:
```javascript
public function getRules() {
return array(
'report' => array(
'username' => array('name' => 'username', 'require' => true),
'msg' => array('name' => 'msg', 'require' => true),
),
);
}
public function report() {
DI()->logger->info($this->username, $this->msg);
}
```
客戶端在需要的場景,如用戶打開應用,請求:
```
http://dev.phalapi.com/demo/?service=DogstarTest.Report&username=dogstar&msg=enter%20app
```
即可看到:
```javascript
2015-02-07 21:01:13|INFO|dogstar|enter app
```
到后期,若我們需要統計用戶的登錄情況時,可以這樣統計:
```javascript
$ cat ./Runtime/log/201502/20150207.log | grep "enter app" | awk -F '|' '{print $3}' | sort | uniq -c
11 dogstar
5 King
2 Tom
```
###(3)debug 開發調試類
此類為開發調試用,用法如上,這里不再贅述。以下是一些簡單的示例:
```javascript
DI()->logger->debug('just for test');
DI()->logger->debug('just for test', '一些其他的描述 ...');
DI()->logger->debug('just for test', array('name' => 'dogstar', 'password' => '******'));
```
##1.17.2 使用DI()->logger->log()進行更靈活的分類
若上面的error/info/debug都不能滿足項目的需求時,可以這樣更靈活地進行日志紀錄:
```javascript
DI()->logger->log('demo', 'add user exp', array('name' => 'dogstar', 'after' => 12));
DI()->logger->log('test', 'add user exp', array('name' => 'dogstar', 'after' => 12));
//對應的日志
2015-02-07 21:13:27|DEMO|add user exp|{"name":"dogstar","before":10,"addExp":2,"after":12,"reason":"help one more phper"}
2015-02-07 21:15:39|TEST|add user exp|{"name":"dogstar","after":12}
```
注意到,DI()->logger->log()第一個參數為日志分類的名稱,在寫入日志時會自動轉換為大寫。其接口函數簽名為:
```javascript
/**
* 日志紀錄
*
* 可根據不同需要,將日志寫入不同的媒介
*
* @param string $type 日志類型,如:info/debug/error, etc
* @param string $msg 日志關鍵描述
* @param string/array $data 場景上下文信息
* @return NULL
*/
abstract public function log($type, $msg, $data);
```
##1.17.3 別忘記了日志的級別設置
上面的三類日志分別對應的標識為:
+ error 系統異常類:PhalApi_Logger::LOG_LEVEL_ERROR
+ info 業務紀錄類:PhalApi_Logger::LOG_LEVEL_INFO
+ debug 開發調試類:PhalApi_Logger::LOG_LEVEL_DEBUG
根據不同的項目在不同環境下的需要,我們可以這樣有選擇性地將需要的日志分類寫入保存:
```javascript
//日志紀錄
DI()->logger = new PhalApi_Logger_File(API_ROOT . '/Runtime',
PhalApi_Logger::LOG_LEVEL_DEBUG | PhalApi_Logger::LOG_LEVEL_INFO | PhalApi_Logger::LOG_LEVEL_ERROR);
```
多個日志級別需要使用或運算進行組合。
##1.17.4 擴展你的日志存儲
普遍情況下,我們認為將日志存放在文件是比較合理的,因為便于查看、管理和統計。當然,如果你的項目需要將日志紀錄在數據中,也可以快速擴展實現。如實現數據庫的存儲思路:
```javascript
//$ vim ./Apps/Common/Logger/DB.php
class Common_Logger_DB extends PhalApi_Logger {
public function log($type, $msg, $data) {
//TODO 數據庫的日志寫入 ...
}
```
隨后,利用DI注冊一下即可:
```javascript
//日志紀錄 - DB
DI()->logger = new Common_Logger_DB($dbConfig,
PhalApi_Logger::LOG_LEVEL_DEBUG | PhalApi_Logger::LOG_LEVEL_INFO | PhalApi_Logger::LOG_LEVEL_ERROR);
```
- 歡迎使用PhalApi!
- 接口,從簡單開始!
- [1.1]-下載與安裝
- [1.2]-創建一個自己的項目
- [1.3]-在線體驗
- [1.4]-文檔、幫助和官網
- [1.10]-對PhalApi框架的抉擇
- [1.11]-快速入門(backup)
- [1.12]-參數規則:接口參數規則配置
- [1.13]-統一的接口請求方式:_sevice=XXX.XXX
- [1.14]-統一的返回格式和結構:ret-data-msg
- [1.15]-數據庫操作:基于NotORM的使用及優化
- [1.16]-配置讀取:內外網環境配置的完美切換
- [1.17]-日記紀錄:簡化版的日記接口
- [1.18]-快速函數:人性化的關懷
- [1.19]-DI服務速查:各資源服務一覽表
- [1.20]-DB操作:數據庫基本操作速查
- [1.21]-類的自動加載:遵循PEAR包的命名規范
- [1.22]-簽名驗證:自定義簽名規則
- [1.23]-請求和響應:GET和POST兩者皆可得及超越JSON格式返回
- [1.24]-緩存策略:更靈活地可配置化的多級緩存
- [1.25]-國際化翻譯:為走向國際化提前做好翻譯準備
- [1.26]-數據安全:數據對稱加密方案
- [1.27]-精益開發:更富表現力的Model層和重量級數據獲取的應對方案
- [1.28]-COOKIE:對COOKIE原生態的支持及記憶加密升級版
- [1.29]-開放與封閉:多入口和統一初始化
- [1.30]-保持的力量:接口開發最佳實踐
- [1.31]-新型計劃任務:以接口形式實現的計劃任務
- [2.11]-核心思想:DI依賴注入-讓資源更可控
- [2.12]-海量數據:可配置的分庫分表
- [2.13]-接口調試:在線SQL語句查看與性能優化
- [2.14]-測試驅動開發:意圖導向編程下的接口開發
- [2.15]-演進:新型計劃任務續篇
- [2.16]-領域驅動設計:應對復雜領域業務的Domain層
- [2.17]-微服務:Api接口服務層
- [2.18]-定制化:資源服務的再實現
- [2.19]-擴展庫:可重用的擴展類庫
- [2.20]-約定編程:架構明顯的編程風格
- [2.21]-服務器統一部署方案簡明版:CentOs---Nginx---php-fpm---MySql-[--Memcached]
- [2.22]-更多工具:精益項目和團隊建設
- [3.1]-擴展類庫:微信開發
- [3.2]-擴展類庫:代理模式下phprpc協議的輕松支持
- [3.3]-擴展類庫:基于PHPMailer的郵件發送
- [3.4]-擴展類庫:優酷開放平臺接口調用
- [3.5]-擴展類庫:七牛云存儲接口調用
- [3.6]-擴展類庫:新型計劃任務
- [3.8]-擴展類庫:用戶、會話和第三方登錄集成
- [3.9]-擴展類庫:swoole支持下的長鏈接和異步任務實現
- [3.11]-擴展類庫:基于FastRoute的快速路由
- [4.2]-開發實戰2:模擬優酷開放平臺接口項目開發
- [4.3]-開發實戰3:一個簡單的小型項目開發(奔跑吧兄弟投票活動)
- [5.1]-架構與思想:PhalApi核心設計和思想解讀
- [5.2]-雜談:扯一些PhalApi的前世和今生
- [5.3]-框架總結:術語表和PHP開發建議
- [5.4]-許可
- [5.5]-聯系和加入我們
- [5.6]-更新日記
- [5.8]-致框架貢獻者:加入PhalApi開源指南
- [6.1]-基于接口查詢語言的SDK包
- [6.2]-SDK包(JAVA版)
- [6.3]-SDK包(PHP版)
- [6.4]-SDK包(Objective-C版)
- [6.5]-SDK包(javascript版)
- [6.6]-SDK包(Ruby版)
- [8.1]-PhalApi視頻教程
- 附錄1:接口文檔參考模板