Evolving Business Operation Logging: From AOP Annotations to Binlog Time Windows
This article examines the need for comprehensive business operation logging in a central system, outlines the benefits of audit, security, monitoring, and analysis, and walks through three progressive solutions—AOP with annotations, AOP with SpEL, and a Binlog‑based time‑window approach—detailing their implementations, trade‑offs, and architectural considerations.
0. Background
In a recent project the system sits at the core of a business data pipeline, receiving upstream data and forwarding processed results downstream. To improve issue‑resolution efficiency and provide richer tooling for users, the team decided to record the full lifecycle of core business operations.
0.1 Benefits
Audit & Compliance : Track who performed which operation and when.
Security : Detect intrusion attempts and support post‑incident analysis.
Error Diagnosis & Monitoring : Provide crucial context for troubleshooting and performance analysis.
User Behavior Analysis : Gain business insights and improve customer service.
Data Recovery : Assist in backup and restoration processes.
Process Improvement : Enable workflow optimization based on logged data.
0.2 Goals
Enhance traceability and transparency of data, ensuring smooth and monitorable business processes. The core question to solve is: "Who performed what action on which object at what time?"
1. Solution 1.0 – AOP + Annotation
Using Spring AOP and a custom annotation provides a low‑intrusion way to capture method execution details.
1.1 Define Logging Annotation
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Loggable {
String value() default ""; // additional attributes can be added
}1.2 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();
long executionTime = System.currentTimeMillis() - start;
logger.info(joinPoint.getSignature() + " executed in " + executionTime + "ms");
return proceed;
}
}1.3 Enable AOP and Apply Annotation
@Configuration
@EnableAspectJAutoProxy
public class AopConfig { }
public class SomeService {
@Loggable
public void someBusinessMethod(Object param) {
// business logic
}
}1.4 Logging Logic
The aspect can be extended to record method parameters, return values, exceptions, etc., by injecting a logger (e.g., SLF4J) and adding custom logic before and after method execution.
1.5 Summary of Solution 1.0
While simple and minimally invasive, this approach suffers from limited log granularity, inability to capture complex business scenarios, and difficulty handling cascaded operations across multiple services.
2. Solution 2.0 – AOP + SpEL
To enrich log content, the annotation is extended with SpEL (Spring Expression Language) fields, allowing dynamic extraction of method arguments and business context.
2.1 SpEL Overview
SpEL evaluates expressions at runtime and can be used in annotations, configuration files, and XML. It enables arithmetic, logical, and method‑call expressions.
2.2 Define Extended Annotation
@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 action
String type(); // business module
String subType() default ""; // sub‑module
String bizNo(); // business identifier
String extra() default ""; // additional info
String actionType(); // e.g., CREATE, UPDATE, DELETE
}2.3 Parse SpEL Expressions
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
public class LogRecordParser {
public static Map<String, Object> parseLogRecord(Annotation logRecordAnnotation) {
Map<String, Object> result = new HashMap<>();
ExpressionParser parser = new SpelExpressionParser();
for (String attribute : logRecordAnnotation.getAttributeNames()) {
Object value = logRecordAnnotation.getAttribute(attribute);
Expression expression = parser.parseExpression(attribute);
Object parsedValue = expression.getValue();
result.put(attribute, parsedValue);
}
return result;
}
}2.4 Usage Example
Developers annotate methods with @LogRecord and embed SpEL placeholders (e.g., #{#param.id}) to capture specific business data such as the affected entity ID.
2.5 Summary of Solution 2.0
Pros: Reduces boilerplate, captures richer business context.
Cons: Increases annotation complexity and still requires agreement on log content across product and development teams.
3. Solution 3.0 – Binlog + Time Window
To move logging to the data layer, the team explores using MySQL Binlog combined with a sliding time‑window mechanism (inspired by Flink) to aggregate and correlate changes across tables.
3.1 Binlog Basics
Binlog records every SQL statement that modifies data. It can be consumed to reconstruct data changes.
3.2 Problem & Approach
Problem 1 : Binlog events are unordered and may span multiple tables without a transaction boundary.
Solution : Apply a fixed‑size (e.g., 1‑minute) sliding window to group events; within each window, correlate rows using foreign‑key references.
Problem 2 : Missing operator information when updates are performed automatically.
Solution : Enforce operator stamping at the ORM layer or via database triggers.
3.3 Data Model
@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;
}3.4 Architecture Overview
The pipeline consumes Binlog, parses RowChange objects, groups them by a 1‑minute window, and then performs join operations based on reference fields to reconstruct a complete business operation log.
3.5 Summary of Solution 3.0
Advantages: Captures low‑level data changes without application‑level instrumentation; can be reused for other systems.
Limitations: Requires handling of large, noisy Binlog streams and may lose fine‑grained business semantics.
4. Final Thoughts
The evolution from simple AOP annotations to a Binlog‑driven, windowed architecture illustrates how logging requirements grow with system complexity. While each solution addresses specific shortcomings of its predecessor, the ideal approach often combines multiple techniques and adapts to the concrete business and technical constraints.
Java Architect Handbook
Focused on Java interview questions and practical article sharing, covering algorithms, databases, Spring Boot, microservices, high concurrency, JVM, Docker containers, and ELK-related knowledge. Looking forward to progressing together with you.
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.
