app/proprietary/src/main/resources/templates/AUDIT_USAGE.md
This document provides guidance on how to use the audit system in Stirling PDF.
The audit system provides comprehensive logging of user actions and system events, storing them in a database for later review. This is useful for:
The audit system supports different levels of detail that can be configured in the settings.yml file:
Audit levels are configured in the settings.yml file under the premium section:
premium:
proFeatures:
audit:
enabled: true # Enable/disable audit logging
level: 2 # Audit level (0=OFF, 1=BASIC, 2=STANDARD, 3=VERBOSE)
retentionDays: 90 # Number of days to retain audit logs
The following events are automatically audited (based on configured level):
All HTTP requests are automatically audited with details based on the configured level:
All controller methods with web mapping annotations are automatically audited:
@GetMapping@PostMapping@PutMapping@DeleteMapping@PatchMappingMethods with these annotations are audited at the STANDARD level by default.
The following security events are always audited at the BASIC level:
There are two ways to add audit events from your code:
Inject the AuditService and use it directly:
@Service
@RequiredArgsConstructor
public class MyService {
private final AuditService auditService;
public void processPdf(MultipartFile file) {
// Process the file...
// Add an audit event with default level (STANDARD)
auditService.audit("PDF_PROCESSED", Map.of(
"filename", file.getOriginalFilename(),
"size", file.getSize(),
"operation", "process"
));
// Or specify an audit level
auditService.audit("PDF_PROCESSED_DETAILED", Map.of(
"filename", file.getOriginalFilename(),
"size", file.getSize(),
"operation", "process",
"metadata", file.getContentType(),
"user", "johndoe"
), AuditLevel.VERBOSE);
// Critical security events should use BASIC level to ensure they're always logged
auditService.audit("SECURITY_EVENT", Map.of(
"action", "file_access",
"resource", file.getOriginalFilename()
), AuditLevel.BASIC);
}
}
For simpler auditing, use the @Audited annotation on your methods:
@Service
public class UserService {
// Basic audit level for important security events
@Audited(type = "USER_REGISTRATION", level = AuditLevel.BASIC)
public User registerUser(String username, String email) {
// Method implementation
User user = new User(username, email);
// Save user...
return user;
}
// Sensitive operations should use BASIC but disable argument logging
@Audited(type = "USER_PASSWORD_CHANGE", level = AuditLevel.BASIC, includeArgs = false)
public void changePassword(String username, String newPassword) {
// Change password implementation
// includeArgs=false prevents the password from being included in the audit
}
// Standard level for normal operations (default)
@Audited(type = "USER_LOGIN")
public boolean login(String username, String password) {
// Login implementation
return true;
}
// Verbose level for detailed information
@Audited(type = "USER_SEARCH", level = AuditLevel.VERBOSE, includeResult = true)
public List<User> searchUsers(String query) {
// Search implementation
// At VERBOSE level, this will include both the query and results
return userList;
}
}
With the @Audited annotation:
level parameterincludeArgs = false)includeResult = trueIn addition to the manual methods above, all controller methods with web mapping annotations are automatically audited, even without the @Audited annotation:
@RestController
@RequestMapping("/api/users")
public class UserController {
// This method will be automatically audited
@GetMapping("/{id}")
public ResponseEntity<User> getUser(@PathVariable String id) {
// Method implementation
return ResponseEntity.ok(user);
}
// This method will be automatically audited
@PostMapping
public ResponseEntity<User> createUser(@RequestBody User user) {
// Method implementation
return ResponseEntity.ok(savedUser);
}
// This method uses @Audited and takes precedence over automatic auditing
@Audited(type = "USER_DELETE", level = AuditLevel.BASIC)
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable String id) {
// Method implementation
return ResponseEntity.noContent().build();
}
}
Important notes about automatic controller auditing:
Use consistent event types throughout the application:
FILE_UPLOAD - When a file is uploadedFILE_DOWNLOAD - When a file is downloadedPDF_PROCESS - When a PDF is processed (split, merged, etc.)USER_CREATE - When a user is createdUSER_UPDATE - When a user details are updatedPASSWORD_CHANGE - When a password is changedPERMISSION_CHANGE - When permissions are modifiedSETTINGS_CHANGE - When system settings are changed/auditevents endpoint is disabled to prevent unauthorized access to audit dataAudit events are stored in the audit_events table with the following schema:
id - Unique identifierprincipal - The username or system identifiertype - The event typedata - JSON blob containing event detailstimestamp - When the event occurredPrometheus metrics are available at /actuator/prometheus for monitoring system performance and audit event volume.