Custom Application KPIs

ProTop has the ability to monitor up to eight custom application numeric metrics (Key Performance Indicators or KPIs) and trend the data on the dashboard web server. The data is displayed in the Main Dashboard of the graphical portal. Use this feature to trend application metrics (number of boxes ships, number of widgets made, etc) alongside database performance metrics.

The key to this feature is $PROTOP/lib/usermon.p. If it exists, the dashboard data collector dc/dashboard.p will execute it. A simple-to-follow sample is provided in lib/usermonx.p.

To use these user-defined metrics, follow these steps:

  1. Rename or copy [PROTOPDIR]/lib/usermonx.p to lib/usermon.p
  2. Edit lib/usermon.p and add code to obtain the values you want. You can make your code specific to one database or common to all of your monitored databases. REPLICATION NOTE: If the monitored database is a replication source or target, use the "dictdb" prefix when accessing application tables otherwise you will get an error indicating the table exists in both databases. In Replication Monitoring the agent connects to both the source and the target databases which have the same schema.
  3. Assign theses values to one of the 8 user-defined fields (usrField1 to usrField8)
  4. Assign a label (usrLabel1 to userLabel8) to this field. This name will be used in the dashboard as the legend for your metric.

Note: If you are in a multi-databases environment, you will need a couple extra steps since the databases might have different schemas and usermon.p cannot be compiled:

  1. create a specific program for every database or group of databases with compatible shema, and
  2. add specific code in usermon.p to run these different programs.

Usermon.p contains two sections:

1. Initialization section

This section at the top of the procedure is used to register procedures that will respond when the main dashboard data collector calls for user defined metrics. You can register a default internal procedure to process these calls, or register specific sub programs per database, using ldbname(1) to get the name of the current database.

2. Subscription section (“Usermon” internal procedure)

This internal procedure must be defined in all procedures that need to collect and publish metrics. You can simply keep the one included in usemon.p, or include one in all of your database specific procedures. It contains the logic to calculate your KPI and store them in the user-defined fields.

Example 1 - multi database system, metrics unrelated to database tables

We have many databases, one for each region (East, Europe, West, Asia) and all have their own EDI process that records a log in a folder called /edi/logs. The log files are named after the database name (Ex.: east.log). We want to report the size of these logs for each database.

UserMon.p:

--- Initialization section ---

session:add-super-procedure( this-procedure ). 
subscribe to "usermon" anywhere run-procedure "userMon".
return.

--- Subscription section ---

procedure userMon:
define output parameter ufld1 as decimal   no-undo.
define output parameter ulbl1 as character no-undo.
        ...
define output parameter ufld8 as decimal   no-undo.
define output parameter ulbl8 as character no-undo.

/* get length of EDI log file for each database - we do not need to access to db tables */
/* We then put all the logic in this single procedure */

file-info:FILE-NAME = "/edi/logs/" + ldbname(1) + “.log”.
ASSIGN 
    ufld1 = FILE-INFO:FILE-SIZE   /* field value */
    ulbl1 = “EDI Log Size”.       /* field label used in the dashboard */
return.
end.

We have the same databases per region, but this time, we want to collect the number of open orders in each database. North America databases have a different name for the order table.

UserMon.p:

--- Initialization section ---

CASE ldbname(1):
WHEN “East” OR WHEN “West” THEN RUN VALUE(“lib/america.p”).
WHEN “Europe” THEN RUN VALUE(“lib/europe.p”).
WHEN “Asia” THEN RUN VALUE(“lib/asia.p”).
END CASE.
return.

--- Subscription section (unnecessary if all processing is done in special procedures) ---

america.p:

--- Initialization section ---

session:add-super-procedure( this-procedure ).
subscribe to "usermon" anywhere run-procedure "userMon".
return.

--- Subscription section ---

procedure userMon:
define output parameter ufld1 as decimal   no-undo.
define output parameter ulbl1 as character no-undo.
        ...
define output parameter ufld8 as decimal   no-undo.
define output parameter ulbl8 as character no-undo.

define variable cntOpenOrders as integer no-undo.

for each dictdb.order where status=”open” no-lock:
    Assign cntOpenOrders = cntOpenOrders + 1.
End.

ASSIGN 
    ufld1 = cntOpenOrders        /* field value */
    ulbl1 = “Open Orders”.       /* field label used in the dashboard */
return.
End.

europe.p:

--- Initialization section ---

session:add-super-procedure( this-procedure ).
subscribe to "usermon" anywhere run-procedure "userMon".
return.

--- Subscription section ---

procedure userMon:
define output parameter ufld1 as decimal   no-undo.
define output parameter ulbl1 as character no-undo.
        ...
define output parameter ufld8 as decimal   no-undo.
define output parameter ulbl8 as character no-undo.

define variable cntOpenOrders as integer no-undo.

for each dictdb.commandes where status=”open” no-lock:  /* table name is different for this database */
    Assign cntOpenOrders = cntOpenOrders + 1.
End.

ASSIGN 
    ufld1 = cntOpenOrders        /* field value */
    ulbl1 = “Open Orders”.       /* field label used in the dashboard */
return.
end.