log-record
log-record copied to clipboard
使用注解优雅记录系统日志,操作日志,后端埋点等,支持SpEL表达式,自定义上下文,自定义函数,实体类DIFF等其他高阶处理。
log-record
注æï¼æ¬ä»åºæåçµææ¥æºäºç¾å¢ææ¯å客 ï¼è¥æ¨éè¦å¯»æ¾çæ¯åæä¸ä½è ç代ç ä»åºï¼å¯ä»¥è·³è½¬è¿é ãæ¬ä»åºä»é¶å®ç°äºåæä¸æè¿°ç大é¨åç¹æ§ï¼å¹¶å¸å大éç产ç¯å¢å®è·µåå å¤ç½ç¨æ·åé¦ï¼éçæç»ç¨³å®çç»´æ¤åæ´æ°ï¼ææç»ç¨æ·æä¾æ´å¤å·®å¼åçåè½ã
éè¿Java
注解ä¼é
çè®°å½æä½æ¥å¿ï¼å¹¶æ¯æSpEL
表达å¼ï¼èªå®ä¹ä¸ä¸æï¼èªå®ä¹å½æ°ï¼å®ä½ç±»DIFF
çåè½ï¼æç»æ¥å¿å¯ç±ç¨æ·èªè¡éé并å¤çï¼ææ¨éè³é¢é
ç½®çæ¶æ¯éåï¼æ¯æSpringBoot1&2&3ï¼JDK8~JDK21ï¼ã
éç¨SpringBoot Starter
çæ¹å¼ï¼åªéä¸ä¸ªä¾èµï¼ä¸å¥æ³¨è§£ï¼æ¥å¿è½»æ¾è®°å½ï¼ä¸ä¾µå
¥ä¸å¡é»è¾ï¼
@OperationLog(bizType = "'followerChange'", bizId = "#request.orderId", msg = "'ç¨æ·' + #queryUserName(#request.userId) + 'ä¿®æ¹äºè®¢åçè·è¿äººï¼ä»' + #queryOldFollower(#request.orderId) + 'ä¿®æ¹å°' + #request.newFollower")
public Response<T> function(Request request) {
// ä¸å¡æ§è¡é»è¾
}
SpringBoot1&SpringBoot2(JDK8+)请å¼ç¨ï¼
<dependency>
<groupId>cn.monitor4all</groupId>
<artifactId>log-record-starter</artifactId>
<version>{ææ°çæ¬å·}</version>
</dependency>
SpringBoot3(JDK17+)请å¼ç¨ï¼
<dependency>
<groupId>cn.monitor4all</groupId>
<artifactId>log-record-springboot3-starter</artifactId>
<version>{ææ°çæ¬å·}</version>
</dependency>
ææ°çæ¬å·è¯·æ¥é
Maven
å ¬å ±ä»åº
项ç®èæ¯
大家ä¸å®è§è¿ä¸å¾çæä½æ¥å¿ï¼
å¨ä»£ç å±é¢ï¼å¦ä½ä¼é çè®°å½ä¸é¢çæ¥å¿å¢ï¼
è½æ³å°æç²æ´çæ¹å¼ï¼å°è£ ä¸ä¸ªæä½æ¥å¿è®°å½ç±»ï¼å¦ä¸ï¼
String template = "ç¨æ·%sä¿®æ¹äºè®¢åçè·è¿äººï¼ä»â%sâä¿®æ¹å°â%sâ"
LogUtil.log(orderNo, String.format(tempalte, "å¼ ä¸", "æå", "çäº"), "å¼ ä¸")
è¿ç§æ¹å¼ä¼å¯¼è´ä¸å¡ä»£ç 被记å½æ¥å¿ç代ç ä¾µå ¥ï¼å¯¹äºä»£ç çå¯è¯»æ§åå¯ç»´æ¤æ§æ¥è¯´æ¯ä¸ä¸ªç¾é¾ã
è¿ä¸ªæ¹å¼æ¾ç¶ä¸å¤ä¼é ï¼è®©æ们è¯è¯ä½¿ç¨æ³¨è§£ï¼
@OperationLog(bizType = "'followerChange'", bizId = "'20211102001'", msg = "'ç¨æ· å¼ ä¸ ä¿®æ¹äºè®¢åçè·è¿äººï¼ä» æå ä¿®æ¹å° çäº'")
public Response<T> function(Request request) {
// ä¸å¡æ§è¡é»è¾
}
æ¥å¿çè®°å½è¢«æ¾å°äºæ³¨è§£ï¼å¯¹ä¸å¡ä»£ç 没æä¾µå ¥ã
ä½æ¯æ°çé®é¢æ¥äºï¼æ们该å¦ä½æ订åIDãç¨æ·ä¿¡æ¯ãæ°æ®åºéçæ§å°åãå½æ°å ¥åçæ°å°åä¼ éç»æ³¨è§£å¢ï¼
Spring
ç SpEL
表达å¼ï¼Spring Expression Language
ï¼ å¯ä»¥å¸®å©æ们ï¼éè¿å¼å
¥SpEL
表达å¼ï¼æ们å¯ä»¥è·åå½æ°çå
¥åãè¿æ ·æ们就å¯ä»¥å¯¹ä¸é¢ç注解è¿è¡ä¿®æ¹ï¼
- 订åIDï¼
#request.orderId
- æ°å°å"çäº"ï¼
#request.newFollower
@OperationLog(bizType = "'followerChange'", bizId = "#request.orderId", msg = "'ç¨æ· å¼ ä¸ ä¿®æ¹äºè®¢åçè·è¿äººï¼ä» æå ä¿®æ¹å°' + #request.newFollower")
public Response<T> function(Request request) {
// ä¸å¡æ§è¡é»è¾
}
å¦æ¤ä¸æ¥ï¼è®¢åIDåå°åçæ°å¼å°±å¯ä»¥éè¿è§£æå ¥åå¨æè·åäºã
é®é¢è¿æ²¡æç»æï¼é常æ们çç¨æ·ä¿¡æ¯ï¼user
ï¼ï¼ä»¥åèçè·è¿äººï¼oldFollower
ï¼ï¼æ¯éè¦å¨æ¹æ³ä¸æ¥è¯¢åæè½è·åï¼å
¥åéä¸è¬ä¸ä¼å
å«è¿äºæ°æ®ã
解å³æ¹æ¡ä¹ä¸æ¯æ²¡æï¼æ们å建ä¸ä¸ªå¯ä»¥ä¿åä¸ä¸æçLogRecordContext
åéï¼è®©ç¨æ·æå¨ä¼ é代ç ä¸è®¡ç®åºæ¥çå¼ï¼å交ç»SpEL
解æ ï¼ä»£ç å¦ä¸
@OperationLog(bizType = "'followerChange'", bizId = "#request.orderId", msg = "'ç¨æ·' + #userName + 'ä¿®æ¹äºè®¢åçè·è¿äººï¼ä»' + #oldFollower + 'ä¿®æ¹å°' + #request.newFollower")
public Response<T> function(Request request) {
// ä¸å¡æ§è¡é»è¾
...
// æå¨ä¼ éæ¥å¿ä¸ä¸æï¼ç¨æ·ä¿¡æ¯ å°åæ§å¼
LogRecordContext.putVariable("userName", queryUserName(request.getUserId()));
LogRecordContext.putVariable("oldFollower", queryOldFollower(request.getOrderId()));
}
ä»ä¹ï¼ä½ 说è¿ä¸å°±åä¾µå ¥äºä¸å¡é»è¾äºä¹ï¼
ç¡®å®æ¯çï¼ä¸è¿è¿ç§æ¹æ³è¶³å¤ä¾¿æ·ææï¼å¹¶ä¸ä¼æä»ä¹ç解çå°é¾ã
ä½æ¯å¯¹äºæâ强迫çâçåå¦ï¼è¿æ ·çå®ç°è¿æ¯ä¸å¤ä¼é
ï¼æ们å¯ä»¥ç¨SpEL
æ¯æçèªå®ä¹å½æ°ï¼è§£å³è¿ä¸ªé®é¢ã
SpEL
æ¯æå¨è¡¨è¾¾å¼ä¸ä¼ å
¥ç¨æ·èªå®ä¹å½æ°ï¼æ们å°queryUserName
åqueryOldFollower
è¿ä¸¤ä¸ªå½æ°æåæ¾å
¥SpEL
ç解æå¨ä¸ï¼SpEL
å¨è§£æ表达å¼æ¶ï¼ä¼æ§è¡å¯¹åºå½æ°ã
æç»ï¼æ们ç注解åæäºè¿æ ·ï¼å¹¶ä¸æç»è®°å½äºæ¥å¿ï¼
@OperationLog(bizType = "'followerChange'", bizId = "#request.orderId", msg = "'ç¨æ·' + #queryUserName(#request.userId) + 'ä¿®æ¹äºè®¢åçè·è¿äººï¼ä»' + #queryOldFollower(#request.orderId) + 'ä¿®æ¹å°' + #request.newFollower")
public Response<T> function(Request request) {
// ä¸å¡æ§è¡é»è¾
}
ç¨æ· å¼ ä¸ ä¿®æ¹äºè®¢åçè·è¿äººï¼ä» æå ä¿®æ¹å° çäº
以ä¸ä¾¿æ¯æ¬åºç大è´å®ç°åçã
项ç®ä»ç»
æ¬åºå¸®å©ä½ éè¿æ³¨è§£ä¼é å°è®°å½é¡¹ç®ä¸çæä½æ¥å¿ï¼å¯¹ä¸å¡ä»£ç æ ä¾µå ¥ã
æ¬é¡¹ç®ç¹ç¹ï¼
- å¿«éæ¥å
¥ï¼ä½¿ç¨
Spring Boot Starter
å®ç°ï¼ç¨æ·ç´æ¥å¨pom.xml
å¼å ¥ä¾èµå³å¯ä½¿ç¨ - ä¸å¡æ ä¾µå ¥ï¼æ éä¾µå ¥ä¸å¡ä»£ç ï¼æ¥å¿åé¢åçä»»ä½å¼å¸¸ä¸ä¼å½±ååæ¹æ³æ§è¡
-
SpEL
解æï¼æ¯æSpEL
è¡¨è¾¾å¼ - å®ä½ç±»
Diff
ï¼æ¯æç¸åçè³ä¸å类对象çDiff
- æ¡ä»¶æ³¨è§£ï¼æ»¡è¶³
Condition
æ¡ä»¶åæè®°å½æ¥å¿ï¼éè¿SpEL
è¿è¡è§£æ - èªå®ä¹ä¸ä¸æï¼æ¯ææå¨ä¼ éé®å¼å¯¹ï¼éè¿
SpEL
è¿è¡è§£æ - èªå®ä¹å½æ°ï¼æ¯æ注åèªå®ä¹å½æ°ï¼éè¿
SpEL
è¿è¡è§£æ - å ¨å±æä½äººIDï¼èªå®ä¹æä½äººIDè·åé»è¾
- æå®æ¥å¿æ°æ®ç®¡éï¼èªå®ä¹æä½æ¥å¿å¤çé»è¾ï¼åæ°æ®åºï¼
TLog
ç..ï¼ - æ¯æéå¤æ³¨è§£ï¼åä¸ä¸ªæ¹æ³ä¸å¯ä»¥åå¤ä¸ªæä½æ¥å¿æ³¨è§£
- æ¯æèªå¨éè¯åå
åºå¤çï¼æ¯æé
ç½®éè¯æ¬¡æ°åå¤ç失败å
åºé»è¾
SPI
- æ¯ææ§å¶åé¢æ§è¡æ¶æºï¼æ¹æ³æ§è¡ååï¼
- æ¯æèªå®ä¹æ§è¡æåå¤æ
- æ¯æé注解æ¹å¼æå¨è®°å½æ¥å¿
- èªå®ä¹æ¶æ¯çº¿ç¨æ±
- æ´å¤ç¹æ§çä½ æ¥åæ...
æ¥å¿å®ä½(LogDTO)å å å«ï¼
logIdï¼çæçUUID
bizIdï¼ä¸å¡å¯ä¸ID
bizTypeï¼ä¸å¡ç±»å
exceptionï¼å½æ°æ§è¡å¤±è´¥æ¶åå
¥å¼å¸¸ä¿¡æ¯
operateDateï¼æä½æ§è¡æ¶é´
successï¼å½æ°æ¯å¦æ§è¡æå
msgï¼æ¥å¿å
容
tagï¼èªå®ä¹æ ç¾
returnStr: æ¹æ³æ§è¡æååçè¿åå¼ï¼å符串æJSONåå®ä½ï¼
executionTimeï¼æ¹æ³æ§è¡èæ¶ï¼åä½ï¼æ¯«ç§ï¼
extraï¼é¢å¤ä¿¡æ¯
operatorIdï¼æä½äººID
List<diffDTO>: å®ä½ç±»å¯¹è±¡Diffæ°æ®ï¼å
æ¬åæ´çå段åï¼å段å¼ï¼ç±»åç
æ¥å¿å®ä½å¤æ示ä¾ï¼
{
"bizId":"1",
"bizType":"testObjectDiff",
"executionTime":0,
"extra":"ãç¨æ·å·¥å·ãä»ã1ãåæäºã2ã ãnameãä»ãå¼ ä¸ãåæäºãæåã",
"logId":"38f7f417-2cc3-40ed-8c98-2fe3ee057518",
"msg":"ãç¨æ·å·¥å·ãä»ã1ãåæäºã2ã ãnameãä»ãå¼ ä¸ãåæäºãæåã",
"operateDate":1651116932299,
"operatorId":"æä½äºº",
"returnStr":"{\"id\":1,\"name\":\"å¼ ä¸\"}",
"success":true,
"exception":null,
"tag":"operation",
"diffDTOList":[
{
"diffFieldDTOList":[
{
"fieldName":"id",
"newFieldAlias":"ç¨æ·å·¥å·",
"newValue":2,
"oldFieldAlias":"ç¨æ·å·¥å·",
"oldValue":1
},
{
"fieldName":"name",
"newValue":"æå",
"oldValue":"å¼ ä¸"
}],
"newClassAlias":"ç¨æ·ä¿¡æ¯å®ä½",
"newClassName":"cn.monitor4all.logRecord.test.bean.TestUser",
"oldClassAlias":"ç¨æ·ä¿¡æ¯å®ä½",
"oldClassName":"cn.monitor4all.logRecord.test.bean.TestUser"
},
{
"diffFieldDTOList":[
{
"fieldName":"id",
"newFieldAlias":"ç¨æ·å·¥å·",
"newValue":2,
"oldFieldAlias":"ç¨æ·å·¥å·",
"oldValue":1
},
{
"fieldName":"name",
"newValue":"æå",
"oldValue":"å¼ ä¸"
}],
"newClassAlias":"ç¨æ·ä¿¡æ¯å®ä½",
"newClassName":"cn.monitor4all.logRecord.test.bean.TestUser",
"oldClassAlias":"ç¨æ·ä¿¡æ¯å®ä½",
"oldClassName":"cn.monitor4all.logRecord.test.bean.TestUser"
}]
}
使ç¨æ¹æ³
åªéè¦ç®åçä¸æ¥ï¼
第ä¸æ¥ï¼ SpringBoot
项ç®ä¸å¼å
¥ä¾èµ
SpringBoot1&SpringBoot2(JDK8+)请å¼ç¨ï¼
<dependency>
<groupId>cn.monitor4all</groupId>
<artifactId>log-record-starter</artifactId>
<version>{ææ°çæ¬å·}</version>
</dependency>
SpringBoot3(JDK17+)请å¼ç¨ï¼
<dependency>
<groupId>cn.monitor4all</groupId>
<artifactId>log-record-springboot3-starter</artifactId>
<version>{ææ°çæ¬å·}</version>
</dependency>
ææ°çæ¬å·è¯·æ¥é
Maven
å ¬å ±ä»åºæ¨èä½¿ç¨ >= 1.6.xçæ¬
第äºæ¥ï¼ é ç½®æ¥å¿å¤çæ¹å¼
æ¯æå¤çæ¹å¼ï¼
- èªå®ä¹ééå¤ç
- ç´æ¥åéè³
RabbitMQ
- ç´æ¥åéè³
RocketMQ
- ç´æ¥åéè³
SpringCloud Stream
1. èªå®ä¹ééå¤ç
è¥åªéè¦å¨åä¸åºç¨å
å¤çæ¥å¿ä¿¡æ¯ï¼åªéè¦å®ç°æ¥å£IOperationLogGetService
ï¼ä¾¿å¯å¯¹æ¥å¿è¿è¡å¤çã
@Component
public class CustomFuncTestOperationLogGetService implements IOperationLogGetService {
@Override
public boolean createLog(LogDTO logDTO) {
log.info("logDTO: [{}]", JSON.toJSONString(logDTO));
return true;
}
}
2. ç´æ¥åéè³RabbitMQ
é
ç½®RabbitMQ
åæ°
log-record.data-pipeline=rabbitMq
log-record.rabbit-mq-properties.host=localhost
log-record.rabbit-mq-properties.port=5672
log-record.rabbit-mq-properties.username=admin
log-record.rabbit-mq-properties.password=xxxxxx
log-record.rabbit-mq-properties.queue-name=logRecord
log-record.rabbit-mq-properties.routing-key=
log-record.rabbit-mq-properties.exchange-name=logRecord
3. ç´æ¥åéè³RocketMQ
é
ç½®RocketMQ
åæ°
log-record.data-pipeline=rocketMq
log-record.rocket-mq-properties.topic=logRecord
log-record.rocket-mq-properties.tag=
log-record.rocket-mq-properties.group-name=logRecord
log-record.rocket-mq-properties.namesrv-addr=localhost:9876
4. ç´æ¥åéè³SpringCloud Stream
é
ç½®SpringCloud Stream
åæ°
log-record.data-pipeline=stream
log-record.stream.destination=logRecord
log-record.stream.group=logRecord
# ä¸ºç©ºæ¶ é»è®¤ä¸ºspring.cloud.stream.default-binderæå®çBinder
log-record.stream.binder=
# rocketmq binderä¾å
spring.cloud.stream.rocketmq.binder.name-server=127.0.0.1:9876
spring.cloud.stream.rocketmq.binder.enable-msg-trace=false
第ä¸æ¥ï¼ å¨éè¦è®°å½ç³»ç»æä½çæ¹æ³ä¸ï¼æ·»å 注解
@OperationLog(bizType = "'followerChange'", bizId = "#request.orderId", msg = "'ç¨æ· å¼ ä¸ ä¿®æ¹äºè®¢åçè·è¿äººï¼ä» æå ä¿®æ¹å°' + #request.newFollower")
public Response<T> function(Request request) {
// ä¸å¡æ§è¡é»è¾
}
è¿é¶ç¹æ§
-
SpEL
çä½¿ç¨ -
èªå®ä¹
SpEL
解æé¡ºåº - å ç½®èªå®ä¹å½æ°åèªå®ä¹åæ°
- æ ¹æ®æ¡ä»¶è®°å½æ¥å¿
- å ¨å±æä½äººä¿¡æ¯è·å
- èªå®ä¹ä¸ä¸æ
- èªå®ä¹å½æ°
- èªå®ä¹åæ¹æ³æ¯å¦æ§è¡æå
-
å®ä½ç±»
Diff
- æ¥å¿å¤çéè¯æ¬¡æ°åå åºå½æ°é ç½®
- éå¤æ³¨è§£
- èªå®ä¹æ¶æ¯çº¿ç¨æ±
- å½æ°è¿åå¼è®°å½å¼å ³
- é注解æ¹å¼æå¨è®°å½æ¥å¿
- æä½æ¥å¿æ°æ®è¡¨ç»ææ¨è
-
让注解æ¯æ
IDEA
èªå¨è¡¥å ¨
SpELç使ç¨
SpEL
æ¯Spring
å®ç°çæ åç表达å¼è¯è¨ï¼å
·ä½ç使ç¨å¯ä»¥å¦ä¹ å®æ¹ææ¡£æè
èªè¡æç´¢èµæï¼å
¥é¨é常çç®åï¼æ¨èå ç¯æç« ï¼
- http://itmyhome.com/spring/expressions.html
- https://docs.spring.io/spring-framework/docs/3.0.x/reference/expressions.html
éè¦æ³¨æçæ¯ï¼@OperationLog
注解ä¸ï¼é¤äºexecuteBeforeFunc
årecordReturnValue
两个boolean
ç±»åçåæ°ï¼å
¶ä»çåæ°åéè¦ä¸¥æ ¼éµå¾ªSpEL
表达å¼è¯æ³ã
`
举ä¾æ¥è¯´ï¼bizType
ä¸æ们ç»å¸¸ä¼å¡«å
¥å¸¸éï¼ä¾å¦è®¢åå建orderCreate
, 订åä¿®æ¹orderModify
ã
å¨SpEL
表达å¼ä¸ï¼è¥ä¼ å
¥bizType="orderCreate"
ï¼SpELä¼è§£æ失败ï¼å 为纯å符串ä¼è¢«è®¤ä¸ºæ¯ä¸ä¸ªæ¹æ³åï¼å¯¼è´SpEL
æ¾ä¸å°æ¹æ³èæ¥éï¼éè¦ä½¿ç¨bizType="'orderCreate'"
ï¼æè½è¢«æ£ç¡®è§£æã
ææ¶ï¼æ们ä¼ç¨æ举å¼å常éå¼æ¥è§èbizType
çåæ°ï¼åçåæ³å¦ä¸ï¼
@Getter
@AllArgsConstructor
public enum TestEnum {
TYPE1("type1", "æ举1"),
TYPE2("type2", "æ举2");
private final String key;
private final String name;
}
public class TestConstant {
public static final String TYPE1 = "type1";
public static final String TYPE2 = "type2";
}
@OperationLog(bizId = "'1'", bizType = "T(cn.monitor4all.logRecord.test.bean.TestConstant).TYPE1")
@OperationLog(bizId = "'2'", bizType = "T(cn.monitor4all.logRecord.test.bean.TestEnum).TYPE1")
@OperationLog(bizId = "'3'", bizType = "T(cn.monitor4all.logRecord.test.bean.TestEnum).TYPE1.key")
@OperationLog(bizId = "'4'", bizType = "T(cn.monitor4all.logRecord.test.bean.TestEnum).TYPE1.name")
注æï¼bizType
åtag
åæ°å¨ >= 1.2.0çæ¬ä»¥åæè¦æ±ä¸¥æ ¼éµå¾ªSpEL
表达å¼ï¼<= 1.1.x以ä¸çæ¬å为ç´æ¥å¡«åå符串ï¼ä¸æ¯æSpEL
解æã
èªå®ä¹SpEL
解æ顺åº
å¨é»è®¤é
ç½®ä¸ï¼æ³¨è§£åé¢çé»è¾å¨æ¹æ³æ§è¡ä¹åæä¼æ§è¡ï¼è¿æ ·ä¼å¸¦æ¥ä¸ä¸ªé®é¢ï¼å¦æå¨æ¹æ³å
é¨ä¿®æ¹äºæ¹æ³åæ°ï¼SpEL
解æååå¼å°±åæäºæ¹ååçå¼ã
å¯ä»¥ä½¿ç¨LogRecordContext
åå
¥æ§å¼ï¼é¿å
è¿ä¸ªé®é¢ï¼åªæ¯æä¸å®ä»£ç ä¾µå
¥æ§ã
为äºæ»¡è¶³ä¸äºç¹æ®éæ±ï¼æ³¨è§£ä¸æä¾boolean
åæ°executeBeforeFunc
ï¼è¥è®¾ç½®ä¸ºtrue
ï¼åä¼å¨æ¹æ³æ§è¡åå
解æSpEL
åæ°ã è¿æ ·ä¹ä¼å¸¦æ¥è´ä½ç¨ï¼æ¹æ³å
åå
¥çæ°å¼ï¼æ¯å¦èªå®ä¹ä¸ä¸æï¼å°±ä¸ååä¸SpEL
解æäºã
æ¹æ³ä¸å ä¸æ³¨è§£ï¼
@OperationLog(bizId = "#keyInBiz", bizType = "'testExecuteBeforeFunc1'", executeBeforeFunc = true)
@OperationLog(bizId = "#keyInBiz", bizType = "'testExecuteAfterFunc'")
@OperationLog(bizId = "#keyInBiz", bizType = "'testExecuteBeforeFunc2'", executeBeforeFunc = true)
public void testExecuteBeforeFunc() {
LogRecordContext.putVariable("keyInBiz", "valueInBiz");
}
è°ç¨æ¹æ³ï¼
testService.testExecuteBeforeFunc();
å¾å°ç»æï¼
[{"bizId":null, "bizType":"testExecuteBeforeFunc1","diffDTOList":[],"executionTime":0,"extra":"","logId":"8cbed2fc-bb2d-48a7-b9ec-f28e99773151","msg":"","operateDate":1651144119444,"operatorId":"æä½äºº","returnStr":"null","success":true,"tag":"operation"}]
[{"bizId":null, "bizType":"testExecuteBeforeFunc2","diffDTOList":[],"executionTime":0,"extra":"","logId":"a130b60c-791c-4c6f-812e-0475de4b38d2","msg":"","operateDate":1651144119444,"operatorId":"æä½äºº","returnStr":"null","success":true,"tag":"operation"}]
[{"bizId":"valueInBiz","bizType":"testExecuteAfterFunc","diffDTOList":[],"executionTime":0,"extra":"","logId":"80af92f5-8e4a-489e-a626-83f2a696fe71","msg":"","operateDate":1651144119444,"operatorId":"æä½äºº","returnStr":"null","success":true,"tag":"operation"}]
å ç½®èªå®ä¹å½æ°åèªå®ä¹åæ°
- å¯ä»¥ç´æ¥ä½¿ç¨çèªå®ä¹åæ°ï¼
-
_return
ï¼åæ¹æ³çè¿åå¼ -
_errorMsg
ï¼åæ¹æ³çå¼å¸¸ä¿¡æ¯ï¼throwable.getMessage()
ï¼
使ç¨ç¤ºä¾ï¼
@OperationLog(bizId = "'1'", bizType = "'testDefaultParamReturn'", msg = "#_return")
注æï¼_return
å_errorMsg
å为æ¹æ³æ§è¡åæèµå¼çåæ°ï¼æ以è¥executeBeforeFunc=true
ï¼è®¾ç½®ä¸ºæ¹æ³æ§è¡åæ§è¡æ¥å¿åé¢ï¼ï¼åè¿ä¸¤ä¸ªå¼ä¸ºnull
ã
- å¯ä»¥ç´æ¥ä½¿ç¨çèªå®ä¹å½æ°ï¼
-
_DIFF
ï¼è¯¦è§ä¸æ¹ å®ä½ç±»Diff
å°è
æ ¹æ®æ¡ä»¶è®°å½æ¥å¿
@OperationLog
注解æ¥æå段condition
ï¼ç¨æ·å¯ä»¥ä½¿ç¨SpEL表达å¼æ¥å³å®è¯¥æ¡æ¥å¿æ¯å¦è®°å½ã
æ¹æ³ä¸å ä¸æ³¨è§£ï¼
@OperationLog(bizId = "'1'", bizType = "'testCondition1'", condition = "#testUser != null")
@OperationLog(bizId = "'2'", bizType = "'testCondition2'", condition = "#testUser.id == 1")
@OperationLog(bizId = "'3'", bizType = "'testCondition3'", condition = "#testUser.id == 2")
public void testCondition(TestUser testUser) {
}
è°ç¨æ¹æ³ï¼
testService.testCondition(new TestUser(1, "å¼ ä¸"));
ä¸è¿°æ³¨è§£ä¸ï¼åªæå两æ¡æ³¨è§£æ»¡è¶³condition
æ¡ä»¶ï¼ä¼è¾åºæ¥å¿ã
å ¨å±æä½äººä¿¡æ¯è·å
大é¨åæ
åµä¸ï¼æä½äººIDå¾å¾ä¸ä¼å¨æ¹æ³åæ°ä¸ä¼ éï¼æ´å¤ä¼æ¯æ¥è¯¢éå¢å
BUC
ä¿¡æ¯ãæ¥è¯¢å¤é¨æå¡ãæ¥è¡¨çè·åãæ以å¼æ¾äºSPI
ï¼åªéè¦å®ç°æ¥å£IOperationLogGetService
ï¼ä¾¿å¯ä»¥ç»ä¸æ³¨å
¥æä½äººIDã
@Component
public class IOperatorIdGetServiceImpl implements IOperatorIdGetService {
@Override
public String getOperatorId() {
// æ¥è¯¢æä½äººä¿¡æ¯
return "å¼ ä¸";
}
}
注æï¼è¥å®ç°äºæ¥å£åä»å¨æ³¨è§£æå¨ä¼ å
¥OperatorID
ï¼åä»¥ä¼ å
¥çOperatorID
ä¼å
ã
èªå®ä¹ä¸ä¸æ
ç´æ¥å¼å
¥ç±»LogRecordContext
ï¼æ¾å
¥é®å¼å¯¹ã
@OperationLog(bizType = "'followerChange'", bizId = "#request.orderId", msg = "'ç¨æ·' + #userName + 'ä¿®æ¹äºè®¢åçè·è¿äººï¼ä»' + #oldFollower + 'ä¿®æ¹å°' + #request.newFollower")
public Response<T> function(Request request) {
// ä¸å¡æ§è¡é»è¾
...
// æå¨ä¼ éæ¥å¿ä¸ä¸æï¼ç¨æ·ä¿¡æ¯ å°åæ§å¼
LogRecordContext.putVariable("userName", queryUserName(request.getUserId()));
LogRecordContext.putVariable("oldFollower", queryOldFollower(request.getOrderId()));
}
LogRecordContextå é¨ä½¿ç¨TransmittableThreadLocalå®ç°ä¸ä¸»çº¿ç¨çThreadLocalä¼ éã
èªå®ä¹å½æ°
å°@LogRecordFunc
注解ç³æå¨éè¦æ³¨åå°SpEL
çèªå®ä¹å½æ°ä¸ï¼åä¸SpEL
表达å¼çè¿ç®ã
注æï¼éè¦å¨ç±»ä¸ä¹å£°æ@LogRecordFunc
ï¼å¦åæ æ³æ¾å°è¯¥å½æ°ã
@LogRecordFunc
å¯ä»¥æ·»å åæ°value
ï¼å®ç°èªå®ä¹æ¹æ³å«åï¼è¥ä¸æ·»å ï¼åé»è®¤ä¸éè¦ååç¼ã
éæèªå®ä¹æ¹æ³ï¼
SpEL
天çæ¯æï¼åæ³å¦ä¸ï¼
@LogRecordFunc("CustomFunctionStatic")
public class CustomFunctionStatic {
@LogRecordFunc("testStaticMethodWithCustomName")
public static String testStaticMethodWithCustomName(){
return "testStaticMethodWithCustomName";
}
@LogRecordFunc
public static String testStaticMethodWithoutCustomName(){
return "testStaticMethodWithoutCustomName";
}
}
ä¸è¿°ä»£ç ä¸ï¼æ³¨åçèªå®ä¹å½æ°å为CustomFunctionStatic_testStaticMethodWithoutCustomName
åCustomFunctionStatic_testStaticMethodWithoutCustomName
ï¼è¥ç±»ä¸ç注解æ´æ¹ä¸º@LogRecordFunc("test")
ï¼å注åçèªå®ä¹å½æ°å为testStaticMethodWithCustomName
åtestStaticMethodWithoutCustomName
ééæèªå®ä¹æ¹æ³ï¼
~~åç主è¦æ¯ä¾é æ们æ¡æ¶å
é¨è½¬æ¢ï¼å°ééææ¹æ³éè¦å
è£
为éææ¹æ³åä¼ ç»SpEL
ãåç详è§#PR25~~
å¨1.6.xçæ¬ä¹åï¼é¨åçæ¬(1.5.x)æ¯æééæèªå®ä¹å½æ°ï¼ä½ç±äºå ¶å¤§é使ç¨åå°ï¼åæ³è¾ä¸ºHackï¼å ¼å®¹æ§ä¸ä½³ï¼å¨JDk11+ååå°éå¶æ´å ä¸¥æ ¼ï¼ï¼å¨1.6.x+ çæ¬åå é¤ï¼ä» æ¯æéææ¹æ³ã
注æï¼ææèªå®ä¹å½æ°å¯å¨åºç¨å¯å¨æ¶çæ¥å¿ä¸æ¾å°
2022-06-09 11:35:18.672 INFO 73757 --- [ main] c.a.i.l.f.CustomFunctionRegistrar : LogRecord register custom function [public static java.lang.String cn.monitor4all.logRecord.test.service.CustomFunctionStaticService.testStaticMethodWithCustomName()] as name [CustomFunctionStatic_testStaticMethodWithoutCustomName]
2022-06-09 11:35:18.672 INFO 73757 --- [ main] c.a.i.l.f.CustomFunctionRegistrar : LogRecord register custom function [public static java.lang.String cn.monitor4all.logRecord.test.service.CustomFunctionStaticService.testStaticMethodWithoutCustomName()] as name [CustomFunctionStatic_testStaticMethodWithoutCustomName]
2022-06-09 11:35:18.672 INFO 73757 --- [ main] c.a.i.l.f.CustomFunctionRegistrar : LogRecord register custom function [public static java.lang.String cn.monitor4all.logRecord.function.CustomFunctionObjectDiff.objectDiff(java.lang.Object,java.lang.Object)] as name [_DIFF]
注解ä¸ä½¿ç¨ï¼
@OperationLog(bizId = "#CustomFunctionStatic_testStaticMethodWithCustomName()", bizType = "'testStaticMethodWithCustomName'")
@OperationLog(bizId = "#CustomFunctionStatic_testStaticMethodWithoutCustomName()", bizType = "'testStaticMethodWithoutCustomName'")
public void testCustomFunc() {
}
èªå®ä¹åæ¹æ³æ¯å¦æ§è¡æå
@OperationLog
注解ä¸æsuccess
åæ°ï¼ç¨äºæ ¹æ®è¿åä½æå
¶ä»æ
åµä¸èªå®ä¹æ¥å¿å®ä½ä¸çsuccess
å段ã
é»è®¤æ åµä¸ï¼æ¹æ³æ¯å¦æ§è¡æååå³äºæ¯å¦æåºå¼å¸¸ï¼è¥æªæåºå¼å¸¸ï¼é»è®¤ä¸ºæ¹æ³æ§è¡æåã
ä½å¾å¤æ¶åï¼æ们çæ¹æ³æ§è¡æåå¯è½åå³äºæ¹æ³å é¨è°ç¨çæ¥å£çè¿åå¼ï¼å¦ä¸æ示ï¼
@OperationLog(
success = "#isSuccess",
bizId = "#request.trade.id",
bizType = "'createOrder'",
)
@Override
public Result<Void> createOrder(Request request) {
try {
Response response = tradeCreateService.create(request);
LogRecordContext.putVariable("isSuccess", response.getIsSuccess());
return Result.ofSuccess();
} catch (Exception e) {
return Result.ofSysError();
}
}
å¯ä»¥éè¿æ¥å£è¿åçresponse.getIsSuccess()
æ¥è¡¨å该å建订åæ¹æ³æ¯å¦æ§è¡æåã
å®ä½ç±»Diff
æ¯æ两个对象ï¼ç¸åæè
ä¸åç类对象çå¯ï¼å¯¹è±¡çDiff
ã
æå¦ä¸æ³¨è§£ï¼
-
@LogRecordDiffField
ï¼å¨å段ä¸ç³æ@LogRecordDiffField(alias = "ç¨æ·å·¥å·", ignored = true)
ï¼alias
å«å为å¯éå段ãignored
为å¯éå段ï¼é»è®¤ä¸ºfalse
ï¼è¥ä¸ºtrue
ï¼å该å段ä¸åä¸DIFF
ã -
@LogRecordDiffObject
ï¼å¨ç±»ä¸å 许å¯ä»¥ç³æ@LogRecordDiffObject(alias = "ç¨æ·ä¿¡æ¯å®ä½")
ï¼alias
å«å为å¯éå段ï¼é»è®¤ç±»ä¸ææå段ä¼è¿è¡DIFF
ï¼å¯éè¿enableAllFields
æå¨å ³éï¼å ³éåçäºè¯¥æ³¨è§£åªç¨äºè·åç±»å«åã
类对象使ç¨ç¤ºä¾ï¼
@LogRecordDiffObject(alias = "ç¨æ·ä¿¡æ¯å®ä½")
public class TestUser {
private Integer id;
private String name;
private String job;
}
æè åç¬ä¸ºç±»ä¸çå段DIFFï¼
public class TestUser {
@LogRecordDiffField(alias = "ç¨æ·å·¥å·")
private Integer id;
@LogRecordDiffField(alias = "ç¨æ·å·¥å·", ignored = true)
private String name;
}
å¨@OperationLog
注解ä¸ï¼å¯ä»¥éè¿è°ç¨å
ç½®å®ç°çèªå®ä¹å½æ°_DIFF
ï¼ä¼ å
¥ä¸¤ä¸ªå¯¹è±¡å³å¯æ¿å°Diff
ç»æã
@OperationLog(bizId = "'1'", bizType = "'testObjectDiff'", msg = "#_DIFF(#oldObject, #testUser)", extra = "#_DIFF(#oldObject, #testUser)")
public void testObjectDiff(TestUser testUser) {
LogRecordContext.putVariable("oldObject", new TestUser(1, "å¼ ä¸"));
}
æ¯è¾å®æåçç»æå¨æ¥å¿å®ä½ä¸ä»¥diffDTO
å®ä½åç°ã
{
"diffFieldDTOList":[
{
"fieldName":"id",
"newFieldAlias":"ç¨æ·å·¥å·",
"newValue":2,
"oldFieldAlias":"ç¨æ·å·¥å·",
"oldValue":1
},
{
"fieldName":"name",
"newValue":"æå",
"oldValue":"å¼ ä¸"
}],
"newClassAlias":"ç¨æ·ä¿¡æ¯å®ä½",
"newClassName":"cn.monitor4all.logRecord.test.bean.TestUser",
"oldClassAlias":"ç¨æ·ä¿¡æ¯å®ä½",
"oldClassName":"cn.monitor4all.logRecord.test.bean.TestUser"
}
è°ç¨æ¹æ³ï¼
testService.testObjectDiff(new TestUser(2, "æå"));
æç»å¾å°çæ¥å¿æ¶æ¯å®ä½logDTO
ï¼
{
"bizId":"1",
"bizType":"testObjectDiff",
"executionTime":0,
"extra":"ãç¨æ·å·¥å·ãä»ã1ãåæäºã2ã ãnameãä»ãå¼ ä¸ãåæäºãæåã",
"logId":"38f7f417-2cc3-40ed-8c98-2fe3ee057518",
"msg":"ãç¨æ·å·¥å·ãä»ã1ãåæäºã2ã ãnameãä»ãå¼ ä¸ãåæäºãæåã",
"operateDate":1651116932299,
"operatorId":"æä½äºº",
"returnStr":"{\"id\":1,\"name\":\"å¼ ä¸\"}",
"success":true,
"exception":null,
"tag":"operation",
"diffDTOList":[
{
"diffFieldDTOList":[
{
"fieldName":"id",
"newFieldAlias":"ç¨æ·å·¥å·",
"newValue":2,
"oldFieldAlias":"ç¨æ·å·¥å·",
"oldValue":1
},
{
"fieldName":"name",
"newValue":"æå",
"oldValue":"å¼ ä¸"
}],
"newClassAlias":"ç¨æ·ä¿¡æ¯å®ä½",
"newClassName":"cn.monitor4all.logRecord.test.bean.TestUser",
"oldClassAlias":"ç¨æ·ä¿¡æ¯å®ä½",
"oldClassName":"cn.monitor4all.logRecord.test.bean.TestUser"
},
{
"diffFieldDTOList":[
{
"fieldName":"id",
"newFieldAlias":"ç¨æ·å·¥å·",
"newValue":2,
"oldFieldAlias":"ç¨æ·å·¥å·",
"oldValue":1
},
{
"fieldName":"name",
"newValue":"æå",
"oldValue":"å¼ ä¸"
}],
"newClassAlias":"ç¨æ·ä¿¡æ¯å®ä½",
"newClassName":"cn.monitor4all.logRecord.test.bean.TestUser",
"oldClassAlias":"ç¨æ·ä¿¡æ¯å®ä½",
"oldClassName":"cn.monitor4all.logRecord.test.bean.TestUser"
}]
}
å¯ä»¥éè¿Spring
é
ç½®ï¼å¿½ç¥å¯¹æ¯çæ°æ§å¯¹è±¡ä¸å¼ä¸ºnullçå段ï¼å½¢å¦ï¼
log-record.diff-ignore-new-object-null-value=true # 忽ç¥æ°å¯¹è±¡ä¸nullå¼å段ï¼é»è®¤ä¸ºfalse
log-record.diff-ignore-old-object-null-value=true # 忽ç¥æ§å¯¹è±¡ä¸nullå¼å段ï¼é»è®¤ä¸ºfalse
æ¤å¤ï¼å¯ä»¥éè¿Spring
é
ç½®èªå®ä¹DIFF
çæ åè¾åºæ ¼å¼ï¼å½¢å¦ï¼
log-record.diff-msg-format=ï¼é»è®¤å¼ä¸ºã${_fieldName}ãä»ã${_oldValue}ãåæäºã${_newValue}ãï¼
log-record.diff-msg-separator=ï¼é»è®¤å¼ä¸º" "ç©ºæ ¼ï¼
è¿æ¯æåä¸ä¸ªæ³¨è§£ä¸å¤æ¬¡è°ç¨_DIFF
, å¦ä¸ï¼
/**
* æµè¯å®ä½ç±»DIFFï¼ä½¿ç¨å¤ä¸ª_DIFF
*/
@OperationLog(bizId = "'1'", bizType = "'testMultipleDiff'", msg = "'第ä¸ä¸ªDIFFï¼' + #_DIFF(#oldObject1, #testUser) + '第äºä¸ªDIFF' + #_DIFF(#oldObject2, #testUser)")
public void testMultipleDiff(TestUser testUser) {
LogRecordContext.putVariable("oldObject1", new TestUser(1, "å¼ ä¸"));
LogRecordContext.putVariable("oldObject2", new TestUser(3, "çäº"));
}
注æï¼ç®åDIFF
åè½æ¯æå®å
¨ä¸åçç±»ä¹é´è¿è¡DIFF
ï¼å¯¹äºååçåºç¡ç±»åï¼è¿è¡equals
对æ¯ï¼å¯¹äºååçéåºç¡ç±»åï¼ååç¨fastjson
çtoJSON
è½åï¼è½¬ä¸ºJSONObject
è¿è¡å¯¹æ¯ï¼æ¬è´¨ä¸æ¯å°å¯¹è±¡æ å°ä¸ºmap
è¿è¡map.equals
ã
æ¥å¿å¤çéè¯æ¬¡æ°åå åºå½æ°é ç½®
æ 论æ¯æ¬å°å¤çæ¥å¿ï¼æè
åéå°æ¶æ¯ç®¡éå¤çæ¥å¿ï¼é½ä¼åå¨å¤çå¼å¸¸éè¦éè¯çåºæ¯ãå¯ä»¥éè¿properties
é
ç½®ï¼
log-record.retry.retry-times=5 # é»è®¤ä¸º0次éè¯ï¼å³æ¥å¿å¤çæ¹æ³åªæ§è¡1次
é
ç½®åæ¡æ¶ä¼éæ°æ§è¡createLog
ç´è³è¾¾å°æ大éè¯æ¬¡æ°ã
è¥è¶
è¿äºéè¯æ¬¡æ°ï¼å¯ä»¥éè¿å®ç°SPI
æ¥å£ cn.monitor4all.logRecord.service.LogRecordErrorHandlerService
æ¥è¿è¡å
åºé»è¾å¤çï¼è¿éå°æ¬å°æ¥å¿å¤çåæ¶æ¯ç®¡éå
åºå¤çåå¼äºã
@Component
public class LogRecordErrorHandlerServiceImpl implements LogRecordErrorHandlerService {
@Override
public void operationLogGetErrorHandler() {
log.error("operation log get service error reached max retryTimes!");
}
@Override
public void dataPipelineErrorHandler() {
log.error("data pipeline send log error reached max retryTimes!");
}
}
éå¤æ³¨è§£
@OperationLog(bizId = "#testClass.testId", bizType = "'testType1'", msg = "#testFunc(#testClass.testId)")
@OperationLog(bizId = "#testClass.testId", bizType = "'testType2'", msg = "#testFunc(#testClass.testId)")
@OperationLog(bizId = "#testClass.testId", bizType = "'testType3'", msg = "'ç¨æ·å°æ§å¼' + #old + 'æ´æ¹ä¸ºæ°å¼' + #testClass.testStr")
æ们è¿å ä¸äºéå¤æ³¨è§£çæ¯æï¼å¯ä»¥å¨ä¸ä¸ªæ¹æ³ä¸åæ¶å å¤ä¸ª@OperationLog
ï¼ä¼ä¿è¯æç
§@OperationLog
ä»ä¸å°ä¸ç顺åºè¾åºæ¥å¿ã
èªå®ä¹æ¶æ¯çº¿ç¨æ±
starteræä¾äºå¦ä¸é ç½®ï¼
log-record.thread-pool.pool-size=4ï¼çº¿ç¨æ± æ ¸å¿çº¿ç¨å¤§å° é»è®¤ä¸º4ï¼
log-record.thread-pool.enabled=trueï¼çº¿ç¨æ± å¼å
³ é»è®¤ä¸ºå¼å¯ è¥å
³éå使ç¨ä¸å¡çº¿ç¨è¿è¡æ¶æ¯å¤çåéï¼
å¨ç»è£
好logDTO
åï¼é»è®¤ä¼ä½¿ç¨çº¿ç¨æ± 对æ¶æ¯è¿è¡å¤çï¼åéè³æ¬å°çå¬å½æ°æè
æ¶æ¯éååéè
ï¼ä¹å¯ä»¥éè¿é
ç½®å
³é线ç¨æ± ï¼è®©ä¸»çº¿ç¨æ§è¡å
¨é¨æ¶æ¯å¤çé»è¾ã
注æï¼logDTO
çç»è£
é»è¾å¨åé¢ä¸ï¼è¯¥åé¢ä»ç¶å¨å½æ°æ§è¡ç线ç¨ä¸è¿è¡ã
é»è®¤çº¿ç¨æ± é ç½®å¦ä¸ï¼æç»çç¥ä¸ºä¸¢å¼ï¼ï¼
return new ThreadPoolExecutor(poolSize, poolSize, 0L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1024), THREAD_FACTORY, new ThreadPoolExecutor.AbortPolicy());
æ¤å¤ï¼è¿æä¾äºç¨æ·ä¼ å ¥èªå®ä¹çº¿ç¨æ± çæ¹å¼ï¼ç¨æ·å¯èªè¡å®ç°cn.monitor4all.logRecord.thread.ThreadPoolProviderï¼ä¼ å ¥çº¿ç¨æ± ã
示ä¾ï¼
public class CustomThreadPoolProvider implements ThreadPoolProvider {
private static ThreadPoolExecutor EXECUTOR;
private static final ThreadFactory THREAD_FACTORY = new CustomizableThreadFactory("custom-log-record-");
private CustomThreadPoolProvider() {
log.info("CustomThreadPoolProvider init");
EXECUTOR = new ThreadPoolExecutor(3, 3, 0L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100), THREAD_FACTORY, new ThreadPoolExecutor.AbortPolicy());
}
@Override
public ThreadPoolExecutor buildLogRecordThreadPool() {
return EXECUTOR;
}
}
å½æ°è¿åå¼è®°å½å¼å ³
@OperationLog
注解æä¾å¸å°å¼recordReturnValue()
ç¨äºæ¯å¦å¼å¯è®°å½å½æ°è¿åå¼ï¼é»è®¤å
³éï¼é²æ¢è¿åå¼å®ä½è¿å¤§ï¼é æåºååæ¶æ§è½æ¶èè¿å¤ã
é注解æ¹å¼
å¨å®é ä¸å¡åºæ¯ä¸ï¼å¾å¤æ¶åç±äºæ³¨è§£çéå¶ï¼æ æ³å¾å¥½ç使ç¨æ³¨è§£è®°å½æ¥å¿ï¼æ¤æ¶å¯ä»¥ä½¿ç¨çº¯æå¨çæ¹å¼è¿è¡æ¥å¿è®°å½ã
æ¡æ¶æä¾äºæå¨è®°å½æ¥å¿çæ¹æ³ï¼
cn.monitor4all.logRecord.util.OperationLogUtil
LogRequest logRequest = LogRequest.builder()
.bizId("testBizId")
.bizType("testBuildLogRequest")
.success(true)
.msg("testMsg")
.tag("testTag")
.returnStr("testReturnStr")
.extra("testExtra")
// å
¶ä»å段
.build();
OperationLogUtil.log(logRequest);
使ç¨è¯¥æ¹å¼è®°å½æ¥å¿ï¼æ³¨è§£å¸¦æ¥çç¸å ³åè½åæ æ³ä½¿ç¨ï¼å¦SpEL表达å¼ï¼èªå®ä¹å½æ°çã
æä½æ¥å¿æ°æ®è¡¨ç»ææ¨è
以MySQL表为ä¾ï¼
CREATE TABLE `operation_log` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主é®',
`gmt_create` datetime NOT NULL COMMENT 'å建æ¶é´',
`gmt_modified` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT 'ä¿®æ¹æ¶é´',
`biz_id` varchar(128) NOT NULL COMMENT 'ä¸å¡ID',
`biz_type` varchar(64) DEFAULT NULL COMMENT 'ä¸å¡ç±»å',
`tag` varchar(64) DEFAULT NULL COMMENT 'æ ç¾',
`operation_date` datetime DEFAULT NULL COMMENT 'æä½æ§è¡æ¶é´',
`msg` varchar(512) DEFAULT NULL COMMENT 'æä½å
容',
`extra` varchar(512) DEFAULT NULL COMMENT 'éå ä¿¡æ¯',
`operation_status` tinyint(4) DEFAULT NULL COMMENT 'æä½ç»æç¶æ',
`operation_time` int(11) DEFAULT NULL COMMENT 'æä½èæ¶',
`content_return` varchar(512) COMMENT 'æ¹æ³è¿åå
容',
`content_exception` varchar(512) COMMENT 'æ¹æ³å¼å¸¸å
容',
`operator_id` varchar(32) DEFAULT NULL COMMENT 'æä½äººID',
`operator_name` varchar(32) DEFAULT NULL COMMENT 'æä½äººå§å',
PRIMARY KEY (`id`),
KEY `idx_biz_id` (`biz_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='æä½æ¥å¿è¡¨';
让注解æ¯æIDEA
èªå¨è¡¥å
¨
å¨èªå®ä¹æ³¨è§£æ³å®ç°ç±»ä¼¼@Cacheable
çèªå¨è¡¥å
¨ï¼å
¶å®æ¯IDEA
çIDE
èªå·±çæ¯æï¼å¯ä»¥å¨é
ç½®ä¸å°æ¬äºæ¹åºç注解添å ä¸å»ï¼ä»èæ¯æèªå¨è¡¥å
¨åSpEL
表达å¼æ ¡éªã
SpringBoot3(JDK17+)çæ¬ä¸SpringBoot1&SpringBoot2(JDK8+)çæ¬ä½¿ç¨å·®å¼
æ¬æ¡æ¶å°½å¯è½å¨ä¸åSpringBootçæ¬ä¸æä¾ç»ä¸çåè½åç¹æ§ï¼ä½ç±äºJDkå ¼å®¹çé®é¢ï¼å¨ä½¿ç¨ä¸ä»æä¸äºå·®å¼ã
å¨è¿éå举éè¦æ¬æ¡æ¶ä½¿ç¨è 注æçå·®å¼ï¼
SpringBoot3æ æ³è·åå½æ°å ¥å
ç±äºJDK11+以ä¸æ¶ç´§äºå¯¹åå°ç使ç¨ï¼å¯¼è´SpringBoot3æ æ³è·åå½æ°å ¥åï¼æ以å¨SpringBoot3çæ¬ä¸ï¼æ æ³ä½¿ç¨åæ°åè·åå½æ°å ¥åã
ä¾å¦å¨SpringBoot1&SpringBoot2ä¸å¯ä»¥è¿æ ·åï¼
@OperationLog(bizId = "#bizId", bizType = "'testBizIdWithSpEL'")
public void testBizIdWithSpEL(String bizId) {
}
ä½æ¯SpringBoot3ä¸ï¼åªè½ä½¿ç¨p0
ãp1
çåæ°åè·åå½æ°å
¥åï¼åæ°çç»å¯¹ä½ç½®ä¸æ ï¼ï¼å¦ä¸ï¼
@OperationLog(bizId = "#p0", bizType = "'testBizIdWithSpEL'")
public void testBizIdWithSpEL(String bizId) {
}
åºç¨åºæ¯
以ä¸ç½åäºä¸äºå®é çåºç¨åºæ¯ï¼å æ¬æä¸å¡ä¸å®é 使ç¨ï¼å¹¶ä¸å·²ç»ä¸çº¿ä½¿ç¨çåºæ¯ã
æä½æ¥å¿
CRM
ç³»ç»ï¼å¨ç¨æ·è¿è¡äºç¼è¾æä½åï¼æ¿å°ç¨æ·æä½çæ°æ®ï¼æ§è¡æ¥å¿åå
¥ã
ç³»ç»æ¥å¿
æä½æ¥å¿æ¯ä¸»è¦çåè½ï¼å½ç¶ä¹å¯ä»¥å ¼é¡¾ä¸äºç³»ç»æ¥å¿è®°å½çæä½ï¼æ¯å¦åªæ¯æ³ç®åè®°å½æ¹æ³æ§è¡æ¶é´ï¼åºå ¥åçï¼ä¹å¯ä»¥éè¿è¯¥åºè½»æ¾åå°ã
å端åç¹
ä¸ç³»ç»æ¥å¿ç±»ä¼¼ï¼å¯ä»¥è®°å½ä¸äºç¨æ·æä½åç¹ã
éç¥
åºç¨ä¹é´éè¿å ³é®æä½çæ¥å¿æ¶æ¯ï¼äºç¸éç¥ã
Demo
å½ä½ è§å¾ç¨æ³ä¸çæï¼å¯ä»¥æ¥çåå æµè¯ç¨ä¾ï¼éé¢ææ为详ç»ä¸æå ¨ç使ç¨ç¤ºä¾ã
å¦å¤æä¾å®æ´SpringBoot2&3 Demo项ç®:
https://github.com/qqxx6661/systemLog
Release Note
éå½
ç¼è¯æ³¨æ
ç±äºæåäºç¶å模åï¼å¨ä¸åJDKä¸ï¼è¯·éæ°ç¼è¯log-record-coreï¼åç¼è¯å¯¹åºçæ¬çlog-record-starterï¼å¦åä¼å¯¼è´ç¼è¯å¤±è´¥ï¼åå æµè¯å¼å¸¸ï¼ã
åå¸çæ¬æ³¨æ
请å°log-record-core, log-record-starter, log-record-springboot3-starteré½ç¼è¯æå åå¸å°Mavenå ¬å ±ä»åºã
é å¥æç¨æç«
- å¦ä½ä½¿ç¨æ³¨è§£ä¼é
çè®°å½æä½æ¥å¿
https://mp.weixin.qq.com/s/q2qmffH8t-ou2apOa6BiPQ - å¦ä½æ交èªå·±ç项ç®å°Mavenå
Œ
±ä»åº
https://mp.weixin.qq.com/s/B9LA6be_cPAKACbZot_Nrg
å ³æ³¨æ
å ¬ä¼å·ï¼å端ææ¯æ¼«è°
å ¨ç½å客åï¼è®ä¸åé ±
å¦æè§å¾è¯¥é¡¹ç®å¯¹ä½ æç¨ï¼è¯·ç¹ä¸ªstarï¼è°¢è°¢ï¼