[TOC]
# **1. 啟用注解**
`@GoEnableLogger`
`@GoLogger`
# **2. 注意事項**
> 如需使用,需開啟@GoEnableLogger,類、方法上加入@GoLogger注解即可,注解優先級 `方法 > 類`
print:是否打印,默認開啟true
format:是否格式化,默認關閉false
operation:方法說明,默認空""
storage:日志存儲,默認LogStorageProvider(可實現LogStorage接口自定義保存)
# **3. 示例說明**
## **3.1 不輸出**
```
@GoLogger(print = false)
@RequestMapping("/noprint")
public Result noprint(BaseVo base, PageVo page) {
return R.succ();
}
```
```
日志無輸出
```
## **3.2 默認輸出**
```
@GoLogger
@RequestMapping("/print")
public Result print(BaseVo base, PageVo page) {
return R.succ();
}
```
```
[FastBoot][ INFO][06-27 01:02:19]-->[http-nio-8080-exec-1:3995353][loggerAroundAspect(LoggerAspect.java:109)] | - | request print | [{"id":"-1","keyword":""},{"limit":25,"page":0,"size":25}]
[FastBoot][ INFO][06-27 01:02:19]-->[http-nio-8080-exec-1:3995366][loggerAroundAspect(LoggerAspect.java:120)] | - | response time 11ms | print | {"code":0,"msg":"操作成功","status":true}
```
## **3.3 格式化輸出**
```
@GoLogger(format = true)
@RequestMapping("/format")
public Result format(BaseVo base, PageVo page) {
return R.succ();
}
```
```
[FastBoot][ INFO][06-27 01:03:55]-->[http-nio-8080-exec-5:4091420][loggerAroundAspect(LoggerAspect.java:109)] | - | request format |
[
{
"id":"-1",
"keyword":""
},
{
"limit":25,
"page":0,
"size":25
}
]
[FastBoot][ INFO][06-27 01:03:55]-->[http-nio-8080-exec-5:4091421][loggerAroundAspect(LoggerAspect.java:120)] | - | response time 1ms | format |
{
"code":0,
"msg":"操作成功",
"status":true
}
```
## **3.4 格式化輸出、存儲**
```
@GoLogger(format = true, storage = LogStorageMysqlProvider.class)
@RequestMapping("/storage")
public Result storage(BaseVo base, PageVo page) {
return R.succ();
}
```
```
[FastBoot][ INFO][06-27 01:06:17]-->[http-nio-8080-exec-1:4234217][loggerAroundAspect(LoggerAspect.java:109)] | - | request storage |
[
{
"id":"-1",
"keyword":""
},
{
"limit":25,
"page":0,
"size":25
}
]
[FastBoot][ INFO][06-27 01:06:17]-->[http-nio-8080-exec-1:4234232][loggerAroundAspect(LoggerAspect.java:120)] | - | response time 14ms | storage |
{
"code":0,
"msg":"操作成功",
"status":true
}
[FastBoot][ INFO][06-27 01:06:17]-->[http-nio-8080-exec-1:4234267][logSQL(Slf4JLogger.java:60)] | - | time 0ms | statement | insert into xx_log (create_date, ip, is_del, method, req, res, time, type, update_date, url, id) values ('2021-06-27T01:06:17.907+0800', '0:0:0:0:0:0:0:1', false, 'storage', '{}', '{"code":0,"msg":"操作成功","status":true}', 14, 'GET', '2021-06-27T01:06:17.907+0800', '//logger/storage', 'L1408834011744309248')
[FastBoot][ INFO][06-27 01:06:17]-->[http-nio-8080-exec-1:4234284][logSQL(Slf4JLogger.java:60)] | - | time 14ms | commit |
[FastBoot][ INFO][06-27 01:06:17]-->[http-nio-8080-exec-1:4234285][record(LogStorageMysqlProvider.java:49)] | - log record id L1408834011744309248
```
## **3.5 優先級**
```
@RestController
@RequestMapping("/body")
@GoLogger(storage = LogStorageMysqlProvider.class)
public class BodyController extends BaseController {
@RequestMapping(value = "result")
public Result result() {
return R.succ(MockData.map());
}
}
```
```
[FastBoot][ INFO][06-27 01:33:14]-->[http-nio-8080-exec-5:5850503][loggerAroundAspect(LoggerAspect.java:109)] | - | request result | []
[FastBoot][ INFO][06-27 01:33:14]-->[http-nio-8080-exec-5:5850504][loggerAroundAspect(LoggerAspect.java:120)] | - | response time 0ms | result | {"code":0,"msg":"操作成功","data":{"k1":"1","k2":2,"k3":"3","k4":4.1,"k5":5.2,"k6":true,"k7":"7","k8":1624728794169},"status":true}
[FastBoot][ INFO][06-27 01:33:14]-->[http-nio-8080-exec-5:5850510][logSQL(Slf4JLogger.java:60)] | - | time 1ms | statement | insert into xx_log (create_date, ip, is_del, method, req, res, time, type, update_date, url, id) values ('2021-06-27T01:33:14.172+0800', '0:0:0:0:0:0:0:1', false, 'result', '{}', '{"code":0,"msg":"操作成功","data":{"k1":"1","k2":2,"k3":"3","k4":4.1,"k5":5.2,"k6":true,"k7":"7","k8":1624728794169},"status":true}', 0, 'GET', '2021-06-27T01:33:14.172+0800', '/body/result', 'L1408840790767177728')
[FastBoot][ INFO][06-27 01:33:14]-->[http-nio-8080-exec-5:5850516][logSQL(Slf4JLogger.java:60)] | - | time 4ms | commit |
[FastBoot][ INFO][06-27 01:33:14]-->[http-nio-8080-exec-5:5850518][record(LogStorageMysqlProvider.java:49)] | - log record id L1408840790767177728
```
# **4. 自定義存儲**
## **4.1 表結構**
```
CREATE?TABLE?`xx_log`?(
??`id`?varchar(255)?NOT?NULL?COMMENT?'主鍵',
??`create_date`?datetime(6)?NOT?NULL?COMMENT?'創建時間',
??`update_date`?datetime?NOT?NULL?COMMENT?'更新時間',
??`ip`?varchar(255)?DEFAULT?NULL?COMMENT?'請求ip',
??`url`?varchar(255)?DEFAULT?NULL?COMMENT?'請求地址',
??`method`?varchar(255)?DEFAULT?NULL?COMMENT?'請求方法',
??`type`?varchar(255)?DEFAULT?NULL?COMMENT?'請求類型',
??`req`?longtext?COMMENT?'請求參數',
??`res`?longtext?COMMENT?'響應結果',
??`time`?bigint(20)?DEFAULT?NULL?COMMENT?'請求耗時',
??PRIMARY?KEY?(`id`)
)?ENGINE=InnoDB?DEFAULT?CHARSET=utf8mb4
```
## **4.2 實體類**
```
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@FieldNameConstants(innerTypeName = "FIELDS")
@Table(name = "xx_log")
@Entity
@EntityListeners(AuditingEntityListener.class)
@DynamicInsert
@DynamicUpdate
@Where(clause = "is_del=0")
@SQLDelete(sql = "update xx_log set is_del=1 where id = ?")
@SQLDeleteAll(sql = "update xx_log set is_del=1 where id = ?")
public class LogRecord extends JpaPlusEntity<LogRecord> {
private static final long serialVersionUID = 1L;
/**
* 主鍵,例(L1408447004119666688)
*/
@Id
@GeneratedValue(generator = "idGenerator")
@GenericGenerator(name = "idGenerator", // 名稱
strategy = "com.xiesx.FastBoot.db.jpa.identifier.IdWorkerGenerator", // 生成策略
parameters = {// 生成參數
@Parameter(name = "prefix", value = "L"), // 前綴,L
@Parameter(name = "workerId", value = "1"), // 終端ID,默認0
@Parameter(name = "centerId", value = "1") // 數據中心ID,默認0
})
@JSONField(ordinal = 1)
private String id;
/**
* 創建時間
*/
@CreatedDate
@Column(updatable = false, nullable = false)
@JSONField(ordinal = 2)
private Date createDate;
/**
* 修改時間
*/
@LastModifiedDate
@Column(nullable = false)
@JSONField(ordinal = 3)
private Date updateDate;
/**
* 請求IP
*/
@Column
@JSONField(ordinal = 4)
private String ip;
/**
* 方法
*/
@Column
@JSONField(ordinal = 5)
private String method;
/**
* 方式
*/
@Column
@JSONField(ordinal = 6)
private String type;
/**
* 地址
*/
@Column
@JSONField(ordinal = 7)
private String url;
/**
* 請求參數
*/
@JSONField(serialize = false)
private String req;
/**
* 響應結果
*/
@JSONField(serialize = false)
private String res;
/**
* 執行時間(毫秒)
*/
@Column
@JSONField(ordinal = 10)
private Long time;
/**
* 是否刪除
*/
@Column
@JSONField(serialize = false)
private Boolean isDel = false;
```
該實體類,可以通過 `fast-generator`生成
## **4.3 持久類**
```
public interface LogRecordRepository extends JpaPlusRepository<LogRecord, String> {
}
```
該持久類,可以通過 `fast-generator`生成
## **4.4 實現類**
```
@Log4j2
public class LogStorageMysqlProvider extends LogStorageProvider {
private final static String UNKNOWN = "unknown";
private static final String[] HEAD_INFO = {
"X-Forwarded-For",
"Proxy-Client-IP",
"WL-Proxy-Client-IP",
"HTTP_X_FORWARDED_FOR",
"HTTP_X_FORWARDED",
"HTTP_X_CLUSTER_CLIENT_IP",
"HTTP_CLIENT_IP",
"HTTP_FORWARDED_FOR",
"HTTP_FORWARDED",
"HTTP_VIA",
"REMOTE_ADDR",
"PROXY_FORWARDED_FOR",
"X-Real-IP"};
LogRecordRepository mLogRecordRepository;
public LogStorageMysqlProvider(String operation, String method, Object[] args, Long time) {
super(operation, method, args, time);
mLogRecordRepository = SpringHelper.getBean(LogRecordRepository.class);
}
@Override
public void record(HttpServletRequest request, Object result) {
super.record(request, result);
// 構造日志
LogRecord logRecord = new LogRecord()//
.setIp(getIpAddr(request))//
.setMethod(method)//
.setType(type)//
.setUrl(uri)//
.setReq(JSON.toJSONString(parameters))//
.setRes(JSON.toJSONString(result))//
.setTime(time);
// 保存日志
logRecord = mLogRecordRepository.insertOrUpdate(logRecord);
// 打印日志編號
log.info("log record id {}", logRecord.getId());
}
/**
* 獲取ip
*
* @param request
* @return
*/
public static String getIpAddr(HttpServletRequest request) {
for (String header : HEAD_INFO) {
String ip = request.getHeader(header);
if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
if (ip.contains(",")) {
String[] ips = ip.split(",");
for (String s : ips) {
if (!(UNKNOWN.equalsIgnoreCase(s))) {
ip = s;
break;
}
}
}
return ip;
}
}
return request.getRemoteAddr();
}
}
```
> 示例默認實現了mysql的存儲,可以存MongoDB...等其他數據庫
# **5. p6spy輸出**
## **5.1 配置文件**(內置)
spy.properties
```
module.log=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory
# 自定義日志打印
logMessageFormat=com.xiesx.springboot.core.logger.pkaq.P6SpyLogger
# 使用日志系統記錄sql
appender=com.p6spy.engine.spy.appender.Slf4JLogger
# 配置記錄Log例外
excludecategories=info,debug,result,batc,resultset
# 設置使用p6spy driver代理
deregisterdrivers=true
# 日期格式
dateformat=yyyy-MM-dd HH:mm:ss
# 實際驅動
driverlist=com.mysql.cj.jdbc.Driver
# 是否開啟慢SQL記錄
outagedetection=true
# 慢SQL記錄標準 (秒)
outagedetectioninterval=2
```
## **5.2 使用環境**
實際使用中建議本地開發環境`application-local`使用`p6spy`
### **5.2.1 開發環境**
```
spring:
datasource:
driver-class-name: com.p6spy.engine.spy.P6SpyDriver
url: jdbc:p6spy:mysql://127.0.0.1:3307/dbname?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&autoReconnect=true&useSSL=false&serverTimezone=Asia/Shanghai
username: xxxx
password: xxxx
```
### **5.2.1 生產環境**
```
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3307/dbname?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&autoReconnect=true&useSSL=false&serverTimezone=Asia/Shanghai
username: xxxx
password: xxxx
```
## **5.3 驗證打印**
### **5.3.1 默認?**
```
[FastBoot][ INFO][06-27 01:43:14]-->[http-nio-9090-exec-3:2007963][logSQL(Slf4JLogger.java:60)] | - | took 1ms | | statement | select * from sys_config where k=?
```
### **5.3.2 p6spy**
```
[FastBoot][ INFO][06-27 01:43:14]-->[http-nio-9090-exec-3:2007963][logSQL(Slf4JLogger.java:60)] | - | took 1ms | | statement | select * from sys_config where k='update'
```