Custom session state change notifications

Overview

FIXEdge can trigger alert notifications about FIX Session and FIXEdge Transport Adaptor (TA) state changes.

The alerts can be handled on a Business Logic Layer and processed by Business rules and BL Scripting with JavaScript.

The events can be forwarded to the SMTP Transport Adaptor that is intended to convert information from FIX messages to emails and send them via the SMTP Service.

Notification messages use a custom format representing the Email (C) message

The SMTP TA is configured in the FIXEdge.properties file. The full list of the configuration parameters is here: Configuration.

SMTP Transport Adapter configuration with Gmail SMTP Server

For engaging the Gmail SMTP server, one should enable less secure apps & your Google Account in Gmail SMTP settings.

FIXEdge.properties
#------------------------------------------------------------
# Transport Layer Section
#------------------------------------------------------------
 
#Comma separated list of identifiers of Transport Adapters should be loaded.
TransportLayer.TransportAdapters = TransportLayer.SmtpTA
 
#------------------------------------------------------------
# SMTP Adaptor configuration
#------------------------------------------------------------
 
TransportLayer.SmtpTA.Description = SMTP Transport Adaptor
TransportLayer.SmtpTA.DllName  = bin/SMTPAdaptorDll.dll
TransportLayer.SmtpTA.Type = DLL
TransportLayer.SmtpTA.SMTPSessions = SMTPClient
 
# Google SMTP Configuration
TransportLayer.SmtpTA.SMTPSession.SMTPClient.ServerName = smtp.gmail.com
TransportLayer.SmtpTA.SMTPSession.SMTPClient.SecureConnection = SSL
TransportLayer.SmtpTA.SMTPSession.SMTPClient.ServerPort = 465
TransportLayer.SmtpTA.SMTPSession.SMTPClient.Login = sender@gmail.com
TransportLayer.SmtpTA.SMTPSession.SMTPClient.Password = password
TransportLayer.SmtpTA.SMTPSession.SMTPClient.From = sender@gmail.com
TransportLayer.SmtpTA.SMTPSession.SMTPClient.To = receiver@epam.com;
 
TransportLayer.SmtpTA.SMTPSession.SMTPClient.SmartEmailProcessing = true

Format of Email 35=C message

Once the state of the session or adapter is changed, FIXEdge creates an Email (C) message that can be processed with Business Logic and configured in BL_Config.xml.

The event is logged with the TRACE level:

FixEdge.log
2015-03-26 15:18:12,413 UTC   TRACE   [BL_Layer]  140009470453504  Process incoming message. [8=FIX.4.4 9=189 35=C 49=fake 56=fake 34=1 52=99990909-17:17:17 164=7 94=0 42=20150326-15:17:09 147=[NOTE] FIXEDGE:ICEProxy Established 33=5 58=N 58=1 58=FIXEDGE:ICEProxy 58=Established 58=AttemptToConnect 10=238 ]

The SMTP TA can transform this message into an email.

Mapping for FIXEdge.parameters to email content:

Email attribute

Comments

FromUsing the value of TransportLayer.SmtpTA.SMTPSession.<Session>.From  property from FIXEdge.properties
ToUsing the value of TransportLayer.SmtpTA.SMTPSession.<Session>.To  property from FIXEdge.properties
CCUsing the value of TransportLayer.SmtpTA.SMTPSession.<Session>.CC property from FIXEdge.properties
BCCUsing the value of TransportLayer.SmtpTA.SMTPSession.<Session>.BCC  property from FIXEdge.properties

SmartEmailProcessing is disabled

This is the default option:

FIXEdge.properties
TransportLayer.SmtpTA.SMTPSession.SMTPClient.SmartEmailProcessing = false

The SMTP Adapter can process any message on the BL and convert it to an email with the following format:

Item

Email Content

Placeholder explanation

SubjectMessage '<MsgType>' from 'fake' to 'fake'.

MsgType - is a type of message handled on the Business Logic Layer
Message Body<RAW FIX MessageRAW FIX Message - Contains the original RAW FIX message with SOH delimiters

SmartEmailProcessing_false.msg

SmartEmailProcessing is enabled

The email is created based on the content of the Email (C) message

The subject is taken from (147) Subject and the body is composed of (58) Text tag value entries of the repeating group, with size defined in (33) LinesOfText.

FIXEdge.properties
TransportLayer.SmtpTA.SMTPSession.SMTPClient.SmartEmailProcessing = true

Converts messages 35=C to an email with the following format:

Item

Email Content

Placeholder explanation

Subject

[<Severity>] <SenderCompId>:<TargetCompId><Connection status>


The subject is taken from (147) Subject of an Email (C) message 

Severitynotification severity type.
Possible values are: NOTE, WARN, ERROR

  • SenderCompId- value of tag (49) SenderCompID 
  • TargetCompId - value of tag (56) TargetCompID 
  • Connection status- new state of the session.
    Possible values are: AttemptToConnect, Established, Terminated correctly, Non-gracefully terminated
Message Body

<Severity>
<Event Code>
<Session Id>
<Connection status>


Original FIX message:
<RAW FIX Message>

Message content is composed with (58) Text tag value entries of the repeating group, with size defined in (33) LinesOfText as part of the Email (C) message  

  • Severity - notification severity type. Entry #0 of the LineOfText group.
    Possible values are: N, W, E
  • Event Code - internal event code. Entry #1 of the LineOfText group.
  • Session Id - the pair of (49) SenderCompID  and (56) TargetCompID with ':' delimiter. Entry #2 of the LineOfText group.
  • Connection status - new state of the session. Entry #3 of the LineOfText group.
    Possible values are: AttemptToConnect, Established, Terminated correctly, Non-gracefully terminated
  • RAW FIX Message - Contains the original RAW FIX message with SOH delimiters

SmartEmailProcessing_true.msg

Simple email notification - Business Logic example

A user can filter session state alerts by checking the value of the (147) Subject tag of an Email (C) message from a fake:fake session and send the messages to the SMTP Adapter.

BL_Config.xml
<!-- Send email on every session status change. Ignore Temp sessions.-->
<Rule Description="Send emails with session state change notifications" >
    <Source>
        <!--Apply to each internal message -->
        <FixSession SenderCompID="fake" TargetCompID="fake" />
    </Source>
    <Condition>
        <!--Apply to  35=C only -->
        <MsgType>
            <Val>C</Val>
        </MsgType>
        <!-- Apply to messages with 147 tag filled with session status  -->
        <MatchField Field="147" Value=".*(AttemptToConnect|Established|Terminated correctly|Non-gracefully terminated)" />
    </Condition>
    <Action>
        <!-- Forward the message to SmtpClient  -->
        <Send>
            <Client Name="SMTPClient"/>
        </Send>
    </Action>
</Rule> 

The MatchField condition accepts the list of possible session states here, i.e.: AttemptToConnect, Established, Terminated correctly, Non-gracefully terminated

Example of an email notification with customized email content

A user can filter session state alerts by checking the value of the (147) Subject tag of an Email (C) message from a fake:fake session and change the message content with JavaScript before sending to the SMTP Adapter.

The business logic is the following:

BL_Config.xml
<!-- Send email on every session status change. Ignore Temp sessions.-->
<Rule Description="Send emails with session state change notifications">
    <Source>
        <!--Apply to each internal message -->
        <FixSession SenderCompID=".*" TargetCompID=".*" />
    </Source>
    <Condition>
        <Script Language="JavaScript" FileName="../FIXEdge1/conf/isStateNotification.js"/>
    </Condition>
    <Action>
        <Script Language="JavaScript" FileName="../FIXEdge1/conf/prepareEmail.js"/>
        <Send>
            <Client Name="SMTPClient"/>
        </Send>
    </Action>
</Rule>

In order to use the custom implementation of emails, the SMTP Transport Adaptor must have DefaultSmartEmailProcessing or SmartEmailProcessing enabled.

FIXEdge.properties
TransportLayer.SmtpTA.SMTPSession.SMTPClient.SmartEmailProcessing = true
 
# Or for multiple SMTP sessions configuration
TransportLayer.SmtpTA.SMTPSessions.DefaultSmartEmailProcessing=true

If this property is not defined, the SMTP Transport Adaptor uses a default one, which is false.

For example, outgoing emails should have the following changes:

  • Subject text was adjusted and the priority of the event got remapped, as well as one of 3 statuses: Online, Stopped as expected, Down
  • Session id contains a Session Qualifier
  • Date and time of the event
  • Highlighted previous and current statuses
  • Contact information
  • Original event message before modifications
  • Ignore redundant email notifications

This can be achieved by modifying (147) Subject and (58) Text tag value entries of the repeating group, with size defined in (33) LinesOfText. The following mapping would be used:

Item

Email Content

Placeholder explanation

Subject

[<Severity>] Session Notice <Session Id>. <Connection status>

examples:

  • [LOW] Session Notice INITIATOR:FIXEDGE. Online
  • [MEDIUM] Session Notice INITIATOR:FIXEDGE:User2. Down


The subject is taken from  (147) Subject of  Email (C) message 

  • Severity- notification severity type. 
    Possible values are: LOW, MEDIUM, HIGH
  • Session Id - the combination of (49) SenderCompID(56) TargetCompID and Session Qualifier with ':' delimiter.
  • Connection status - new state of the session. 
    Possible values are: Online, Stopped as expected, Down
  • RAW FIX Message - Contains the original RAW FIX message with SOH delimiters
Message Body

PRIORITY: <Severity>, <Severity level>

DATE and TIME: <Datetime in UTC format>

CONNECTION NAME: <Connection Name>

CURRENT CONNECTION STATUS:  <Current Status>

PREVIOUS CONNECTION STATUS: <Previous Status>

FIXEDGE NOTIFICATION EVENT MESSAGE: <Original FIXEdge Notification message>


<Message Contact Details>


Original FIX message:

<Raw FIX Message>

  • Severity- notification severity type. 
    Possible values are: LOW, MEDIUM, HIGH
  • Severity level- the numeric value of the severity level and impact according to ITSM recommendations 
    Possible values are: 3, 2, 1
  • Datetime in UTC format - a value of DateTime in UTC of the event if format YYYYMMDD-hh:mm:ss

  • Connection Name - value of session's id value of tag 56 TargetCompID, ":" and tag 49 SenderCompId

  • Current Status - The current (new) status of the session. 

  • Previous Status - The previous status of the session.  

  • Original FIXEdge Notification message - the original internal FIXEdge event message with pipe '|' symbol as delimiter

  • Message Contact Details - Contact information of EPAM B2BITS support team.

  • Raw FIX Message - The resulted modified Email (C) message sent to the SMTP adapter. It's appended at the end automatically.

JavaScript isStateNotification.js for filtering messages:

isStateNotification.js
// The script check if an important session state notification should be routed to the SMTP TA.
result = false; // by default the message should be ignored.
 
function isImportantEvent(current, prev){
    if (prev == 'Established' && current == 'Non-gracefully terminated')
        // Switching state from established to Non-gracefully terminated is redundant
        // Non-gracefully terminated -> AttemptToConnect state change will be used as identification of session disconnection
        return false;                          
    else
        return true;
}
 
//The message type should be Email (35=C).
if (getStringField(35) == "C")
    {
    // Get default subject from tag 147.
    status = getStringField(147);
     
    // Regex for session events only: [STATUS] SenderCompId:TargetCompId NEW_STATE
    var regexp = /.*\s+(\S+):(\S+)\s+(.*)/g;
    match = regexp.exec(status);
     
    if (match != null) {
        //target = match[1];
        //sender = match[2];
        // Email content is located in the group 33
        hndl = getGroup(33);
        numberOfLines = getNumField(33); // Get number of entries in the group from LinesOfText(33) field
     
        if (isGroupValid(hndl) && numberOfLines >= 4 && numberOfLines <= 5) { // Session state events have 4 and 5 entries.
            currentStatus = getStringField(hndl, 3, 58);
            if (numberOfLines == 5) { // Events with previous state has 5 lines
                previousStatus = getStringField(hndl, 4, 58);
                result = isImportantEvent(currentStatus, previousStatus);
            } else {
                result = true; // all messages with initial state are important.
            }
        } // end if hdnl
    } // end if match
}
result;

The JavaScript describing the mapping of prepareEmail.js above:

prepareEmail.js
// The script customizes the session state notification emails.
// https://btobits.com/fixopaedia/fixdic44/index.html?message_Email_C.html
// Email custom format
  
// Functions for severity
function getSeverityText(code) {
  // Convert letter from severity to human readable text
  switch (code) {
    case "N": return "LOW";
    case "W": return "MEDIUM";
    case "E": return "HIGH";
    default: return "UNKNOWN";
  }// end switch
}
  
function getSeverityNumber(code) {
  // Convert letter from severity to severity code
  switch (code) {
    case "N": return "3"; //A minor incident with low impact
    case "W": return "2"; // A major incident with significant impact
    case "E": return "1"; //A critical incident with very high impact
    default: return "UNKNOWN";
  }// end switch
}
  
// convert FIXEdge status to a new format: Online, Online, Stopped as expected, Down
function getStatusForSubject(currentStatus) {
  // Convert letter from severity to severity code
  switch (currentStatus) {
    case "AttemptToConnect":
    case "Non-gracefully terminated":  
        return "Down";
    case "Established":
        return "Online";
    case "Terminated correctly":
        return "Stopped as expected";
    default: return currentStatus;
  }// end switch
}
  
// Fix original message serialization
var original_message = serializeMessage("|");
 
// Get default subject from tag 147
status = getStringField(147);
  
// Regex for session events only: [STATUS] SenderCompId:TargetCompId NEW_STATE
var regexp = /.*\s+(\S+):(\S+)\s+(.*)/g;
match = regexp.exec(status);
  
if (match != null) {
  target = match[1];
  sender = match[2];
  qualifier = getStringField(50);
  sessionId = target + ":" + sender;
   
  if (qualifier != null) // update session id if the session has qualifier.
     sessionId = sessionId + ":" + qualifier;
  
  // Email content is located in the group 33
  hndl = getGroup(33);
  numberOfLines = getNumField(33); // Get number of entries in the group from LinesOfText(33) field
  
  if (isGroupValid(hndl) && numberOfLines >= 4 && numberOfLines <= 5) { // Session state events have 4 and 5 entries.
    // convert severity to human readable text and the numeric value
    // according to ITSM recommendations about severity levels and impact
    severity = getStringField(hndl, 0, 58);
    priority = "PRIORITY: \t\t\t\t" + getSeverityText(severity) + ", " + getSeverityNumber(severity);
     
    dateTimeUtc = "DATE and TIME: \t\t\t" + getCurrentDateStr(DATETIMEUtc); // A new line with timestamp of the event.
    connectionName = "CONNECTION NAME: \t\t\t" + sessionId; // sender:target:qualifier
    currentStatus = getStringField(hndl, 3, 58);
    currentStatusLine = "CURRENT CONNECTION STATUS: \t" + currentStatus;
    if (numberOfLines == 5) {
      previousConnectionStatus = "PREVIOUS CONNECTION STATUS: \t" + getStringField(hndl, 4, 58);
    } else {
      previousConnectionStatus = "PREVIOUS CONNECTION STATUS: \t" + "Initial"; // unknown previous status is Initial.
    }
     
    fixEdgeNotificationMsg = "FIXEDGE NOTIFICATION EVENT MESSAGE: " + original_message;
    contactDetails = "\n\nIf you need assistance on this notice please contact the FIXEdge Support Team emailing SupportFIXAntenna@epam.com or please call tel:+44-20-369-58-166";
  
    // Subject generation
    subject = "[" + getSeverityText(severity) + "] Session Notice " + sessionId + ". " + getStatusForSubject(currentStatus);
    setStringField(147, subject);
  
    // Set number of total lines starting from 1
    setNumField(33, 7);
  
    // Setting the values of text based on the n number of lines from group handle 33 in repeating group tag 58 staring from 0
    setStringField(hndl, 0, 58, priority);
    setStringField(hndl, 1, 58, dateTimeUtc);
    setStringField(hndl, 2, 58, connectionName);
    setStringField(hndl, 3, 58, currentStatusLine);
    setStringField(hndl, 4, 58, previousConnectionStatus);
    setStringField(hndl, 5, 58, fixEdgeNotificationMsg);
    setStringField(hndl, 6, 58, contactDetails);
 
  } // end if hdnl
} // end if match
 
//print("Updated Message: "+ serializeMessage("|"));

Email examples

Custom Notification. Session is Down.msg

Custom Notification. Session is Online.msg

Status description

  • Established - The FIX session is online and is sending heartbeats.
  • AttemptToConnect - The FIX session is down.
    For the initiator session: the session is about to try to connect.
    For the acceptor session: the session is listening to connections.
  • Non-gracefully terminated - The session is dropped unexpectedly, not as per the configured schedules.
  • Terminated correctly - The session is dropped and it is expected or the session is stopped by the schedule.
    For example, FIXEdge is configured to terminate a session after receiving a logout:  IntradayLogoutTolerance = false, RecreateOnLogout = false, TerminateOnLogout = true.
  • Reconnecting The initiator is trying to connect to the counterparty after a disconnection.

Status changes

State changes

Event description

(147) Email Subject

NULL â†’ Established 

Transport adapter with name <AdaptorName> has been initialized.[NOTE] <AdaptorName> Established

NULL → AttemptToConnect

Initial → AttemptToConnect

The FIX Session <(49) SenderCompID>:<(56) TargetCompID has been initialized and is ready to perform the following scheduled actions:

  • in the case of the acceptor - accept a connection
  • in the case of the initiator - connect to the target destination

Severity is set to NOTE because the action is expected.

If events don't have the previous state, they will have the NULL state instead of the Initial state.

[NOTE] <(49) SenderCompID>:<(56) TargetCompID AttemptToConnect
AttemptToConnect â†’ Established

The FIX Session <(49) SenderCompID>:<(56) TargetCompIDhas been established.

Severity is set to NOTE because the action is expected.

[NOTE] <(49) SenderCompID>:<(56) TargetCompIDEstablished
Established â†’ Non-gracefully terminated

The FIX Session <(49) SenderCompID>:<(56) TargetCompID has been disconnected.

Possible reasons:

  • received a Logout (5) message
  • the counterparty closed the socket
  • network disorder

The severity is set to WARN because the disconnection is not expected at this time according to the configuration.

[WARN] <(49) SenderCompID>:<(56) TargetCompID Non-gracefully terminated

Non-gracefully terminated â†’ AttemptToConnect

The FIX Session <(49) SenderCompID>:<(56) TargetCompID has been recovered and is ready to perform the following scheduled actions:

  • in the case of the acceptor- accept a connection
  • in the case of the initiator - connect to the target destination

Severity is set to NOTE because the action is expected.

[NOTE] <(49) SenderCompID>:<(56) TargetCompID AttemptToConnect
Established â†’ Terminated correctly

The FIX Session <(49) SenderCompID>:<(56) TargetCompID has been disconnected as expected after receiving a Logout (5) message.

Severity is set to NOTE because the disconnection is expected at this time according to the configuration.

[NOTE] <(49) SenderCompID>:<(56) TargetCompIDTerminated correctly

Terminated correctly â†’ AttemptToConnect

The FIX Session <(49) SenderCompID>:<(56) TargetCompID has been forced to recreate and is ready to perform the following scheduled actions:

  • in the case of the acceptor - accept a connection
  • in the case of the initiator - connect to the target destination

The severity is set to WARN because the disconnection is not expected at this time according to the configuration.

[WARN] <(49) SenderCompID>:<(56) TargetCompIDAttemptToConnect

Sending emails about certain Logout message content

Sometimes the counterparty sends a Logout (5) FIX message instead of confirming Logon (A). FIXEdge can handle this situation and send a notification email about this.

This may be useful when the Logout contains a reason (for example the credentials have been expired).

The example below generates an email if the Logout contains a certain value of the SessionStatus (1409) tag.

Handling a Logout with DestroySessionEvent routing with JavaScript

FIXEdge raises the DestroySessionEvent when it receives a FIX message (35=5, logout) when the session is being closed by the counterparty.

If the logout contains SessionStatus (1409), FIXEdge can check it and call DestroySessionAction with a Script, for example, to route the message to the SMTP Transport Adapter where it will be converted to an email.

The configuration below notifies about 1409=5 (Invalid username or password) and 1409=6 (Account locked) Logout reasons from all of the sessions

BL_Config.xml
<?xml version="1.0" encoding="UTF-8"?>
<FIXEdge>
    <BusinessLayer>
        <DestroySessionEvent Description="Sending email in case of getting Logout with tag 1409">
            <Source>
                <FixSession SenderCompID=".*" TargetCompID=".*" />
            </Source>
            <Condition>
                <EqualField Field="1409">
                    <Val>5</Val>
                    <Val>6</Val>
                </EqualField>
            </Condition>
            <DestroySessionAction>
                <Script Language="JavaScript" FileName="../FIXEdge1/conf/sendSMTP.js" />
            </DestroySessionAction>
        </DestroySessionEvent>
        <DefaultRule>
            <Action>
                <DoNothing/>
            </Action>
        </DefaultRule>
    </BusinessLayer>
</FIXEdge>

JavaScript sendSMTP.js just sends a FIX message (Logout) to SMTP TA

sendSMTP.js
send("SMTPClient");
  • Email examples: 
    Invalid_username _or_password.msg
  • FIX message example:

    8=FIX.4.4|9=108|35=5|49=EXCHANGE|56=FIXEDGE|34=1|57=T0052FIX1|52=20200818-19:12:22.049|1409=5|58=Invalid username or password|10=128|

Troubleshooting

Running the Send action from DestroySessionAction outside of JavaScript is not supported

<DestroySessionEvent> can't route a message with the Send instruction outside of JavaScript

The examples below lead to the errors:

  1. Sending to the FIX session:

    <DestroySessionAction>
    	<Send>
    		<Client Name="SMTPClient"/>
    	</Send>
    </DestroySessionAction>

    Resulted with error: Incorrect event found: found unknown action 'Send'

  2. Sending to a Transport Adapter:

    <DestroySessionAction>
    	<Client Name="SMTPClient"/>
    </DestroySessionAction>

    Resulted with error: Unable to parse business rules: Invalid BL rule: section <Action> has unexpected element <Client>

Solution:

Call the Send function from JavaScript

<DestroySessionAction>
	<Script Language="JavaScript" FileName="../FIXEdge1/conf/sendSMTP.js"/>
</DestroySessionAction>

sendSMTP.js:

sendSMTP.js
send("SMTPClient");

Other notifications

Apart from the Email (C) message about a session state change, FIXEdge can also generate other internal notifications:

  • Logon
  • Logout
  • Sequence Gap
  • Session Reject
  • Session state change
  • Business/Overload protection events
  • Fatal error

These events have a custom message type 35=UFL defined in fixdic40.xml.

Support for internal 35=UFL messages is mandatory, hence the fixidc40.xml dictionary is mandatory for correct FIXEdge functioning.

Related pages