-
Language:
English
-
Language:
English
Red Hat Training
A Red Hat training course is available for Red Hat Fuse
Chapter 18. Auditing
18.1. SwitchYard Auditing
SwitchYard possesses auditing functionality. It traces exchanges through their various mediation states. The auditing functionality requires the CDI environment (the
META-INF/beans.xml
file) to run. The auditing functionality also works in a test environment.
18.2. Enable Custom Auditors
Audit mechanism requires CDI runtime environment to run.
To enable custom auditors, define the Auditor implementations with the
@Named
annotation. It helps Apache Camel component to recognize all the auditor implementations. Camel Exchange Bus, a default implementation used by SwitchYard, look up for bean definitions with @Audit
annotation.
@Audit @Named("custom auditor") public class SimpleAuditor implements Auditor { @Override public void beforeCall(Processors processor, Exchange exchange) { System.out.println("Before " + processor.name()); } @Override public void afterCall(Processors processor, Exchange exchange) { System.out.println("After " + processor.name()); } }
Note
Do not include any state inside the Custom Auditor's field. Red Hat recommends you to use exchange properties or message headers to store values.
18.3. Mediation State
Mediation state is the term used to described the interim states a SwitchYard exchange goes through as it is sent from a service consumer to a service provider.
18.4. List of Mediation States
- Domain handlers
- In this state all the handlers defined in
switchyard.xml
are executed. This is an early phase of mediation where you can either implement own logic or choose the service provider logic to use. - Addressing
- If this is not specified by the domain handlers then the addressing handler will determine what to do by using the consumer contract.
- Transaction
- If the service is required to run a transaction this handler starts it.
- Security
- This state verifies constraints related to authentication and authorization.
- General policy
- This executes checks other than those for security and transactions.
- Validation
- This executes custom validators.
- Transformation
- This prepares the payload by calling a provider.
- Validation (2)
- This validates the transformed payload.
- Provider call
- This calls the provisional service.
- Transaction (2)
- This commits or, if necessary, rolls back the transaction.
If the service consumer is synchronous and the exchange pattern is set to in-out, then some of these handlers may be called once again:
- Domain handlers
- These are called when a response is generated by a provider service.
- Validation
- This verifies the output generated by the provider.
- Transformation
- This converts the payload to the structure required by the consumer.
- Validation
- This checks the output after the transformation has occurred.
- Consumer callback
- This returns the exchange to the service consumer.
18.5. Create a Custom Auditor
Prerequisities
- CDI Runtime
- Annotate your auditor implementations with @Named in order to have Camel recognize them.
Note
The Camel Exchange Bus looks for bean definitions with the @Audit annotation.Here is code that shows what a very simple auditor would look like:@Audit @Named("custom auditor") public class SimpleAuditor implements Auditor { @Override public void beforeCall(Processors processor, Exchange exchange) { System.out.println("Before " + processor.name()); } @Override public void afterCall(Processors processor, Exchange exchange) { System.out.println("After " + processor.name()); } }
Important
Be aware that the afterCall method is not called if the step it surrounds throws an exception. If this happens, afterCall will be skipped.
Result
You can see many statements like 'Before DOMAIN_HANDLERS' and 'Before ADDRESSING' appearing in the server console. This is because every step of mediation is surrounded by this SimpleAuditor class.
18.6. Determine Location for Audit Assignment
In SwitchYard, you may choose to provide an argument to the @Audit annotation. The accepted values for this comes from org.switchyard.bus.camel.processors.Processors enumeration. For example, the following combination can handle only validation occurrences:
@Audit(Processors.VALIDATION)
Note the following important facts about validation, transformation, and transaction in SwitchYard:
- The validation is executed twice for in-only exchanges and four times for in-out exchanges.
- The validation occurs before and after transformation of inbound messages.
- When SwitchYard sends outgoing messages, the validation occurs before and after transformation of outbound messages.
- Transformation is executed once for in-only exchanges and twice for in-out exchanges.
- Transaction phase is always executed twice.
If you want to implement only one execution of your auditor, use the following combination:
@Audit(Processors.PROVIDER_CALLBACK).Here, the auditor is executed just before sending exchange to service implementation. You can also implement one auditor instance with few mediation steps. For example, a bean with annotation following:
@Audit({Processors.PROVIDER_CALLBACK, Processors.CONSUMER_CALLBACK})This bean is executed twice. One pair of before or after call for provider service and second pair for outgoing response.
18.7. Use Exchange Properties
As only one instance of auditor is created by default and there is no guarantee for dispatching order, ensure that the custom auditors do not preserve state inside any of the fields. If you want to store values, use exchange properties or message headers. Here is an example of how to count processing time using Exchange properties as temporary storage:
@Named("custom auditor") public class SimpleAuditor implements Auditor { private Logger _logger = Logger.getLogger(SimpleAuditor.class); @Override public void beforeCall(Processors processor, Exchange exchange) { exchange.setProperty("time", System.currentTimeMillis()); } @Override public void afterCall(Processors processor, Exchange exchange) { long time = System.currentTimeMillis() - exchange.getProperty("time", 0, Long.class); _logger.info("Step " + processor.name() + " took " + time + "ms"); } }