Mastering BizLog SDK: Seamless Log Recording for Spring Boot Applications

This article introduces the BizLog SDK for Java, explains its Spring Boot autoconfiguration, demonstrates how to add Maven dependencies, enable logging with @EnableLogRecord, craft log messages using @LogRecordAnnotation with SpEL expressions, and extend the framework with custom parse functions and operator services.

Java High-Performance Architecture
Java High-Performance Architecture
Java High-Performance Architecture
Mastering BizLog SDK: Seamless Log Recording for Spring Boot Applications

Component Overview

The BizLog SDK provides a unified way to record who performed what action, when, and on which business entity in Java applications. It offers Spring Boot autoconfiguration and can also be manually configured for Spring MVC via XML.

Basic Usage

Maven Dependency

<dependency>
    <groupId>io.github.mouzt</groupId>
    <artifactId>bizlog-sdk</artifactId>
    <version>1.0.1</version>
</dependency>

Enable Logging in Spring Boot

@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableTransactionManagement
@EnableLogRecord(tenant = "com.mzt.test")
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class, args);
    }
}

The tenant parameter identifies the tenant; a single tenant identifier can be used for multiple services under the same business.

Log Recording

1. Simple Log Record

@LogRecordAnnotation(
    success = "{{#order.purchaseName}} placed an order, purchased product \"{{#order.productName}}\", result:{{#_ret}}",
    prefix = LogRecordType.ORDER,
    bizNo = "{{#order.orderNo}}"
)
public boolean createOrder(Order order) {
    log.info("【创建订单】orderNo={}", order.getOrderNo());
    // db insert order
    return true;
}

This will output a log such as "Zhang San placed an order, purchased product \"Super Value Red Braised Pork Set\", result:true".

2. Record Failure Log

@LogRecordAnnotation(
    fail = "Order creation failed, reason: \"{{#_errorMsg}}\"",
    success = "{{#order.purchaseName}} placed an order, purchased product \"{{#order.productName}}\", result:{{#_ret}}",
    prefix = LogRecordType.ORDER,
    bizNo = "{{#order.orderNo}}"
)
public boolean createOrder(Order order) {
    log.info("【创建订单】orderNo={}", order.getOrderNo());
    // db insert order
    return true;
}

The #_errorMsg variable captures the exception message when an error occurs.

3. Log Category

@LogRecordAnnotation(
    fail = "Order creation failed, reason: \"{{#_errorMsg}}\"",
    category = "MANAGER",
    success = "{{#order.purchaseName}} placed an order, purchased product \"{{#order.productName}}\", result:{{#_ret}}",
    prefix = LogRecordType.ORDER,
    bizNo = "{{#order.orderNo}}"
)
public boolean createOrder(Order order) { /* ... */ }

The category field helps classify logs (e.g., user actions vs. manager operations) for easier querying.

4. Detail Field

@LogRecordAnnotation(
    fail = "Order creation failed, reason: \"{{#_errorMsg}}\"",
    category = "MANAGER_VIEW",
    detail = "{{#order.toString()}}",
    success = "{{#order.purchaseName}} placed an order, purchased product \"{{#order.productName}}\", result:{{#_ret}}",
    prefix = LogRecordType.ORDER,
    bizNo = "{{#order.orderNo}}"
)
public boolean createOrder(Order order) { /* ... */ }

The detail field can store a JSON string or the result of order.toString() to retain full change information.

5. Specifying the Operator

Two approaches are provided:

Manually set the operator attribute in the annotation (requires an operator method parameter).

Implement IOperatorGetService to automatically obtain the current user from thread context or other sources.

@Configuration
public class LogRecordConfiguration {
    @Bean
    public IOperatorGetService operatorGetService() {
        return () -> Optional.of(OrgUserUtils.getCurrentUser())
            .map(u -> new OperatorDO(u.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 Parse Functions

Implement IParseFunction to create reusable functions used inside SpEL templates.

@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 + ")";
    }
}

Usage in annotation:

@LogRecordAnnotation(
    success = "Updated order ORDER{#orderId}}, details...",
    prefix = LogRecordType.ORDER,
    bizNo = "{{#order.orderNo}}",
    detail = "{{#order.toString()}}"
)
public boolean update(Long orderId, Order order) { return false; }

Advanced Features

SpEL ternary expressions for conditional log messages.

Adding custom variables via LogRecordContext.putVariable(name, value) for use in templates and custom functions.

Diff list parsing to generate logs like "added X, removed Y".

@LogRecordAnnotation(
    success = "{DIFF_LIST{'Document Address'}}",
    bizNo = "{{#id}}",
    prefix = REQUIREMENT
)
public void updateRequirementDocLink(String currentMisId, Long id, List<String> docLinks) { /* ... */ }

@Component
public class DiffListParseFunction implements IParseFunction {
    @Override
    public String functionName() { return "DIFF_LIST"; }
    @Override
    public String apply(String value) {
        // compare oldList and newList stored in LogRecordContext
        // build human‑readable diff string
        return result;
    }
}

Extension Points

Custom IOperatorGetService implementation to fetch the operator from security context.

Implement ILogRecordService to persist logs to a database, Elasticsearch, or any storage.

Create additional IParseFunction implementations for domain‑specific transformations.

Change Log & TODO

Name

Status

Support Context Variable

1.0.4 supported

Support Object Diff

TODO

Support List Log Recording

TODO

Important Note

The log interceptor runs after the method execution, so SpEL expressions see the modified method parameters.

Source Code

GitHub repository: https://github.com/mouzt/mzt-biz-log

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaSpELloggingSpring BootannotationBizLog SDK
Java High-Performance Architecture
Written by

Java High-Performance Architecture

Sharing Java development articles and resources, including SSM architecture and the Spring ecosystem (Spring Boot, Spring Cloud, MyBatis, Dubbo, Docker), Zookeeper, Redis, architecture design, microservices, message queues, Git, etc.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.