In this post I introduce the features of spt-development-audit-spring and describe how to integrate it into a Spring Boot application with the spt-development-audit-spring-boot starter, demonstrated with the demo project created as part of the v2.0.0 release of the spt-development-* projects. spt-development-audit-spring
has a dependency on spt-development-cid which is integrated into the demo project with spt-development-cid-web as described in an earlier post. The demo project also integrates spt-development-logging-spring and spt-development-cid-jms-spring and has tests that use spt-development-test.
Demo project
The demo project provides a simple ‘books’ REST API backed by and in-memory H2 database with basic authentication configured with Spring Security. Once running, the REST API can then be exercised with cURL as follows:
See the README for more detail.
Auditing
There are many reasons why you might want to add auditing to your application. The main reason we wanted to add auditing to SPT Contractors was to be able to trace through how records reached a particular state; having this information has been invaluable on past projects for replaying when things go wrong and answering user queries when records are in a state they don’t expect. We wanted an auditing solution that was simple to implement without polluting my business logic with calls to persist the audit records. Additionally, we wanted another service to be responsible for persisting the audit records which could potentially be extended to perform analysis or transformations at a later date. Out of these requirements spt-development-audit-spring
was born.
spt-development-audit-spring
The demo project uses the spt-development-audit-spring-boot-starter
to pull in the required dependencies and automatically configure the auditor. The demo project also has a dependency on the spt-development-cid-web-spring-boot starter in order to pull in and configure spt-development-cid-web
and its dependencies so that the correlation ID on the audit event records is set correctly (see earlier post for more details). The demo project also uses the spt-development-logging-spring-boot starter (also discussed in my earlier post) and the spt-development-cid-jms-spring-boot starter that I will talk about in greater depth, later in this post.
Auditing with spt-development-audit-spring
is implemented at the method level, usually a service method, by decorating the method with an @Audited
annotation that has a type
(typically this will be an identifier for the domain that the audit event relates to) and a subType
(typically this will be an identifier for the type of action that is being audited, such as CREATE or DELETE).
With this in place when we successfully create a new book, the audit event is written to the logs.
We now know when a book is created which is OK, but for the auditing to be really useful we need the audit events to include details about the record being created. We do this wth the @Audited.Id
and @Audited.Detail
annotations.
In this example we are telling the auditor to extract the ID from the the id
field of the object returned by the BookService::create()
method and to populate the details
field of the audit event record with the parameters annotated with @Auited.Detail
. Now we see the book details and the ID of the book record that was created in the audit event log.
Multiple parameters can be annotated with @Audited.Detail
but if you do, the name
[of the parameters] must be specified. The @Audited.Id
parameter can also be applied to a parameter as shown in the BookService::update()
method.
The spt-development-audit-spring-boot-starter
configures the Slf4jAuditEventWriter
bean by default, which is an instance of the AuditEventWriter
interface. In a production service you probably want your adit event records persisted to some kind of database, in which case you will need to create a bean that is an instance of AuditEventWriter
or if your service methods are transactional, an instance of TransactionAwareAuditEventWriter
so that the audit events are only written if the transaction is successfully committed. For SPT Contractors, we developed a separate service responsible for persisting the audit event records read from a JMS queue and would recommend this approach in general. Creating a JmsTemplate
bean and setting the spt.audit.jms.destination
property results in the spt-development-audit-spring-boot-starter
instantiating a JmsAuditEventWriter
bean which writes the audit event records to the configured JMS queue, rather than to the logs with Slf4jAuditEventWriter
. The demo project uses an in-memory Artemis JMS queue to demonstrate this.
Actuator audit events
It is very straight forward to integrate spt-development-auditor
with Actuator Auditing which allows you to treat business audit events and actuator audit events (for example generated by Spring Security) in a consistent manner. Simply create a class that extends AbstractAuditListener
inject a AuditEventWriter
bean and in the AbstractAuditListener::onAuditEvent()
method write the audit events with the audit event writer. The demo project uses this approach to audit successful and unsuccessful login attempts.
spt-development-cid-jms-spring
spt-development-cid-jms-spring
integrates spt-development-cid
into a Spring JMS (listener) project, initialising the correlation ID from the correlation ID of the received JMS message. The demo project shows the easiest way to integrate spt-development-cid-jms-spring
into a Spring Boot application, with spt-development-cid-jms-spring-boot-starter
. If your listener methods have a single Message
parameter, there is nothing further to do. If your listener methods accept a @Payload
annotated parameter, they will need an additional parameter annotated with the @Header
annotation and the name set to jms_correlationId
as shown in the AuditListener::onMessage
method of the demo project.
With this in place we can pass CorrelationId.get()
into our log statements and/or integrate spt-development-logging-spring
and see the correlation ID set on the JMS messages in our logs. This makes it very simple to propagate the correlation ID from service to service when communicating via JMS, by setting the correlation ID as shown by this code from spt-development-audit-spring
.