Creating an HTTP Outbound Logger
Using Mule’s Server Notifications
Marcos Villalba
INITIAL REQUIREMENTS
The task at hand required us to create some kind of listener/interceptor to be triggered whenever we were about to hit a http outbound component. This logger was supposed to write down URL and payload of the http outbound call we were about to do.
Other requirements were to be reusable, easy to add to any project, and have the ability to connect/disconnect via config files. All of this combined would make for quite a useful tool for testing and troubleshooting.
FIRST APPROACH
We started with an out of the box interceptor – this approach is quite useful for attaching behavior to Mule components. All official docs here.
Simply adding interceptor components in our flow, and referring them to a java class, implementing EnvelopeInterceptor or AbstractEnvelopeInterceptor Interfaces, flow will be intercepted.
<flow name=”interceptorFlow”> <http:listener config-ref=”HTTP_Listener_Configuration” path=”/input” doc:name=”HTTP”/> <set-payload value=”#[‘sample payload’]” doc:name=”Set Payload”/> <custom-interceptor class=”com.ms3.logging.interceptor.LoggingInterceptor” /> <http:request config-ref=”HTTP_Request_Configuration” path=”destination_path” method=”GET” doc:name=”HTTP”/> </flow> |
With an implementation class:
public class LoggingInterceptor extends AbstractEnvelopeInterceptor implements Interceptor{ @Override public MuleEvent process(MuleEvent event){ //flow intercepted! //lets do something here! |
At this point, we are free to recover the message context, flow variables, payload, etc and process them how we see fit. However, this approach was not successful in providing us the needed URL and payload content.
Now we ask, why was this approach unsuccessful? Well, our objective was to intercept the flow, and access http outbound transport parameters (host,port,path etc). These variables belong to the http component and not to the flow or message, so an alternative approach was needed.
In conclusion.. we need to go deeper and listen to the http component directly!
MULE SERVER NOTIFICATIONS
Mule provides an internal notification mechanism that you can use to access changes that occur on the Mule Server, such as a flow component being added, a Mule Model being initialized, or Mule being started. You can set up your agents or flow components to react to these notifications.
Message notifications that are fired by the code provide a snapshot of all information sent in and out of the Mule Server, and are fired whenever a message is received or sent. All official docs here.
In other words, our developer friends from MuleSoft fire thousands of notifications when different events happen deep inside the code. We can catch these notifications and use it in our favor and get some insight to what is happening within our applications.
THE ArganoMS3 IMPLEMENTATION
In our particular case, we want to listen/catch a notification that is being fired by the http component (DefaultHttpRequester) just before the actual network call. At this particular moment, We will ask the component “hey, what is the URL,port,path.. you are about to hit?” It will provide us with the necessary information that we can then record. So lets get to work and show you how it is done.
All of these notifications fired by the code are disabled by default because of if left on there would be significant performance impact, So we need to enable them and then inject a java class that will be used to handle the notifications. Here is the mule configuration elements to enable events and the receiving class.
<spring:beans> <spring:bean name=”messageProcessorListener” class=”com.ms3.httpListener.HttpNotificationListener”/> </spring:beans> <notifications> |
Our class HttpNotificationListener will be listening for notifications that will be firing from within the core Mule code, but… which notifications will we get? There will be hundreds fired per second, so we need a way of selecting which ones are the ones that we are looking for and filter all the rest of the noise out of the class.
For this, we need to select which interface our class will be implementing. Mulesoft gives the developers a list of all the possible NotificationListener interfaces, each one of them will be triggered under a particular situation/change/scenario. Here’s a complete list.
Some dev notes here:
- We selected MessageProcessorNotificationListener, triggered whenever a message processor was invoked. Since this is quite generic, we narrow it by listening to DefaultHttpRequester processor.
- All classes implementing NotificationListener must implement method onNotification().
- The input parameter of this method will depend on the NotificationListener used.
- Once the method is triggered, we can access all the parameters of the current message processor. In our case, the desired DefaultHttpRequester.
public class HttpNotificationListener implements MessageProcessorNotificationListener<MessageProcessorNotification> {
@Override public void onNotification(MessageProcessorNotification notification) { MessageProcessor messageProcessor = notification.getProcessor(); if(messageProcessor instanceof DefaultHttpRequester) { DefaultHttpRequester httpRequester = ((DefaultHttpRequester) messageProcessor); String msgId = notification.getSource().getMessage().getMessageRootId(); String outbound_URL = httpRequester.getHost()+”_”+ httpRequester.getPort()+”_”+ httpRequester.getPath()+”_”+ httpRequester.getMethod(); //log all this info somewhere! } } } |
CONCLUSION
Mule Server notifications are an extremely flexible, powerful Mule capability. Since there is not much documentation out there, you will need to dive into Mule´s source code to see what notification is being fired in the part of the code you are interested in interacting with.
Dont be shy!
Contact ArganoMS3 today to see how we can help you with your Mulesoft project contact@ms3-inc.com
LINKS
Very Interesting.
Does this get invoked only once i.e before the request is sent or both before and after invocation?