User Tools

Site Tools


Sidebar

Table Of Contents

endurox-ee:v8.0.x:guides:ee_devguide

Enduro/X Enterprise Edition Developer Guide

Enduro/X Enterprise Edition Developer Guide


Chapter 1. Overview

This document gives insight on how to tailor and use Enduro/X Enterprise Edition features in your application.

Chapter 2. Custom monitoring entries via SNMP

One of the module features, is to provide developers simple way to exposing monitoring entries via SNMP channel. This can be done, thanks to eesnmpagx(8) extension to monitor user application specific tm_mib(5) class T_USERDATA. The developer shall implement the interaction protocol as described in tm_mib(5) and return the required data fields for the T_USERDATA. After such implementation, the data is exposed in format as described in ENDUROX-MIB.txt, table enduroxUserdataTable.

This section will describe the necessary steps to implement simple XATMI server, which would demonstrate how to return require data the SNMP channel.

For sake of simplicity, the implementation of SNMP user data service will be done in Python language (i.e. based on endurox-python module). However the actual implementation of the service can be done in any of Enduro/X supported language: C/C++/Java/Go (and Python).

2.1. Writing the sample service

Following sample service will return following enduroxUserdataTable:

  • Integer number
  • String, representing "system status"
  • Gauge64

The actual field value shall be denoted in TA_EX_UVTYP which are bitwise flags field. The flags can be combined. Following constants are defined:

  • 0x0001 string (exUserdataTaExUvstr have a value)
  • 0x0002 int32 (exUserdataTaExUvint32 have a value)
  • 0x0004 gauge32 (exUserdataTaExUvg32 have a value)
  • 0x0008 counter64 (exUserdataTaExUvc64 have a value)

Following example assumes that test is performed by user1 which home directory is located at /home/user1 and application is configured in snmp_test directory. Prepare directory for sample service:

$ cd /home/user1

$ mkdir snmp_test

Create SNMP data service, filename /home/user1/snmp_test/bin/snmp_metrics.py:

#!/usr/bin/env python3

import sys
import endurox as e
import random

# Get the size of a C long on the current platform
class Server:

    def tpsvrinit(self, args):
        e.tplog_info("Doing server init...");
        e.tpadvertise("USERMETRICS")
        return 0

    def tpsvrdone(self):
        e.tplog_info("Server shutdown")

    def USERMETRICS(self, args):

        e.tplogprintubf(e.log_info, "Incoming request:", args.data)

        # remember that all occurrences of the supported fields must be filled,
        # even with default values.
        # load integer value
        args.data["data"].TA_LMID[0] = e.tpgetnodeid()
        args.data["data"].TA_EX_UVNAME[0] = "txn.nr_total"
        args.data["data"].TA_EX_UVSTR[0] = ""
        args.data["data"].TA_EX_UVTYP[0] = 0x0001
        args.data["data"].TA_EX_UVINT32[0] = random.randint(1,1000)
        args.data["data"].TA_EX_UVG32[0] = 0
        args.data["data"].TA_EX_UVC64[0] = 0

        # load system status in second occurrence of the UBF buffer
        # string value
        args.data["data"].TA_LMID[1] = e.tpgetnodeid()
        args.data["data"].TA_EX_UVNAME[1] = "system.status"
        args.data["data"].TA_EX_UVSTR[1] = "nominal"
        args.data["data"].TA_EX_UVTYP[1] = 0x0002
        args.data["data"].TA_EX_UVINT32[1] = 0
        args.data["data"].TA_EX_UVG32[1] = 0
        args.data["data"].TA_EX_UVC64[1] = 0

        # gauge64 value
        args.data["data"].TA_LMID[2] = e.tpgetnodeid()
        args.data["data"].TA_EX_UVNAME[2] = "txn.nr_approved"
        args.data["data"].TA_EX_UVSTR[2] = ""
        args.data["data"].TA_EX_UVTYP[2] = 0x0008
        args.data["data"].TA_EX_UVINT32[2] = 0
        args.data["data"].TA_EX_UVG32[2] = 0
        args.data["data"].TA_EX_UVC64[2] = 12312444

        # OK approve the buffer...
        args.data["data"].TA_ERROR = 0

        # No more data for this request. Multiple "reqeusts/pages" are supported, but for sake of
        # the simplicity, that is not used in this example.
        # if that is required for some reason, see the details in *tm_mib(5)* man page.
        args.data["data"].TA_MORE = 0
        # number of occurrences of data loaded.
        args.data["data"].TA_OCCURS = 3
        args.data["data"].TA_CURSOR = "some_unique_cursor"
        args.data["data"].TA_STATUS = "OK"

        return e.tpreturn(e.TPSUCCESS, 0, args.data)

if __name__ == "__main__":
    e.tprun(Server(), sys.argv)

2.2. Configuring the runtime system

This assumes that Net-SNMP is already configured according to the Enduro/X EE Administration Manual.

Provision a runtime. Following example assumes that test is performed by user1 which home directory, which is located at /home/user1.

-- provision runtime and use defaults
$ xadmin provision -d -y

-- ensure that our sample service has execute permissions
$ chmod +x /home/user1/snmp_test/bin/snmp_metrics.py

Update process definition file ndrxconfig.xml(5), so that Enduro/X would start the SNMP metrics service, as well as the eesnmpagx.

edit /home/user1/snmp_test/conf/ndrxconfig.xml file:

...
        ...

        <!-- New service, start. Shall be started somewhere before cpmsrv -->

        <server name="snmp_metrics.py">
            <min>1</min>
            <max>1</max>
            <srvid>500</srvid>
            <sysopt>-e ${NDRX_ULOG}/snmp_metrics.log -- </sysopt>
        </server>

        <!-- New service, end -->
        ...
        <server name="cpmsrv">
            <min>1</min>
            <max>1</max>
            <srvid>9999</srvid>
            <sysopt>-e ${NDRX_ULOG}/cpmsrv.log -r -- -k3 -i1</sysopt>
        </server>
    </servers>
    <clients>
        ...
        <!-- ensure that eesnmpagx binary is started -->
       <client cmdline="eesnmpagx">
           <exec tag="SNMP" autostart="Y" log="${NDRX_ULOG}/eesnmpagx.log"/>
       </client>
    </clients>

...

app.ini shall be modified, to have the configuration for the eesnmpagx. User data service shall be configured. Additionally, Excompat UBF field table shall be registered with the Enduro/X, this table contains the UBF fields used by the SNMP engine (thos fields are dynamically used by the snmp_metrics.py script).

Edit /home/user1/snmp_test/conf/app.ini:

[@global]
...
# Add "Excompat"
FIELDTBLS=Exfields,Excompat

/usr/share/endurox/ubftab
# append FLDTBLDIR with the standard location of the Enduro/X field table
# file path, as Excompat is not provided to the application directory by the
# xadmin provision script:
FLDTBLDIR=${NDRX_APPHOME}/ubftab:/usr/share/endurox/ubftab

...

# add new section for eesnmpagx:
[@eesnmpagx]
host=127.0.0.1
port=705
userdatasvc=USERMETRICS

2.3. Start the application and read the metrics

$ cd /home/user1/snmp_test/conf

$ source settest1

$ xadmin start -y

Enduro/X 8.0.8, build Jul 27 2023 23:42:33, using epoll for LINUX (64 bits)

Enduro/X Middleware Platform for Distributed Transaction Processing
Copyright (C) 2009-2016 ATR Baltic Ltd.
Copyright (C) 2017-2023 Mavimax Ltd. All Rights Reserved.

This software is released under one of the following licenses:
AGPLv3 (exceptions for Java, Go) or Mavimax license for commercial use.

* Shared resources opened...
* Enduro/X back-end (ndrxd) is not running
* ndrxd PID (from PID file): 37331
* ndrxd idle instance started.
exec cconfsrv -k 0myWI5nu -i 1 -e /home/user1/snmp_test/log/cconfsrv.log -r --  :
        process id=37333 ... Started.
exec cconfsrv -k 0myWI5nu -i 2 -e /home/user1/snmp_test/log/cconfsrv.log -r --  :
        process id=37334 ... Started.
exec tpadmsv -k 0myWI5nu -i 10 -e /home/user1/snmp_test/log/tpadmsv.log -r --  :
...
exec snmp_metrics.py -k 0myWI5nu -i 500 -e /home/user1/snmp_test/log/snmp_metrics.log --  --  :
        process id=37414 ... Started.

-- Check the service status:
$ xadmin psc  | grep USER
...
* Shared resources opened...
* ndrxd PID (from PID file): 37331
Nd Service Name Routine Name Prog Name SRVID #SUCC #FAIL      MAX     LAST STAT
-- ------------ ------------ --------- ----- ----- ----- -------- -------- -----
 1 USERMETRICS  USERMETRICS  snmp_met+   500     0     0      0ms      0ms AVAIL

-- Check the eesnmpagx process status
$ xadmin pc
...
SNMP/- - running pid 38039 (Sat Jul 29 22:52:30 2023)

Once application is booted, snmpwalk will be used to show the entries read via SNMP:

$ snmpwalk -v 2c -c public localhost ENDUROX-MIB::enduroxUserdataTable

ENDUROX-MIB::exUserdataAgNodeid.1.1."txn.nr_total" = INTEGER: 1
ENDUROX-MIB::exUserdataAgNodeid.1.1."system.status" = INTEGER: 1
ENDUROX-MIB::exUserdataAgNodeid.1.1."txn.nr_approved" = INTEGER: 1
ENDUROX-MIB::exUserdataTaLmid.1.1."txn.nr_total" = INTEGER: 1
ENDUROX-MIB::exUserdataTaLmid.1.1."system.status" = INTEGER: 1
ENDUROX-MIB::exUserdataTaLmid.1.1."txn.nr_approved" = INTEGER: 1
ENDUROX-MIB::exUserdataTaExUvname.1.1."txn.nr_total" = STRING: "txn.nr_total"
ENDUROX-MIB::exUserdataTaExUvname.1.1."system.status" = STRING: "system.status"
ENDUROX-MIB::exUserdataTaExUvname.1.1."txn.nr_approved" = STRING: "txn.nr_approved"
ENDUROX-MIB::exUserdataTaExUvtyp.1.1."txn.nr_total" = INTEGER: 1
ENDUROX-MIB::exUserdataTaExUvtyp.1.1."system.status" = INTEGER: 2
ENDUROX-MIB::exUserdataTaExUvtyp.1.1."txn.nr_approved" = INTEGER: 8
ENDUROX-MIB::exUserdataTaExUvstr.1.1."txn.nr_total" = ""
ENDUROX-MIB::exUserdataTaExUvstr.1.1."system.status" = STRING: "nominal"
ENDUROX-MIB::exUserdataTaExUvstr.1.1."txn.nr_approved" = ""
ENDUROX-MIB::exUserdataTaExUvint32.1.1."txn.nr_total" = INTEGER: 754
ENDUROX-MIB::exUserdataTaExUvint32.1.1."system.status" = INTEGER: 0
ENDUROX-MIB::exUserdataTaExUvint32.1.1."txn.nr_approved" = INTEGER: 0
ENDUROX-MIB::exUserdataTaExUvg32.1.1."txn.nr_total" = Gauge32: 0
ENDUROX-MIB::exUserdataTaExUvg32.1.1."system.status" = Gauge32: 0
ENDUROX-MIB::exUserdataTaExUvg32.1.1."txn.nr_approved" = Gauge32: 0
ENDUROX-MIB::exUserdataTaExUvc64.1.1."txn.nr_total" = Counter64: 0
ENDUROX-MIB::exUserdataTaExUvc64.1.1."system.status" = Counter64: 0
ENDUROX-MIB::exUserdataTaExUvc64.1.1."txn.nr_approved" = Counter64: 12312444
ENDUROX-MIB::exUserdataTaExUvc64.1.1."txn.nr_approved" = No more variables left in this MIB View (It is past the end of the MIB tree)

As it could be seen from snmpwalk output, that all data items are successfully returned from the metrics service.

2.4. Ulog Trap messages

Enduro/X SNMP handler can be enabled to monitor for ULOG messages and post them as a SNMP traps. If setting is enabled (trap_enable=1 added to the [@eesnmpagx] section), for every ULOG message, trap enduroxUlogNotification is generated. Trap messages has severity, which is extracted from ULOG message (case of the keyword is ignored):

  • Severity codes: 1 - fatal, in case if "fatal" is found in the message.
  • Severity codes: 2 - error, in case if "error", "info" or "died" is found in the message in any case.
  • Severity codes: 3 - warning, in case if "warn" or "warning" is found the message.
  • Severity codes: 4 - info, in case if "info" is found the message. This also is default level, if no keywords found in the userlog(3) message text.
  • Severity codes: 5 - debug, in case if "debug" or "trace" is found the message.

NOTE: eesnmpagx(8) parses ULOG from the file end position which is at the moment, when eesnmpagx(8) is started. This means that messages written to userlog(3) before the eesnmpagx run would not be sent to SNMP trap handlers (e.g. system boot, services init ulog entries).

To demonstrate the trap functionality, lets add service for our metrics XATMI server, which would trigger traps by userlog() entries. This demonstration assumes that trap configuration is performed according to the Enduro/X EE Administration Manual.

Edit /home/user1/snmp_test/bin/snmp_metrics.py:

    def tpsvrinit(self, args):
        e.tplog_info("Doing server init...");
        e.tpadvertise("USERMETRICS")

        # New service:
        e.tpadvertise("GENTRAP")

        return 0
    ...

    # New service code:
    def GENTRAP(self, args):

        e.userlog("Trap service called")
        e.userlog("WARNING: new metrics shall be added to this server")

        return e.tpreturn(e.TPSUCCESS, 0, args.data)

Updated the app.ini configuration file, for having trap sending enabled:

Edit /home/user1/snmp_test/conf/app.ini:

...

# add new section for eesnmpagx:
[@eesnmpagx]
...
# added new flag:
trap_enable=1

Restart relevant services to activate new functionality. For trap generation service call, ud(8) utility is used. In this example empty UBF buffer is set to GENTRAP service.

-- Restart eesnmpagx client:
$ xadmin rc SNMP

-- Restart service:
$ xadmin restart snmp_metrics.py

-- Make a call (NOTE: tab is needed between "SVCNM" and "GENTRAP"):
$ cat << EOF | ud
SRVCNM  GENTRAP

EOF

Wait some few seconds, and check the traps file:

$ tail /var/log/snmptt/snmptt.log

...
Mon Jul 31 01:09:14 2023 ENDUROX-MIB::enduroxUlogNotification Normal "Status Events" 172.19.0.2 - Ulog entry 1 1 info 20230730 22091386 84092 python3 Trap service called
Mon Jul 31 01:09:14 2023 ENDUROX-MIB::enduroxUlogNotification Normal "Status Events" 172.19.0.2 - Ulog entry 1 1 warning 20230730 22091386 84092 python3 WARNING: new metrics shall be added to this server
...

Chapter 3. Conclusions

The Enduro/X EE module provides developers with a range of features to enhance the system’s functionality. One notable feature is SNMP, which simplifies the process of exposing user application data using an industry-standard protocol for application monitoring.

SNMP is widely supported by various monitoring suites and serves as the de facto standard for network management and monitoring. By implementing the SNMP protocol in the Enduro/X EE module, developers gain unlimited options for monitoring their applications.

This streamlined approach enables developers to focus on the core functionalities of their application without getting bogged down in the complexities of SNMP protocol implementation. As a result, developers can save valuable development time, reduce potential errors, and enjoy a more straightforward integration process.