##PHP日志接口规范
关于日志系统,PHP规范给出了相当好的说明和定义,请见: [Logger Interface](http://www.php-fig.org/psr/psr-3/)
![apic](http://webtools.qiniudn.com/20150411005257_2caf170c179348eca546ba5332837d09)
##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"}
```
截图效果:
![apic](http://webtools.qiniudn.com/20150411005257_37a0566c79a78c8958d8d00a83c7f840)
###(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:接口文档参考模板