Skip to content

CiprianPesu/Spring-Boot-AOP-Audit-Library

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Audit Library

Library Name: Audit Library
Purpose: Lightweight, annotation-driven audit logging for Spring Boot applications using AspectJ AOP

Overview

This library provides automatic method-level auditing through a simple @Audit annotation.

When a method is annotated with @Audit, the following data is captured and persisted in a dedicated database:

  • Execution timestamp
  • Current user (resolved via AuditResolver)
  • Application/module identifier (resolved via AuditResolver)
  • Event type (custom value or default "METHOD_EXECUTED")
  • Method name
  • Input parameters (JSON-serialized, with safe handling of MultipartFile)
  • Method result / response body (JSON-serialized)
  • HTTP status code (when method returns ResponseEntity)

Auditing uses a separate DataSource, EntityManagerFactory and TransactionManager — isolated from the main application database.

Key Features

  • Zero-configuration auditing via annotation
  • JSON serialization of arguments and results
  • Special handling for file uploads (MultipartFile → metadata only)
  • Pluggable user & application context via AuditResolver
  • Automatic detection of ResponseEntity responses
  • Dedicated audit datasource (audit.datasource.* properties)
  • Uses hibernate.hbm2ddl.auto=update (development-friendly)

Main Components

1. @Audit Annotation

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Audit {
    String value() default "";
}

Example

@Audit("PATIENT_CREATED")
public ResponseEntity<PatientDto> createPatient(@RequestBody PatientCreateDto dto) { … }

@Audit
public List<Appointment> findAppointmentsByPatient(Long patientId) { … }   // → "METHOD_EXECUTED"

@Audit("REPORT_DOWNLOADED")
public ResponseEntity<Resource> downloadMedicalReport(String reportId) { … }

2. AuditResolver (you must provide this bean)

public interface AuditResolver {
@Nullable String resolveCurrentUser();
@Nullable String resolveApplicationIdentifier();
}

Example

@Configuration
public class AuditConfig {

    @Value("${audit.applicationName}")
    private String applicationName;

    @Bean
    @Primary
    public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory);
    }

    @Bean
    public AuditResolver auditUserResolver() {
        return new AuditResolver() {
            @Override
            public String resolveCurrentUser() {
                Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

                if (!(authentication instanceof JwtAuthenticationToken)
                        || !authentication.isAuthenticated()) {
                    return null;
                }

                Jwt jwt = (Jwt) authentication.getPrincipal();

                return jwt.getClaim("name");
            }

            @Override
            public String resolveApplicationIdentifier() {
                return applicationName;
            }
        };
    }
}

3. Table Configuration

@Entity
@Table(name = "audit_events", indexes = {
        @Index(name = "idx_audit_timestamp", columnList = "timestamp"),
        @Index(name = "idx_audit_user", columnList = "userName"),
        @Index(name = "idx_audit_event_type", columnList = "eventType"),
        @Index(name = "idx_audit_method_name", columnList = "methodName"),
        @Index(name = "idx_audit_app_identification", columnList = "appIdentification")
})
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class AuditEvent {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private LocalDateTime timestamp;
    private String userName;
    private String appIdentification;
    private String eventType;
    private String methodName;

    @Column(columnDefinition = "TEXT")
    private String methodResult;
    private String methodResultStatus;

    @Column(columnDefinition = "TEXT")
    private String parameters;

}

Indexes

The following indexes are defined to improve query performance:

Index Name Column Purpose
idx_audit_timestamp timestamp Speeds up time-based queries (e.g., logs within a date range)
idx_audit_user userName Optimizes filtering by user
idx_audit_event_type eventType Improves queries by event category
idx_audit_method_name methodName Helps trace specific method executions

Fields

Field Name Type Description
id Long Primary key (auto-generated)
timestamp LocalDateTime Time when the event occurred
userName String User who triggered the event
appIdentification String Identifier of the application
eventType String Type/category of the event
methodName String Name of the executed method
methodResult String (TEXT) Result/output of the method
methodResultStatus String Status of execution (e.g., 200, 401)
parameters String (TEXT) Input parameters passed to the method

4. Configuration

audit:
    datasource:
        url: [DB_URL]
        username: [DB_USERNAME]
        password: [DB_PASSWORD]

5. Dependencies, Build & Integration Guide

** Audit Library**

Current date reference: March 2026

5.1. Dependencies used in the library

The library is deliberately lightweight and tries to reuse Spring Boot starters where possible.

Core / Required dependencies
<!-- Spring Boot starters -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>         <!-- brings AspectJ -->
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jackson</artifactId>
</dependency>

<!-- Jackson (used for serialization of params & results) -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
</dependency>

<!-- Lombok -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <scope>provided</scope>
</dependency>

5.2. How to build the library

Prerequisites
Java 21
Maven 3.9+
Build commands
# Clean & build (including tests if you have them)
mvn clean package

# Skip tests (common in CI when no integration tests yet)
mvn clean package -DskipTests

# Install to local .m2 repository (useful for local testing)
mvn clean install

# Deploy to your company's GitLab / Nexus / Artifactory
mvn clean deploy
The artifact is published to:
<distributionManagement>
    <repository>
        <id>repo-name</id>
        <url>repo-url>
    </repository>
</distributionManagement>

6. How to use the library in another Spring Boot project

Step 1 – Add dependency
<dependency>
    <groupId>audit</groupId>
    <artifactId>audit</artifactId>
    <version>1.0.0</version>   <!-- or latest version -->
</dependency>
Step 2 If using a private repository, make sure you have it in your pom.xml or settings.xml
<repositories>
    <repository>
        <id>repo-name</id>
        <url>repo-url>
    </repository>
</repositories>
Step 3 Configure audit datasource
Step 4 Provide AuditResolver bean ( refer to 2.)
Step 5 Configure audit datasource ( refer to 4.)
Step 6 Annotate methods you want to audit ( refer to 1.)

About

Lightweight, annotation-driven audit logging for Spring Boot applications using AspectJ AOP

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages