- 11 minutes to read

Custom Connector for enabling logging from Mule ESB

Supercharge your Mule ESB logging with the Nodinite Custom Connector! Replace the standard Logger and Business Events shapes for a unified, scalable, and business-friendly logging experience—on-premise or in the cloud.

Supported versions:

  • 3.9
  • 3.8
  • 3.7
  • 3.6

For MuleSoft run-time 4 and later, use this guide as inspiration to build your own custom connector.

The Nodinite Custom Connector is a ready-to-use template that helps you get started with advanced logging in minutes.

graph LR subgraph "Mule ESB" subgraph "Flow 1" roFlow1(fal:fa-sitemap INT001: Invoices) end subgraph "Flow 2" roFlow2(fal:fa-sitemap INT002: Exchange rates ) end subgraph "Logging sub flow" roFlow1 --> roLogSink roFlow2 --> roLogSink roLogSink("fal:fa-bolt Nodinite Custom Connector") --> roId1["fal:fa-list Queue
fal:fa-folder Folder
..."] end end subgraph "Nodinite Server" roLogAPI(fal:fa-cloud-arrow-down LogAPI) roPS(fal:fa-truck-pickup Pickup Service)--> roLogAPI roId1 -. Async.-x roPS end

Example: The Nodinite Custom Connector centralizes logging from multiple Mule ESB flows for streamlined monitoring and troubleshooting.

*Example usage of the :Nodinite: custom connector for Mule ESB flows.*

To enable logging from your Mule ESB flows, simply add the Nodinite Custom Connector (Prefixed Log ... in the examples). Use the Nodinite Custom Connector instead of the Logger or Business Events shapes for a consistent, future-proof approach.

Feature Pros Cons Comment
Logger Built in - Limited options and hardcodes your solution
- Hard to replace
- Requires lots of code/configuration
- Inconsistent logging quality
- Log files (on-premise) waste disk space and must be managed
- Long delays before data is visible in the cloud (sometimes >12 hours)
- Configuration must change when moving from on-premise to cloud
Requires a configured log appender
Business Events Built in All cons as above, plus:
- Requires Enterprise edition
- Limited to provided key/values (no payload)
Expensive and very limited options
Nodinite Custom Connector - Always logs the body
- Consistent key/value (context properties)
- Easy to replace with another logging solution
- Faster time for logged events to be visible
- All logic is within the custom connector and logging sub flow
- Consistent quality is easier to achieve
- Works equally on-premise and in the cloud, no code changes needed when migrating
Requires adding the Log shape (custom connector) to all flows Download our template and start using it instead of Logger and Business Events

How do I get started with logging from Mule ESB using the Nodinite custom connector?

First, read the Asynchronous Logging user guide and install the Pickup Service.

Step 1: Download the Nodinite Custom Connector

Go to the Nodinite portal and download the ZIP file with the custom connector.

Step 2: Add Custom Connector to Anypoint Studio

Add the ZIP file to your Anypoint Studio project. The result should look like this:

Anypoint Studio 6
Custom Connector - Anypoint Studio
Example of Nodinite Custom Connector added to Anypoint Studio.

Anypoint Studio 7
Import the JAR package:
Import

Step 3: Add Custom Connector to Flow

In your Mule ESB flows, add the Nodinite logging custom connector where needed (before/after transformation, exception handling, conditional flows, sub flows, etc.).
Example flow

Step 4: Code for Target Destination

Logging is implemented as a generic, reusable sub flow:
Sub flow logging
Example of a logging sub flow.

The logging sub flow creates the JSON Log Event and posts it to a destination such as:

Destination Pros Cons Comment
Log API Available with Nodinite - Not highly available
- Connectivity required
- Synchronous (not recommended for production)
- Does not scale as well as queues/databases
Great for POCs and initial testing. Avoid in production.
ActiveMQ - Free (Open Source)
- Scales well
- Supports fail-over clustering
- Requires extra coding/configuration Recommended
AnypointMQ - Scales well
- Highly available
- Requires enterprise subscription
- More costly
Not currently supported by Pickup Service. Contact support if needed.
PostgreSQL - Scales well - Requires extra coding/configuration

Choose the best destination for your needs. With this approach, you only need to change the destination in one place if requirements change.

Step 5: Configure Pickup Service

The Pickup Service fetches your JSON Log Events from the destination you coded for in the previous step.

Step 6: Verify and Fine-tune

Verify and fine-tune logging according to your business needs.

Tuning and Best Practices

Start small—implement the Custom Connector in a few Mule ESB flows before rolling it out everywhere.

The following event fields are mandatory; the rest are optional (set to null or omit). Providing more details about the Log Event improves the end-user experience with Nodinite.

Mandatory Data Type Field Value Comment
string LogAgentValueId 42 Who (Log Agents) sent the data
string EndPointName "INT101: Receive Hello World Log Events" Name of Endpoint transport
string EndPointUri "C:\DropArea\in" URI for Endpoint transport
number EndPointDirection 0 Direction for Endpoint transport
number EndPointTypeId 60 Type of Endpoint transport
string OriginalMessageTypeName "https://nodinite.com/Customers/1.0#Batch" Message Type Name
string LogDateTime "2018-05-03T13:37:00.123Z" Client Log datetime (UTC format)

See the Json Log Event user guide for full details.

Exception Handling

Add the custom connector to your exception handling and set the Log Status Code according to your business case. This provides user-friendly texts for the business.

Correlation

See the Mule ESB Correlation user guide.

Message Types

Providing the Message Type is mandatory.

Many Nodinite logging features depend on well-known Message Types. For example, when extracting values for Search Fields, Nodinite uses Search Field Expressions bound to named Message Types.

Tip

Provide unique names for message types to get the best logging experience with Nodinite.

Context Options

Nodinite offers a wide range of logging options. See the Context Options user guide for more information.

Repair and Resubmit

With Context Options, you can add properties to logged JSON Log Events that Nodinite can use for repairing and resubmitting messages. Build your Mule ESB flows to handle resubmitted messages.

Log Views

Involve your business and create role-based self-service Log Views. This reduces incidents and helps the business understand integration solutions.

Next Step

How to Add or manage Search Fields
How to Add or manage Log Views


Example flow configuration using the downloadable Nodinite custom connector

<?xml version="1.0" encoding="UTF-8"?>

<mule xmlns:nodinite="http://www.mulesoft.org/schema/mule/nodinite" xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns:scripting="http://www.mulesoft.org/schema/mule/scripting" xmlns:file="http://www.mulesoft.org/schema/mule/file" xmlns:json="http://www.mulesoft.org/schema/mule/json" xmlns:batch="http://www.mulesoft.org/schema/mule/batch" xmlns:tracking="http://www.mulesoft.org/schema/mule/ee/tracking" xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
	xmlns:spring="http://www.springframework.org/schema/beans" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/file http://www.mulesoft.org/schema/mule/file/current/mule-file.xsd
http://www.mulesoft.org/schema/mule/ee/tracking http://www.mulesoft.org/schema/mule/ee/tracking/current/mule-tracking-ee.xsd
http://www.mulesoft.org/schema/mule/json http://www.mulesoft.org/schema/mule/json/current/mule-json.xsd
http://www.mulesoft.org/schema/mule/batch http://www.mulesoft.org/schema/mule/batch/current/mule-batch.xsd
http://www.mulesoft.org/schema/mule/scripting http://www.mulesoft.org/schema/mule/scripting/current/mule-scripting.xsd
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd
http://www.mulesoft.org/schema/mule/nodinite http://www.mulesoft.org/schema/mule/nodinite/current/mule-nodinite.xsd">
    <spring:beans>
        <spring:bean class="int001.filemove.transform.NodiniteLoggerService" name="CreateLogEventBean"/>
    </spring:beans>
    <http:request-config name="Nodinite_HTTP_Request_Configuration" host="demo.nodinite.com" port="80" basePath="/LogAPI/api/" doc:name="HTTP Request Configuration"/>
    <nodinite:config name="Nodinite__Configuration"  doc:name="Nodinite: Configuration"/>
    <flow name="int001.filemove.transformFlow">
        <file:inbound-endpoint path="C:\Temp\mule\int001.filemove.transform\in\" responseTimeout="10000" doc:name="File"/>
        <byte-array-to-string-transformer doc:name="Byte Array to String"/>
        <scripting:component doc:name="Groovy - set up logging variables">
            <scripting:script engine="Groovy"><![CDATA[sessionVars['correlationId'] = message.id;

message.correlationId = sessionVars['correlationId'];

sessionVars['nodiniteMessageTypeName'] = "MuleOrderBatch#1.0";
sessionVars['nodiniteLogText'] = "File Received";
sessionVars['nodiniteLogStatus'] = 0;
sessionVars['nodiniteEndPointDirection'] = 0;

sessionVars['nodiniteContextValues'] = [receivedFileName: flowVars['originalFilename']];

return payload;]]></scripting:script>
        </scripting:component>
        <logger message="Logging Correlation Id: #[sessionVars.correlationId]" level="INFO" doc:name="Logger"/>
        <flow-ref name="int001.filemove.nodiniteloggingflow" doc:name="Log"/>
        <choice doc:name="Choice">
            <when expression="flowVars.originalFilename.endsWith('.json')">
                <scripting:component doc:name="Update logging vars before looping">
                    <scripting:script engine="Groovy"><![CDATA[message.correlationId = sessionVars['correlationId'];

sessionVars['nodiniteMessageTypeName'] = "MuleOrderBatch#1.0";
sessionVars['nodiniteLogText'] = "Starting to debatch file";
sessionVars['nodiniteLogStatus'] = 0;
sessionVars['nodiniteEndPointDirection'] = 0;

sessionVars['nodiniteContextValues'] = [receivedFileName: flowVars['originalFilename']];

return payload;]]></scripting:script>
                </scripting:component>
                <flow-ref name="int001.filemove.nodiniteloggingflow" doc:name="Log Before Processing"/>
                <json:object-to-json-transformer mimeType="application/json" doc:name="Object to JSON"/>
                <json:json-to-object-transformer returnClass="java.util.List" doc:name="JSON to Object"/>
                <foreach collection="#[payload]" doc:name="For Each">
                    <flow-ref name="int0int001.filemove.processSingleOrder" doc:name="processOrder"/>
                </foreach>
            </when>
            <otherwise>
                <scripting:component doc:name="Update logging variables">
                    <scripting:script engine="Groovy"><![CDATA[sessionVars['nodiniteMessageTypeName'] = "Unknown";
sessionVars['nodiniteLogText'] = "Message extension is wrong - should be JSON.";
sessionVars['nodiniteLogStatus'] = -1;
sessionVars['nodiniteEndPointDirection'] = 0;

sessionVars['nodiniteContextValues'] = [receivedFileName: "#[flowVars.originalFileName]"];

return payload;]]></scripting:script>
                </scripting:component>
                <flow-ref name="int001.filemove.nodiniteloggingflow" doc:name="Log error message"/>
                <file:outbound-endpoint path="C:\Temp\mule\int001.filemove.transform\invalid\" outputPattern="#[flowVars.originalFilename]" responseTimeout="10000" doc:name="MoveToInvalidFolder"/>
            </otherwise>
        </choice>
    </flow>
    <sub-flow name="int0int001.filemove.processSingleOrder">
        <set-variable variableName="currentOrderId" value="#[payload.OrderId]" doc:name="Variable"/>
        <json:object-to-json-transformer doc:name="Object to JSON"/>
        <scripting:component doc:name="Before processing">
            <scripting:script engine="Groovy"><![CDATA[message.correlationId = sessionVars['correlationId'];

sessionVars['nodiniteMessageTypeName'] = "MuleOrder#1.0";
sessionVars['nodiniteLogText'] = "Starting to process order";
sessionVars['nodiniteLogStatus'] = 0;
sessionVars['nodiniteEndPointDirection'] = 0;

sessionVars['nodiniteContextValues'] = [receivedFileName: flowVars['originalFilename'], orderId: flowVars.currentOrderId.toString(), isGDPRData: "true"];

return payload;]]></scripting:script>
        </scripting:component>
        <flow-ref name="int001.filemove.nodiniteloggingflow" doc:name="Log single order"/>
        <file:outbound-endpoint path="C:\Temp\mule\int001.filemove.transform\out" outputPattern="#[flowVars.currentOrderId].json" responseTimeout="10000" doc:name="File"/>
        <scripting:component doc:name="After processing">
            <scripting:script engine="Groovy"><![CDATA[message.correlationId = sessionVars['correlationId'];

sessionVars['nodiniteMessageTypeName'] = "MuleOrder#1.0";
sessionVars['nodiniteLogText'] = "Done processing order";
sessionVars['nodiniteLogStatus'] = 0;
sessionVars['nodiniteEndPointDirection'] = 1;

sessionVars['nodiniteContextValues'] = [receivedFileName: flowVars['originalFilename'], orderId: flowVars['currentOrderId'].toString(), outFullName: "C:\\Temp\\mule\\int001.filemove.transform\\out\\" + flowVars['currentOrderId'].toString() + ".json", outDirectory: "C:\\Temp\\mule\\int001.filemove.transform\\out\\", outFileName: flowVars['currentOrderId'].toString() + ".json"];

return payload;]]></scripting:script>
        </scripting:component>
        <flow-ref name="int001.filemove.nodiniteloggingflow" doc:name="Log done single order"/>
    </sub-flow>
    <sub-flow name="int001.filemove.nodiniteloggingflow">
        <logger message="#[sessionVars.nodiniteLogText]" level="INFO" doc:name="Logger"/>
        <set-variable variableName="payloadBeforeNodiniteLogEvent" value="#[payload]" doc:name="Variable"/>
        <nodinite:create-log-event config-ref="Nodinite__Configuration" endPointName="int001.filemove.transformFlow" endpointUri="mule.developer" endPointDirection="#[sessionVars.nodiniteEndPointDirection]" originalMessageTypeName="#[sessionVars.nodiniteMessageTypeName]" logStatus="#[sessionVars.nodiniteLogStatus]" logText="#[sessionVars.nodiniteLogText]" payload="#[payload]" doc:name="Nodinite" processMachineName="roma.dev" processModuleName="int001.filemove.nodiniteloggingflow" processModuleType="Mule Flow" processName="int001.filemove.transformFlow">
            <nodinite:context-properties ref="#[sessionVars.nodiniteContextValues]"/>
        </nodinite:create-log-event>
        <http:request config-ref="Nodinite_HTTP_Request_Configuration" path="logEvent/logEvent" method="POST" doc:name="HTTP">
            <http:request-builder>
                <http:header headerName="Content-Type" value="application/json"/>
            </http:request-builder>
        </http:request>
        <set-payload value="#[flowVars.payloadBeforeNodiniteLogEvent]" doc:name="Set Payload"/>
    </sub-flow>
</mule>