Implementing System Operation Logs with Spring AOP

Custom Annotation for Logging

Define an annotation to mark methods requiring logging:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AuditLog {
    String category() default "";
    String action() default "";
}

Log Entity Structure

Create a data model for log records:

@Data
public class SystemLog {
    private Long id;
    private String userId;
    private LocalDateTime timestamp;
    private String category;
    private String action;
    private String methodSignature;
    private String parameters;
    private String outcome;
    private String error;
    private Long duration;
    private String clientAddress;
}

AOP Aspect Implementation

Implement the logging aspect:

@Aspect
@Component
@RequiredArgsConstructor
public class LoggingAspect {
    private final LogPersister logPersister;

    @Pointcut("@annotation(com.example.AuditLog)")
    public void auditedMethods() {}

    @Around("auditedMethods()")
    public Object logOperation(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        SystemLog logEntry = new SystemLog();
        logEntry.setTimestamp(LocalDateTime.now());

        HttpServletRequest request = ((ServletRequestAttributes)
            RequestContextHolder.currentRequestAttributes()).getRequest();
        logEntry.setClientAddress(request.getRemoteAddr());

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        AuditLog auditAnnotation = method.getAnnotation(AuditLog.class);
        
        logEntry.setCategory(auditAnnotation.category());
        logEntry.setAction(auditAnnotation.action());
        logEntry.setMethodSignature(method.getDeclaringClass().getName() + "." + method.getName());
        logEntry.setParameters(Arrays.toString(joinPoint.getArgs()));

        try {
            Object result = joinPoint.proceed();
            logEntry.setOutcome("SUCCESS");
            return result;
        } catch (Exception e) {
            logEntry.setOutcome("FAILURE");
            logEntry.setError(e.getMessage());
            throw e;
        } finally {
            logEntry.setDuration(System.currentTimeMillis() - start);
            persistLog(logEntry);
        }
    }

    private void persistLog(SystemLog logEntry) {
        try {
            logPersister.save(logEntry);
        } catch (Exception e) {
            // Handle persistence failure
        }
    }
}

Database Persistence

Define the repository interface:

public interface SystemLogRepository {
    @Insert("INSERT INTO system_logs (user_id, timestamp, category, action, " +
           "method, parameters, outcome, error, duration, client_ip) " +
           "VALUES (#{userId}, #{timestamp}, #{category}, #{action}, " +
           "#{methodSignature}, #{parameters}, #{outcome}, #{error}, " +
           "#{duration}, #{clientAddress})")
    @Options(useGeneratedKeys = true, keyProperty = "id")
    void insert(SystemLog log);
}

Usage Example

Apply the annotation to methods:

@RestController
public class UserController {
    
    @PostMapping("/users")
    @AuditLog(category = "USER_MANAGEMENT", action = "CREATE_USER")
    public User createUser(@RequestBody User user) {
        return userService.save(user);
    }
}

Database Schema

CREATE TABLE system_logs (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    user_id VARCHAR(50) NOT NULL,
    timestamp DATETIME NOT NULL,
    category VARCHAR(100) NOT NULL,
    action VARCHAR(255) NOT NULL,
    method VARCHAR(255) NOT NULL,
    parameters TEXT,
    outcome VARCHAR(50),
    error TEXT,
    duration BIGINT,
    client_ip VARCHAR(50)
);

Tags: Spring aop logging java database

Posted on Wed, 29 Jul 2026 16:57:51 +0000 by ipruthi