Table of Contents
This document gives insight on how to tailor and use Enduro/X Enterprise Edition features in your application.
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).
Following sample service will return following enduroxUserdataTable:
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:
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)
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
$ 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.
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):
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 ...
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.