How to Build Scalable Business Operation Logging with AOP, SpEL, and Binlog

This article explores a step‑by‑step evolution of business operation logging—from a simple AOP‑annotation approach, through enriched SpEL expressions, to a robust Binlog‑based solution with time‑window aggregation—highlighting benefits, challenges, code examples, and architectural diagrams for backend developers.

Architect
Architect
Architect
How to Build Scalable Business Operation Logging with AOP, SpEL, and Binlog

Background

In recent projects the system needs a business operation log statistics feature. Because the system sits at the core of the business chain, it receives upstream data and forwards user‑generated data downstream. To improve issue‑resolution efficiency and provide more tooling for users, we plan to record the full lifecycle of core business data.

Benefits of Business Operation Logs

Audit and compliance : Track data‑change history and identify who performed which operation and when.

Security

Intrusion detection: Analyze logs to spot abnormal or unauthorized access.

Post‑incident analysis: Use logs to determine attack scope and impact.

Error diagnosis and system monitoring

Troubleshooting: Provide key information for rapid fault location and repair.

Performance monitoring: Analyze response time and resource consumption.

User behavior analysis

Business insight: Derive valuable insights from user operation patterns to guide product improvement and market strategy.

Customer service: Help support staff understand user issues for targeted assistance.

Data recovery : Assist backup and restoration when data loss or corruption occurs.

Business rule and process improvement : Analyze and optimize workflows to increase efficiency.

Goal

Enhance data traceability and transparency, ensuring smooth and monitorable business processes. The expected system effects are:

Solution 1.0: AOP + Annotation

Using Spring AOP and a custom annotation provides a low‑intrusion way to capture core business operations before and after execution.

Define Log Annotation

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Loggable {
    String value() default "";
    // additional attributes such as operation type, level, etc.
}

Create AOP Aspect

@Aspect
@Component
public class LoggingAspect {
    @Around("@annotation(loggable)")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint, Loggable loggable) throws Throwable {
        long start = System.currentTimeMillis();
        Object proceed = joinPoint.proceed(); // execute target method
        long executionTime = System.currentTimeMillis() - start;
        logger.info(joinPoint.getSignature() + " executed in " + executionTime + "ms");
        return proceed;
    }
}

Configure Spring AOP + Mark Annotation

@Configuration
@EnableAspectJAutoProxy
public class AopConfig {
    // other beans if needed
}

public class SomeService {
    @Loggable
    public void someBusinessMethod(Object someParam) {
        // business logic
    }
}

Log Recording Logic

@Autowired
private Logger logger; // e.g., SLF4J logger

@Around("@annotation(loggable)")
public Object logBusinessOperation(ProceedingJoinPoint joinPoint, Loggable loggable) throws Throwable {
    long start = System.currentTimeMillis();
    try {
        Object result = joinPoint.proceed();
        return result;
    } catch (Exception e) {
        throw e;
    } finally {
        long executionTime = System.currentTimeMillis() - start;
        logger.info("{} executed in {} ms", joinPoint.getSignature(), executionTime);
    }
}

Solution Summary

The basic framework is now coded; after deployment the system will start persisting user operation logs.

Solution 2.0: AOP + SpEL

Solution 1.0 records fixed‑template logs. To embed richer business context (e.g., "User X modified project ID=001"), we extend the annotation and evaluate SpEL expressions at runtime.

SpEL Overview

Spring Expression Language (SpEL) evaluates expressions against runtime objects, allowing access to properties, methods, arithmetic, logical operations, and more. It is used in @Value, XML, and annotation configurations.

Expression Definition

@Repeatable(LogRecords.class)
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface LogRecord {
    String success();
    String fail() default "";
    String operator() default ""; // who performed the operation
    String type();                // business module
    String subType() default ""; // sub‑module
    String bizNo();               // business identifier
    String extra() default "";  // extra info
    String actionType();          // e.g., edit, add, delete
}

Expression Usage

By parsing the annotation fields with SpEL, we can capture full method parameters, return values, and contextual data, greatly expanding the log’s informational breadth.

Solution Summary

Pros: Reduces repetitive code, simplifies integration, and allows unlimited extension of business data.

Cons: Still introduces annotation overhead and requires product‑R&D alignment on log content.

Solution 3.0: Binlog + Time Window

Binlog records every change to MySQL tables in binary format. It can be leveraged to sense data‑level events directly from the database.

Problems and Idea

Problem 1 : Binlog entries are unordered and may span multiple tables, making it hard to handle cascaded updates without a transaction.

Problem 2 : The updater (operator) is often missing because upstream services don’t set it.

To address Problem 1 we borrow Flink’s sliding time‑window concept: group binlog events into fixed‑size windows (e.g., 1 minute) and then correlate rows within each window, using transaction keys when available.

By also capturing reference fields between tables, the windowed processing can resolve cascaded updates.

Binlog Data Structures

@Data
public static class RowChange {
    private int tableId;
    private List<RowDatas> rowDatas;
    private String eventType;
    private boolean isDdl;
}

@Data
public static class RowDatas {
    private List<DataColumn> afterColumns;
    private List<DataColumn> beforeColumns;
}

@Data
public static class DataColumn {
    private int sqlType;
    private boolean isNull;
    private String mysqlType;
    private String name;
    private boolean isKey;
    private int index;
    private boolean updated;
    private String value;
}

Architecture Diagram

Solution Summary

Binlog gives fine‑grained data change awareness, but also captures non‑application changes (e.g., batch jobs), which may be noisy.

Solution 3 weakens the rich business‑scene fields (action type, sub‑type), reducing granularity.

The design can be reused for other systems to centralize log collection.

Conclusion

Architecture evolves through trade‑offs; there is no perfect solution. The key is to adapt the logging strategy to the specific tech stack and business needs, balancing elegance, invasiveness, and completeness.

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.

Backend ArchitectureaopSpELBinlogbusiness logging
Architect
Written by

Architect

Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.

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.