BizLog SDK: Usage, Configuration, and Extension Guide for Spring Boot
This article introduces the BizLog SDK for Spring Boot, explaining how to add Maven dependencies, enable logging with @EnableLogRecord, configure log records using @LogRecordAnnotation for success, failure, categories, details, operators, custom parsing functions, and shows how to extend the framework with custom services and implementations.
This document provides a comprehensive guide to the BizLog SDK, a logging component designed for Spring Boot applications. It explains the problem the component solves—recording who performed what action on which object at what time—and details its features, usage, and extensibility.
Adding the Maven Dependency
<dependency>
<groupId>io.github.mouzt</groupId>
<artifactId>bizlog-sdk</artifactId>
<version>1.0.1</version>
</dependency>Enabling the Log Record Switch
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableTransactionManagement
@EnableLogRecord(tenant = "com.mzt.test")
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}Basic Log Record Annotation Usage
@LogRecordAnnotation(success = "{{#order.purchaseName}}下了一个订单,购买商品「{{#order.productName}}」,下单结果:{{#_ret}}",
prefix = LogRecordType.ORDER, bizNo = "{{#order.orderNo}}")
public boolean createOrder(Order order) {
log.info("【创建订单】orderNo={}", order.getOrderNo());
// db insert order
return true;
}The above example logs a successful order creation. If an exception occurs, a failure log can be recorded:
@LogRecordAnnotation(
fail = "创建订单失败,失败原因:「{{#_errorMsg}}」",
success = "{{#order.purchaseName}}下了一个订单,购买商品「{{#order.productName}}」,下单结果:{{#_ret}}",
prefix = LogRecordType.ORDER, bizNo = "{{#order.orderNo}}")
public boolean createOrder(Order order) {
log.info("【创建订单】orderNo={}", order.getOrderNo());
// db insert order
return true;
}Additional fields such as category , detail , and operator can be added to the annotation to classify logs, store extra information, or specify the operator:
@LogRecordAnnotation(
fail = "创建订单失败,失败原因:「{{#_errorMsg}}」",
category = "MANAGER",
detail = "{{#order.toString()}}",
success = "{{#order.purchaseName}}下了一个订单,购买商品「{{#order.productName}}」,下单结果:{{#_ret}}",
prefix = LogRecordType.ORDER, bizNo = "{{#order.orderNo}}")
public boolean createOrder(Order order) { ... }To specify the operator manually, include the operator attribute and ensure the method has a corresponding parameter:
@LogRecordAnnotation(
fail = "创建订单失败,失败原因:「{{#_errorMsg}}」",
category = "MANAGER_VIEW",
detail = "{{#order.toString()}}",
operator = "{{#currentUser}}",
success = "{{#order.purchaseName}}下了一个订单,购买商品「{{#order.productName}}」,下单结果:{{#_ret}}",
prefix = LogRecordType.ORDER, bizNo = "{{#order.orderNo}}")
public boolean createOrder(Order order, String currentUser) { ... }For automatic operator retrieval, implement the IOperatorGetService interface and register it as a Spring bean:
@Configuration
public class LogRecordConfiguration {
@Bean
public IOperatorGetService operatorGetService() {
return () -> Optional.of(OrgUserUtils.getCurrentUser())
.map(a -> new OperatorDO(a.getMisId()))
.orElseThrow(() -> new IllegalArgumentException("user is null"));
}
}
@Service
public class DefaultOperatorGetServiceImpl implements IOperatorGetService {
@Override
public OperatorDO getUser() {
OperatorDO operatorDO = new OperatorDO();
operatorDO.setOperatorId("SYSTEM");
return operatorDO;
}
}Custom Parsing Functions
To transform log variables, implement IParseFunction . For example, converting an order ID to a readable string:
@Component
public class OrderParseFunction implements IParseFunction {
@Resource @Lazy private OrderQueryService orderQueryService;
@Override
public String functionName() { return "ORDER"; }
@Override
public String apply(String value) {
if (StringUtils.isEmpty(value)) { return value; }
Order order = orderQueryService.queryOrder(Long.parseLong(value));
return order.getProductName() + "(" + value + ")";
}
}Use the function in the annotation:
@LogRecordAnnotation(success = "更新了订单ORDER{#orderId}},更新内容为...",
prefix = LogRecordType.ORDER, bizNo = "{{#order.orderNo}}",
detail = "{{#order.toString()}}")
public boolean update(Long orderId, Order order) { return false; }SpEL ternary expressions can also be used in log messages:
@LogRecordAnnotation(prefix = LogRecordTypeConstant.CUSTOM_ATTRIBUTE, bizNo = "{{#businessLineId}}",
success = "{{#disable ? '停用' : '启用'}}了自定义属性{ATTRIBUTE{#attributeId}}")
public CustomAttributeVO disableAttribute(Long businessLineId, Long attributeId, boolean disable) { return xxx; }Framework Extension Points
Implement custom IOperatorGetService to retrieve the current user from the application context:
@Service
public class DefaultOperatorGetServiceImpl implements IOperatorGetService {
@Override
public Operator getUser() {
return Optional.ofNullable(UserUtils.getUser())
.map(a -> new Operator(a.getName(), a.getLogin()))
.orElseThrow(() -> new IllegalArgumentException("user is null"));
}
}Implement ILogRecordService to persist logs to a database, Elasticsearch, etc. Only the record method is required for saving:
@Service
public class DbLogRecordServiceImpl implements ILogRecordService {
@Resource private LogRecordMapper logRecordMapper;
@Override @Transactional(propagation = Propagation.REQUIRES_NEW)
public void record(LogRecord logRecord) {
log.info("【logRecord】log={}", logRecord);
LogRecordPO logRecordPO = LogRecordPO.toPo(logRecord);
logRecordMapper.insert(logRecordPO);
}
@Override public List
queryLog(String bizKey, Collection
types) { return Lists.newArrayList(); }
@Override public PageDO
queryLogByBizNo(String bizNo, Collection
types, PageRequestDO pageRequestDO) {
return logRecordMapper.selectByBizNoAndCategory(bizNo, types, pageRequestDO);
}
}Custom parse functions can also be created for user IDs, converting them to readable names:
@Component
public class UserParseFunction implements IParseFunction {
private final Splitter splitter = Splitter.on(",").trimResults();
@Resource @Lazy private UserQueryService userQueryService;
@Override public String functionName() { return "USER"; }
@Override public String apply(String value) {
if (StringUtils.isEmpty(value)) { return value; }
List
userIds = Lists.newArrayList(splitter.split(value));
List
misDOList = userQueryService.getUserList(userIds);
Map
userMap = StreamUtil.extractMap(misDOList, User::getId);
StringBuilder sb = new StringBuilder();
for (String userId : userIds) {
sb.append(userId);
if (userMap.get(userId) != null) {
sb.append("(").append(userMap.get(userId).getUsername()).append(")");
}
sb.append(",");
}
return sb.toString().replaceAll(",$", "");
}
}Variables available in @LogRecordAnnotation include method parameters, return value ( #_ret ), exception message ( #_errorMsg ), and any SpEL static method calls.
Note that the logging interceptor runs after method execution, so any modifications to method parameters are reflected in the SpEL expressions used for log content.
For the full source code, visit the GitHub repository: https://github.com/mouzt/mzt-biz-log .
Architect's Tech Stack
Java backend, microservices, distributed systems, containerized programming, and more.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.