April 3, 2019

Logging in automation scripts

I have to admit, I'm a big fan of automation scripts.
Recent updates released with Maximo 7.6.0.9 have almost covered all the possible customization needs including library scripts, REST APIs, MIF processing, before/after save event. All the new features are well documented in this somewhat secret document.

However whatever nice feature will be added in the next feature pack, we will never have a debugger like we have with Java and Eclipse. This could be a serious problem when you have to develop and maintain a complex set of scripts in your environment.
The best way to mitigate such problem is to correctly use Maximo logging APIs.

In my projects I usually define a custom logger in the Logging application. It's a good practice to give a short name of your customer. In this example I have defined mxdev logger for my MaximoDev customer.



I can now log messages to this custom logger using Maximo APIs. In the following example I first import the MXLoggerFactory class, then I get the reference to my mxdev logger and then I use the MxLogger APIs to write messages in the system log.


from psdi.util.logging import MXLoggerFactory

logger = MXLoggerFactory.getLogger("maximo.mxdev")

logger.info("Entering SR_INIT script for ticket " + mbo.getString("TICKETID"))
logger.debug("This is a debug message")


There are several good reasons for doing that.
  1. I can select the logging level of my scripts dynamically in the Logger applications. I typically have that set to DEBUG in development and test environment. In production I set that to WARN or INFO to reduce verbosity.
  2. Logging is always a good way of commenting the code.
  3. It allows me to search for a specific string in the scripts when I see strange behaviors in the logs.

March 18, 2019

Avoiding FetchResultStopLimit errors in Java or scripts

Today I had to face an issue deleting a large set of records from a Maximo table using an automation script. My script was something like this.

mboSet = MXServer.getMXServer().getMboSet("MYTABLE", mbo.getUserInfo())
mboSet.deleteAll()
mboSet.save()

Unfortunately the table I had to purge (MYTABLE in the example) was having more than 5000 rows so when I launched the script I got the following error.
BMXAA7387E - While attempting to retrieve 5001 of MYTABLE, the operation was terminated because the preset limit 5000 was exceeded for retrieving MYTABLE into a single set. Reduce the number of selected objects for the operation.
The simple solution would have been to increase the mxe.db.fetchResultStopLimit Maximo system parameter as documented in this post but I was looking for a more elegant solution.
Searching a little in the Maximo Java code i discovered the MboSet.setLogLargFetchResultDisabled() method that was exactly what I was looking for. Calling this method before the bulk operation will disable logging of large fetch result set to avoid FetchResultLogLimit errors. As a positive side effect it also increased the performances a lot.

The updated script now works like a charm.

mboSet = MXServer.getMXServer().getMboSet("MYTABLE", mbo.getUserInfo())
scSet.setWhere(where)
# disable logging of large fetch result set to avoid FetchResultLogLimit errors
mboSet.setLogLargFetchResultDisabled(True)
mboSet.deleteAll()
mboSet.save()

November 28, 2018

Automation Script to reset user's Start Centers

In a previous post I have explained how to force the reload of a the start center for a specific group of users.
I have now developed a useful automation script that can be invoked from the Security Group application to automatically perform this task with just one click.
Register the script as a Script with an Action Launch Point and link it to a sigoption and to a menuaction, toolbar icon or application button as described in this post or this one.


# Reset users Start Centers
# Object: MAXGROUP
# Resets the Start Centers for all users assigned to the selected Security Group
# Should be called when all users are logged off so the start center is reloaded after the login
# See: http://maximodev.blogspot.com/2012/11/how-to-reset-users-start-centers.html

from psdi.server import MXServer
from psdi.mbo import MboConstants
from psdi.util.logging import MXLoggerFactory


def deleteSc(objectName, where):
 scSet = MXServer.getMXServer().getMboSet(objectName, mbo.getUserInfo())
 scSet.setWhere(where)
 logger.debug("Deleting rows from " + objectName)
 # disable logging of large fetch result set to avoid FetchResultLogLimit errors
 scSet.setLogLargFetchResultDisabled(True)
 scSet.deleteAll()
 scSet.save()


logger = MXLoggerFactory.getLogger("maximo.maximodev")
logger.debug("Entering ASSET_INIT script")

logger.info("Entering ASTS_RESET_STARTCENTER")
grpname = mbo.getString("GROUPNAME")

where1 = "scconfigid IN (SELECT scconfigid FROM scconfig WHERE groupname='" + grpname + "')"
where2 = "layoutid IN (SELECT layoutid FROM layout WHERE " +where1+ ")"


deleteSc("RSCONFIG", where2)
deleteSc("FACONFIG", where2)
deleteSc("INBXCONFIG", where2)
deleteSc("KPILCONFIG", where2)
deleteSc("KPIGCONFIG", where2)
deleteSc("ACTIONSCFG", where2)
deleteSc("PORTLETDISPLAY", where2)
deleteSc("LAYOUT", where2)
deleteSc("SCCONFIG", where1)

September 28, 2018

MTTx Terminology

When it comes to asset reliability measurement all the different MTTx acronyms start to appear but sometimes is not clear to everybody the exact meanings of these terms.
In this post I want to give a very simple explanation of these reliability KPIs.


  • MTTD - Mean Time To Detect - How long it takes to discover a problem.
  • MTTK - Mean Time to Know - How long it takes to understand the problem.
  • MTTR - Mean Time To Repair - How long it takes to fix the problem.
  • MTTF - Mean Time To Failure - Amount of time the system is available and operating. Also known as "uptime".
  • MTBF - Mean Time Between Failures - Amount of time that elapses between one failure and the next.


MTBF is the sum of MTTF and MTTR, the total time required for a device to fail and that failure to be repaired.
MTBF = MTTR + MTTF

Here is a nice representation for these KPIs.